1//===- ReducerWorkItem.cpp - Wrapper for Module and MachineFunction -------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ReducerWorkItem.h"
10#include "TestRunner.h"
11#include "llvm/Analysis/ModuleSummaryAnalysis.h"
12#include "llvm/Analysis/ProfileSummaryInfo.h"
13#include "llvm/Bitcode/BitcodeReader.h"
14#include "llvm/Bitcode/BitcodeWriter.h"
15#include "llvm/CodeGen/CommandFlags.h"
16#include "llvm/CodeGen/MIRParser/MIRParser.h"
17#include "llvm/CodeGen/MIRPrinter.h"
18#include "llvm/CodeGen/MachineDominators.h"
19#include "llvm/CodeGen/MachineFrameInfo.h"
20#include "llvm/CodeGen/MachineFunction.h"
21#include "llvm/CodeGen/MachineJumpTableInfo.h"
22#include "llvm/CodeGen/MachineModuleInfo.h"
23#include "llvm/CodeGen/MachineRegisterInfo.h"
24#include "llvm/CodeGen/PseudoSourceValueManager.h"
25#include "llvm/CodeGen/TargetInstrInfo.h"
26#include "llvm/IR/Constants.h"
27#include "llvm/IR/Instructions.h"
28#include "llvm/IR/ModuleSummaryIndex.h"
29#include "llvm/IR/Operator.h"
30#include "llvm/IR/Verifier.h"
31#include "llvm/IRReader/IRReader.h"
32#include "llvm/MC/TargetRegistry.h"
33#include "llvm/Passes/PassBuilder.h"
34#include "llvm/Support/MemoryBufferRef.h"
35#include "llvm/Support/SourceMgr.h"
36#include "llvm/Support/TargetSelect.h"
37#include "llvm/Support/ToolOutputFile.h"
38#include "llvm/Support/WithColor.h"
39#include "llvm/Target/TargetMachine.h"
40#include "llvm/TargetParser/Host.h"
41#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
42#include "llvm/Transforms/Utils/Cloning.h"
43#include <optional>
44
45using namespace llvm;
46
47ReducerWorkItem::ReducerWorkItem() = default;
48ReducerWorkItem::~ReducerWorkItem() = default;
49
50extern cl::OptionCategory LLVMReduceOptions;
51static cl::opt<std::string> TargetTriple("mtriple",
52 cl::desc("Set the target triple"),
53 cl::cat(LLVMReduceOptions));
54static cl::opt<bool> PrintInvalidMachineReductions(
55 "print-invalid-reduction-machine-verifier-errors",
56 cl::desc(
57 "Print machine verifier errors on invalid reduction attempts triple"),
58 cl::cat(LLVMReduceOptions));
59
60static cl::opt<bool> TmpFilesAsBitcode(
61 "write-tmp-files-as-bitcode",
62 cl::desc("Always write temporary files as bitcode instead of textual IR"),
63 cl::init(Val: false), cl::cat(LLVMReduceOptions));
64
65static void cloneFrameInfo(
66 MachineFrameInfo &DstMFI, const MachineFrameInfo &SrcMFI,
67 const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) {
68 DstMFI.setFrameAddressIsTaken(SrcMFI.isFrameAddressTaken());
69 DstMFI.setReturnAddressIsTaken(SrcMFI.isReturnAddressTaken());
70 DstMFI.setHasStackMap(SrcMFI.hasStackMap());
71 DstMFI.setHasPatchPoint(SrcMFI.hasPatchPoint());
72 DstMFI.setUseLocalStackAllocationBlock(
73 SrcMFI.getUseLocalStackAllocationBlock());
74 DstMFI.setOffsetAdjustment(SrcMFI.getOffsetAdjustment());
75
76 DstMFI.ensureMaxAlignment(Alignment: SrcMFI.getMaxAlign());
77 assert(DstMFI.getMaxAlign() == SrcMFI.getMaxAlign() &&
78 "we need to set exact alignment");
79
80 DstMFI.setAdjustsStack(SrcMFI.adjustsStack());
81 DstMFI.setHasCalls(SrcMFI.hasCalls());
82 DstMFI.setHasOpaqueSPAdjustment(SrcMFI.hasOpaqueSPAdjustment());
83 DstMFI.setHasCopyImplyingStackAdjustment(
84 SrcMFI.hasCopyImplyingStackAdjustment());
85 DstMFI.setHasVAStart(SrcMFI.hasVAStart());
86 DstMFI.setHasMustTailInVarArgFunc(SrcMFI.hasMustTailInVarArgFunc());
87 DstMFI.setHasTailCall(SrcMFI.hasTailCall());
88
89 if (SrcMFI.isMaxCallFrameSizeComputed())
90 DstMFI.setMaxCallFrameSize(SrcMFI.getMaxCallFrameSize());
91
92 DstMFI.setCVBytesOfCalleeSavedRegisters(
93 SrcMFI.getCVBytesOfCalleeSavedRegisters());
94
95 if (MachineBasicBlock *SavePt = SrcMFI.getSavePoint())
96 DstMFI.setSavePoint(Src2DstMBB.find(Val: SavePt)->second);
97 if (MachineBasicBlock *RestorePt = SrcMFI.getRestorePoint())
98 DstMFI.setRestorePoint(Src2DstMBB.find(Val: RestorePt)->second);
99
100
101 auto CopyObjectProperties = [](MachineFrameInfo &DstMFI,
102 const MachineFrameInfo &SrcMFI, int FI) {
103 if (SrcMFI.isStatepointSpillSlotObjectIndex(ObjectIdx: FI))
104 DstMFI.markAsStatepointSpillSlotObjectIndex(ObjectIdx: FI);
105 DstMFI.setObjectSSPLayout(ObjectIdx: FI, Kind: SrcMFI.getObjectSSPLayout(ObjectIdx: FI));
106 DstMFI.setObjectZExt(ObjectIdx: FI, IsZExt: SrcMFI.isObjectZExt(ObjectIdx: FI));
107 DstMFI.setObjectSExt(ObjectIdx: FI, IsSExt: SrcMFI.isObjectSExt(ObjectIdx: FI));
108 };
109
110 for (int i = 0, e = SrcMFI.getNumObjects() - SrcMFI.getNumFixedObjects();
111 i != e; ++i) {
112 int NewFI;
113
114 assert(!SrcMFI.isFixedObjectIndex(i));
115 if (SrcMFI.isVariableSizedObjectIndex(ObjectIdx: i)) {
116 NewFI = DstMFI.CreateVariableSizedObject(Alignment: SrcMFI.getObjectAlign(ObjectIdx: i),
117 Alloca: SrcMFI.getObjectAllocation(ObjectIdx: i));
118 } else {
119 NewFI = DstMFI.CreateStackObject(
120 Size: SrcMFI.getObjectSize(ObjectIdx: i), Alignment: SrcMFI.getObjectAlign(ObjectIdx: i),
121 isSpillSlot: SrcMFI.isSpillSlotObjectIndex(ObjectIdx: i), Alloca: SrcMFI.getObjectAllocation(ObjectIdx: i),
122 ID: SrcMFI.getStackID(ObjectIdx: i));
123 DstMFI.setObjectOffset(ObjectIdx: NewFI, SPOffset: SrcMFI.getObjectOffset(ObjectIdx: i));
124 }
125
126 CopyObjectProperties(DstMFI, SrcMFI, i);
127
128 (void)NewFI;
129 assert(i == NewFI && "expected to keep stable frame index numbering");
130 }
131
132 // Copy the fixed frame objects backwards to preserve frame index numbers,
133 // since CreateFixedObject uses front insertion.
134 for (int i = -1; i >= (int)-SrcMFI.getNumFixedObjects(); --i) {
135 assert(SrcMFI.isFixedObjectIndex(i));
136 int NewFI = DstMFI.CreateFixedObject(
137 Size: SrcMFI.getObjectSize(ObjectIdx: i), SPOffset: SrcMFI.getObjectOffset(ObjectIdx: i),
138 IsImmutable: SrcMFI.isImmutableObjectIndex(ObjectIdx: i), isAliased: SrcMFI.isAliasedObjectIndex(ObjectIdx: i));
139 CopyObjectProperties(DstMFI, SrcMFI, i);
140
141 (void)NewFI;
142 assert(i == NewFI && "expected to keep stable frame index numbering");
143 }
144
145 for (unsigned I = 0, E = SrcMFI.getLocalFrameObjectCount(); I < E; ++I) {
146 auto LocalObject = SrcMFI.getLocalFrameObjectMap(i: I);
147 DstMFI.mapLocalFrameObject(ObjectIndex: LocalObject.first, Offset: LocalObject.second);
148 }
149
150 DstMFI.setCalleeSavedInfo(SrcMFI.getCalleeSavedInfo());
151
152 if (SrcMFI.hasStackProtectorIndex()) {
153 DstMFI.setStackProtectorIndex(SrcMFI.getStackProtectorIndex());
154 }
155
156 // FIXME: Needs test, missing MIR serialization.
157 if (SrcMFI.hasFunctionContextIndex()) {
158 DstMFI.setFunctionContextIndex(SrcMFI.getFunctionContextIndex());
159 }
160}
161
162static void cloneJumpTableInfo(
163 MachineFunction &DstMF, const MachineJumpTableInfo &SrcJTI,
164 const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) {
165
166 auto *DstJTI = DstMF.getOrCreateJumpTableInfo(JTEntryKind: SrcJTI.getEntryKind());
167
168 std::vector<MachineBasicBlock *> DstBBs;
169
170 for (const MachineJumpTableEntry &Entry : SrcJTI.getJumpTables()) {
171 for (MachineBasicBlock *X : Entry.MBBs)
172 DstBBs.push_back(x: Src2DstMBB.find(Val: X)->second);
173
174 DstJTI->createJumpTableIndex(DestBBs: DstBBs);
175 DstBBs.clear();
176 }
177}
178
179static void cloneMemOperands(MachineInstr &DstMI, MachineInstr &SrcMI,
180 MachineFunction &SrcMF, MachineFunction &DstMF) {
181 // The new MachineMemOperands should be owned by the new function's
182 // Allocator.
183 PseudoSourceValueManager &PSVMgr = DstMF.getPSVManager();
184
185 // We also need to remap the PseudoSourceValues from the new function's
186 // PseudoSourceValueManager.
187 SmallVector<MachineMemOperand *, 2> NewMMOs;
188 for (MachineMemOperand *OldMMO : SrcMI.memoperands()) {
189 MachinePointerInfo NewPtrInfo(OldMMO->getPointerInfo());
190 if (const PseudoSourceValue *PSV =
191 dyn_cast_if_present<const PseudoSourceValue *>(Val&: NewPtrInfo.V)) {
192 switch (PSV->kind()) {
193 case PseudoSourceValue::Stack:
194 NewPtrInfo.V = PSVMgr.getStack();
195 break;
196 case PseudoSourceValue::GOT:
197 NewPtrInfo.V = PSVMgr.getGOT();
198 break;
199 case PseudoSourceValue::JumpTable:
200 NewPtrInfo.V = PSVMgr.getJumpTable();
201 break;
202 case PseudoSourceValue::ConstantPool:
203 NewPtrInfo.V = PSVMgr.getConstantPool();
204 break;
205 case PseudoSourceValue::FixedStack:
206 NewPtrInfo.V = PSVMgr.getFixedStack(
207 FI: cast<FixedStackPseudoSourceValue>(Val: PSV)->getFrameIndex());
208 break;
209 case PseudoSourceValue::GlobalValueCallEntry:
210 NewPtrInfo.V = PSVMgr.getGlobalValueCallEntry(
211 GV: cast<GlobalValuePseudoSourceValue>(Val: PSV)->getValue());
212 break;
213 case PseudoSourceValue::ExternalSymbolCallEntry:
214 NewPtrInfo.V = PSVMgr.getExternalSymbolCallEntry(
215 ES: cast<ExternalSymbolPseudoSourceValue>(Val: PSV)->getSymbol());
216 break;
217 case PseudoSourceValue::TargetCustom:
218 default:
219 // FIXME: We have no generic interface for allocating custom PSVs.
220 report_fatal_error(reason: "Cloning TargetCustom PSV not handled");
221 }
222 }
223
224 MachineMemOperand *NewMMO = DstMF.getMachineMemOperand(
225 PtrInfo: NewPtrInfo, f: OldMMO->getFlags(), MemTy: OldMMO->getMemoryType(),
226 base_alignment: OldMMO->getBaseAlign(), AAInfo: OldMMO->getAAInfo(), Ranges: OldMMO->getRanges(),
227 SSID: OldMMO->getSyncScopeID(), Ordering: OldMMO->getSuccessOrdering(),
228 FailureOrdering: OldMMO->getFailureOrdering());
229 NewMMOs.push_back(Elt: NewMMO);
230 }
231
232 DstMI.setMemRefs(MF&: DstMF, MemRefs: NewMMOs);
233}
234
235static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF,
236 MachineModuleInfo &DestMMI) {
237 auto DstMF = std::make_unique<MachineFunction>(
238 args&: SrcMF->getFunction(), args: SrcMF->getTarget(), args: SrcMF->getSubtarget(),
239 args&: SrcMF->getContext(), args: SrcMF->getFunctionNumber());
240 DenseMap<MachineBasicBlock *, MachineBasicBlock *> Src2DstMBB;
241
242 auto *SrcMRI = &SrcMF->getRegInfo();
243 auto *DstMRI = &DstMF->getRegInfo();
244
245 // Clone blocks.
246 for (MachineBasicBlock &SrcMBB : *SrcMF) {
247 MachineBasicBlock *DstMBB =
248 DstMF->CreateMachineBasicBlock(BB: SrcMBB.getBasicBlock());
249 Src2DstMBB[&SrcMBB] = DstMBB;
250
251 DstMBB->setCallFrameSize(SrcMBB.getCallFrameSize());
252
253 if (SrcMBB.isIRBlockAddressTaken())
254 DstMBB->setAddressTakenIRBlock(SrcMBB.getAddressTakenIRBlock());
255 if (SrcMBB.isMachineBlockAddressTaken())
256 DstMBB->setMachineBlockAddressTaken();
257
258 // FIXME: This is not serialized
259 if (SrcMBB.hasLabelMustBeEmitted())
260 DstMBB->setLabelMustBeEmitted();
261
262 DstMBB->setAlignment(SrcMBB.getAlignment());
263
264 // FIXME: This is not serialized
265 DstMBB->setMaxBytesForAlignment(SrcMBB.getMaxBytesForAlignment());
266
267 DstMBB->setIsEHPad(SrcMBB.isEHPad());
268 DstMBB->setIsEHScopeEntry(SrcMBB.isEHScopeEntry());
269 DstMBB->setIsEHContTarget(SrcMBB.isEHContTarget());
270 DstMBB->setIsEHFuncletEntry(SrcMBB.isEHFuncletEntry());
271
272 // FIXME: These are not serialized
273 DstMBB->setIsCleanupFuncletEntry(SrcMBB.isCleanupFuncletEntry());
274 DstMBB->setIsBeginSection(SrcMBB.isBeginSection());
275 DstMBB->setIsEndSection(SrcMBB.isEndSection());
276
277 DstMBB->setSectionID(SrcMBB.getSectionID());
278 DstMBB->setIsInlineAsmBrIndirectTarget(
279 SrcMBB.isInlineAsmBrIndirectTarget());
280
281 // FIXME: This is not serialized
282 if (std::optional<uint64_t> Weight = SrcMBB.getIrrLoopHeaderWeight())
283 DstMBB->setIrrLoopHeaderWeight(*Weight);
284 }
285
286 const MachineFrameInfo &SrcMFI = SrcMF->getFrameInfo();
287 MachineFrameInfo &DstMFI = DstMF->getFrameInfo();
288
289 // Copy stack objects and other info
290 cloneFrameInfo(DstMFI, SrcMFI, Src2DstMBB);
291
292 if (MachineJumpTableInfo *SrcJTI = SrcMF->getJumpTableInfo()) {
293 cloneJumpTableInfo(DstMF&: *DstMF, SrcJTI: *SrcJTI, Src2DstMBB);
294 }
295
296 // Remap the debug info frame index references.
297 DstMF->VariableDbgInfos = SrcMF->VariableDbgInfos;
298
299 // Clone virtual registers
300 for (unsigned I = 0, E = SrcMRI->getNumVirtRegs(); I != E; ++I) {
301 Register Reg = Register::index2VirtReg(Index: I);
302 Register NewReg = DstMRI->createIncompleteVirtualRegister(
303 Name: SrcMRI->getVRegName(Reg));
304 assert(NewReg == Reg && "expected to preserve virtreg number");
305
306 DstMRI->setRegClassOrRegBank(Reg: NewReg, RCOrRB: SrcMRI->getRegClassOrRegBank(Reg));
307
308 LLT RegTy = SrcMRI->getType(Reg);
309 if (RegTy.isValid())
310 DstMRI->setType(VReg: NewReg, Ty: RegTy);
311
312 // Copy register allocation hints.
313 const auto *Hints = SrcMRI->getRegAllocationHints(VReg: Reg);
314 if (Hints)
315 for (Register PrefReg : Hints->second)
316 DstMRI->addRegAllocationHint(VReg: NewReg, PrefReg);
317 }
318
319 const TargetSubtargetInfo &STI = DstMF->getSubtarget();
320 const TargetInstrInfo *TII = STI.getInstrInfo();
321 const TargetRegisterInfo *TRI = STI.getRegisterInfo();
322
323 // Link blocks.
324 for (auto &SrcMBB : *SrcMF) {
325 auto *DstMBB = Src2DstMBB[&SrcMBB];
326 DstMF->push_back(MBB: DstMBB);
327
328 for (auto It = SrcMBB.succ_begin(), IterEnd = SrcMBB.succ_end();
329 It != IterEnd; ++It) {
330 auto *SrcSuccMBB = *It;
331 auto *DstSuccMBB = Src2DstMBB[SrcSuccMBB];
332 DstMBB->addSuccessor(Succ: DstSuccMBB, Prob: SrcMBB.getSuccProbability(Succ: It));
333 }
334
335 for (auto &LI : SrcMBB.liveins_dbg())
336 DstMBB->addLiveIn(RegMaskPair: LI);
337
338 // Make sure MRI knows about registers clobbered by unwinder.
339 if (DstMBB->isEHPad()) {
340 if (auto *RegMask = TRI->getCustomEHPadPreservedMask(MF: *DstMF))
341 DstMRI->addPhysRegsUsedFromRegMask(RegMask);
342 }
343 }
344
345 // Track predefined/named regmasks which we ignore.
346 DenseSet<const uint32_t *> ConstRegisterMasks(llvm::from_range,
347 TRI->getRegMasks());
348
349 // Clone instructions.
350 for (auto &SrcMBB : *SrcMF) {
351 auto *DstMBB = Src2DstMBB[&SrcMBB];
352 for (auto &SrcMI : SrcMBB) {
353 const auto &MCID = TII->get(Opcode: SrcMI.getOpcode());
354 auto *DstMI = DstMF->CreateMachineInstr(MCID, DL: SrcMI.getDebugLoc(),
355 /*NoImplicit=*/true);
356 DstMI->setFlags(SrcMI.getFlags());
357 DstMI->setAsmPrinterFlag(SrcMI.getAsmPrinterFlags());
358
359 DstMBB->push_back(MI: DstMI);
360 for (auto &SrcMO : SrcMI.operands()) {
361 MachineOperand DstMO(SrcMO);
362 DstMO.clearParent();
363
364 // Update MBB.
365 if (DstMO.isMBB())
366 DstMO.setMBB(Src2DstMBB[DstMO.getMBB()]);
367 else if (DstMO.isRegMask()) {
368 DstMRI->addPhysRegsUsedFromRegMask(RegMask: DstMO.getRegMask());
369
370 if (!ConstRegisterMasks.count(V: DstMO.getRegMask())) {
371 uint32_t *DstMask = DstMF->allocateRegMask();
372 std::memcpy(dest: DstMask, src: SrcMO.getRegMask(),
373 n: sizeof(*DstMask) *
374 MachineOperand::getRegMaskSize(NumRegs: TRI->getNumRegs()));
375 DstMO.setRegMask(DstMask);
376 }
377 }
378
379 DstMI->addOperand(Op: DstMO);
380 }
381
382 cloneMemOperands(DstMI&: *DstMI, SrcMI, SrcMF&: *SrcMF, DstMF&: *DstMF);
383 }
384 }
385
386 DstMF->setAlignment(SrcMF->getAlignment());
387 DstMF->setExposesReturnsTwice(SrcMF->exposesReturnsTwice());
388 DstMF->setHasInlineAsm(SrcMF->hasInlineAsm());
389 DstMF->setHasWinCFI(SrcMF->hasWinCFI());
390
391 DstMF->getProperties().reset().set(SrcMF->getProperties());
392
393 if (!SrcMF->getFrameInstructions().empty() ||
394 !SrcMF->getLongjmpTargets().empty() || !SrcMF->getEHContTargets().empty())
395 report_fatal_error(reason: "cloning not implemented for machine function property");
396
397 DstMF->setCallsEHReturn(SrcMF->callsEHReturn());
398 DstMF->setCallsUnwindInit(SrcMF->callsUnwindInit());
399 DstMF->setHasEHContTarget(SrcMF->hasEHContTarget());
400 DstMF->setHasEHScopes(SrcMF->hasEHScopes());
401 DstMF->setHasEHFunclets(SrcMF->hasEHFunclets());
402 DstMF->setHasFakeUses(SrcMF->hasFakeUses());
403 DstMF->setIsOutlined(SrcMF->isOutlined());
404
405 if (!SrcMF->getLandingPads().empty() ||
406 !SrcMF->getCodeViewAnnotations().empty() ||
407 !SrcMF->getTypeInfos().empty() ||
408 !SrcMF->getFilterIds().empty() ||
409 SrcMF->hasAnyWasmLandingPadIndex() ||
410 SrcMF->hasAnyCallSiteLandingPad() ||
411 SrcMF->hasAnyCallSiteLabel() ||
412 !SrcMF->getCallSitesInfo().empty())
413 report_fatal_error(reason: "cloning not implemented for machine function property");
414
415 DstMF->setDebugInstrNumberingCount(SrcMF->DebugInstrNumberingCount);
416
417 if (!DstMF->cloneInfoFrom(OrigMF: *SrcMF, Src2DstMBB))
418 report_fatal_error(reason: "target does not implement MachineFunctionInfo cloning");
419
420 DstMRI->freezeReservedRegs();
421
422 DstMF->verify(p: nullptr, Banner: "", OS: &errs(), /*AbortOnError=*/true);
423 return DstMF;
424}
425
426static void initializeTargetInfo() {
427 InitializeAllTargets();
428 InitializeAllTargetMCs();
429 InitializeAllAsmPrinters();
430 InitializeAllAsmParsers();
431}
432
433void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {
434 if (MMI) {
435 printMIR(OS&: ROS, M: *M);
436 for (Function &F : *M) {
437 if (auto *MF = MMI->getMachineFunction(F))
438 printMIR(OS&: ROS, MMI: *MMI, MF: *MF);
439 }
440 } else {
441 M->print(OS&: ROS, /*AssemblyAnnotationWriter=*/AAW: nullptr,
442 /*ShouldPreserveUseListOrder=*/true);
443 }
444}
445
446bool ReducerWorkItem::verify(raw_fd_ostream *OS) const {
447 if (verifyModule(M: *M, OS))
448 return true;
449
450 if (!MMI)
451 return false;
452
453 for (const Function &F : getModule()) {
454 if (const MachineFunction *MF = MMI->getMachineFunction(F)) {
455 // With the current state of quality, most reduction attempts fail the
456 // machine verifier. Avoid spamming large function dumps on nearly every
457 // attempt until the situation is better.
458 if (!MF->verify(p: nullptr, Banner: "",
459 /*OS=*/PrintInvalidMachineReductions ? &errs() : nullptr,
460 /*AbortOnError=*/false)) {
461
462 if (!PrintInvalidMachineReductions) {
463 WithColor::warning(OS&: errs())
464 << "reduction attempt on function '" << MF->getName()
465 << "' failed machine verifier (debug with "
466 "-print-invalid-reduction-machine-verifier-errors)\n";
467 }
468 return true;
469 }
470 }
471 }
472
473 return false;
474}
475
476bool ReducerWorkItem::isReduced(const TestRunner &Test) const {
477 const bool UseBitcode = Test.inputIsBitcode() || TmpFilesAsBitcode;
478
479 SmallString<128> CurrentFilepath;
480
481 // Write ReducerWorkItem to tmp file
482 int FD;
483 std::error_code EC = sys::fs::createTemporaryFile(
484 Prefix: "llvm-reduce", Suffix: isMIR() ? "mir" : (UseBitcode ? "bc" : "ll"), ResultFD&: FD,
485 ResultPath&: CurrentFilepath,
486 Flags: UseBitcode && !isMIR() ? sys::fs::OF_None : sys::fs::OF_Text);
487 if (EC) {
488 WithColor::error(OS&: errs(), Prefix: Test.getToolName())
489 << "error making unique filename: " << EC.message() << '\n';
490 exit(status: 1);
491 }
492
493 ToolOutputFile Out(CurrentFilepath, FD);
494
495 writeOutput(OS&: Out.os(), EmitBitcode: UseBitcode);
496
497 Out.os().close();
498 if (Out.os().has_error()) {
499 WithColor::error(OS&: errs(), Prefix: Test.getToolName())
500 << "error emitting bitcode to file '" << CurrentFilepath
501 << "': " << Out.os().error().message() << '\n';
502 exit(status: 1);
503 }
504
505 // Current Chunks aren't interesting
506 return Test.run(Filename: CurrentFilepath);
507}
508
509std::unique_ptr<ReducerWorkItem>
510ReducerWorkItem::clone(const TargetMachine *TM) const {
511 auto CloneMMM = std::make_unique<ReducerWorkItem>();
512 if (TM) {
513 // We're assuming the Module IR contents are always unchanged by MIR
514 // reductions, and can share it as a constant.
515 CloneMMM->M = M;
516
517 // MachineModuleInfo contains a lot of other state used during codegen which
518 // we won't be using here, but we should be able to ignore it (although this
519 // is pretty ugly).
520 CloneMMM->MMI = std::make_unique<MachineModuleInfo>(args&: TM);
521
522 for (const Function &F : getModule()) {
523 if (auto *MF = MMI->getMachineFunction(F))
524 CloneMMM->MMI->insertFunction(F, MF: cloneMF(SrcMF: MF, DestMMI&: *CloneMMM->MMI));
525 }
526 } else {
527 CloneMMM->M = CloneModule(M: *M);
528 }
529 return CloneMMM;
530}
531
532/// Try to produce some number that indicates a function is getting smaller /
533/// simpler.
534static uint64_t computeMIRComplexityScoreImpl(const MachineFunction &MF) {
535 uint64_t Score = 0;
536 const MachineFrameInfo &MFI = MF.getFrameInfo();
537
538 // Add for stack objects
539 Score += MFI.getNumObjects();
540
541 // Add in the block count.
542 Score += 2 * MF.size();
543
544 const MachineRegisterInfo &MRI = MF.getRegInfo();
545 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
546 Register Reg = Register::index2VirtReg(Index: I);
547 if (const auto *Hints = MRI.getRegAllocationHints(VReg: Reg))
548 Score += Hints->second.size();
549 }
550
551 for (const MachineBasicBlock &MBB : MF) {
552 for (const MachineInstr &MI : MBB) {
553 const unsigned Opc = MI.getOpcode();
554
555 // Reductions may want or need to introduce implicit_defs, so don't count
556 // them.
557 // TODO: These probably should count in some way.
558 if (Opc == TargetOpcode::IMPLICIT_DEF ||
559 Opc == TargetOpcode::G_IMPLICIT_DEF)
560 continue;
561
562 // Each instruction adds to the score
563 Score += 4;
564
565 if (Opc == TargetOpcode::PHI || Opc == TargetOpcode::G_PHI ||
566 Opc == TargetOpcode::INLINEASM || Opc == TargetOpcode::INLINEASM_BR)
567 ++Score;
568
569 if (MI.getFlags() != 0)
570 ++Score;
571
572 // Increase weight for more operands.
573 for (const MachineOperand &MO : MI.operands()) {
574 ++Score;
575
576 // Treat registers as more complex.
577 if (MO.isReg()) {
578 ++Score;
579
580 // And subregisters as even more complex.
581 if (MO.getSubReg()) {
582 ++Score;
583 if (MO.isDef())
584 ++Score;
585 }
586 } else if (MO.isRegMask())
587 ++Score;
588 }
589 }
590 }
591
592 return Score;
593}
594
595uint64_t ReducerWorkItem::computeMIRComplexityScore() const {
596 uint64_t Score = 0;
597
598 for (const Function &F : getModule()) {
599 if (auto *MF = MMI->getMachineFunction(F))
600 Score += computeMIRComplexityScoreImpl(MF: *MF);
601 }
602
603 return Score;
604}
605
606// FIXME: ReduceOperandsSkip has similar function, except it uses larger numbers
607// for more reduced.
608static unsigned classifyReductivePower(const Value *V) {
609 if (auto *C = dyn_cast<ConstantData>(Val: V)) {
610 if (C->isNullValue())
611 return 0;
612 if (C->isOneValue())
613 return 1;
614 if (isa<UndefValue>(Val: V))
615 return 2;
616 return 3;
617 }
618
619 if (isa<GlobalValue>(Val: V))
620 return 4;
621
622 // TODO: Account for expression size
623 if (isa<ConstantExpr>(Val: V))
624 return 5;
625
626 if (isa<Constant>(Val: V))
627 return 1;
628
629 if (isa<Argument>(Val: V))
630 return 6;
631
632 if (isa<Instruction>(Val: V))
633 return 7;
634
635 return 0;
636}
637
638// TODO: Additional flags and attributes may be complexity reducing. If we start
639// adding flags and attributes, they could have negative cost.
640static uint64_t computeIRComplexityScoreImpl(const Function &F) {
641 uint64_t Score = 1; // Count the function itself
642 SmallVector<std::pair<unsigned, MDNode *>> MDs;
643
644 AttributeList Attrs = F.getAttributes();
645 for (AttributeSet AttrSet : Attrs)
646 Score += AttrSet.getNumAttributes();
647
648 for (const BasicBlock &BB : F) {
649 ++Score;
650
651 for (const Instruction &I : BB) {
652 ++Score;
653
654 if (const auto *OverflowOp = dyn_cast<OverflowingBinaryOperator>(Val: &I)) {
655 if (OverflowOp->hasNoUnsignedWrap())
656 ++Score;
657 if (OverflowOp->hasNoSignedWrap())
658 ++Score;
659 } else if (const auto *Trunc = dyn_cast<TruncInst>(Val: &I)) {
660 if (Trunc->hasNoSignedWrap())
661 ++Score;
662 if (Trunc->hasNoUnsignedWrap())
663 ++Score;
664 } else if (const auto *ExactOp = dyn_cast<PossiblyExactOperator>(Val: &I)) {
665 if (ExactOp->isExact())
666 ++Score;
667 } else if (const auto *NNI = dyn_cast<PossiblyNonNegInst>(Val: &I)) {
668 if (NNI->hasNonNeg())
669 ++Score;
670 } else if (const auto *PDI = dyn_cast<PossiblyDisjointInst>(Val: &I)) {
671 if (PDI->isDisjoint())
672 ++Score;
673 } else if (const auto *GEP = dyn_cast<GEPOperator>(Val: &I)) {
674 if (GEP->isInBounds())
675 ++Score;
676 if (GEP->hasNoUnsignedSignedWrap())
677 ++Score;
678 if (GEP->hasNoUnsignedWrap())
679 ++Score;
680 } else if (const auto *FPOp = dyn_cast<FPMathOperator>(Val: &I)) {
681 FastMathFlags FMF = FPOp->getFastMathFlags();
682 if (FMF.allowReassoc())
683 ++Score;
684 if (FMF.noNaNs())
685 ++Score;
686 if (FMF.noInfs())
687 ++Score;
688 if (FMF.noSignedZeros())
689 ++Score;
690 if (FMF.allowReciprocal())
691 ++Score;
692 if (FMF.allowContract())
693 ++Score;
694 if (FMF.approxFunc())
695 ++Score;
696 }
697
698 for (const Value *Operand : I.operands()) {
699 ++Score;
700 Score += classifyReductivePower(V: Operand);
701 }
702
703 I.getAllMetadata(MDs);
704 Score += MDs.size();
705 MDs.clear();
706 }
707 }
708
709 return Score;
710}
711
712uint64_t ReducerWorkItem::computeIRComplexityScore() const {
713 uint64_t Score = 0;
714
715 const Module &M = getModule();
716 Score += M.named_metadata_size();
717
718 SmallVector<std::pair<unsigned, MDNode *>, 32> GlobalMetadata;
719 for (const GlobalVariable &GV : M.globals()) {
720 ++Score;
721
722 if (GV.hasInitializer())
723 Score += classifyReductivePower(V: GV.getInitializer());
724
725 // TODO: Account for linkage?
726
727 GV.getAllMetadata(MDs&: GlobalMetadata);
728 Score += GlobalMetadata.size();
729 GlobalMetadata.clear();
730 }
731
732 for (const GlobalAlias &GA : M.aliases())
733 Score += classifyReductivePower(V: GA.getAliasee());
734
735 for (const GlobalIFunc &GI : M.ifuncs())
736 Score += classifyReductivePower(V: GI.getResolver());
737
738 for (const Function &F : M)
739 Score += computeIRComplexityScoreImpl(F);
740
741 return Score;
742}
743
744void ReducerWorkItem::writeOutput(raw_ostream &OS, bool EmitBitcode) const {
745 // Requesting bitcode emission with mir is nonsense, so just ignore it.
746 if (EmitBitcode && !isMIR())
747 writeBitcode(OutStream&: OS);
748 else
749 print(ROS&: OS, /*AnnotationWriter=*/p: nullptr);
750}
751
752void ReducerWorkItem::readBitcode(MemoryBufferRef Data, LLVMContext &Ctx,
753 StringRef ToolName) {
754 Expected<BitcodeFileContents> IF = llvm::getBitcodeFileContents(Buffer: Data);
755 if (!IF) {
756 WithColor::error(OS&: errs(), Prefix: ToolName) << IF.takeError();
757 exit(status: 1);
758 }
759
760 BitcodeModule BM = IF->Mods[0];
761 Expected<BitcodeLTOInfo> LI = BM.getLTOInfo();
762 if (!LI) {
763 WithColor::error(OS&: errs(), Prefix: ToolName) << LI.takeError();
764 exit(status: 1);
765 }
766
767 Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(Context&: Ctx);
768 if (!MOrErr) {
769 WithColor::error(OS&: errs(), Prefix: ToolName) << MOrErr.takeError();
770 exit(status: 1);
771 }
772
773 LTOInfo = std::make_unique<BitcodeLTOInfo>(args&: *LI);
774 M = std::move(MOrErr.get());
775}
776
777void ReducerWorkItem::writeBitcode(raw_ostream &OutStream) const {
778 const bool ShouldPreserveUseListOrder = true;
779
780 if (LTOInfo && LTOInfo->IsThinLTO && LTOInfo->EnableSplitLTOUnit) {
781 PassBuilder PB;
782 LoopAnalysisManager LAM;
783 FunctionAnalysisManager FAM;
784 CGSCCAnalysisManager CGAM;
785 ModuleAnalysisManager MAM;
786 PB.registerModuleAnalyses(MAM);
787 PB.registerCGSCCAnalyses(CGAM);
788 PB.registerFunctionAnalyses(FAM);
789 PB.registerLoopAnalyses(LAM);
790 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
791 ModulePassManager MPM;
792 MPM.addPass(Pass: ThinLTOBitcodeWriterPass(OutStream, nullptr,
793 ShouldPreserveUseListOrder));
794 MPM.run(IR&: *M, AM&: MAM);
795 } else {
796 std::unique_ptr<ModuleSummaryIndex> Index;
797 if (LTOInfo && LTOInfo->HasSummary) {
798 ProfileSummaryInfo PSI(*M);
799 Index = std::make_unique<ModuleSummaryIndex>(
800 args: buildModuleSummaryIndex(M: *M, GetBFICallback: nullptr, PSI: &PSI));
801 }
802 WriteBitcodeToFile(M: getModule(), Out&: OutStream, ShouldPreserveUseListOrder,
803 Index: Index.get());
804 }
805}
806
807std::pair<std::unique_ptr<ReducerWorkItem>, bool>
808llvm::parseReducerWorkItem(StringRef ToolName, StringRef Filename,
809 LLVMContext &Ctxt,
810 std::unique_ptr<TargetMachine> &TM, bool IsMIR) {
811 bool IsBitcode = false;
812 Triple TheTriple;
813
814 auto MMM = std::make_unique<ReducerWorkItem>();
815
816 if (IsMIR) {
817 initializeTargetInfo();
818
819 auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
820 if (std::error_code EC = FileOrErr.getError()) {
821 WithColor::error(OS&: errs(), Prefix: ToolName) << EC.message() << '\n';
822 return {nullptr, false};
823 }
824
825 std::unique_ptr<MIRParser> MParser =
826 createMIRParser(Contents: std::move(FileOrErr.get()), Context&: Ctxt);
827
828 auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
829 StringRef OldDLStr) -> std::optional<std::string> {
830 // NB: We always call createTargetMachineForTriple() even if an explicit
831 // DataLayout is already set in the module since we want to use this
832 // callback to setup the TargetMachine rather than doing it later.
833 std::string IRTargetTriple = DataLayoutTargetTriple.str();
834 if (!TargetTriple.empty())
835 IRTargetTriple = Triple::normalize(Str: TargetTriple);
836 TheTriple = Triple(IRTargetTriple);
837 if (TheTriple.getTriple().empty())
838 TheTriple.setTriple(sys::getDefaultTargetTriple());
839 ExitOnError ExitOnErr(std::string(ToolName) + ": error: ");
840 TM = ExitOnErr(codegen::createTargetMachineForTriple(TargetTriple: TheTriple.str()));
841
842 return TM->createDataLayout().getStringRepresentation();
843 };
844
845 std::unique_ptr<Module> M = MParser->parseIRModule(DataLayoutCallback: SetDataLayout);
846
847 MMM->MMI = std::make_unique<MachineModuleInfo>(args: TM.get());
848 MParser->parseMachineFunctions(M&: *M, MMI&: *MMM->MMI);
849 MMM->M = std::move(M);
850 } else {
851 SMDiagnostic Err;
852 ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
853 MemoryBuffer::getFileOrSTDIN(Filename);
854 if (std::error_code EC = MB.getError()) {
855 WithColor::error(OS&: errs(), Prefix: ToolName)
856 << Filename << ": " << EC.message() << "\n";
857 return {nullptr, false};
858 }
859
860 if (!isBitcode(BufPtr: (const unsigned char *)(*MB)->getBufferStart(),
861 BufEnd: (const unsigned char *)(*MB)->getBufferEnd())) {
862 std::unique_ptr<Module> Result = parseIR(Buffer: **MB, Err, Context&: Ctxt);
863 if (!Result) {
864 Err.print(ProgName: ToolName.data(), S&: errs());
865 return {nullptr, false};
866 }
867 MMM->M = std::move(Result);
868 } else {
869 IsBitcode = true;
870 MMM->readBitcode(Data: MemoryBufferRef(**MB), Ctx&: Ctxt, ToolName);
871
872 if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit)
873 initializeTargetInfo();
874 }
875 }
876 if (MMM->verify(OS: &errs())) {
877 WithColor::error(OS&: errs(), Prefix: ToolName)
878 << Filename << " - input module is broken!\n";
879 return {nullptr, false};
880 }
881 return {std::move(MMM), IsBitcode};
882}
883