//===- ReducerWorkItem.cpp - Wrapper for Module and MachineFunction -------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "ReducerWorkItem.h" #include "TestRunner.h" #include "llvm/Analysis/ModuleSummaryAnalysis.h" #include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/MIRParser/MIRParser.h" #include "llvm/CodeGen/MIRPrinter.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/WithColor.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" #include "llvm/Transforms/Utils/Cloning.h" #include using namespace llvm; ReducerWorkItem::ReducerWorkItem() = default; ReducerWorkItem::~ReducerWorkItem() = default; extern cl::OptionCategory LLVMReduceOptions; static cl::opt TargetTriple("mtriple", cl::desc("Set the target triple"), cl::cat(LLVMReduceOptions)); static cl::opt TmpFilesAsBitcode( "write-tmp-files-as-bitcode", cl::desc("Always write temporary files as bitcode instead of textual IR"), cl::init(false), cl::cat(LLVMReduceOptions)); static void cloneFrameInfo( MachineFrameInfo &DstMFI, const MachineFrameInfo &SrcMFI, const DenseMap &Src2DstMBB) { DstMFI.setFrameAddressIsTaken(SrcMFI.isFrameAddressTaken()); DstMFI.setReturnAddressIsTaken(SrcMFI.isReturnAddressTaken()); DstMFI.setHasStackMap(SrcMFI.hasStackMap()); DstMFI.setHasPatchPoint(SrcMFI.hasPatchPoint()); DstMFI.setUseLocalStackAllocationBlock( SrcMFI.getUseLocalStackAllocationBlock()); DstMFI.setOffsetAdjustment(SrcMFI.getOffsetAdjustment()); DstMFI.ensureMaxAlignment(SrcMFI.getMaxAlign()); assert(DstMFI.getMaxAlign() == SrcMFI.getMaxAlign() && "we need to set exact alignment"); DstMFI.setAdjustsStack(SrcMFI.adjustsStack()); DstMFI.setHasCalls(SrcMFI.hasCalls()); DstMFI.setHasOpaqueSPAdjustment(SrcMFI.hasOpaqueSPAdjustment()); DstMFI.setHasCopyImplyingStackAdjustment( SrcMFI.hasCopyImplyingStackAdjustment()); DstMFI.setHasVAStart(SrcMFI.hasVAStart()); DstMFI.setHasMustTailInVarArgFunc(SrcMFI.hasMustTailInVarArgFunc()); DstMFI.setHasTailCall(SrcMFI.hasTailCall()); if (SrcMFI.isMaxCallFrameSizeComputed()) DstMFI.setMaxCallFrameSize(SrcMFI.getMaxCallFrameSize()); DstMFI.setCVBytesOfCalleeSavedRegisters( SrcMFI.getCVBytesOfCalleeSavedRegisters()); if (MachineBasicBlock *SavePt = SrcMFI.getSavePoint()) DstMFI.setSavePoint(Src2DstMBB.find(SavePt)->second); if (MachineBasicBlock *RestorePt = SrcMFI.getRestorePoint()) DstMFI.setRestorePoint(Src2DstMBB.find(RestorePt)->second); auto CopyObjectProperties = [](MachineFrameInfo &DstMFI, const MachineFrameInfo &SrcMFI, int FI) { if (SrcMFI.isStatepointSpillSlotObjectIndex(FI)) DstMFI.markAsStatepointSpillSlotObjectIndex(FI); DstMFI.setObjectSSPLayout(FI, SrcMFI.getObjectSSPLayout(FI)); DstMFI.setObjectZExt(FI, SrcMFI.isObjectZExt(FI)); DstMFI.setObjectSExt(FI, SrcMFI.isObjectSExt(FI)); }; for (int i = 0, e = SrcMFI.getNumObjects() - SrcMFI.getNumFixedObjects(); i != e; ++i) { int NewFI; assert(!SrcMFI.isFixedObjectIndex(i)); if (SrcMFI.isVariableSizedObjectIndex(i)) { NewFI = DstMFI.CreateVariableSizedObject(SrcMFI.getObjectAlign(i), SrcMFI.getObjectAllocation(i)); } else { NewFI = DstMFI.CreateStackObject( SrcMFI.getObjectSize(i), SrcMFI.getObjectAlign(i), SrcMFI.isSpillSlotObjectIndex(i), SrcMFI.getObjectAllocation(i), SrcMFI.getStackID(i)); DstMFI.setObjectOffset(NewFI, SrcMFI.getObjectOffset(i)); } CopyObjectProperties(DstMFI, SrcMFI, i); (void)NewFI; assert(i == NewFI && "expected to keep stable frame index numbering"); } // Copy the fixed frame objects backwards to preserve frame index numbers, // since CreateFixedObject uses front insertion. for (int i = -1; i >= (int)-SrcMFI.getNumFixedObjects(); --i) { assert(SrcMFI.isFixedObjectIndex(i)); int NewFI = DstMFI.CreateFixedObject( SrcMFI.getObjectSize(i), SrcMFI.getObjectOffset(i), SrcMFI.isImmutableObjectIndex(i), SrcMFI.isAliasedObjectIndex(i)); CopyObjectProperties(DstMFI, SrcMFI, i); (void)NewFI; assert(i == NewFI && "expected to keep stable frame index numbering"); } for (unsigned I = 0, E = SrcMFI.getLocalFrameObjectCount(); I < E; ++I) { auto LocalObject = SrcMFI.getLocalFrameObjectMap(I); DstMFI.mapLocalFrameObject(LocalObject.first, LocalObject.second); } DstMFI.setCalleeSavedInfo(SrcMFI.getCalleeSavedInfo()); if (SrcMFI.hasStackProtectorIndex()) { DstMFI.setStackProtectorIndex(SrcMFI.getStackProtectorIndex()); } // FIXME: Needs test, missing MIR serialization. if (SrcMFI.hasFunctionContextIndex()) { DstMFI.setFunctionContextIndex(SrcMFI.getFunctionContextIndex()); } } static void cloneMemOperands(MachineInstr &DstMI, MachineInstr &SrcMI, MachineFunction &SrcMF, MachineFunction &DstMF) { // The new MachineMemOperands should be owned by the new function's // Allocator. PseudoSourceValueManager &PSVMgr = DstMF.getPSVManager(); // We also need to remap the PseudoSourceValues from the new function's // PseudoSourceValueManager. SmallVector NewMMOs; for (MachineMemOperand *OldMMO : SrcMI.memoperands()) { MachinePointerInfo NewPtrInfo(OldMMO->getPointerInfo()); if (const PseudoSourceValue *PSV = NewPtrInfo.V.dyn_cast()) { switch (PSV->kind()) { case PseudoSourceValue::Stack: NewPtrInfo.V = PSVMgr.getStack(); break; case PseudoSourceValue::GOT: NewPtrInfo.V = PSVMgr.getGOT(); break; case PseudoSourceValue::JumpTable: NewPtrInfo.V = PSVMgr.getJumpTable(); break; case PseudoSourceValue::ConstantPool: NewPtrInfo.V = PSVMgr.getConstantPool(); break; case PseudoSourceValue::FixedStack: NewPtrInfo.V = PSVMgr.getFixedStack( cast(PSV)->getFrameIndex()); break; case PseudoSourceValue::GlobalValueCallEntry: NewPtrInfo.V = PSVMgr.getGlobalValueCallEntry( cast(PSV)->getValue()); break; case PseudoSourceValue::ExternalSymbolCallEntry: NewPtrInfo.V = PSVMgr.getExternalSymbolCallEntry( cast(PSV)->getSymbol()); break; case PseudoSourceValue::TargetCustom: default: // FIXME: We have no generic interface for allocating custom PSVs. report_fatal_error("Cloning TargetCustom PSV not handled"); } } MachineMemOperand *NewMMO = DstMF.getMachineMemOperand( NewPtrInfo, OldMMO->getFlags(), OldMMO->getMemoryType(), OldMMO->getBaseAlign(), OldMMO->getAAInfo(), OldMMO->getRanges(), OldMMO->getSyncScopeID(), OldMMO->getSuccessOrdering(), OldMMO->getFailureOrdering()); NewMMOs.push_back(NewMMO); } DstMI.setMemRefs(DstMF, NewMMOs); } static std::unique_ptr cloneMF(MachineFunction *SrcMF, MachineModuleInfo &DestMMI) { auto DstMF = std::make_unique( SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(), SrcMF->getFunctionNumber(), DestMMI); DenseMap Src2DstMBB; auto *SrcMRI = &SrcMF->getRegInfo(); auto *DstMRI = &DstMF->getRegInfo(); // Clone blocks. for (MachineBasicBlock &SrcMBB : *SrcMF) { MachineBasicBlock *DstMBB = DstMF->CreateMachineBasicBlock(SrcMBB.getBasicBlock()); Src2DstMBB[&SrcMBB] = DstMBB; if (SrcMBB.isIRBlockAddressTaken()) DstMBB->setAddressTakenIRBlock(SrcMBB.getAddressTakenIRBlock()); if (SrcMBB.isMachineBlockAddressTaken()) DstMBB->setMachineBlockAddressTaken(); // FIXME: This is not serialized if (SrcMBB.hasLabelMustBeEmitted()) DstMBB->setLabelMustBeEmitted(); DstMBB->setAlignment(SrcMBB.getAlignment()); // FIXME: This is not serialized DstMBB->setMaxBytesForAlignment(SrcMBB.getMaxBytesForAlignment()); DstMBB->setIsEHPad(SrcMBB.isEHPad()); DstMBB->setIsEHScopeEntry(SrcMBB.isEHScopeEntry()); DstMBB->setIsEHCatchretTarget(SrcMBB.isEHCatchretTarget()); DstMBB->setIsEHFuncletEntry(SrcMBB.isEHFuncletEntry()); // FIXME: These are not serialized DstMBB->setIsCleanupFuncletEntry(SrcMBB.isCleanupFuncletEntry()); DstMBB->setIsBeginSection(SrcMBB.isBeginSection()); DstMBB->setIsEndSection(SrcMBB.isEndSection()); DstMBB->setSectionID(SrcMBB.getSectionID()); DstMBB->setIsInlineAsmBrIndirectTarget( SrcMBB.isInlineAsmBrIndirectTarget()); // FIXME: This is not serialized if (std::optional Weight = SrcMBB.getIrrLoopHeaderWeight()) DstMBB->setIrrLoopHeaderWeight(*Weight); } const MachineFrameInfo &SrcMFI = SrcMF->getFrameInfo(); MachineFrameInfo &DstMFI = DstMF->getFrameInfo(); // Copy stack objects and other info cloneFrameInfo(DstMFI, SrcMFI, Src2DstMBB); // Remap the debug info frame index references. DstMF->VariableDbgInfos = SrcMF->VariableDbgInfos; // Clone virtual registers for (unsigned I = 0, E = SrcMRI->getNumVirtRegs(); I != E; ++I) { Register Reg = Register::index2VirtReg(I); Register NewReg = DstMRI->createIncompleteVirtualRegister( SrcMRI->getVRegName(Reg)); assert(NewReg == Reg && "expected to preserve virtreg number"); DstMRI->setRegClassOrRegBank(NewReg, SrcMRI->getRegClassOrRegBank(Reg)); LLT RegTy = SrcMRI->getType(Reg); if (RegTy.isValid()) DstMRI->setType(NewReg, RegTy); // Copy register allocation hints. const auto &Hints = SrcMRI->getRegAllocationHints(Reg); for (Register PrefReg : Hints.second) DstMRI->addRegAllocationHint(NewReg, PrefReg); } const TargetSubtargetInfo &STI = DstMF->getSubtarget(); const TargetInstrInfo *TII = STI.getInstrInfo(); const TargetRegisterInfo *TRI = STI.getRegisterInfo(); // Link blocks. for (auto &SrcMBB : *SrcMF) { auto *DstMBB = Src2DstMBB[&SrcMBB]; DstMF->push_back(DstMBB); for (auto It = SrcMBB.succ_begin(), IterEnd = SrcMBB.succ_end(); It != IterEnd; ++It) { auto *SrcSuccMBB = *It; auto *DstSuccMBB = Src2DstMBB[SrcSuccMBB]; DstMBB->addSuccessor(DstSuccMBB, SrcMBB.getSuccProbability(It)); } for (auto &LI : SrcMBB.liveins_dbg()) DstMBB->addLiveIn(LI); // Make sure MRI knows about registers clobbered by unwinder. if (DstMBB->isEHPad()) { if (auto *RegMask = TRI->getCustomEHPadPreservedMask(*DstMF)) DstMRI->addPhysRegsUsedFromRegMask(RegMask); } } DenseSet ConstRegisterMasks; // Track predefined/named regmasks which we ignore. for (const uint32_t *Mask : TRI->getRegMasks()) ConstRegisterMasks.insert(Mask); // Clone instructions. for (auto &SrcMBB : *SrcMF) { auto *DstMBB = Src2DstMBB[&SrcMBB]; for (auto &SrcMI : SrcMBB) { const auto &MCID = TII->get(SrcMI.getOpcode()); auto *DstMI = DstMF->CreateMachineInstr(MCID, SrcMI.getDebugLoc(), /*NoImplicit=*/true); DstMI->setFlags(SrcMI.getFlags()); DstMI->setAsmPrinterFlag(SrcMI.getAsmPrinterFlags()); DstMBB->push_back(DstMI); for (auto &SrcMO : SrcMI.operands()) { MachineOperand DstMO(SrcMO); DstMO.clearParent(); // Update MBB. if (DstMO.isMBB()) DstMO.setMBB(Src2DstMBB[DstMO.getMBB()]); else if (DstMO.isRegMask()) { DstMRI->addPhysRegsUsedFromRegMask(DstMO.getRegMask()); if (!ConstRegisterMasks.count(DstMO.getRegMask())) { uint32_t *DstMask = DstMF->allocateRegMask(); std::memcpy(DstMask, SrcMO.getRegMask(), sizeof(*DstMask) * MachineOperand::getRegMaskSize(TRI->getNumRegs())); DstMO.setRegMask(DstMask); } } DstMI->addOperand(DstMO); } cloneMemOperands(*DstMI, SrcMI, *SrcMF, *DstMF); } } DstMF->setAlignment(SrcMF->getAlignment()); DstMF->setExposesReturnsTwice(SrcMF->exposesReturnsTwice()); DstMF->setHasInlineAsm(SrcMF->hasInlineAsm()); DstMF->setHasWinCFI(SrcMF->hasWinCFI()); DstMF->getProperties().reset().set(SrcMF->getProperties()); if (!SrcMF->getFrameInstructions().empty() || !SrcMF->getLongjmpTargets().empty() || !SrcMF->getCatchretTargets().empty()) report_fatal_error("cloning not implemented for machine function property"); DstMF->setCallsEHReturn(SrcMF->callsEHReturn()); DstMF->setCallsUnwindInit(SrcMF->callsUnwindInit()); DstMF->setHasEHCatchret(SrcMF->hasEHCatchret()); DstMF->setHasEHScopes(SrcMF->hasEHScopes()); DstMF->setHasEHFunclets(SrcMF->hasEHFunclets()); if (!SrcMF->getLandingPads().empty() || !SrcMF->getCodeViewAnnotations().empty() || !SrcMF->getTypeInfos().empty() || !SrcMF->getFilterIds().empty() || SrcMF->hasAnyWasmLandingPadIndex() || SrcMF->hasAnyCallSiteLandingPad() || SrcMF->hasAnyCallSiteLabel() || !SrcMF->getCallSitesInfo().empty()) report_fatal_error("cloning not implemented for machine function property"); DstMF->setDebugInstrNumberingCount(SrcMF->DebugInstrNumberingCount); if (!DstMF->cloneInfoFrom(*SrcMF, Src2DstMBB)) report_fatal_error("target does not implement MachineFunctionInfo cloning"); DstMRI->freezeReservedRegs(*DstMF); DstMF->verify(nullptr, "", /*AbortOnError=*/true); return DstMF; } static void initializeTargetInfo() { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); } void ReducerWorkItem::print(raw_ostream &ROS, void *p) const { if (MMI) { printMIR(ROS, *M); for (Function &F : *M) { if (auto *MF = MMI->getMachineFunction(F)) printMIR(ROS, *MF); } } else { M->print(ROS, /*AssemblyAnnotationWriter=*/nullptr, /*ShouldPreserveUseListOrder=*/true); } } bool ReducerWorkItem::verify(raw_fd_ostream *OS) const { if (verifyModule(*M, OS)) return true; if (!MMI) return false; for (const Function &F : getModule()) { if (const MachineFunction *MF = MMI->getMachineFunction(F)) { if (!MF->verify(nullptr, "", /*AbortOnError=*/false)) return true; } } return false; } bool ReducerWorkItem::isReduced(const TestRunner &Test) const { const bool UseBitcode = Test.inputIsBitcode() || TmpFilesAsBitcode; SmallString<128> CurrentFilepath; // Write ReducerWorkItem to tmp file int FD; std::error_code EC = sys::fs::createTemporaryFile( "llvm-reduce", isMIR() ? "mir" : (UseBitcode ? "bc" : "ll"), FD, CurrentFilepath, UseBitcode && !isMIR() ? sys::fs::OF_None : sys::fs::OF_Text); if (EC) { errs() << "Error making unique filename: " << EC.message() << "!\n"; exit(1); } ToolOutputFile Out(CurrentFilepath, FD); writeOutput(Out.os(), UseBitcode); Out.os().close(); if (Out.os().has_error()) { errs() << "Error emitting bitcode to file '" << CurrentFilepath << "': " << Out.os().error().message(); exit(1); } // Current Chunks aren't interesting return Test.run(CurrentFilepath); } std::unique_ptr ReducerWorkItem::clone(const TargetMachine *TM) const { auto CloneMMM = std::make_unique(); if (TM) { // We're assuming the Module IR contents are always unchanged by MIR // reductions, and can share it as a constant. CloneMMM->M = M; // MachineModuleInfo contains a lot of other state used during codegen which // we won't be using here, but we should be able to ignore it (although this // is pretty ugly). const LLVMTargetMachine *LLVMTM = static_cast(TM); CloneMMM->MMI = std::make_unique(LLVMTM); for (const Function &F : getModule()) { if (auto *MF = MMI->getMachineFunction(F)) CloneMMM->MMI->insertFunction(F, cloneMF(MF, *CloneMMM->MMI)); } } else { CloneMMM->M = CloneModule(*M); } return CloneMMM; } /// Try to produce some number that indicates a function is getting smaller / /// simpler. static uint64_t computeMIRComplexityScoreImpl(const MachineFunction &MF) { uint64_t Score = 0; const MachineFrameInfo &MFI = MF.getFrameInfo(); // Add for stack objects Score += MFI.getNumObjects(); // Add in the block count. Score += 2 * MF.size(); const MachineRegisterInfo &MRI = MF.getRegInfo(); for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { Register Reg = Register::index2VirtReg(I); Score += MRI.getRegAllocationHints(Reg).second.size(); } for (const MachineBasicBlock &MBB : MF) { for (const MachineInstr &MI : MBB) { const unsigned Opc = MI.getOpcode(); // Reductions may want or need to introduce implicit_defs, so don't count // them. // TODO: These probably should count in some way. if (Opc == TargetOpcode::IMPLICIT_DEF || Opc == TargetOpcode::G_IMPLICIT_DEF) continue; // Each instruction adds to the score Score += 4; if (Opc == TargetOpcode::PHI || Opc == TargetOpcode::G_PHI || Opc == TargetOpcode::INLINEASM || Opc == TargetOpcode::INLINEASM_BR) ++Score; if (MI.getFlags() != 0) ++Score; // Increase weight for more operands. for (const MachineOperand &MO : MI.operands()) { ++Score; // Treat registers as more complex. if (MO.isReg()) { ++Score; // And subregisters as even more complex. if (MO.getSubReg()) { ++Score; if (MO.isDef()) ++Score; } } else if (MO.isRegMask()) ++Score; } } } return Score; } uint64_t ReducerWorkItem::computeMIRComplexityScore() const { uint64_t Score = 0; for (const Function &F : getModule()) { if (auto *MF = MMI->getMachineFunction(F)) Score += computeMIRComplexityScoreImpl(*MF); } return Score; } // FIXME: ReduceOperandsSkip has similar function, except it uses larger numbers // for more reduced. static unsigned classifyReductivePower(const Value *V) { if (auto *C = dyn_cast(V)) { if (C->isNullValue()) return 0; if (C->isOneValue()) return 1; if (isa(V)) return 2; return 3; } if (isa(V)) return 4; // TODO: Account for expression size if (isa(V)) return 5; if (isa(V)) return 1; if (isa(V)) return 6; if (isa(V)) return 7; return 0; } // TODO: Additional flags and attributes may be complexity reducing. If we start // adding flags and attributes, they could have negative cost. static uint64_t computeIRComplexityScoreImpl(const Function &F) { uint64_t Score = 1; // Count the function itself SmallVector> MDs; AttributeList Attrs = F.getAttributes(); for (AttributeSet AttrSet : Attrs) Score += AttrSet.getNumAttributes(); for (const BasicBlock &BB : F) { ++Score; for (const Instruction &I : BB) { ++Score; if (const auto *OverflowOp = dyn_cast(&I)) { if (OverflowOp->hasNoUnsignedWrap()) ++Score; if (OverflowOp->hasNoSignedWrap()) ++Score; } else if (const auto *GEP = dyn_cast(&I)) { if (GEP->isInBounds()) ++Score; } else if (const auto *ExactOp = dyn_cast(&I)) { if (ExactOp->isExact()) ++Score; } else if (const auto *FPOp = dyn_cast(&I)) { FastMathFlags FMF = FPOp->getFastMathFlags(); if (FMF.allowReassoc()) ++Score; if (FMF.noNaNs()) ++Score; if (FMF.noInfs()) ++Score; if (FMF.noSignedZeros()) ++Score; if (FMF.allowReciprocal()) ++Score; if (FMF.allowContract()) ++Score; if (FMF.approxFunc()) ++Score; } for (const Value *Operand : I.operands()) { ++Score; Score += classifyReductivePower(Operand); } I.getAllMetadata(MDs); Score += MDs.size(); MDs.clear(); } } return Score; } uint64_t ReducerWorkItem::computeIRComplexityScore() const { uint64_t Score = 0; const Module &M = getModule(); Score += M.named_metadata_size(); SmallVector, 32> GlobalMetadata; for (const GlobalVariable &GV : M.globals()) { ++Score; if (GV.hasInitializer()) Score += classifyReductivePower(GV.getInitializer()); // TODO: Account for linkage? GV.getAllMetadata(GlobalMetadata); Score += GlobalMetadata.size(); GlobalMetadata.clear(); } for (const GlobalAlias &GA : M.aliases()) Score += classifyReductivePower(GA.getAliasee()); for (const GlobalIFunc &GI : M.ifuncs()) Score += classifyReductivePower(GI.getResolver()); for (const Function &F : M) Score += computeIRComplexityScoreImpl(F); return Score; } void ReducerWorkItem::writeOutput(raw_ostream &OS, bool EmitBitcode) const { // Requesting bitcode emission with mir is nonsense, so just ignore it. if (EmitBitcode && !isMIR()) writeBitcode(OS); else print(OS, /*AnnotationWriter=*/nullptr); } void ReducerWorkItem::readBitcode(MemoryBufferRef Data, LLVMContext &Ctx, StringRef ToolName) { Expected IF = llvm::getBitcodeFileContents(Data); if (!IF) { WithColor::error(errs(), ToolName) << IF.takeError(); exit(1); } BitcodeModule BM = IF->Mods[0]; Expected LI = BM.getLTOInfo(); Expected> MOrErr = BM.parseModule(Ctx); if (!LI || !MOrErr) { WithColor::error(errs(), ToolName) << IF.takeError(); exit(1); } LTOInfo = std::make_unique(*LI); M = std::move(MOrErr.get()); } void ReducerWorkItem::writeBitcode(raw_ostream &OutStream) const { if (LTOInfo && LTOInfo->IsThinLTO && LTOInfo->EnableSplitLTOUnit) { PassBuilder PB; LoopAnalysisManager LAM; FunctionAnalysisManager FAM; CGSCCAnalysisManager CGAM; ModuleAnalysisManager MAM; PB.registerModuleAnalyses(MAM); PB.registerCGSCCAnalyses(CGAM); PB.registerFunctionAnalyses(FAM); PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); ModulePassManager MPM; MPM.addPass(ThinLTOBitcodeWriterPass(OutStream, nullptr)); MPM.run(*M, MAM); } else { std::unique_ptr Index; if (LTOInfo && LTOInfo->HasSummary) { ProfileSummaryInfo PSI(*M); Index = std::make_unique( buildModuleSummaryIndex(*M, nullptr, &PSI)); } WriteBitcodeToFile(getModule(), OutStream, Index.get()); } } std::pair, bool> llvm::parseReducerWorkItem(StringRef ToolName, StringRef Filename, LLVMContext &Ctxt, std::unique_ptr &TM, bool IsMIR) { bool IsBitcode = false; Triple TheTriple; auto MMM = std::make_unique(); if (IsMIR) { initializeTargetInfo(); auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true); if (std::error_code EC = FileOrErr.getError()) { WithColor::error(errs(), ToolName) << EC.message() << '\n'; return {nullptr, false}; } std::unique_ptr MParser = createMIRParser(std::move(FileOrErr.get()), Ctxt); auto SetDataLayout = [&](StringRef DataLayoutTargetTriple, StringRef OldDLStr) -> std::optional { // If we are supposed to override the target triple, do so now. std::string IRTargetTriple = DataLayoutTargetTriple.str(); if (!TargetTriple.empty()) IRTargetTriple = Triple::normalize(TargetTriple); TheTriple = Triple(IRTargetTriple); if (TheTriple.getTriple().empty()) TheTriple.setTriple(sys::getDefaultTargetTriple()); std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error); if (!TheTarget) { WithColor::error(errs(), ToolName) << Error; exit(1); } // Hopefully the MIR parsing doesn't depend on any options. TargetOptions Options; std::optional RM = codegen::getExplicitRelocModel(); std::string CPUStr = codegen::getCPUStr(); std::string FeaturesStr = codegen::getFeaturesStr(); TM = std::unique_ptr(TheTarget->createTargetMachine( TheTriple.getTriple(), CPUStr, FeaturesStr, Options, RM, codegen::getExplicitCodeModel(), CodeGenOpt::Default)); assert(TM && "Could not allocate target machine!"); return TM->createDataLayout().getStringRepresentation(); }; std::unique_ptr M = MParser->parseIRModule(SetDataLayout); LLVMTargetMachine *LLVMTM = static_cast(TM.get()); MMM->MMI = std::make_unique(LLVMTM); MParser->parseMachineFunctions(*M, *MMM->MMI); MMM->M = std::move(M); } else { SMDiagnostic Err; ErrorOr> MB = MemoryBuffer::getFileOrSTDIN(Filename); if (std::error_code EC = MB.getError()) { WithColor::error(errs(), ToolName) << Filename << ": " << EC.message() << "\n"; return {nullptr, false}; } if (!isBitcode((const unsigned char *)(*MB)->getBufferStart(), (const unsigned char *)(*MB)->getBufferEnd())) { std::unique_ptr Result = parseIRFile(Filename, Err, Ctxt); if (!Result) { Err.print(ToolName.data(), errs()); return {nullptr, false}; } MMM->M = std::move(Result); } else { IsBitcode = true; MMM->readBitcode(MemoryBufferRef(**MB), Ctxt, ToolName); if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit) initializeTargetInfo(); } } if (MMM->verify(&errs())) { WithColor::error(errs(), ToolName) << Filename << " - input module is broken!\n"; return {nullptr, false}; } return {std::move(MMM), IsBitcode}; }