xref: /llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.cpp (revision bb3f5e1fed7c6ba733b7f273e93f5d3930976185)
1fd41738eSMarkus Lavin //===- ReducerWorkItem.cpp - Wrapper for Module and MachineFunction -------===//
2fd41738eSMarkus Lavin //
3fd41738eSMarkus Lavin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fd41738eSMarkus Lavin // See https://llvm.org/LICENSE.txt for license information.
5fd41738eSMarkus Lavin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fd41738eSMarkus Lavin //
7fd41738eSMarkus Lavin //===----------------------------------------------------------------------===//
8fd41738eSMarkus Lavin 
9fd41738eSMarkus Lavin #include "ReducerWorkItem.h"
10592536a9SMatt Arsenault #include "TestRunner.h"
11592536a9SMatt Arsenault #include "llvm/Analysis/ModuleSummaryAnalysis.h"
12592536a9SMatt Arsenault #include "llvm/Analysis/ProfileSummaryInfo.h"
136b3956e1SMatthew Voss #include "llvm/Bitcode/BitcodeReader.h"
14592536a9SMatt Arsenault #include "llvm/Bitcode/BitcodeWriter.h"
151747a93bSMatt Arsenault #include "llvm/CodeGen/CommandFlags.h"
16fd41738eSMarkus Lavin #include "llvm/CodeGen/MIRParser/MIRParser.h"
17fd41738eSMarkus Lavin #include "llvm/CodeGen/MIRPrinter.h"
18fd41738eSMarkus Lavin #include "llvm/CodeGen/MachineDominators.h"
19f163106fSMatt Arsenault #include "llvm/CodeGen/MachineFrameInfo.h"
20fd41738eSMarkus Lavin #include "llvm/CodeGen/MachineFunction.h"
21fd41738eSMarkus Lavin #include "llvm/CodeGen/MachineFunctionPass.h"
22748f861bSMatt Arsenault #include "llvm/CodeGen/MachineJumpTableInfo.h"
2342c7f494SClemens Wasser #include "llvm/CodeGen/MachineModuleInfo.h"
24fd41738eSMarkus Lavin #include "llvm/CodeGen/MachineRegisterInfo.h"
25ea668144SNikita Popov #include "llvm/CodeGen/PseudoSourceValueManager.h"
26fd41738eSMarkus Lavin #include "llvm/CodeGen/TargetInstrInfo.h"
27c23ac22fSMatt Arsenault #include "llvm/IR/Constants.h"
28c23ac22fSMatt Arsenault #include "llvm/IR/Instructions.h"
296b3956e1SMatthew Voss #include "llvm/IR/ModuleSummaryIndex.h"
30c23ac22fSMatt Arsenault #include "llvm/IR/Operator.h"
31fd41738eSMarkus Lavin #include "llvm/IR/Verifier.h"
32fd41738eSMarkus Lavin #include "llvm/IRReader/IRReader.h"
331747a93bSMatt Arsenault #include "llvm/MC/TargetRegistry.h"
34592536a9SMatt Arsenault #include "llvm/Passes/PassBuilder.h"
356b3956e1SMatthew Voss #include "llvm/Support/MemoryBufferRef.h"
3671c3a551Sserge-sans-paille #include "llvm/Support/SourceMgr.h"
376b3956e1SMatthew Voss #include "llvm/Support/TargetSelect.h"
38592536a9SMatt Arsenault #include "llvm/Support/ToolOutputFile.h"
391747a93bSMatt Arsenault #include "llvm/Support/WithColor.h"
40fd41738eSMarkus Lavin #include "llvm/Target/TargetMachine.h"
41d768bf99SArchibald Elliott #include "llvm/TargetParser/Host.h"
42592536a9SMatt Arsenault #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
43fd41738eSMarkus Lavin #include "llvm/Transforms/Utils/Cloning.h"
44110fe4f4SKrzysztof Parzyszek #include <optional>
45fd41738eSMarkus Lavin 
46333ffafbSMatt Arsenault using namespace llvm;
47333ffafbSMatt Arsenault 
48333ffafbSMatt Arsenault ReducerWorkItem::ReducerWorkItem() = default;
49333ffafbSMatt Arsenault ReducerWorkItem::~ReducerWorkItem() = default;
50333ffafbSMatt Arsenault 
511747a93bSMatt Arsenault extern cl::OptionCategory LLVMReduceOptions;
521747a93bSMatt Arsenault static cl::opt<std::string> TargetTriple("mtriple",
531747a93bSMatt Arsenault                                          cl::desc("Set the target triple"),
541747a93bSMatt Arsenault                                          cl::cat(LLVMReduceOptions));
5571ca9fcbSMatt Arsenault static cl::opt<bool> PrintInvalidMachineReductions(
5671ca9fcbSMatt Arsenault     "print-invalid-reduction-machine-verifier-errors",
5771ca9fcbSMatt Arsenault     cl::desc(
5871ca9fcbSMatt Arsenault         "Print machine verifier errors on invalid reduction attempts triple"),
5971ca9fcbSMatt Arsenault     cl::cat(LLVMReduceOptions));
601747a93bSMatt Arsenault 
61592536a9SMatt Arsenault static cl::opt<bool> TmpFilesAsBitcode(
62592536a9SMatt Arsenault     "write-tmp-files-as-bitcode",
63592536a9SMatt Arsenault     cl::desc("Always write temporary files as bitcode instead of textual IR"),
64592536a9SMatt Arsenault     cl::init(false), cl::cat(LLVMReduceOptions));
656b3956e1SMatthew Voss 
66f163106fSMatt Arsenault static void cloneFrameInfo(
67f163106fSMatt Arsenault     MachineFrameInfo &DstMFI, const MachineFrameInfo &SrcMFI,
68a27b9ab3SMatt Arsenault     const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) {
69f163106fSMatt Arsenault   DstMFI.setFrameAddressIsTaken(SrcMFI.isFrameAddressTaken());
70f163106fSMatt Arsenault   DstMFI.setReturnAddressIsTaken(SrcMFI.isReturnAddressTaken());
71f163106fSMatt Arsenault   DstMFI.setHasStackMap(SrcMFI.hasStackMap());
72f163106fSMatt Arsenault   DstMFI.setHasPatchPoint(SrcMFI.hasPatchPoint());
73f163106fSMatt Arsenault   DstMFI.setUseLocalStackAllocationBlock(
74f163106fSMatt Arsenault       SrcMFI.getUseLocalStackAllocationBlock());
75f163106fSMatt Arsenault   DstMFI.setOffsetAdjustment(SrcMFI.getOffsetAdjustment());
76f163106fSMatt Arsenault 
77f163106fSMatt Arsenault   DstMFI.ensureMaxAlignment(SrcMFI.getMaxAlign());
78f163106fSMatt Arsenault   assert(DstMFI.getMaxAlign() == SrcMFI.getMaxAlign() &&
79f163106fSMatt Arsenault          "we need to set exact alignment");
80f163106fSMatt Arsenault 
81f163106fSMatt Arsenault   DstMFI.setAdjustsStack(SrcMFI.adjustsStack());
82f163106fSMatt Arsenault   DstMFI.setHasCalls(SrcMFI.hasCalls());
83f163106fSMatt Arsenault   DstMFI.setHasOpaqueSPAdjustment(SrcMFI.hasOpaqueSPAdjustment());
84f163106fSMatt Arsenault   DstMFI.setHasCopyImplyingStackAdjustment(
85f163106fSMatt Arsenault       SrcMFI.hasCopyImplyingStackAdjustment());
86f163106fSMatt Arsenault   DstMFI.setHasVAStart(SrcMFI.hasVAStart());
87f163106fSMatt Arsenault   DstMFI.setHasMustTailInVarArgFunc(SrcMFI.hasMustTailInVarArgFunc());
88f163106fSMatt Arsenault   DstMFI.setHasTailCall(SrcMFI.hasTailCall());
89debfb96bSMatt Arsenault 
90debfb96bSMatt Arsenault   if (SrcMFI.isMaxCallFrameSizeComputed())
91f163106fSMatt Arsenault     DstMFI.setMaxCallFrameSize(SrcMFI.getMaxCallFrameSize());
92f163106fSMatt Arsenault 
93f163106fSMatt Arsenault   DstMFI.setCVBytesOfCalleeSavedRegisters(
94f163106fSMatt Arsenault       SrcMFI.getCVBytesOfCalleeSavedRegisters());
95f163106fSMatt Arsenault 
96f163106fSMatt Arsenault   if (MachineBasicBlock *SavePt = SrcMFI.getSavePoint())
97f163106fSMatt Arsenault     DstMFI.setSavePoint(Src2DstMBB.find(SavePt)->second);
98f163106fSMatt Arsenault   if (MachineBasicBlock *RestorePt = SrcMFI.getRestorePoint())
99f163106fSMatt Arsenault     DstMFI.setRestorePoint(Src2DstMBB.find(RestorePt)->second);
100f163106fSMatt Arsenault 
101a27b9ab3SMatt Arsenault 
102a27b9ab3SMatt Arsenault   auto CopyObjectProperties = [](MachineFrameInfo &DstMFI,
103a27b9ab3SMatt Arsenault                                  const MachineFrameInfo &SrcMFI, int FI) {
104a27b9ab3SMatt Arsenault     if (SrcMFI.isStatepointSpillSlotObjectIndex(FI))
105a27b9ab3SMatt Arsenault       DstMFI.markAsStatepointSpillSlotObjectIndex(FI);
106a27b9ab3SMatt Arsenault     DstMFI.setObjectSSPLayout(FI, SrcMFI.getObjectSSPLayout(FI));
107a27b9ab3SMatt Arsenault     DstMFI.setObjectZExt(FI, SrcMFI.isObjectZExt(FI));
108a27b9ab3SMatt Arsenault     DstMFI.setObjectSExt(FI, SrcMFI.isObjectSExt(FI));
109a27b9ab3SMatt Arsenault   };
110a27b9ab3SMatt Arsenault 
111a27b9ab3SMatt Arsenault   for (int i = 0, e = SrcMFI.getNumObjects() - SrcMFI.getNumFixedObjects();
112f163106fSMatt Arsenault        i != e; ++i) {
113f163106fSMatt Arsenault     int NewFI;
114f163106fSMatt Arsenault 
115a27b9ab3SMatt Arsenault     assert(!SrcMFI.isFixedObjectIndex(i));
116a27b9ab3SMatt Arsenault     if (SrcMFI.isVariableSizedObjectIndex(i)) {
117f163106fSMatt Arsenault       NewFI = DstMFI.CreateVariableSizedObject(SrcMFI.getObjectAlign(i),
118f163106fSMatt Arsenault                                                SrcMFI.getObjectAllocation(i));
119f163106fSMatt Arsenault     } else {
120f163106fSMatt Arsenault       NewFI = DstMFI.CreateStackObject(
121f163106fSMatt Arsenault           SrcMFI.getObjectSize(i), SrcMFI.getObjectAlign(i),
122f163106fSMatt Arsenault           SrcMFI.isSpillSlotObjectIndex(i), SrcMFI.getObjectAllocation(i),
123f163106fSMatt Arsenault           SrcMFI.getStackID(i));
124f163106fSMatt Arsenault       DstMFI.setObjectOffset(NewFI, SrcMFI.getObjectOffset(i));
125f163106fSMatt Arsenault     }
126f163106fSMatt Arsenault 
127a27b9ab3SMatt Arsenault     CopyObjectProperties(DstMFI, SrcMFI, i);
128f163106fSMatt Arsenault 
129a27b9ab3SMatt Arsenault     (void)NewFI;
130a27b9ab3SMatt Arsenault     assert(i == NewFI && "expected to keep stable frame index numbering");
131a27b9ab3SMatt Arsenault   }
132a27b9ab3SMatt Arsenault 
133a27b9ab3SMatt Arsenault   // Copy the fixed frame objects backwards to preserve frame index numbers,
134a27b9ab3SMatt Arsenault   // since CreateFixedObject uses front insertion.
135a27b9ab3SMatt Arsenault   for (int i = -1; i >= (int)-SrcMFI.getNumFixedObjects(); --i) {
136a27b9ab3SMatt Arsenault     assert(SrcMFI.isFixedObjectIndex(i));
137a27b9ab3SMatt Arsenault     int NewFI = DstMFI.CreateFixedObject(
138a27b9ab3SMatt Arsenault       SrcMFI.getObjectSize(i), SrcMFI.getObjectOffset(i),
139a27b9ab3SMatt Arsenault       SrcMFI.isImmutableObjectIndex(i), SrcMFI.isAliasedObjectIndex(i));
140a27b9ab3SMatt Arsenault     CopyObjectProperties(DstMFI, SrcMFI, i);
141a27b9ab3SMatt Arsenault 
142a27b9ab3SMatt Arsenault     (void)NewFI;
143a27b9ab3SMatt Arsenault     assert(i == NewFI && "expected to keep stable frame index numbering");
144f163106fSMatt Arsenault   }
145f163106fSMatt Arsenault 
146f163106fSMatt Arsenault   for (unsigned I = 0, E = SrcMFI.getLocalFrameObjectCount(); I < E; ++I) {
147f163106fSMatt Arsenault     auto LocalObject = SrcMFI.getLocalFrameObjectMap(I);
148f163106fSMatt Arsenault     DstMFI.mapLocalFrameObject(LocalObject.first, LocalObject.second);
149f163106fSMatt Arsenault   }
150f163106fSMatt Arsenault 
151a27b9ab3SMatt Arsenault   DstMFI.setCalleeSavedInfo(SrcMFI.getCalleeSavedInfo());
152f163106fSMatt Arsenault 
153f163106fSMatt Arsenault   if (SrcMFI.hasStackProtectorIndex()) {
154a27b9ab3SMatt Arsenault     DstMFI.setStackProtectorIndex(SrcMFI.getStackProtectorIndex());
155f163106fSMatt Arsenault   }
156f163106fSMatt Arsenault 
157f163106fSMatt Arsenault   // FIXME: Needs test, missing MIR serialization.
158f163106fSMatt Arsenault   if (SrcMFI.hasFunctionContextIndex()) {
159a27b9ab3SMatt Arsenault     DstMFI.setFunctionContextIndex(SrcMFI.getFunctionContextIndex());
160f163106fSMatt Arsenault   }
161f163106fSMatt Arsenault }
162f163106fSMatt Arsenault 
163748f861bSMatt Arsenault static void cloneJumpTableInfo(
164748f861bSMatt Arsenault     MachineFunction &DstMF, const MachineJumpTableInfo &SrcJTI,
165748f861bSMatt Arsenault     const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) {
166748f861bSMatt Arsenault 
167748f861bSMatt Arsenault   auto *DstJTI = DstMF.getOrCreateJumpTableInfo(SrcJTI.getEntryKind());
168748f861bSMatt Arsenault 
169748f861bSMatt Arsenault   std::vector<MachineBasicBlock *> DstBBs;
170748f861bSMatt Arsenault 
171748f861bSMatt Arsenault   for (const MachineJumpTableEntry &Entry : SrcJTI.getJumpTables()) {
172748f861bSMatt Arsenault     for (MachineBasicBlock *X : Entry.MBBs)
173748f861bSMatt Arsenault       DstBBs.push_back(Src2DstMBB.find(X)->second);
174748f861bSMatt Arsenault 
175748f861bSMatt Arsenault     DstJTI->createJumpTableIndex(DstBBs);
176748f861bSMatt Arsenault     DstBBs.clear();
177748f861bSMatt Arsenault   }
178748f861bSMatt Arsenault }
179748f861bSMatt Arsenault 
18071720976SMatt Arsenault static void cloneMemOperands(MachineInstr &DstMI, MachineInstr &SrcMI,
18171720976SMatt Arsenault                              MachineFunction &SrcMF, MachineFunction &DstMF) {
18271720976SMatt Arsenault   // The new MachineMemOperands should be owned by the new function's
18371720976SMatt Arsenault   // Allocator.
18471720976SMatt Arsenault   PseudoSourceValueManager &PSVMgr = DstMF.getPSVManager();
18571720976SMatt Arsenault 
18671720976SMatt Arsenault   // We also need to remap the PseudoSourceValues from the new function's
18771720976SMatt Arsenault   // PseudoSourceValueManager.
18871720976SMatt Arsenault   SmallVector<MachineMemOperand *, 2> NewMMOs;
18971720976SMatt Arsenault   for (MachineMemOperand *OldMMO : SrcMI.memoperands()) {
19071720976SMatt Arsenault     MachinePointerInfo NewPtrInfo(OldMMO->getPointerInfo());
19171720976SMatt Arsenault     if (const PseudoSourceValue *PSV =
1927021182dSShraiysh Vaishay             dyn_cast_if_present<const PseudoSourceValue *>(NewPtrInfo.V)) {
19371720976SMatt Arsenault       switch (PSV->kind()) {
19471720976SMatt Arsenault       case PseudoSourceValue::Stack:
19571720976SMatt Arsenault         NewPtrInfo.V = PSVMgr.getStack();
19671720976SMatt Arsenault         break;
19771720976SMatt Arsenault       case PseudoSourceValue::GOT:
19871720976SMatt Arsenault         NewPtrInfo.V = PSVMgr.getGOT();
19971720976SMatt Arsenault         break;
20071720976SMatt Arsenault       case PseudoSourceValue::JumpTable:
20171720976SMatt Arsenault         NewPtrInfo.V = PSVMgr.getJumpTable();
20271720976SMatt Arsenault         break;
20371720976SMatt Arsenault       case PseudoSourceValue::ConstantPool:
20471720976SMatt Arsenault         NewPtrInfo.V = PSVMgr.getConstantPool();
20571720976SMatt Arsenault         break;
20671720976SMatt Arsenault       case PseudoSourceValue::FixedStack:
20771720976SMatt Arsenault         NewPtrInfo.V = PSVMgr.getFixedStack(
20871720976SMatt Arsenault             cast<FixedStackPseudoSourceValue>(PSV)->getFrameIndex());
20971720976SMatt Arsenault         break;
21071720976SMatt Arsenault       case PseudoSourceValue::GlobalValueCallEntry:
21171720976SMatt Arsenault         NewPtrInfo.V = PSVMgr.getGlobalValueCallEntry(
21271720976SMatt Arsenault             cast<GlobalValuePseudoSourceValue>(PSV)->getValue());
21371720976SMatt Arsenault         break;
21471720976SMatt Arsenault       case PseudoSourceValue::ExternalSymbolCallEntry:
21571720976SMatt Arsenault         NewPtrInfo.V = PSVMgr.getExternalSymbolCallEntry(
21671720976SMatt Arsenault             cast<ExternalSymbolPseudoSourceValue>(PSV)->getSymbol());
21771720976SMatt Arsenault         break;
21871720976SMatt Arsenault       case PseudoSourceValue::TargetCustom:
21971720976SMatt Arsenault       default:
22071720976SMatt Arsenault         // FIXME: We have no generic interface for allocating custom PSVs.
22171720976SMatt Arsenault         report_fatal_error("Cloning TargetCustom PSV not handled");
22271720976SMatt Arsenault       }
22371720976SMatt Arsenault     }
22471720976SMatt Arsenault 
22571720976SMatt Arsenault     MachineMemOperand *NewMMO = DstMF.getMachineMemOperand(
22671720976SMatt Arsenault         NewPtrInfo, OldMMO->getFlags(), OldMMO->getMemoryType(),
22771720976SMatt Arsenault         OldMMO->getBaseAlign(), OldMMO->getAAInfo(), OldMMO->getRanges(),
22871720976SMatt Arsenault         OldMMO->getSyncScopeID(), OldMMO->getSuccessOrdering(),
22971720976SMatt Arsenault         OldMMO->getFailureOrdering());
23071720976SMatt Arsenault     NewMMOs.push_back(NewMMO);
23171720976SMatt Arsenault   }
23271720976SMatt Arsenault 
23371720976SMatt Arsenault   DstMI.setMemRefs(DstMF, NewMMOs);
23471720976SMatt Arsenault }
23571720976SMatt Arsenault 
2367c2db666SMatt Arsenault static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF,
2377c2db666SMatt Arsenault                                                 MachineModuleInfo &DestMMI) {
238fd41738eSMarkus Lavin   auto DstMF = std::make_unique<MachineFunction>(
239fd41738eSMarkus Lavin       SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(),
24063e16478SMatt Arsenault       SrcMF->getContext(), SrcMF->getFunctionNumber());
241fd41738eSMarkus Lavin   DenseMap<MachineBasicBlock *, MachineBasicBlock *> Src2DstMBB;
242fd41738eSMarkus Lavin 
243fd41738eSMarkus Lavin   auto *SrcMRI = &SrcMF->getRegInfo();
244fd41738eSMarkus Lavin   auto *DstMRI = &DstMF->getRegInfo();
245fd41738eSMarkus Lavin 
246f163106fSMatt Arsenault   // Clone blocks.
24753d88581SMatt Arsenault   for (MachineBasicBlock &SrcMBB : *SrcMF) {
24853d88581SMatt Arsenault     MachineBasicBlock *DstMBB =
24953d88581SMatt Arsenault         DstMF->CreateMachineBasicBlock(SrcMBB.getBasicBlock());
25053d88581SMatt Arsenault     Src2DstMBB[&SrcMBB] = DstMBB;
25153d88581SMatt Arsenault 
2522dcf0512SJay Foad     DstMBB->setCallFrameSize(SrcMBB.getCallFrameSize());
2532dcf0512SJay Foad 
254cfd2c5ceSEli Friedman     if (SrcMBB.isIRBlockAddressTaken())
255cfd2c5ceSEli Friedman       DstMBB->setAddressTakenIRBlock(SrcMBB.getAddressTakenIRBlock());
256cfd2c5ceSEli Friedman     if (SrcMBB.isMachineBlockAddressTaken())
257cfd2c5ceSEli Friedman       DstMBB->setMachineBlockAddressTaken();
25853d88581SMatt Arsenault 
25953d88581SMatt Arsenault     // FIXME: This is not serialized
26053d88581SMatt Arsenault     if (SrcMBB.hasLabelMustBeEmitted())
26153d88581SMatt Arsenault       DstMBB->setLabelMustBeEmitted();
26253d88581SMatt Arsenault 
26353d88581SMatt Arsenault     DstMBB->setAlignment(SrcMBB.getAlignment());
26453d88581SMatt Arsenault 
26553d88581SMatt Arsenault     // FIXME: This is not serialized
26653d88581SMatt Arsenault     DstMBB->setMaxBytesForAlignment(SrcMBB.getMaxBytesForAlignment());
26753d88581SMatt Arsenault 
26853d88581SMatt Arsenault     DstMBB->setIsEHPad(SrcMBB.isEHPad());
26953d88581SMatt Arsenault     DstMBB->setIsEHScopeEntry(SrcMBB.isEHScopeEntry());
27053d88581SMatt Arsenault     DstMBB->setIsEHCatchretTarget(SrcMBB.isEHCatchretTarget());
27153d88581SMatt Arsenault     DstMBB->setIsEHFuncletEntry(SrcMBB.isEHFuncletEntry());
27253d88581SMatt Arsenault 
27353d88581SMatt Arsenault     // FIXME: These are not serialized
27453d88581SMatt Arsenault     DstMBB->setIsCleanupFuncletEntry(SrcMBB.isCleanupFuncletEntry());
27553d88581SMatt Arsenault     DstMBB->setIsBeginSection(SrcMBB.isBeginSection());
27653d88581SMatt Arsenault     DstMBB->setIsEndSection(SrcMBB.isEndSection());
27753d88581SMatt Arsenault 
27853d88581SMatt Arsenault     DstMBB->setSectionID(SrcMBB.getSectionID());
27953d88581SMatt Arsenault     DstMBB->setIsInlineAsmBrIndirectTarget(
28053d88581SMatt Arsenault         SrcMBB.isInlineAsmBrIndirectTarget());
28153d88581SMatt Arsenault 
28253d88581SMatt Arsenault     // FIXME: This is not serialized
28389fae41eSFangrui Song     if (std::optional<uint64_t> Weight = SrcMBB.getIrrLoopHeaderWeight())
28453d88581SMatt Arsenault       DstMBB->setIrrLoopHeaderWeight(*Weight);
28553d88581SMatt Arsenault   }
286f163106fSMatt Arsenault 
287f163106fSMatt Arsenault   const MachineFrameInfo &SrcMFI = SrcMF->getFrameInfo();
288f163106fSMatt Arsenault   MachineFrameInfo &DstMFI = DstMF->getFrameInfo();
289f163106fSMatt Arsenault 
290f163106fSMatt Arsenault   // Copy stack objects and other info
291a27b9ab3SMatt Arsenault   cloneFrameInfo(DstMFI, SrcMFI, Src2DstMBB);
292f163106fSMatt Arsenault 
293748f861bSMatt Arsenault   if (MachineJumpTableInfo *SrcJTI = SrcMF->getJumpTableInfo()) {
294748f861bSMatt Arsenault     cloneJumpTableInfo(*DstMF, *SrcJTI, Src2DstMBB);
295748f861bSMatt Arsenault   }
296748f861bSMatt Arsenault 
297f163106fSMatt Arsenault   // Remap the debug info frame index references.
298f163106fSMatt Arsenault   DstMF->VariableDbgInfos = SrcMF->VariableDbgInfos;
299f163106fSMatt Arsenault 
3007b57ef67SMatt Arsenault   // Clone virtual registers
3017b57ef67SMatt Arsenault   for (unsigned I = 0, E = SrcMRI->getNumVirtRegs(); I != E; ++I) {
3027b57ef67SMatt Arsenault     Register Reg = Register::index2VirtReg(I);
3037b57ef67SMatt Arsenault     Register NewReg = DstMRI->createIncompleteVirtualRegister(
3047b57ef67SMatt Arsenault       SrcMRI->getVRegName(Reg));
3057b57ef67SMatt Arsenault     assert(NewReg == Reg && "expected to preserve virtreg number");
306f163106fSMatt Arsenault 
3077b57ef67SMatt Arsenault     DstMRI->setRegClassOrRegBank(NewReg, SrcMRI->getRegClassOrRegBank(Reg));
308e33b07f8SMatt Arsenault 
3097b57ef67SMatt Arsenault     LLT RegTy = SrcMRI->getType(Reg);
310a0f9e4edSMatt Arsenault     if (RegTy.isValid())
3117b57ef67SMatt Arsenault       DstMRI->setType(NewReg, RegTy);
312fd41738eSMarkus Lavin 
3133217ca08SMatt Arsenault     // Copy register allocation hints.
31441491c77SAlexis Engelke     const auto *Hints = SrcMRI->getRegAllocationHints(Reg);
31541491c77SAlexis Engelke     if (Hints)
31641491c77SAlexis Engelke       for (Register PrefReg : Hints->second)
3177b57ef67SMatt Arsenault         DstMRI->addRegAllocationHint(NewReg, PrefReg);
3183217ca08SMatt Arsenault   }
3193217ca08SMatt Arsenault 
32053d88581SMatt Arsenault   const TargetSubtargetInfo &STI = DstMF->getSubtarget();
32153d88581SMatt Arsenault   const TargetInstrInfo *TII = STI.getInstrInfo();
32253d88581SMatt Arsenault   const TargetRegisterInfo *TRI = STI.getRegisterInfo();
32353d88581SMatt Arsenault 
324fd41738eSMarkus Lavin   // Link blocks.
325fd41738eSMarkus Lavin   for (auto &SrcMBB : *SrcMF) {
326fd41738eSMarkus Lavin     auto *DstMBB = Src2DstMBB[&SrcMBB];
327fd41738eSMarkus Lavin     DstMF->push_back(DstMBB);
32853d88581SMatt Arsenault 
329fd41738eSMarkus Lavin     for (auto It = SrcMBB.succ_begin(), IterEnd = SrcMBB.succ_end();
330fd41738eSMarkus Lavin          It != IterEnd; ++It) {
331fd41738eSMarkus Lavin       auto *SrcSuccMBB = *It;
332fd41738eSMarkus Lavin       auto *DstSuccMBB = Src2DstMBB[SrcSuccMBB];
33353d88581SMatt Arsenault       DstMBB->addSuccessor(DstSuccMBB, SrcMBB.getSuccProbability(It));
334fd41738eSMarkus Lavin     }
33556303223SMatt Arsenault 
33656303223SMatt Arsenault     for (auto &LI : SrcMBB.liveins_dbg())
337fd41738eSMarkus Lavin       DstMBB->addLiveIn(LI);
33853d88581SMatt Arsenault 
33953d88581SMatt Arsenault     // Make sure MRI knows about registers clobbered by unwinder.
34053d88581SMatt Arsenault     if (DstMBB->isEHPad()) {
34153d88581SMatt Arsenault       if (auto *RegMask = TRI->getCustomEHPadPreservedMask(*DstMF))
34253d88581SMatt Arsenault         DstMRI->addPhysRegsUsedFromRegMask(RegMask);
343fd41738eSMarkus Lavin     }
34453d88581SMatt Arsenault   }
34553d88581SMatt Arsenault 
3460f9d9eddSMatt Arsenault   DenseSet<const uint32_t *> ConstRegisterMasks;
3470f9d9eddSMatt Arsenault 
3480f9d9eddSMatt Arsenault   // Track predefined/named regmasks which we ignore.
3490f9d9eddSMatt Arsenault   for (const uint32_t *Mask : TRI->getRegMasks())
3500f9d9eddSMatt Arsenault     ConstRegisterMasks.insert(Mask);
3510f9d9eddSMatt Arsenault 
352fd41738eSMarkus Lavin   // Clone instructions.
353fd41738eSMarkus Lavin   for (auto &SrcMBB : *SrcMF) {
354fd41738eSMarkus Lavin     auto *DstMBB = Src2DstMBB[&SrcMBB];
355fd41738eSMarkus Lavin     for (auto &SrcMI : SrcMBB) {
35653d88581SMatt Arsenault       const auto &MCID = TII->get(SrcMI.getOpcode());
357fd41738eSMarkus Lavin       auto *DstMI = DstMF->CreateMachineInstr(MCID, SrcMI.getDebugLoc(),
358fd41738eSMarkus Lavin                                               /*NoImplicit=*/true);
35918b9c463SMatt Arsenault       DstMI->setFlags(SrcMI.getFlags());
36018b9c463SMatt Arsenault       DstMI->setAsmPrinterFlag(SrcMI.getAsmPrinterFlags());
36118b9c463SMatt Arsenault 
362fd41738eSMarkus Lavin       DstMBB->push_back(DstMI);
363fd41738eSMarkus Lavin       for (auto &SrcMO : SrcMI.operands()) {
364fd41738eSMarkus Lavin         MachineOperand DstMO(SrcMO);
365fd41738eSMarkus Lavin         DstMO.clearParent();
3667b57ef67SMatt Arsenault 
367fd41738eSMarkus Lavin         // Update MBB.
3687b57ef67SMatt Arsenault         if (DstMO.isMBB())
369fd41738eSMarkus Lavin           DstMO.setMBB(Src2DstMBB[DstMO.getMBB()]);
3700f9d9eddSMatt Arsenault         else if (DstMO.isRegMask()) {
3717b57ef67SMatt Arsenault           DstMRI->addPhysRegsUsedFromRegMask(DstMO.getRegMask());
372f163106fSMatt Arsenault 
3730f9d9eddSMatt Arsenault           if (!ConstRegisterMasks.count(DstMO.getRegMask())) {
3740f9d9eddSMatt Arsenault             uint32_t *DstMask = DstMF->allocateRegMask();
3750f9d9eddSMatt Arsenault             std::memcpy(DstMask, SrcMO.getRegMask(),
3760f9d9eddSMatt Arsenault                         sizeof(*DstMask) *
3770f9d9eddSMatt Arsenault                             MachineOperand::getRegMaskSize(TRI->getNumRegs()));
3780f9d9eddSMatt Arsenault             DstMO.setRegMask(DstMask);
3790f9d9eddSMatt Arsenault           }
3800f9d9eddSMatt Arsenault         }
3810f9d9eddSMatt Arsenault 
382fd41738eSMarkus Lavin         DstMI->addOperand(DstMO);
383fd41738eSMarkus Lavin       }
38471720976SMatt Arsenault 
38571720976SMatt Arsenault       cloneMemOperands(*DstMI, SrcMI, *SrcMF, *DstMF);
386fd41738eSMarkus Lavin     }
387fd41738eSMarkus Lavin   }
388fd41738eSMarkus Lavin 
389193fde75SMatt Arsenault   DstMF->setAlignment(SrcMF->getAlignment());
390193fde75SMatt Arsenault   DstMF->setExposesReturnsTwice(SrcMF->exposesReturnsTwice());
391193fde75SMatt Arsenault   DstMF->setHasInlineAsm(SrcMF->hasInlineAsm());
392193fde75SMatt Arsenault   DstMF->setHasWinCFI(SrcMF->hasWinCFI());
393193fde75SMatt Arsenault 
394193fde75SMatt Arsenault   DstMF->getProperties().reset().set(SrcMF->getProperties());
395193fde75SMatt Arsenault 
396193fde75SMatt Arsenault   if (!SrcMF->getFrameInstructions().empty() ||
397193fde75SMatt Arsenault       !SrcMF->getLongjmpTargets().empty() ||
398193fde75SMatt Arsenault       !SrcMF->getCatchretTargets().empty())
399193fde75SMatt Arsenault     report_fatal_error("cloning not implemented for machine function property");
400193fde75SMatt Arsenault 
401193fde75SMatt Arsenault   DstMF->setCallsEHReturn(SrcMF->callsEHReturn());
402193fde75SMatt Arsenault   DstMF->setCallsUnwindInit(SrcMF->callsUnwindInit());
403193fde75SMatt Arsenault   DstMF->setHasEHCatchret(SrcMF->hasEHCatchret());
404193fde75SMatt Arsenault   DstMF->setHasEHScopes(SrcMF->hasEHScopes());
405193fde75SMatt Arsenault   DstMF->setHasEHFunclets(SrcMF->hasEHFunclets());
406d826b0c9SStephen Tozer   DstMF->setHasFakeUses(SrcMF->hasFakeUses());
407267708f9Swangpc   DstMF->setIsOutlined(SrcMF->isOutlined());
408193fde75SMatt Arsenault 
409193fde75SMatt Arsenault   if (!SrcMF->getLandingPads().empty() ||
410193fde75SMatt Arsenault       !SrcMF->getCodeViewAnnotations().empty() ||
411193fde75SMatt Arsenault       !SrcMF->getTypeInfos().empty() ||
412193fde75SMatt Arsenault       !SrcMF->getFilterIds().empty() ||
413193fde75SMatt Arsenault       SrcMF->hasAnyWasmLandingPadIndex() ||
414193fde75SMatt Arsenault       SrcMF->hasAnyCallSiteLandingPad() ||
415193fde75SMatt Arsenault       SrcMF->hasAnyCallSiteLabel() ||
416193fde75SMatt Arsenault       !SrcMF->getCallSitesInfo().empty())
417193fde75SMatt Arsenault     report_fatal_error("cloning not implemented for machine function property");
418193fde75SMatt Arsenault 
419193fde75SMatt Arsenault   DstMF->setDebugInstrNumberingCount(SrcMF->DebugInstrNumberingCount);
420193fde75SMatt Arsenault 
421cc5a1b3dSMatt Arsenault   if (!DstMF->cloneInfoFrom(*SrcMF, Src2DstMBB))
422cc5a1b3dSMatt Arsenault     report_fatal_error("target does not implement MachineFunctionInfo cloning");
423cc5a1b3dSMatt Arsenault 
42463a5dc4aSJay Foad   DstMRI->freezeReservedRegs();
425cc5a1b3dSMatt Arsenault 
42671ca9fcbSMatt Arsenault   DstMF->verify(nullptr, "", &errs(), /*AbortOnError=*/true);
427fd41738eSMarkus Lavin   return DstMF;
428fd41738eSMarkus Lavin }
429fd41738eSMarkus Lavin 
4306b3956e1SMatthew Voss static void initializeTargetInfo() {
4316b3956e1SMatthew Voss   InitializeAllTargets();
4326b3956e1SMatthew Voss   InitializeAllTargetMCs();
4336b3956e1SMatthew Voss   InitializeAllAsmPrinters();
4346b3956e1SMatthew Voss   InitializeAllAsmParsers();
4356b3956e1SMatthew Voss }
4366b3956e1SMatthew Voss 
437fd41738eSMarkus Lavin void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {
4387c2db666SMatt Arsenault   if (MMI) {
439fd41738eSMarkus Lavin     printMIR(ROS, *M);
4407c2db666SMatt Arsenault     for (Function &F : *M) {
4417c2db666SMatt Arsenault       if (auto *MF = MMI->getMachineFunction(F))
4429a258664SMatt Arsenault         printMIR(ROS, *MMI, *MF);
4437c2db666SMatt Arsenault     }
444fd41738eSMarkus Lavin   } else {
4458a8af120SMarkus Lavin     M->print(ROS, /*AssemblyAnnotationWriter=*/nullptr,
4468a8af120SMarkus Lavin              /*ShouldPreserveUseListOrder=*/true);
447fd41738eSMarkus Lavin   }
448fd41738eSMarkus Lavin }
44935264e71SMatt Arsenault 
450592536a9SMatt Arsenault bool ReducerWorkItem::verify(raw_fd_ostream *OS) const {
451592536a9SMatt Arsenault   if (verifyModule(*M, OS))
452592536a9SMatt Arsenault     return true;
453592536a9SMatt Arsenault 
454592536a9SMatt Arsenault   if (!MMI)
455592536a9SMatt Arsenault     return false;
456592536a9SMatt Arsenault 
457592536a9SMatt Arsenault   for (const Function &F : getModule()) {
458592536a9SMatt Arsenault     if (const MachineFunction *MF = MMI->getMachineFunction(F)) {
45971ca9fcbSMatt Arsenault       // With the current state of quality, most reduction attempts fail the
46071ca9fcbSMatt Arsenault       // machine verifier. Avoid spamming large function dumps on nearly every
46171ca9fcbSMatt Arsenault       // attempt until the situation is better.
46271ca9fcbSMatt Arsenault       if (!MF->verify(nullptr, "",
46371ca9fcbSMatt Arsenault                       /*OS=*/PrintInvalidMachineReductions ? &errs() : nullptr,
46471ca9fcbSMatt Arsenault                       /*AbortOnError=*/false)) {
46571ca9fcbSMatt Arsenault 
46671ca9fcbSMatt Arsenault         if (!PrintInvalidMachineReductions) {
46771ca9fcbSMatt Arsenault           WithColor::warning(errs())
46871ca9fcbSMatt Arsenault               << "reduction attempt on function '" << MF->getName()
46971ca9fcbSMatt Arsenault               << "' failed machine verifier (debug with "
47071ca9fcbSMatt Arsenault                  "-print-invalid-reduction-machine-verifier-errors)\n";
47171ca9fcbSMatt Arsenault         }
472592536a9SMatt Arsenault         return true;
473592536a9SMatt Arsenault       }
474592536a9SMatt Arsenault     }
47571ca9fcbSMatt Arsenault   }
476592536a9SMatt Arsenault 
477592536a9SMatt Arsenault   return false;
478592536a9SMatt Arsenault }
479592536a9SMatt Arsenault 
480592536a9SMatt Arsenault bool ReducerWorkItem::isReduced(const TestRunner &Test) const {
481592536a9SMatt Arsenault   const bool UseBitcode = Test.inputIsBitcode() || TmpFilesAsBitcode;
482592536a9SMatt Arsenault 
483592536a9SMatt Arsenault   SmallString<128> CurrentFilepath;
484592536a9SMatt Arsenault 
485592536a9SMatt Arsenault   // Write ReducerWorkItem to tmp file
486592536a9SMatt Arsenault   int FD;
487592536a9SMatt Arsenault   std::error_code EC = sys::fs::createTemporaryFile(
488592536a9SMatt Arsenault       "llvm-reduce", isMIR() ? "mir" : (UseBitcode ? "bc" : "ll"), FD,
489592536a9SMatt Arsenault       CurrentFilepath,
490592536a9SMatt Arsenault       UseBitcode && !isMIR() ? sys::fs::OF_None : sys::fs::OF_Text);
491592536a9SMatt Arsenault   if (EC) {
492c0a10b27SMatt Arsenault     WithColor::error(errs(), Test.getToolName())
493c0a10b27SMatt Arsenault         << "error making unique filename: " << EC.message() << '\n';
494592536a9SMatt Arsenault     exit(1);
495592536a9SMatt Arsenault   }
496592536a9SMatt Arsenault 
497592536a9SMatt Arsenault   ToolOutputFile Out(CurrentFilepath, FD);
498592536a9SMatt Arsenault 
499d78b4c44SMatt Arsenault   writeOutput(Out.os(), UseBitcode);
500592536a9SMatt Arsenault 
501592536a9SMatt Arsenault   Out.os().close();
502592536a9SMatt Arsenault   if (Out.os().has_error()) {
503c0a10b27SMatt Arsenault     WithColor::error(errs(), Test.getToolName())
504c0a10b27SMatt Arsenault         << "error emitting bitcode to file '" << CurrentFilepath
505c0a10b27SMatt Arsenault         << "': " << Out.os().error().message() << '\n';
506592536a9SMatt Arsenault     exit(1);
507592536a9SMatt Arsenault   }
508592536a9SMatt Arsenault 
509592536a9SMatt Arsenault   // Current Chunks aren't interesting
510592536a9SMatt Arsenault   return Test.run(CurrentFilepath);
511592536a9SMatt Arsenault }
512592536a9SMatt Arsenault 
513592536a9SMatt Arsenault std::unique_ptr<ReducerWorkItem>
514592536a9SMatt Arsenault ReducerWorkItem::clone(const TargetMachine *TM) const {
515592536a9SMatt Arsenault   auto CloneMMM = std::make_unique<ReducerWorkItem>();
516592536a9SMatt Arsenault   if (TM) {
517592536a9SMatt Arsenault     // We're assuming the Module IR contents are always unchanged by MIR
518592536a9SMatt Arsenault     // reductions, and can share it as a constant.
519592536a9SMatt Arsenault     CloneMMM->M = M;
520592536a9SMatt Arsenault 
521592536a9SMatt Arsenault     // MachineModuleInfo contains a lot of other state used during codegen which
522592536a9SMatt Arsenault     // we won't be using here, but we should be able to ignore it (although this
523592536a9SMatt Arsenault     // is pretty ugly).
524*bb3f5e1fSMatin Raayai     CloneMMM->MMI = std::make_unique<MachineModuleInfo>(TM);
525592536a9SMatt Arsenault 
526592536a9SMatt Arsenault     for (const Function &F : getModule()) {
527592536a9SMatt Arsenault       if (auto *MF = MMI->getMachineFunction(F))
528592536a9SMatt Arsenault         CloneMMM->MMI->insertFunction(F, cloneMF(MF, *CloneMMM->MMI));
529592536a9SMatt Arsenault     }
530592536a9SMatt Arsenault   } else {
531592536a9SMatt Arsenault     CloneMMM->M = CloneModule(*M);
532592536a9SMatt Arsenault   }
533592536a9SMatt Arsenault   return CloneMMM;
534592536a9SMatt Arsenault }
535592536a9SMatt Arsenault 
53635264e71SMatt Arsenault /// Try to produce some number that indicates a function is getting smaller /
53735264e71SMatt Arsenault /// simpler.
53835264e71SMatt Arsenault static uint64_t computeMIRComplexityScoreImpl(const MachineFunction &MF) {
53935264e71SMatt Arsenault   uint64_t Score = 0;
54035264e71SMatt Arsenault   const MachineFrameInfo &MFI = MF.getFrameInfo();
54135264e71SMatt Arsenault 
54235264e71SMatt Arsenault   // Add for stack objects
54335264e71SMatt Arsenault   Score += MFI.getNumObjects();
54435264e71SMatt Arsenault 
54535264e71SMatt Arsenault   // Add in the block count.
54635264e71SMatt Arsenault   Score += 2 * MF.size();
54735264e71SMatt Arsenault 
548a0dcbe45SMatt Arsenault   const MachineRegisterInfo &MRI = MF.getRegInfo();
549a0dcbe45SMatt Arsenault   for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
550a0dcbe45SMatt Arsenault     Register Reg = Register::index2VirtReg(I);
55141491c77SAlexis Engelke     if (const auto *Hints = MRI.getRegAllocationHints(Reg))
55241491c77SAlexis Engelke       Score += Hints->second.size();
553a0dcbe45SMatt Arsenault   }
554a0dcbe45SMatt Arsenault 
55535264e71SMatt Arsenault   for (const MachineBasicBlock &MBB : MF) {
55635264e71SMatt Arsenault     for (const MachineInstr &MI : MBB) {
55735264e71SMatt Arsenault       const unsigned Opc = MI.getOpcode();
55835264e71SMatt Arsenault 
55935264e71SMatt Arsenault       // Reductions may want or need to introduce implicit_defs, so don't count
56035264e71SMatt Arsenault       // them.
56135264e71SMatt Arsenault       // TODO: These probably should count in some way.
56235264e71SMatt Arsenault       if (Opc == TargetOpcode::IMPLICIT_DEF ||
56335264e71SMatt Arsenault           Opc == TargetOpcode::G_IMPLICIT_DEF)
56435264e71SMatt Arsenault         continue;
56535264e71SMatt Arsenault 
56635264e71SMatt Arsenault       // Each instruction adds to the score
56735264e71SMatt Arsenault       Score += 4;
56835264e71SMatt Arsenault 
56935264e71SMatt Arsenault       if (Opc == TargetOpcode::PHI || Opc == TargetOpcode::G_PHI ||
57035264e71SMatt Arsenault           Opc == TargetOpcode::INLINEASM || Opc == TargetOpcode::INLINEASM_BR)
57135264e71SMatt Arsenault         ++Score;
57235264e71SMatt Arsenault 
57335264e71SMatt Arsenault       if (MI.getFlags() != 0)
57435264e71SMatt Arsenault         ++Score;
57535264e71SMatt Arsenault 
57635264e71SMatt Arsenault       // Increase weight for more operands.
57735264e71SMatt Arsenault       for (const MachineOperand &MO : MI.operands()) {
57835264e71SMatt Arsenault         ++Score;
57935264e71SMatt Arsenault 
58035264e71SMatt Arsenault         // Treat registers as more complex.
58135264e71SMatt Arsenault         if (MO.isReg()) {
58235264e71SMatt Arsenault           ++Score;
58335264e71SMatt Arsenault 
58435264e71SMatt Arsenault           // And subregisters as even more complex.
58535264e71SMatt Arsenault           if (MO.getSubReg()) {
58635264e71SMatt Arsenault             ++Score;
58735264e71SMatt Arsenault             if (MO.isDef())
58835264e71SMatt Arsenault               ++Score;
58935264e71SMatt Arsenault           }
59035264e71SMatt Arsenault         } else if (MO.isRegMask())
59135264e71SMatt Arsenault           ++Score;
59235264e71SMatt Arsenault       }
59335264e71SMatt Arsenault     }
59435264e71SMatt Arsenault   }
59535264e71SMatt Arsenault 
59635264e71SMatt Arsenault   return Score;
59735264e71SMatt Arsenault }
59835264e71SMatt Arsenault 
59935264e71SMatt Arsenault uint64_t ReducerWorkItem::computeMIRComplexityScore() const {
60035264e71SMatt Arsenault   uint64_t Score = 0;
60135264e71SMatt Arsenault 
60235264e71SMatt Arsenault   for (const Function &F : getModule()) {
60335264e71SMatt Arsenault     if (auto *MF = MMI->getMachineFunction(F))
60435264e71SMatt Arsenault       Score += computeMIRComplexityScoreImpl(*MF);
60535264e71SMatt Arsenault   }
60635264e71SMatt Arsenault 
60735264e71SMatt Arsenault   return Score;
60835264e71SMatt Arsenault }
609c23ac22fSMatt Arsenault 
610c23ac22fSMatt Arsenault // FIXME: ReduceOperandsSkip has similar function, except it uses larger numbers
611c23ac22fSMatt Arsenault // for more reduced.
612c23ac22fSMatt Arsenault static unsigned classifyReductivePower(const Value *V) {
613c23ac22fSMatt Arsenault   if (auto *C = dyn_cast<ConstantData>(V)) {
614c23ac22fSMatt Arsenault     if (C->isNullValue())
615c23ac22fSMatt Arsenault       return 0;
616c23ac22fSMatt Arsenault     if (C->isOneValue())
617c23ac22fSMatt Arsenault       return 1;
618c23ac22fSMatt Arsenault     if (isa<UndefValue>(V))
619c23ac22fSMatt Arsenault       return 2;
620c23ac22fSMatt Arsenault     return 3;
621c23ac22fSMatt Arsenault   }
622c23ac22fSMatt Arsenault 
623c23ac22fSMatt Arsenault   if (isa<GlobalValue>(V))
624c23ac22fSMatt Arsenault     return 4;
625c23ac22fSMatt Arsenault 
626c23ac22fSMatt Arsenault   // TODO: Account for expression size
627c23ac22fSMatt Arsenault   if (isa<ConstantExpr>(V))
628c23ac22fSMatt Arsenault     return 5;
629c23ac22fSMatt Arsenault 
630c23ac22fSMatt Arsenault   if (isa<Constant>(V))
631c23ac22fSMatt Arsenault     return 1;
632c23ac22fSMatt Arsenault 
633c23ac22fSMatt Arsenault   if (isa<Argument>(V))
634c23ac22fSMatt Arsenault     return 6;
635c23ac22fSMatt Arsenault 
636c23ac22fSMatt Arsenault   if (isa<Instruction>(V))
637c23ac22fSMatt Arsenault     return 7;
638c23ac22fSMatt Arsenault 
639c23ac22fSMatt Arsenault   return 0;
640c23ac22fSMatt Arsenault }
641c23ac22fSMatt Arsenault 
642c23ac22fSMatt Arsenault // TODO: Additional flags and attributes may be complexity reducing. If we start
643c23ac22fSMatt Arsenault // adding flags and attributes, they could have negative cost.
644c23ac22fSMatt Arsenault static uint64_t computeIRComplexityScoreImpl(const Function &F) {
645c23ac22fSMatt Arsenault   uint64_t Score = 1; // Count the function itself
646c23ac22fSMatt Arsenault   SmallVector<std::pair<unsigned, MDNode *>> MDs;
647c23ac22fSMatt Arsenault 
648c23ac22fSMatt Arsenault   AttributeList Attrs = F.getAttributes();
649c23ac22fSMatt Arsenault   for (AttributeSet AttrSet : Attrs)
650c23ac22fSMatt Arsenault     Score += AttrSet.getNumAttributes();
651c23ac22fSMatt Arsenault 
652c23ac22fSMatt Arsenault   for (const BasicBlock &BB : F) {
653c23ac22fSMatt Arsenault     ++Score;
654c23ac22fSMatt Arsenault 
655c23ac22fSMatt Arsenault     for (const Instruction &I : BB) {
656c23ac22fSMatt Arsenault       ++Score;
657c23ac22fSMatt Arsenault 
658c23ac22fSMatt Arsenault       if (const auto *OverflowOp = dyn_cast<OverflowingBinaryOperator>(&I)) {
659c23ac22fSMatt Arsenault         if (OverflowOp->hasNoUnsignedWrap())
660c23ac22fSMatt Arsenault           ++Score;
661c23ac22fSMatt Arsenault         if (OverflowOp->hasNoSignedWrap())
662c23ac22fSMatt Arsenault           ++Score;
663b74182edSNikita Popov       } else if (const auto *Trunc = dyn_cast<TruncInst>(&I)) {
664b74182edSNikita Popov         if (Trunc->hasNoSignedWrap())
665b74182edSNikita Popov           ++Score;
666b74182edSNikita Popov         if (Trunc->hasNoUnsignedWrap())
667c23ac22fSMatt Arsenault           ++Score;
668c23ac22fSMatt Arsenault       } else if (const auto *ExactOp = dyn_cast<PossiblyExactOperator>(&I)) {
669c23ac22fSMatt Arsenault         if (ExactOp->isExact())
670c23ac22fSMatt Arsenault           ++Score;
671b74182edSNikita Popov       } else if (const auto *NNI = dyn_cast<PossiblyNonNegInst>(&I)) {
672b74182edSNikita Popov         if (NNI->hasNonNeg())
673b74182edSNikita Popov           ++Score;
674b74182edSNikita Popov       } else if (const auto *PDI = dyn_cast<PossiblyDisjointInst>(&I)) {
675b74182edSNikita Popov         if (PDI->isDisjoint())
676b74182edSNikita Popov           ++Score;
677b74182edSNikita Popov       } else if (const auto *GEP = dyn_cast<GEPOperator>(&I)) {
678b74182edSNikita Popov         if (GEP->isInBounds())
679b74182edSNikita Popov           ++Score;
680b74182edSNikita Popov         if (GEP->hasNoUnsignedSignedWrap())
681b74182edSNikita Popov           ++Score;
682b74182edSNikita Popov         if (GEP->hasNoUnsignedWrap())
683b74182edSNikita Popov           ++Score;
684c23ac22fSMatt Arsenault       } else if (const auto *FPOp = dyn_cast<FPMathOperator>(&I)) {
685c23ac22fSMatt Arsenault         FastMathFlags FMF = FPOp->getFastMathFlags();
686c23ac22fSMatt Arsenault         if (FMF.allowReassoc())
687c23ac22fSMatt Arsenault           ++Score;
688c23ac22fSMatt Arsenault         if (FMF.noNaNs())
689c23ac22fSMatt Arsenault           ++Score;
690c23ac22fSMatt Arsenault         if (FMF.noInfs())
691c23ac22fSMatt Arsenault           ++Score;
692c23ac22fSMatt Arsenault         if (FMF.noSignedZeros())
693c23ac22fSMatt Arsenault           ++Score;
694c23ac22fSMatt Arsenault         if (FMF.allowReciprocal())
695c23ac22fSMatt Arsenault           ++Score;
696c23ac22fSMatt Arsenault         if (FMF.allowContract())
697c23ac22fSMatt Arsenault           ++Score;
698c23ac22fSMatt Arsenault         if (FMF.approxFunc())
699c23ac22fSMatt Arsenault           ++Score;
700c23ac22fSMatt Arsenault       }
701c23ac22fSMatt Arsenault 
702c23ac22fSMatt Arsenault       for (const Value *Operand : I.operands()) {
703c23ac22fSMatt Arsenault         ++Score;
704c23ac22fSMatt Arsenault         Score += classifyReductivePower(Operand);
705c23ac22fSMatt Arsenault       }
706c23ac22fSMatt Arsenault 
707c23ac22fSMatt Arsenault       I.getAllMetadata(MDs);
708c23ac22fSMatt Arsenault       Score += MDs.size();
709c23ac22fSMatt Arsenault       MDs.clear();
710c23ac22fSMatt Arsenault     }
711c23ac22fSMatt Arsenault   }
712c23ac22fSMatt Arsenault 
713c23ac22fSMatt Arsenault   return Score;
714c23ac22fSMatt Arsenault }
715c23ac22fSMatt Arsenault 
716c23ac22fSMatt Arsenault uint64_t ReducerWorkItem::computeIRComplexityScore() const {
717c23ac22fSMatt Arsenault   uint64_t Score = 0;
718c23ac22fSMatt Arsenault 
719c23ac22fSMatt Arsenault   const Module &M = getModule();
720c23ac22fSMatt Arsenault   Score += M.named_metadata_size();
721c23ac22fSMatt Arsenault 
722c23ac22fSMatt Arsenault   SmallVector<std::pair<unsigned, MDNode *>, 32> GlobalMetadata;
723c23ac22fSMatt Arsenault   for (const GlobalVariable &GV : M.globals()) {
724c23ac22fSMatt Arsenault     ++Score;
725c23ac22fSMatt Arsenault 
726c23ac22fSMatt Arsenault     if (GV.hasInitializer())
7270782d97fSMatt Arsenault       Score += classifyReductivePower(GV.getInitializer());
728c23ac22fSMatt Arsenault 
729c23ac22fSMatt Arsenault     // TODO: Account for linkage?
730c23ac22fSMatt Arsenault 
731c23ac22fSMatt Arsenault     GV.getAllMetadata(GlobalMetadata);
732c23ac22fSMatt Arsenault     Score += GlobalMetadata.size();
733c23ac22fSMatt Arsenault     GlobalMetadata.clear();
734c23ac22fSMatt Arsenault   }
735c23ac22fSMatt Arsenault 
736a6000c14SMatt Arsenault   for (const GlobalAlias &GA : M.aliases())
737a6000c14SMatt Arsenault     Score += classifyReductivePower(GA.getAliasee());
738a6000c14SMatt Arsenault 
739a6000c14SMatt Arsenault   for (const GlobalIFunc &GI : M.ifuncs())
740a6000c14SMatt Arsenault     Score += classifyReductivePower(GI.getResolver());
741a6000c14SMatt Arsenault 
742c23ac22fSMatt Arsenault   for (const Function &F : M)
743c23ac22fSMatt Arsenault     Score += computeIRComplexityScoreImpl(F);
744c23ac22fSMatt Arsenault 
745c23ac22fSMatt Arsenault   return Score;
746c23ac22fSMatt Arsenault }
747592536a9SMatt Arsenault 
748592536a9SMatt Arsenault void ReducerWorkItem::writeOutput(raw_ostream &OS, bool EmitBitcode) const {
749592536a9SMatt Arsenault   // Requesting bitcode emission with mir is nonsense, so just ignore it.
750592536a9SMatt Arsenault   if (EmitBitcode && !isMIR())
751592536a9SMatt Arsenault     writeBitcode(OS);
752592536a9SMatt Arsenault   else
753592536a9SMatt Arsenault     print(OS, /*AnnotationWriter=*/nullptr);
754592536a9SMatt Arsenault }
755592536a9SMatt Arsenault 
756592536a9SMatt Arsenault void ReducerWorkItem::readBitcode(MemoryBufferRef Data, LLVMContext &Ctx,
757592536a9SMatt Arsenault                                   StringRef ToolName) {
758592536a9SMatt Arsenault   Expected<BitcodeFileContents> IF = llvm::getBitcodeFileContents(Data);
759592536a9SMatt Arsenault   if (!IF) {
760592536a9SMatt Arsenault     WithColor::error(errs(), ToolName) << IF.takeError();
761592536a9SMatt Arsenault     exit(1);
762592536a9SMatt Arsenault   }
763592536a9SMatt Arsenault   BitcodeModule BM = IF->Mods[0];
764592536a9SMatt Arsenault   Expected<BitcodeLTOInfo> LI = BM.getLTOInfo();
765592536a9SMatt Arsenault   Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(Ctx);
766592536a9SMatt Arsenault   if (!LI || !MOrErr) {
767592536a9SMatt Arsenault     WithColor::error(errs(), ToolName) << IF.takeError();
768592536a9SMatt Arsenault     exit(1);
769592536a9SMatt Arsenault   }
770592536a9SMatt Arsenault   LTOInfo = std::make_unique<BitcodeLTOInfo>(*LI);
771592536a9SMatt Arsenault   M = std::move(MOrErr.get());
772592536a9SMatt Arsenault }
773592536a9SMatt Arsenault 
774592536a9SMatt Arsenault void ReducerWorkItem::writeBitcode(raw_ostream &OutStream) const {
775592536a9SMatt Arsenault   if (LTOInfo && LTOInfo->IsThinLTO && LTOInfo->EnableSplitLTOUnit) {
776592536a9SMatt Arsenault     PassBuilder PB;
777592536a9SMatt Arsenault     LoopAnalysisManager LAM;
778592536a9SMatt Arsenault     FunctionAnalysisManager FAM;
779592536a9SMatt Arsenault     CGSCCAnalysisManager CGAM;
780592536a9SMatt Arsenault     ModuleAnalysisManager MAM;
781592536a9SMatt Arsenault     PB.registerModuleAnalyses(MAM);
782592536a9SMatt Arsenault     PB.registerCGSCCAnalyses(CGAM);
783592536a9SMatt Arsenault     PB.registerFunctionAnalyses(FAM);
784592536a9SMatt Arsenault     PB.registerLoopAnalyses(LAM);
785592536a9SMatt Arsenault     PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
786592536a9SMatt Arsenault     ModulePassManager MPM;
787592536a9SMatt Arsenault     MPM.addPass(ThinLTOBitcodeWriterPass(OutStream, nullptr));
788592536a9SMatt Arsenault     MPM.run(*M, MAM);
789592536a9SMatt Arsenault   } else {
790592536a9SMatt Arsenault     std::unique_ptr<ModuleSummaryIndex> Index;
791592536a9SMatt Arsenault     if (LTOInfo && LTOInfo->HasSummary) {
792592536a9SMatt Arsenault       ProfileSummaryInfo PSI(*M);
793592536a9SMatt Arsenault       Index = std::make_unique<ModuleSummaryIndex>(
794592536a9SMatt Arsenault           buildModuleSummaryIndex(*M, nullptr, &PSI));
795592536a9SMatt Arsenault     }
796363d99dbSMatt Arsenault     WriteBitcodeToFile(getModule(), OutStream,
797363d99dbSMatt Arsenault                        /*ShouldPreserveUseListOrder=*/true, Index.get());
798592536a9SMatt Arsenault   }
799592536a9SMatt Arsenault }
800592536a9SMatt Arsenault 
801592536a9SMatt Arsenault std::pair<std::unique_ptr<ReducerWorkItem>, bool>
802592536a9SMatt Arsenault llvm::parseReducerWorkItem(StringRef ToolName, StringRef Filename,
803592536a9SMatt Arsenault                            LLVMContext &Ctxt,
804592536a9SMatt Arsenault                            std::unique_ptr<TargetMachine> &TM, bool IsMIR) {
805592536a9SMatt Arsenault   bool IsBitcode = false;
806592536a9SMatt Arsenault   Triple TheTriple;
807592536a9SMatt Arsenault 
808592536a9SMatt Arsenault   auto MMM = std::make_unique<ReducerWorkItem>();
809592536a9SMatt Arsenault 
810592536a9SMatt Arsenault   if (IsMIR) {
811592536a9SMatt Arsenault     initializeTargetInfo();
812592536a9SMatt Arsenault 
813592536a9SMatt Arsenault     auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
814592536a9SMatt Arsenault     if (std::error_code EC = FileOrErr.getError()) {
815592536a9SMatt Arsenault       WithColor::error(errs(), ToolName) << EC.message() << '\n';
816592536a9SMatt Arsenault       return {nullptr, false};
817592536a9SMatt Arsenault     }
818592536a9SMatt Arsenault 
819592536a9SMatt Arsenault     std::unique_ptr<MIRParser> MParser =
820592536a9SMatt Arsenault         createMIRParser(std::move(FileOrErr.get()), Ctxt);
821592536a9SMatt Arsenault 
822592536a9SMatt Arsenault     auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
823592536a9SMatt Arsenault                              StringRef OldDLStr) -> std::optional<std::string> {
824a8f8613dSAlex Richardson       // NB: We always call createTargetMachineForTriple() even if an explicit
825a8f8613dSAlex Richardson       // DataLayout is already set in the module since we want to use this
826a8f8613dSAlex Richardson       // callback to setup the TargetMachine rather than doing it later.
827592536a9SMatt Arsenault       std::string IRTargetTriple = DataLayoutTargetTriple.str();
828592536a9SMatt Arsenault       if (!TargetTriple.empty())
829592536a9SMatt Arsenault         IRTargetTriple = Triple::normalize(TargetTriple);
830592536a9SMatt Arsenault       TheTriple = Triple(IRTargetTriple);
831592536a9SMatt Arsenault       if (TheTriple.getTriple().empty())
832592536a9SMatt Arsenault         TheTriple.setTriple(sys::getDefaultTargetTriple());
833a8f8613dSAlex Richardson       ExitOnError ExitOnErr(std::string(ToolName) + ": error: ");
834a8f8613dSAlex Richardson       TM = ExitOnErr(codegen::createTargetMachineForTriple(TheTriple.str()));
835592536a9SMatt Arsenault 
836592536a9SMatt Arsenault       return TM->createDataLayout().getStringRepresentation();
837592536a9SMatt Arsenault     };
838592536a9SMatt Arsenault 
839592536a9SMatt Arsenault     std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);
840592536a9SMatt Arsenault 
841*bb3f5e1fSMatin Raayai     MMM->MMI = std::make_unique<MachineModuleInfo>(TM.get());
842592536a9SMatt Arsenault     MParser->parseMachineFunctions(*M, *MMM->MMI);
843592536a9SMatt Arsenault     MMM->M = std::move(M);
844592536a9SMatt Arsenault   } else {
845592536a9SMatt Arsenault     SMDiagnostic Err;
846592536a9SMatt Arsenault     ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
847592536a9SMatt Arsenault         MemoryBuffer::getFileOrSTDIN(Filename);
848592536a9SMatt Arsenault     if (std::error_code EC = MB.getError()) {
849592536a9SMatt Arsenault       WithColor::error(errs(), ToolName)
850592536a9SMatt Arsenault           << Filename << ": " << EC.message() << "\n";
851592536a9SMatt Arsenault       return {nullptr, false};
852592536a9SMatt Arsenault     }
853592536a9SMatt Arsenault 
854592536a9SMatt Arsenault     if (!isBitcode((const unsigned char *)(*MB)->getBufferStart(),
855592536a9SMatt Arsenault                    (const unsigned char *)(*MB)->getBufferEnd())) {
856c5fa6b16SMatt Arsenault       std::unique_ptr<Module> Result = parseIR(**MB, Err, Ctxt);
857592536a9SMatt Arsenault       if (!Result) {
858592536a9SMatt Arsenault         Err.print(ToolName.data(), errs());
859592536a9SMatt Arsenault         return {nullptr, false};
860592536a9SMatt Arsenault       }
861592536a9SMatt Arsenault       MMM->M = std::move(Result);
862592536a9SMatt Arsenault     } else {
863592536a9SMatt Arsenault       IsBitcode = true;
864592536a9SMatt Arsenault       MMM->readBitcode(MemoryBufferRef(**MB), Ctxt, ToolName);
865592536a9SMatt Arsenault 
866592536a9SMatt Arsenault       if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit)
867592536a9SMatt Arsenault         initializeTargetInfo();
868592536a9SMatt Arsenault     }
869592536a9SMatt Arsenault   }
870592536a9SMatt Arsenault   if (MMM->verify(&errs())) {
871592536a9SMatt Arsenault     WithColor::error(errs(), ToolName)
872592536a9SMatt Arsenault         << Filename << " - input module is broken!\n";
873592536a9SMatt Arsenault     return {nullptr, false};
874592536a9SMatt Arsenault   }
875592536a9SMatt Arsenault   return {std::move(MMM), IsBitcode};
876592536a9SMatt Arsenault }
877