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