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