898 lines · cpp
1//===- ReducerWorkItem.cpp - Wrapper for Module and MachineFunction -------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ReducerWorkItem.h"10#include "TestRunner.h"11#include "llvm/Analysis/ModuleSummaryAnalysis.h"12#include "llvm/Analysis/ProfileSummaryInfo.h"13#include "llvm/Bitcode/BitcodeReader.h"14#include "llvm/Bitcode/BitcodeWriter.h"15#include "llvm/CodeGen/CommandFlags.h"16#include "llvm/CodeGen/MIRParser/MIRParser.h"17#include "llvm/CodeGen/MIRPrinter.h"18#include "llvm/CodeGen/MachineDominators.h"19#include "llvm/CodeGen/MachineFrameInfo.h"20#include "llvm/CodeGen/MachineFunction.h"21#include "llvm/CodeGen/MachineJumpTableInfo.h"22#include "llvm/CodeGen/MachineModuleInfo.h"23#include "llvm/CodeGen/MachineRegisterInfo.h"24#include "llvm/CodeGen/PseudoSourceValueManager.h"25#include "llvm/CodeGen/TargetInstrInfo.h"26#include "llvm/IR/Constants.h"27#include "llvm/IR/Instructions.h"28#include "llvm/IR/ModuleSummaryIndex.h"29#include "llvm/IR/Operator.h"30#include "llvm/IR/Verifier.h"31#include "llvm/IRReader/IRReader.h"32#include "llvm/MC/TargetRegistry.h"33#include "llvm/Passes/PassBuilder.h"34#include "llvm/Support/MemoryBufferRef.h"35#include "llvm/Support/SourceMgr.h"36#include "llvm/Support/TargetSelect.h"37#include "llvm/Support/ToolOutputFile.h"38#include "llvm/Support/WithColor.h"39#include "llvm/Target/TargetMachine.h"40#include "llvm/TargetParser/Host.h"41#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"42#include "llvm/Transforms/Utils/Cloning.h"43#include <optional>44 45using namespace llvm;46 47ReducerWorkItem::ReducerWorkItem() = default;48ReducerWorkItem::~ReducerWorkItem() = default;49 50extern cl::OptionCategory LLVMReduceOptions;51static cl::opt<std::string> TargetTriple("mtriple",52 cl::desc("Set the target triple"),53 cl::cat(LLVMReduceOptions));54static cl::opt<bool> PrintInvalidMachineReductions(55 "print-invalid-reduction-machine-verifier-errors",56 cl::desc(57 "Print machine verifier errors on invalid reduction attempts triple"),58 cl::cat(LLVMReduceOptions));59 60static cl::opt<bool> TmpFilesAsBitcode(61 "write-tmp-files-as-bitcode",62 cl::desc("Always write temporary files as bitcode instead of textual IR"),63 cl::init(false), cl::cat(LLVMReduceOptions));64 65static SaveRestorePoints constructSaveRestorePoints(66 const SaveRestorePoints &SRPoints,67 const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &BBMap) {68 SaveRestorePoints Pts{};69 for (auto &Src : SRPoints)70 Pts.insert({BBMap.find(Src.first)->second, Src.second});71 return Pts;72}73 74static void cloneFrameInfo(75 MachineFrameInfo &DstMFI, const MachineFrameInfo &SrcMFI,76 const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) {77 DstMFI.setFrameAddressIsTaken(SrcMFI.isFrameAddressTaken());78 DstMFI.setReturnAddressIsTaken(SrcMFI.isReturnAddressTaken());79 DstMFI.setHasStackMap(SrcMFI.hasStackMap());80 DstMFI.setHasPatchPoint(SrcMFI.hasPatchPoint());81 DstMFI.setUseLocalStackAllocationBlock(82 SrcMFI.getUseLocalStackAllocationBlock());83 DstMFI.setOffsetAdjustment(SrcMFI.getOffsetAdjustment());84 85 DstMFI.ensureMaxAlignment(SrcMFI.getMaxAlign());86 assert(DstMFI.getMaxAlign() == SrcMFI.getMaxAlign() &&87 "we need to set exact alignment");88 89 DstMFI.setAdjustsStack(SrcMFI.adjustsStack());90 DstMFI.setHasCalls(SrcMFI.hasCalls());91 DstMFI.setHasOpaqueSPAdjustment(SrcMFI.hasOpaqueSPAdjustment());92 DstMFI.setHasCopyImplyingStackAdjustment(93 SrcMFI.hasCopyImplyingStackAdjustment());94 DstMFI.setHasVAStart(SrcMFI.hasVAStart());95 DstMFI.setHasMustTailInVarArgFunc(SrcMFI.hasMustTailInVarArgFunc());96 DstMFI.setHasTailCall(SrcMFI.hasTailCall());97 98 if (SrcMFI.isMaxCallFrameSizeComputed())99 DstMFI.setMaxCallFrameSize(SrcMFI.getMaxCallFrameSize());100 101 DstMFI.setCVBytesOfCalleeSavedRegisters(102 SrcMFI.getCVBytesOfCalleeSavedRegisters());103 104 assert(SrcMFI.getSavePoints().size() < 2 &&105 "Multiple restore points not yet supported!");106 107 DstMFI.setSavePoints(108 constructSaveRestorePoints(SrcMFI.getSavePoints(), Src2DstMBB));109 110 assert(SrcMFI.getRestorePoints().size() < 2 &&111 "Multiple restore points not yet supported!");112 113 DstMFI.setRestorePoints(114 constructSaveRestorePoints(SrcMFI.getRestorePoints(), Src2DstMBB));115 116 auto CopyObjectProperties = [](MachineFrameInfo &DstMFI,117 const MachineFrameInfo &SrcMFI, int FI) {118 if (SrcMFI.isStatepointSpillSlotObjectIndex(FI))119 DstMFI.markAsStatepointSpillSlotObjectIndex(FI);120 DstMFI.setObjectSSPLayout(FI, SrcMFI.getObjectSSPLayout(FI));121 DstMFI.setObjectZExt(FI, SrcMFI.isObjectZExt(FI));122 DstMFI.setObjectSExt(FI, SrcMFI.isObjectSExt(FI));123 };124 125 for (int i = 0, e = SrcMFI.getNumObjects() - SrcMFI.getNumFixedObjects();126 i != e; ++i) {127 int NewFI;128 129 assert(!SrcMFI.isFixedObjectIndex(i));130 if (SrcMFI.isVariableSizedObjectIndex(i)) {131 NewFI = DstMFI.CreateVariableSizedObject(SrcMFI.getObjectAlign(i),132 SrcMFI.getObjectAllocation(i));133 } else {134 NewFI = DstMFI.CreateStackObject(135 SrcMFI.getObjectSize(i), SrcMFI.getObjectAlign(i),136 SrcMFI.isSpillSlotObjectIndex(i), SrcMFI.getObjectAllocation(i),137 SrcMFI.getStackID(i));138 DstMFI.setObjectOffset(NewFI, SrcMFI.getObjectOffset(i));139 }140 141 CopyObjectProperties(DstMFI, SrcMFI, i);142 143 (void)NewFI;144 assert(i == NewFI && "expected to keep stable frame index numbering");145 }146 147 // Copy the fixed frame objects backwards to preserve frame index numbers,148 // since CreateFixedObject uses front insertion.149 for (int i = -1; i >= (int)-SrcMFI.getNumFixedObjects(); --i) {150 assert(SrcMFI.isFixedObjectIndex(i));151 int NewFI = DstMFI.CreateFixedObject(152 SrcMFI.getObjectSize(i), SrcMFI.getObjectOffset(i),153 SrcMFI.isImmutableObjectIndex(i), SrcMFI.isAliasedObjectIndex(i));154 CopyObjectProperties(DstMFI, SrcMFI, i);155 156 (void)NewFI;157 assert(i == NewFI && "expected to keep stable frame index numbering");158 }159 160 for (unsigned I = 0, E = SrcMFI.getLocalFrameObjectCount(); I < E; ++I) {161 auto LocalObject = SrcMFI.getLocalFrameObjectMap(I);162 DstMFI.mapLocalFrameObject(LocalObject.first, LocalObject.second);163 }164 165 DstMFI.setCalleeSavedInfo(SrcMFI.getCalleeSavedInfo());166 167 if (SrcMFI.hasStackProtectorIndex()) {168 DstMFI.setStackProtectorIndex(SrcMFI.getStackProtectorIndex());169 }170 171 // FIXME: Needs test, missing MIR serialization.172 if (SrcMFI.hasFunctionContextIndex()) {173 DstMFI.setFunctionContextIndex(SrcMFI.getFunctionContextIndex());174 }175}176 177static void cloneJumpTableInfo(178 MachineFunction &DstMF, const MachineJumpTableInfo &SrcJTI,179 const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) {180 181 auto *DstJTI = DstMF.getOrCreateJumpTableInfo(SrcJTI.getEntryKind());182 183 std::vector<MachineBasicBlock *> DstBBs;184 185 for (const MachineJumpTableEntry &Entry : SrcJTI.getJumpTables()) {186 for (MachineBasicBlock *X : Entry.MBBs)187 DstBBs.push_back(Src2DstMBB.find(X)->second);188 189 DstJTI->createJumpTableIndex(DstBBs);190 DstBBs.clear();191 }192}193 194static void cloneMemOperands(MachineInstr &DstMI, MachineInstr &SrcMI,195 MachineFunction &SrcMF, MachineFunction &DstMF) {196 // The new MachineMemOperands should be owned by the new function's197 // Allocator.198 PseudoSourceValueManager &PSVMgr = DstMF.getPSVManager();199 200 // We also need to remap the PseudoSourceValues from the new function's201 // PseudoSourceValueManager.202 SmallVector<MachineMemOperand *, 2> NewMMOs;203 for (MachineMemOperand *OldMMO : SrcMI.memoperands()) {204 MachinePointerInfo NewPtrInfo(OldMMO->getPointerInfo());205 if (const PseudoSourceValue *PSV =206 dyn_cast_if_present<const PseudoSourceValue *>(NewPtrInfo.V)) {207 switch (PSV->kind()) {208 case PseudoSourceValue::Stack:209 NewPtrInfo.V = PSVMgr.getStack();210 break;211 case PseudoSourceValue::GOT:212 NewPtrInfo.V = PSVMgr.getGOT();213 break;214 case PseudoSourceValue::JumpTable:215 NewPtrInfo.V = PSVMgr.getJumpTable();216 break;217 case PseudoSourceValue::ConstantPool:218 NewPtrInfo.V = PSVMgr.getConstantPool();219 break;220 case PseudoSourceValue::FixedStack:221 NewPtrInfo.V = PSVMgr.getFixedStack(222 cast<FixedStackPseudoSourceValue>(PSV)->getFrameIndex());223 break;224 case PseudoSourceValue::GlobalValueCallEntry:225 NewPtrInfo.V = PSVMgr.getGlobalValueCallEntry(226 cast<GlobalValuePseudoSourceValue>(PSV)->getValue());227 break;228 case PseudoSourceValue::ExternalSymbolCallEntry:229 NewPtrInfo.V = PSVMgr.getExternalSymbolCallEntry(230 cast<ExternalSymbolPseudoSourceValue>(PSV)->getSymbol());231 break;232 case PseudoSourceValue::TargetCustom:233 default:234 // FIXME: We have no generic interface for allocating custom PSVs.235 report_fatal_error("Cloning TargetCustom PSV not handled");236 }237 }238 239 MachineMemOperand *NewMMO = DstMF.getMachineMemOperand(240 NewPtrInfo, OldMMO->getFlags(), OldMMO->getMemoryType(),241 OldMMO->getBaseAlign(), OldMMO->getAAInfo(), OldMMO->getRanges(),242 OldMMO->getSyncScopeID(), OldMMO->getSuccessOrdering(),243 OldMMO->getFailureOrdering());244 NewMMOs.push_back(NewMMO);245 }246 247 DstMI.setMemRefs(DstMF, NewMMOs);248}249 250static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF,251 MachineModuleInfo &DestMMI) {252 auto DstMF = std::make_unique<MachineFunction>(253 SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(),254 SrcMF->getContext(), SrcMF->getFunctionNumber());255 DenseMap<MachineBasicBlock *, MachineBasicBlock *> Src2DstMBB;256 257 auto *SrcMRI = &SrcMF->getRegInfo();258 auto *DstMRI = &DstMF->getRegInfo();259 260 // Clone blocks.261 for (MachineBasicBlock &SrcMBB : *SrcMF) {262 MachineBasicBlock *DstMBB =263 DstMF->CreateMachineBasicBlock(SrcMBB.getBasicBlock());264 Src2DstMBB[&SrcMBB] = DstMBB;265 266 DstMBB->setCallFrameSize(SrcMBB.getCallFrameSize());267 268 if (SrcMBB.isIRBlockAddressTaken())269 DstMBB->setAddressTakenIRBlock(SrcMBB.getAddressTakenIRBlock());270 if (SrcMBB.isMachineBlockAddressTaken())271 DstMBB->setMachineBlockAddressTaken();272 273 // FIXME: This is not serialized274 if (SrcMBB.hasLabelMustBeEmitted())275 DstMBB->setLabelMustBeEmitted();276 277 DstMBB->setAlignment(SrcMBB.getAlignment());278 279 // FIXME: This is not serialized280 DstMBB->setMaxBytesForAlignment(SrcMBB.getMaxBytesForAlignment());281 282 DstMBB->setIsEHPad(SrcMBB.isEHPad());283 DstMBB->setIsEHScopeEntry(SrcMBB.isEHScopeEntry());284 DstMBB->setIsEHContTarget(SrcMBB.isEHContTarget());285 DstMBB->setIsEHFuncletEntry(SrcMBB.isEHFuncletEntry());286 287 // FIXME: These are not serialized288 DstMBB->setIsCleanupFuncletEntry(SrcMBB.isCleanupFuncletEntry());289 DstMBB->setIsBeginSection(SrcMBB.isBeginSection());290 DstMBB->setIsEndSection(SrcMBB.isEndSection());291 292 DstMBB->setSectionID(SrcMBB.getSectionID());293 DstMBB->setIsInlineAsmBrIndirectTarget(294 SrcMBB.isInlineAsmBrIndirectTarget());295 296 // FIXME: This is not serialized297 if (std::optional<uint64_t> Weight = SrcMBB.getIrrLoopHeaderWeight())298 DstMBB->setIrrLoopHeaderWeight(*Weight);299 }300 301 const MachineFrameInfo &SrcMFI = SrcMF->getFrameInfo();302 MachineFrameInfo &DstMFI = DstMF->getFrameInfo();303 304 // Copy stack objects and other info305 cloneFrameInfo(DstMFI, SrcMFI, Src2DstMBB);306 307 if (MachineJumpTableInfo *SrcJTI = SrcMF->getJumpTableInfo()) {308 cloneJumpTableInfo(*DstMF, *SrcJTI, Src2DstMBB);309 }310 311 // Remap the debug info frame index references.312 DstMF->VariableDbgInfos = SrcMF->VariableDbgInfos;313 314 // Clone virtual registers315 for (unsigned I = 0, E = SrcMRI->getNumVirtRegs(); I != E; ++I) {316 Register Reg = Register::index2VirtReg(I);317 Register NewReg = DstMRI->createIncompleteVirtualRegister(318 SrcMRI->getVRegName(Reg));319 assert(NewReg == Reg && "expected to preserve virtreg number");320 321 DstMRI->setRegClassOrRegBank(NewReg, SrcMRI->getRegClassOrRegBank(Reg));322 323 LLT RegTy = SrcMRI->getType(Reg);324 if (RegTy.isValid())325 DstMRI->setType(NewReg, RegTy);326 327 // Copy register allocation hints.328 const auto *Hints = SrcMRI->getRegAllocationHints(Reg);329 if (Hints)330 for (Register PrefReg : Hints->second)331 DstMRI->addRegAllocationHint(NewReg, PrefReg);332 }333 334 const TargetSubtargetInfo &STI = DstMF->getSubtarget();335 const TargetInstrInfo *TII = STI.getInstrInfo();336 const TargetRegisterInfo *TRI = STI.getRegisterInfo();337 338 // Link blocks.339 for (auto &SrcMBB : *SrcMF) {340 auto *DstMBB = Src2DstMBB[&SrcMBB];341 DstMF->push_back(DstMBB);342 343 for (auto It = SrcMBB.succ_begin(), IterEnd = SrcMBB.succ_end();344 It != IterEnd; ++It) {345 auto *SrcSuccMBB = *It;346 auto *DstSuccMBB = Src2DstMBB[SrcSuccMBB];347 DstMBB->addSuccessor(DstSuccMBB, SrcMBB.getSuccProbability(It));348 }349 350 for (auto &LI : SrcMBB.liveins_dbg())351 DstMBB->addLiveIn(LI);352 353 // Make sure MRI knows about registers clobbered by unwinder.354 if (DstMBB->isEHPad()) {355 if (auto *RegMask = TRI->getCustomEHPadPreservedMask(*DstMF))356 DstMRI->addPhysRegsUsedFromRegMask(RegMask);357 }358 }359 360 // Track predefined/named regmasks which we ignore.361 DenseSet<const uint32_t *> ConstRegisterMasks(llvm::from_range,362 TRI->getRegMasks());363 364 // Clone instructions.365 for (auto &SrcMBB : *SrcMF) {366 auto *DstMBB = Src2DstMBB[&SrcMBB];367 for (auto &SrcMI : SrcMBB) {368 const auto &MCID = TII->get(SrcMI.getOpcode());369 auto *DstMI = DstMF->CreateMachineInstr(MCID, SrcMI.getDebugLoc(),370 /*NoImplicit=*/true);371 DstMI->setFlags(SrcMI.getFlags());372 DstMI->setAsmPrinterFlag(SrcMI.getAsmPrinterFlags());373 374 DstMBB->push_back(DstMI);375 for (auto &SrcMO : SrcMI.operands()) {376 MachineOperand DstMO(SrcMO);377 DstMO.clearParent();378 379 // Update MBB.380 if (DstMO.isMBB())381 DstMO.setMBB(Src2DstMBB[DstMO.getMBB()]);382 else if (DstMO.isRegMask()) {383 DstMRI->addPhysRegsUsedFromRegMask(DstMO.getRegMask());384 385 if (!ConstRegisterMasks.count(DstMO.getRegMask())) {386 uint32_t *DstMask = DstMF->allocateRegMask();387 std::memcpy(DstMask, SrcMO.getRegMask(),388 sizeof(*DstMask) *389 MachineOperand::getRegMaskSize(TRI->getNumRegs()));390 DstMO.setRegMask(DstMask);391 }392 }393 394 DstMI->addOperand(DstMO);395 }396 397 cloneMemOperands(*DstMI, SrcMI, *SrcMF, *DstMF);398 }399 }400 401 DstMF->setAlignment(SrcMF->getAlignment());402 DstMF->setExposesReturnsTwice(SrcMF->exposesReturnsTwice());403 DstMF->setHasInlineAsm(SrcMF->hasInlineAsm());404 DstMF->setHasWinCFI(SrcMF->hasWinCFI());405 406 DstMF->getProperties().reset().set(SrcMF->getProperties());407 408 if (!SrcMF->getFrameInstructions().empty() ||409 !SrcMF->getLongjmpTargets().empty() || !SrcMF->getEHContTargets().empty())410 report_fatal_error("cloning not implemented for machine function property");411 412 DstMF->setCallsEHReturn(SrcMF->callsEHReturn());413 DstMF->setCallsUnwindInit(SrcMF->callsUnwindInit());414 DstMF->setHasEHContTarget(SrcMF->hasEHContTarget());415 DstMF->setHasEHScopes(SrcMF->hasEHScopes());416 DstMF->setHasEHFunclets(SrcMF->hasEHFunclets());417 DstMF->setHasFakeUses(SrcMF->hasFakeUses());418 DstMF->setIsOutlined(SrcMF->isOutlined());419 420 if (!SrcMF->getLandingPads().empty() ||421 !SrcMF->getCodeViewAnnotations().empty() ||422 !SrcMF->getTypeInfos().empty() ||423 !SrcMF->getFilterIds().empty() ||424 SrcMF->hasAnyWasmLandingPadIndex() ||425 SrcMF->hasAnyCallSiteLandingPad() ||426 SrcMF->hasAnyCallSiteLabel() ||427 !SrcMF->getCallSitesInfo().empty())428 report_fatal_error("cloning not implemented for machine function property");429 430 DstMF->setDebugInstrNumberingCount(SrcMF->DebugInstrNumberingCount);431 432 if (!DstMF->cloneInfoFrom(*SrcMF, Src2DstMBB))433 report_fatal_error("target does not implement MachineFunctionInfo cloning");434 435 DstMRI->freezeReservedRegs();436 437 DstMF->verify(nullptr, "", &errs(), /*AbortOnError=*/true);438 return DstMF;439}440 441static void initializeTargetInfo() {442 InitializeAllTargets();443 InitializeAllTargetMCs();444 InitializeAllAsmPrinters();445 InitializeAllAsmParsers();446}447 448void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {449 if (MMI) {450 printMIR(ROS, *M);451 for (Function &F : *M) {452 if (auto *MF = MMI->getMachineFunction(F))453 printMIR(ROS, *MMI, *MF);454 }455 } else {456 M->print(ROS, /*AssemblyAnnotationWriter=*/nullptr,457 /*ShouldPreserveUseListOrder=*/true);458 }459}460 461bool ReducerWorkItem::verify(raw_fd_ostream *OS) const {462 if (verifyModule(*M, OS))463 return true;464 465 if (!MMI)466 return false;467 468 for (const Function &F : getModule()) {469 if (const MachineFunction *MF = MMI->getMachineFunction(F)) {470 // With the current state of quality, most reduction attempts fail the471 // machine verifier. Avoid spamming large function dumps on nearly every472 // attempt until the situation is better.473 if (!MF->verify(nullptr, "",474 /*OS=*/PrintInvalidMachineReductions ? &errs() : nullptr,475 /*AbortOnError=*/false)) {476 477 if (!PrintInvalidMachineReductions) {478 WithColor::warning(errs())479 << "reduction attempt on function '" << MF->getName()480 << "' failed machine verifier (debug with "481 "-print-invalid-reduction-machine-verifier-errors)\n";482 }483 return true;484 }485 }486 }487 488 return false;489}490 491bool ReducerWorkItem::isReduced(const TestRunner &Test) const {492 const bool UseBitcode = Test.inputIsBitcode() || TmpFilesAsBitcode;493 494 SmallString<128> CurrentFilepath;495 496 // Write ReducerWorkItem to tmp file497 int FD;498 std::error_code EC = sys::fs::createTemporaryFile(499 "llvm-reduce", isMIR() ? "mir" : (UseBitcode ? "bc" : "ll"), FD,500 CurrentFilepath,501 UseBitcode && !isMIR() ? sys::fs::OF_None : sys::fs::OF_Text);502 if (EC) {503 WithColor::error(errs(), Test.getToolName())504 << "error making unique filename: " << EC.message() << '\n';505 exit(1);506 }507 508 ToolOutputFile Out(CurrentFilepath, FD);509 510 writeOutput(Out.os(), UseBitcode);511 512 Out.os().close();513 if (Out.os().has_error()) {514 WithColor::error(errs(), Test.getToolName())515 << "error emitting bitcode to file '" << CurrentFilepath516 << "': " << Out.os().error().message() << '\n';517 exit(1);518 }519 520 // Current Chunks aren't interesting521 return Test.run(CurrentFilepath);522}523 524std::unique_ptr<ReducerWorkItem>525ReducerWorkItem::clone(const TargetMachine *TM) const {526 auto CloneMMM = std::make_unique<ReducerWorkItem>();527 if (TM) {528 // We're assuming the Module IR contents are always unchanged by MIR529 // reductions, and can share it as a constant.530 CloneMMM->M = M;531 532 // MachineModuleInfo contains a lot of other state used during codegen which533 // we won't be using here, but we should be able to ignore it (although this534 // is pretty ugly).535 CloneMMM->MMI = std::make_unique<MachineModuleInfo>(TM);536 537 for (const Function &F : getModule()) {538 if (auto *MF = MMI->getMachineFunction(F))539 CloneMMM->MMI->insertFunction(F, cloneMF(MF, *CloneMMM->MMI));540 }541 } else {542 CloneMMM->M = CloneModule(*M);543 }544 return CloneMMM;545}546 547/// Try to produce some number that indicates a function is getting smaller /548/// simpler.549static uint64_t computeMIRComplexityScoreImpl(const MachineFunction &MF) {550 uint64_t Score = 0;551 const MachineFrameInfo &MFI = MF.getFrameInfo();552 553 // Add for stack objects554 Score += MFI.getNumObjects();555 556 // Add in the block count.557 Score += 2 * MF.size();558 559 const MachineRegisterInfo &MRI = MF.getRegInfo();560 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {561 Register Reg = Register::index2VirtReg(I);562 if (const auto *Hints = MRI.getRegAllocationHints(Reg))563 Score += Hints->second.size();564 }565 566 for (const MachineBasicBlock &MBB : MF) {567 for (const MachineInstr &MI : MBB) {568 const unsigned Opc = MI.getOpcode();569 570 // Reductions may want or need to introduce implicit_defs, so don't count571 // them.572 // TODO: These probably should count in some way.573 if (Opc == TargetOpcode::IMPLICIT_DEF ||574 Opc == TargetOpcode::G_IMPLICIT_DEF)575 continue;576 577 // Each instruction adds to the score578 Score += 4;579 580 if (Opc == TargetOpcode::PHI || Opc == TargetOpcode::G_PHI ||581 Opc == TargetOpcode::INLINEASM || Opc == TargetOpcode::INLINEASM_BR)582 ++Score;583 584 if (MI.getFlags() != 0)585 ++Score;586 587 // Increase weight for more operands.588 for (const MachineOperand &MO : MI.operands()) {589 ++Score;590 591 // Treat registers as more complex.592 if (MO.isReg()) {593 ++Score;594 595 // And subregisters as even more complex.596 if (MO.getSubReg()) {597 ++Score;598 if (MO.isDef())599 ++Score;600 }601 } else if (MO.isRegMask())602 ++Score;603 }604 }605 }606 607 return Score;608}609 610uint64_t ReducerWorkItem::computeMIRComplexityScore() const {611 uint64_t Score = 0;612 613 for (const Function &F : getModule()) {614 if (auto *MF = MMI->getMachineFunction(F))615 Score += computeMIRComplexityScoreImpl(*MF);616 }617 618 return Score;619}620 621// FIXME: ReduceOperandsSkip has similar function, except it uses larger numbers622// for more reduced.623static unsigned classifyReductivePower(const Value *V) {624 if (auto *C = dyn_cast<ConstantData>(V)) {625 if (C->isNullValue())626 return 0;627 if (C->isOneValue())628 return 1;629 if (isa<UndefValue>(V))630 return 2;631 return 3;632 }633 634 if (isa<GlobalValue>(V))635 return 4;636 637 // TODO: Account for expression size638 if (isa<ConstantExpr>(V))639 return 5;640 641 if (isa<Constant>(V))642 return 1;643 644 if (isa<Argument>(V))645 return 6;646 647 if (isa<Instruction>(V))648 return 7;649 650 return 0;651}652 653// TODO: Additional flags and attributes may be complexity reducing. If we start654// adding flags and attributes, they could have negative cost.655static uint64_t computeIRComplexityScoreImpl(const Function &F) {656 uint64_t Score = 1; // Count the function itself657 SmallVector<std::pair<unsigned, MDNode *>> MDs;658 659 AttributeList Attrs = F.getAttributes();660 for (AttributeSet AttrSet : Attrs)661 Score += AttrSet.getNumAttributes();662 663 for (const BasicBlock &BB : F) {664 ++Score;665 666 for (const Instruction &I : BB) {667 ++Score;668 669 if (const auto *OverflowOp = dyn_cast<OverflowingBinaryOperator>(&I)) {670 if (OverflowOp->hasNoUnsignedWrap())671 ++Score;672 if (OverflowOp->hasNoSignedWrap())673 ++Score;674 } else if (const auto *Trunc = dyn_cast<TruncInst>(&I)) {675 if (Trunc->hasNoSignedWrap())676 ++Score;677 if (Trunc->hasNoUnsignedWrap())678 ++Score;679 } else if (const auto *ExactOp = dyn_cast<PossiblyExactOperator>(&I)) {680 if (ExactOp->isExact())681 ++Score;682 } else if (const auto *NNI = dyn_cast<PossiblyNonNegInst>(&I)) {683 if (NNI->hasNonNeg())684 ++Score;685 } else if (const auto *PDI = dyn_cast<PossiblyDisjointInst>(&I)) {686 if (PDI->isDisjoint())687 ++Score;688 } else if (const auto *GEP = dyn_cast<GEPOperator>(&I)) {689 if (GEP->isInBounds())690 ++Score;691 if (GEP->hasNoUnsignedSignedWrap())692 ++Score;693 if (GEP->hasNoUnsignedWrap())694 ++Score;695 } else if (const auto *FPOp = dyn_cast<FPMathOperator>(&I)) {696 FastMathFlags FMF = FPOp->getFastMathFlags();697 if (FMF.allowReassoc())698 ++Score;699 if (FMF.noNaNs())700 ++Score;701 if (FMF.noInfs())702 ++Score;703 if (FMF.noSignedZeros())704 ++Score;705 if (FMF.allowReciprocal())706 ++Score;707 if (FMF.allowContract())708 ++Score;709 if (FMF.approxFunc())710 ++Score;711 }712 713 for (const Value *Operand : I.operands()) {714 ++Score;715 Score += classifyReductivePower(Operand);716 }717 718 I.getAllMetadata(MDs);719 Score += MDs.size();720 MDs.clear();721 }722 }723 724 return Score;725}726 727uint64_t ReducerWorkItem::computeIRComplexityScore() const {728 uint64_t Score = 0;729 730 const Module &M = getModule();731 Score += M.named_metadata_size();732 733 SmallVector<std::pair<unsigned, MDNode *>, 32> GlobalMetadata;734 for (const GlobalVariable &GV : M.globals()) {735 ++Score;736 737 if (GV.hasInitializer())738 Score += classifyReductivePower(GV.getInitializer());739 740 // TODO: Account for linkage?741 742 GV.getAllMetadata(GlobalMetadata);743 Score += GlobalMetadata.size();744 GlobalMetadata.clear();745 }746 747 for (const GlobalAlias &GA : M.aliases())748 Score += classifyReductivePower(GA.getAliasee());749 750 for (const GlobalIFunc &GI : M.ifuncs())751 Score += classifyReductivePower(GI.getResolver());752 753 for (const Function &F : M)754 Score += computeIRComplexityScoreImpl(F);755 756 return Score;757}758 759void ReducerWorkItem::writeOutput(raw_ostream &OS, bool EmitBitcode) const {760 // Requesting bitcode emission with mir is nonsense, so just ignore it.761 if (EmitBitcode && !isMIR())762 writeBitcode(OS);763 else764 print(OS, /*AnnotationWriter=*/nullptr);765}766 767void ReducerWorkItem::readBitcode(MemoryBufferRef Data, LLVMContext &Ctx,768 StringRef ToolName) {769 Expected<BitcodeFileContents> IF = llvm::getBitcodeFileContents(Data);770 if (!IF) {771 WithColor::error(errs(), ToolName) << IF.takeError();772 exit(1);773 }774 775 BitcodeModule BM = IF->Mods[0];776 Expected<BitcodeLTOInfo> LI = BM.getLTOInfo();777 if (!LI) {778 WithColor::error(errs(), ToolName) << LI.takeError();779 exit(1);780 }781 782 Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(Ctx);783 if (!MOrErr) {784 WithColor::error(errs(), ToolName) << MOrErr.takeError();785 exit(1);786 }787 788 LTOInfo = std::make_unique<BitcodeLTOInfo>(*LI);789 M = std::move(MOrErr.get());790}791 792void ReducerWorkItem::writeBitcode(raw_ostream &OutStream) const {793 const bool ShouldPreserveUseListOrder = true;794 795 if (LTOInfo && LTOInfo->IsThinLTO && LTOInfo->EnableSplitLTOUnit) {796 PassBuilder PB;797 LoopAnalysisManager LAM;798 FunctionAnalysisManager FAM;799 CGSCCAnalysisManager CGAM;800 ModuleAnalysisManager MAM;801 PB.registerModuleAnalyses(MAM);802 PB.registerCGSCCAnalyses(CGAM);803 PB.registerFunctionAnalyses(FAM);804 PB.registerLoopAnalyses(LAM);805 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);806 ModulePassManager MPM;807 MPM.addPass(ThinLTOBitcodeWriterPass(OutStream, nullptr,808 ShouldPreserveUseListOrder));809 MPM.run(*M, MAM);810 } else {811 std::unique_ptr<ModuleSummaryIndex> Index;812 if (LTOInfo && LTOInfo->HasSummary) {813 ProfileSummaryInfo PSI(*M);814 Index = std::make_unique<ModuleSummaryIndex>(815 buildModuleSummaryIndex(*M, nullptr, &PSI));816 }817 WriteBitcodeToFile(getModule(), OutStream, ShouldPreserveUseListOrder,818 Index.get());819 }820}821 822std::pair<std::unique_ptr<ReducerWorkItem>, bool>823llvm::parseReducerWorkItem(StringRef ToolName, StringRef Filename,824 LLVMContext &Ctxt,825 std::unique_ptr<TargetMachine> &TM, bool IsMIR) {826 bool IsBitcode = false;827 Triple TheTriple;828 829 auto MMM = std::make_unique<ReducerWorkItem>();830 831 if (IsMIR) {832 initializeTargetInfo();833 834 auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);835 if (std::error_code EC = FileOrErr.getError()) {836 WithColor::error(errs(), ToolName) << EC.message() << '\n';837 return {nullptr, false};838 }839 840 std::unique_ptr<MIRParser> MParser =841 createMIRParser(std::move(FileOrErr.get()), Ctxt);842 843 auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,844 StringRef OldDLStr) -> std::optional<std::string> {845 // NB: We always call createTargetMachineForTriple() even if an explicit846 // DataLayout is already set in the module since we want to use this847 // callback to setup the TargetMachine rather than doing it later.848 std::string IRTargetTriple = DataLayoutTargetTriple.str();849 if (!TargetTriple.empty())850 IRTargetTriple = Triple::normalize(TargetTriple);851 TheTriple = Triple(IRTargetTriple);852 if (TheTriple.getTriple().empty())853 TheTriple.setTriple(sys::getDefaultTargetTriple());854 ExitOnError ExitOnErr(std::string(ToolName) + ": error: ");855 TM = ExitOnErr(codegen::createTargetMachineForTriple(TheTriple.str()));856 857 return TM->createDataLayout().getStringRepresentation();858 };859 860 std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);861 862 MMM->MMI = std::make_unique<MachineModuleInfo>(TM.get());863 MParser->parseMachineFunctions(*M, *MMM->MMI);864 MMM->M = std::move(M);865 } else {866 SMDiagnostic Err;867 ErrorOr<std::unique_ptr<MemoryBuffer>> MB =868 MemoryBuffer::getFileOrSTDIN(Filename);869 if (std::error_code EC = MB.getError()) {870 WithColor::error(errs(), ToolName)871 << Filename << ": " << EC.message() << "\n";872 return {nullptr, false};873 }874 875 if (!isBitcode((const unsigned char *)(*MB)->getBufferStart(),876 (const unsigned char *)(*MB)->getBufferEnd())) {877 std::unique_ptr<Module> Result = parseIR(**MB, Err, Ctxt);878 if (!Result) {879 Err.print(ToolName.data(), errs());880 return {nullptr, false};881 }882 MMM->M = std::move(Result);883 } else {884 IsBitcode = true;885 MMM->readBitcode(MemoryBufferRef(**MB), Ctxt, ToolName);886 887 if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit)888 initializeTargetInfo();889 }890 }891 if (MMM->verify(&errs())) {892 WithColor::error(errs(), ToolName)893 << Filename << " - input module is broken!\n";894 return {nullptr, false};895 }896 return {std::move(MMM), IsBitcode};897}898