aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm16/tools/llvm-reduce/ReducerWorkItem.cpp
diff options
context:
space:
mode:
authorvvvv <vvvv@ydb.tech>2024-02-06 20:01:22 +0300
committervvvv <vvvv@ydb.tech>2024-02-06 20:22:16 +0300
commit0203b7a9a40828bb2bd4c32029b79ff0ea3d1f8f (patch)
treee630d0d5bd0bd29fc8c2d2842ed2cfde781b993a /contrib/libs/llvm16/tools/llvm-reduce/ReducerWorkItem.cpp
parentba27db76d99d12a4f1c06960b5449423218614c4 (diff)
downloadydb-0203b7a9a40828bb2bd4c32029b79ff0ea3d1f8f.tar.gz
llvm16 targets
Diffstat (limited to 'contrib/libs/llvm16/tools/llvm-reduce/ReducerWorkItem.cpp')
-rw-r--r--contrib/libs/llvm16/tools/llvm-reduce/ReducerWorkItem.cpp828
1 files changed, 828 insertions, 0 deletions
diff --git a/contrib/libs/llvm16/tools/llvm-reduce/ReducerWorkItem.cpp b/contrib/libs/llvm16/tools/llvm-reduce/ReducerWorkItem.cpp
new file mode 100644
index 0000000000..74107ad0f0
--- /dev/null
+++ b/contrib/libs/llvm16/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -0,0 +1,828 @@
+//===- 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 <optional>
+
+using namespace llvm;
+
+ReducerWorkItem::ReducerWorkItem() = default;
+ReducerWorkItem::~ReducerWorkItem() = default;
+
+extern cl::OptionCategory LLVMReduceOptions;
+static cl::opt<std::string> TargetTriple("mtriple",
+ cl::desc("Set the target triple"),
+ cl::cat(LLVMReduceOptions));
+
+static cl::opt<bool> 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<MachineBasicBlock *, MachineBasicBlock *> &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<MachineMemOperand *, 2> NewMMOs;
+ for (MachineMemOperand *OldMMO : SrcMI.memoperands()) {
+ MachinePointerInfo NewPtrInfo(OldMMO->getPointerInfo());
+ if (const PseudoSourceValue *PSV =
+ NewPtrInfo.V.dyn_cast<const PseudoSourceValue *>()) {
+ 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<FixedStackPseudoSourceValue>(PSV)->getFrameIndex());
+ break;
+ case PseudoSourceValue::GlobalValueCallEntry:
+ NewPtrInfo.V = PSVMgr.getGlobalValueCallEntry(
+ cast<GlobalValuePseudoSourceValue>(PSV)->getValue());
+ break;
+ case PseudoSourceValue::ExternalSymbolCallEntry:
+ NewPtrInfo.V = PSVMgr.getExternalSymbolCallEntry(
+ cast<ExternalSymbolPseudoSourceValue>(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<MachineFunction> cloneMF(MachineFunction *SrcMF,
+ MachineModuleInfo &DestMMI) {
+ auto DstMF = std::make_unique<MachineFunction>(
+ SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(),
+ SrcMF->getFunctionNumber(), DestMMI);
+ DenseMap<MachineBasicBlock *, MachineBasicBlock *> 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<uint64_t> 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<const uint32_t *> 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>
+ReducerWorkItem::clone(const TargetMachine *TM) const {
+ auto CloneMMM = std::make_unique<ReducerWorkItem>();
+ 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<const LLVMTargetMachine *>(TM);
+ CloneMMM->MMI = std::make_unique<MachineModuleInfo>(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<ConstantData>(V)) {
+ if (C->isNullValue())
+ return 0;
+ if (C->isOneValue())
+ return 1;
+ if (isa<UndefValue>(V))
+ return 2;
+ return 3;
+ }
+
+ if (isa<GlobalValue>(V))
+ return 4;
+
+ // TODO: Account for expression size
+ if (isa<ConstantExpr>(V))
+ return 5;
+
+ if (isa<Constant>(V))
+ return 1;
+
+ if (isa<Argument>(V))
+ return 6;
+
+ if (isa<Instruction>(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<std::pair<unsigned, MDNode *>> 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<OverflowingBinaryOperator>(&I)) {
+ if (OverflowOp->hasNoUnsignedWrap())
+ ++Score;
+ if (OverflowOp->hasNoSignedWrap())
+ ++Score;
+ } else if (const auto *GEP = dyn_cast<GEPOperator>(&I)) {
+ if (GEP->isInBounds())
+ ++Score;
+ } else if (const auto *ExactOp = dyn_cast<PossiblyExactOperator>(&I)) {
+ if (ExactOp->isExact())
+ ++Score;
+ } else if (const auto *FPOp = dyn_cast<FPMathOperator>(&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<std::pair<unsigned, MDNode *>, 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<BitcodeFileContents> IF = llvm::getBitcodeFileContents(Data);
+ if (!IF) {
+ WithColor::error(errs(), ToolName) << IF.takeError();
+ exit(1);
+ }
+ BitcodeModule BM = IF->Mods[0];
+ Expected<BitcodeLTOInfo> LI = BM.getLTOInfo();
+ Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(Ctx);
+ if (!LI || !MOrErr) {
+ WithColor::error(errs(), ToolName) << IF.takeError();
+ exit(1);
+ }
+ LTOInfo = std::make_unique<BitcodeLTOInfo>(*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<ModuleSummaryIndex> Index;
+ if (LTOInfo && LTOInfo->HasSummary) {
+ ProfileSummaryInfo PSI(*M);
+ Index = std::make_unique<ModuleSummaryIndex>(
+ buildModuleSummaryIndex(*M, nullptr, &PSI));
+ }
+ WriteBitcodeToFile(getModule(), OutStream, Index.get());
+ }
+}
+
+std::pair<std::unique_ptr<ReducerWorkItem>, bool>
+llvm::parseReducerWorkItem(StringRef ToolName, StringRef Filename,
+ LLVMContext &Ctxt,
+ std::unique_ptr<TargetMachine> &TM, bool IsMIR) {
+ bool IsBitcode = false;
+ Triple TheTriple;
+
+ auto MMM = std::make_unique<ReducerWorkItem>();
+
+ 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<MIRParser> MParser =
+ createMIRParser(std::move(FileOrErr.get()), Ctxt);
+
+ auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
+ StringRef OldDLStr) -> std::optional<std::string> {
+ // 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<Reloc::Model> RM = codegen::getExplicitRelocModel();
+ std::string CPUStr = codegen::getCPUStr();
+ std::string FeaturesStr = codegen::getFeaturesStr();
+ TM = std::unique_ptr<TargetMachine>(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<Module> M = MParser->parseIRModule(SetDataLayout);
+ LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(TM.get());
+
+ MMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
+ MParser->parseMachineFunctions(*M, *MMM->MMI);
+ MMM->M = std::move(M);
+ } else {
+ SMDiagnostic Err;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> 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<Module> 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};
+}