forked from OSchip/llvm-project
722 lines
24 KiB
C++
722 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"
|
|
|
|
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, const char *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(const char *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) -> 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, 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;
|
|
}
|