We required the test and input arguments for --print-delta-passes which is unhelpful. Also, start printing the help output if no arguments were supplied. It looks like there's more sophisticated ways to accomplish this with the opt library, but it was less work to manually emit these errors.
723 lines
24 KiB
C++
723 lines
24 KiB
C++
//===- 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 "llvm/Bitcode/BitcodeReader.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/Support/Host.h"
|
|
#include "llvm/Support/MemoryBufferRef.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Support/TargetSelect.h"
|
|
#include "llvm/Support/WithColor.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Transforms/Utils/Cloning.h"
|
|
#include <optional>
|
|
|
|
extern cl::OptionCategory LLVMReduceOptions;
|
|
static cl::opt<std::string> TargetTriple("mtriple",
|
|
cl::desc("Set the target triple"),
|
|
cl::cat(LLVMReduceOptions));
|
|
|
|
void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx,
|
|
StringRef ToolName);
|
|
|
|
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();
|
|
}
|
|
|
|
std::pair<std::unique_ptr<ReducerWorkItem>, bool>
|
|
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) -> 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;
|
|
readBitcode(*MMM, MemoryBufferRef(**MB), Ctxt, ToolName);
|
|
|
|
if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit)
|
|
initializeTargetInfo();
|
|
}
|
|
}
|
|
if (verifyReducerWorkItem(*MMM, &errs())) {
|
|
WithColor::error(errs(), ToolName)
|
|
<< Filename << " - input module is broken!\n";
|
|
return {nullptr, false};
|
|
}
|
|
return {std::move(MMM), IsBitcode};
|
|
}
|
|
|
|
std::unique_ptr<ReducerWorkItem>
|
|
cloneReducerWorkItem(const ReducerWorkItem &MMM, const TargetMachine *TM) {
|
|
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 = MMM.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 : MMM.getModule()) {
|
|
if (auto *MF = MMM.MMI->getMachineFunction(F))
|
|
CloneMMM->MMI->insertFunction(F, cloneMF(MF, *CloneMMM->MMI));
|
|
}
|
|
} else {
|
|
CloneMMM->M = CloneModule(*MMM.M);
|
|
}
|
|
return CloneMMM;
|
|
}
|
|
|
|
bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS) {
|
|
if (verifyModule(*MMM.M, OS))
|
|
return true;
|
|
|
|
if (!MMM.MMI)
|
|
return false;
|
|
|
|
for (const Function &F : MMM.getModule()) {
|
|
if (const MachineFunction *MF = MMM.MMI->getMachineFunction(F)) {
|
|
if (!MF->verify(nullptr, "", /*AbortOnError=*/false))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// 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;
|
|
|
|
// TODO: Account for linkage?
|
|
|
|
GV.getAllMetadata(GlobalMetadata);
|
|
Score += GlobalMetadata.size();
|
|
GlobalMetadata.clear();
|
|
}
|
|
|
|
for (const Function &F : M)
|
|
Score += computeIRComplexityScoreImpl(F);
|
|
|
|
return Score;
|
|
}
|