Index: llvm/include/llvm/CodeGen/AsmPrinter.h =================================================================== --- llvm/include/llvm/CodeGen/AsmPrinter.h +++ llvm/include/llvm/CodeGen/AsmPrinter.h @@ -135,6 +135,7 @@ MCSymbol *CurrentFnBegin = nullptr; MCSymbol *CurrentFnEnd = nullptr; MCSymbol *CurExceptionSym = nullptr; + DenseMap ExceptionSymbols; // The garbage collection metadata printer table. void *GCMetadataPrinters = nullptr; // Really a DenseMap. @@ -219,6 +220,23 @@ MCSymbol *getFunctionEnd() const { return CurrentFnEnd; } MCSymbol *getCurExceptionSym(); + // Set the exception symbol associated with the function fragment which begins + // with a given basic block. + void setExceptionSym(const MachineBasicBlock *MBB, MCSymbol *Sym) { + ExceptionSymbols.try_emplace(MBB, Sym); + } + + // Get the exception symbol associated with the function fragment which begins + // with a given basic block. Falls back to getCurExceptionSym() if no + // association is found. + MCSymbol *getExceptionSym(const MachineBasicBlock *MBB) { + auto r = ExceptionSymbols.find(MBB); + if (r == ExceptionSymbols.end()) + return getCurExceptionSym(); + else + return r->second; + } + /// Return information about object file lowering. const TargetLoweringObjectFile &getObjFileLowering() const; Index: llvm/include/llvm/CodeGen/AsmPrinterHandler.h =================================================================== --- llvm/include/llvm/CodeGen/AsmPrinterHandler.h +++ llvm/include/llvm/CodeGen/AsmPrinterHandler.h @@ -67,6 +67,12 @@ /// Process end of an instruction. virtual void endInstruction() = 0; + + /// Process beginning of a basic block during basic block sections. + virtual void beginBasicBlock(const MachineBasicBlock &MBB) {} + + /// Process end of a basic block during basic block sections. + virtual void endBasicBlock(const MachineBasicBlock &MBB) {} }; } // End of namespace llvm Index: llvm/include/llvm/CodeGen/CommandFlags.inc =================================================================== --- llvm/include/llvm/CodeGen/CommandFlags.inc +++ llvm/include/llvm/CodeGen/CommandFlags.inc @@ -238,6 +238,14 @@ cl::desc("Emit functions into separate sections"), cl::init(false)); +static cl::opt BasicBlockSections( + "basicblock-sections", cl::desc("Emit basic blocks into separate sections"), + cl::init(BasicBlockSection::None), + cl::values(clEnumValN(BasicBlockSection::None, "none", "Off"), + clEnumValN(BasicBlockSection::All, "all", "All Basic Blocks"), + clEnumValN(BasicBlockSection::Labels, "labels", + "Labelled Basic Blocks"))); + static cl::opt TLSSize("tls-size", cl::desc("Bit size of immediate TLS offsets"), cl::init(0)); @@ -251,6 +259,11 @@ cl::desc("Give unique names to every section"), cl::init(true)); +static cl::opt UniqueBBSectionNames( + "unique-bb-section-names", + cl::desc("Give unique names to every basic block section"), + cl::init(false)); + static cl::opt EABIVersion("meabi", cl::desc("Set EABI type (default depends on triple):"), cl::init(EABI::Default), @@ -308,7 +321,9 @@ Options.RelaxELFRelocations = RelaxELFRelocations; Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; + Options.BasicBlockSections = BasicBlockSections; Options.UniqueSectionNames = UniqueSectionNames; + Options.UniqueBBSectionNames = UniqueBBSectionNames; Options.TLSSize = TLSSize; Options.EmulatedTLS = EmulatedTLS; Options.ExplicitEmulatedTLS = EmulatedTLS.getNumOccurrences() > 0; Index: llvm/include/llvm/CodeGen/DebugHandlerBase.h =================================================================== --- llvm/include/llvm/CodeGen/DebugHandlerBase.h +++ llvm/include/llvm/CodeGen/DebugHandlerBase.h @@ -118,6 +118,9 @@ void beginFunction(const MachineFunction *MF) override; void endFunction(const MachineFunction *MF) override; + void beginBasicBlock(const MachineBasicBlock &MBB) override; + void endBasicBlock(const MachineBasicBlock &MBB) override; + /// Return Label preceding the instruction. MCSymbol *getLabelBeforeInsn(const MachineInstr *MI); Index: llvm/include/llvm/CodeGen/MachineBasicBlock.h =================================================================== --- llvm/include/llvm/CodeGen/MachineBasicBlock.h +++ llvm/include/llvm/CodeGen/MachineBasicBlock.h @@ -129,10 +129,25 @@ /// Indicate that this basic block is the entry block of a cleanup funclet. bool IsCleanupFuncletEntry = false; + /// Indicate that this basic block begins a new section. + bool IsBeginSection = false; + + /// Indicate that this basic block ends the current section. + bool IsEndSection = false; + + /// Indicate that this basic block belongs to the cold section. + bool IsColdSection = false; + + /// Indicate that this basic block belong to the exception section. + bool IsExceptionSection = false; + /// since getSymbol is a relatively heavy-weight operation, the symbol /// is only computed once and is cached. mutable MCSymbol *CachedMCSymbol = nullptr; + /// Used during basic block sections to marks the end of a basic block. + MCSymbol *EndMCSymbol = nullptr; + // Intrusive list support MachineBasicBlock() = default; @@ -408,6 +423,30 @@ /// Indicates if this is the entry block of a cleanup funclet. void setIsCleanupFuncletEntry(bool V = true) { IsCleanupFuncletEntry = V; } + /// Returns true if this block begins a section. + bool isBeginSection() const { return IsBeginSection; } + + /// Indicate that this basic block begins a new section. + void setBeginSection(bool V = true) { IsBeginSection = V; } + + /// Returns true if this block ends a section. + bool isEndSection() const { return IsEndSection; } + + /// Indicate that this basic block ends a section. + void setEndSection(bool V = true) { IsEndSection = V; } + + /// Returns true if this basic block belongs to the cold section. + bool isColdSection() const { return IsColdSection; } + + /// Indicate that this basic block belongs to the cold section. + void setColdSection(bool V = true) { IsColdSection = V; } + + /// Returns true if this basic block belongs to the exception section. + bool isExceptionSection() const { return IsExceptionSection; } + + /// Indicate that this basic block belongs to the exception section. + void setExceptionSection(bool V = true) { IsExceptionSection = V; } + /// Returns true if it is legal to hoist instructions into this block. bool isLegalToHoistInto() const; @@ -419,6 +458,15 @@ void moveBefore(MachineBasicBlock *NewAfter); void moveAfter(MachineBasicBlock *NewBefore); + /// Insert an unconditional jump to a fallthrough block if any. + void insertUnconditionalFallthroughBranch(); + + /// Returns true if this and MBB belong to the same section. + bool sameSection(const MachineBasicBlock *MBB) const; + + /// Returns the basic block that ends the section which contains this one. + const MachineBasicBlock *getSectionEndMBB() const; + /// Update the terminator instructions in block to account for changes to the /// layout. If the block previously used a fallthrough, it may now need a /// branch, and if it previously used branching it may now be able to use a @@ -803,6 +851,12 @@ /// Return the MCSymbol for this basic block. MCSymbol *getSymbol() const; + /// Sets the MCSymbol corresponding to the end of this basic block. + void setEndMCSymbol(MCSymbol *Sym) { EndMCSymbol = Sym; } + + /// Returns the MCSymbol corresponding to the end of this basic block. + MCSymbol *getEndMCSymbol() const { return EndMCSymbol; } + Optional getIrrLoopHeaderWeight() const { return IrrLoopHeaderWeight; } Index: llvm/include/llvm/CodeGen/MachineFunction.h =================================================================== --- llvm/include/llvm/CodeGen/MachineFunction.h +++ llvm/include/llvm/CodeGen/MachineFunction.h @@ -64,6 +64,7 @@ class MCContext; class MCInstrDesc; class MCSymbol; +class MCSection; class Pass; class PseudoSourceValueManager; class raw_ostream; @@ -243,6 +244,9 @@ // Keep track of jump tables for switch instructions MachineJumpTableInfo *JumpTableInfo; + // Keep track of the function section. + MCSection *Section = nullptr; + // Keeps track of Wasm exception handling related data. This will be null for // functions that aren't using a wasm EH personality. WasmEHFuncInfo *WasmEHInfo = nullptr; @@ -256,6 +260,12 @@ // numbered and this vector keeps track of the mapping from ID's to MBB's. std::vector MBBNumbering; + // Unary encoding of basic block symbols is used to reduce size of ".strtab". + // Basic block number 'i' gets a prefix of length 'i'. The ith character also + // denotes the type of basic block number 'i'. Return blocks are marked with + // 'r', landing pads with 'l' and regular blocks with 'a'. + std::vector MBBSymbolPrefix; + // Pool-allocate MachineFunction-lifetime and IR objects. BumpPtrAllocator Allocator; @@ -331,6 +341,13 @@ bool HasEHScopes = false; bool HasEHFunclets = false; + // True if basic block sections that are generated have been sorted. + bool BBSectionsSorted = false; + // True if sections must be generated for all basic blocks. + bool BasicBlockSections = false; + // True if labels must be generated for all basic blocks. + bool BasicBlockLabels = false; + /// List of C++ TypeInfo used. std::vector TypeInfos; @@ -447,6 +464,12 @@ MachineModuleInfo &getMMI() const { return MMI; } MCContext &getContext() const { return Ctx; } + /// Returns the Section this function belongs to. + MCSection *getSection() const { return Section; } + + /// Indicates the Section this function belongs to. + void setSection(MCSection *S) { Section = S; } + PseudoSourceValueManager &getPSVManager() const { return *PSVManager; } /// Return the DataLayout attached to the Module associated to this MF. @@ -461,6 +484,18 @@ /// getFunctionNumber - Return a unique ID for the current function. unsigned getFunctionNumber() const { return FunctionNumber; } + /// Returns true if this function has basic block sections enabled. + bool getBasicBlockSections() const { return BasicBlockSections; } + + /// Sort the basic blocks according to the sections they belong to. + bool sortBasicBlockSections(); + + /// Indicates that basic block Labels are to be generated for this function. + void setBasicBlockLabels(); + + /// Returns true if basic block labels are to be generated for this function. + bool getBasicBlockLabels() const { return BasicBlockLabels; } + /// getTarget - Return the target machine this machine code is compiled with const LLVMTargetMachine &getTarget() const { return Target; } @@ -1011,6 +1046,10 @@ /// of the instruction stream. void copyCallSiteInfo(const MachineInstr *Old, const MachineInstr *New); + + const std::vector &getMBBSymbolPrefix() const { + return MBBSymbolPrefix; + } }; //===--------------------------------------------------------------------===// Index: llvm/include/llvm/CodeGen/TargetFrameLowering.h =================================================================== --- llvm/include/llvm/CodeGen/TargetFrameLowering.h +++ llvm/include/llvm/CodeGen/TargetFrameLowering.h @@ -178,6 +178,10 @@ virtual void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const = 0; + virtual void + emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) const {} + /// Replace a StackProbe stub (if any) with the actual probe code inline virtual void inlineStackProbe(MachineFunction &MF, MachineBasicBlock &PrologueMBB) const {} Index: llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -65,6 +65,21 @@ MCSection *getSectionForJumpTable(const Function &F, const TargetMachine &TM) const override; + MCSection * + getSectionForMachineBasicBlock(const Function &F, + const MachineBasicBlock &MBB, + const TargetMachine &TM) const override; + + MCSection * + getColdSectionForMachineBasicBlock(const Function &F, + const MachineBasicBlock &MBB, + const TargetMachine &TM) const override; + + MCSection * + getEHSectionForMachineBasicBlock(const Function &F, + const MachineBasicBlock &MBB, + const TargetMachine &TM) const override; + bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, const Function &F) const override; Index: llvm/include/llvm/IR/BasicBlock.h =================================================================== --- llvm/include/llvm/IR/BasicBlock.h +++ llvm/include/llvm/IR/BasicBlock.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/IR/GlobalObject.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/SymbolTableListTraits.h" #include "llvm/IR/Value.h" @@ -428,6 +429,12 @@ Optional getIrrLoopHeaderWeight() const; + /// Set the section prefix for this block. + void setSectionPrefix(StringRef Prefix); + + /// Get the section prefix for this block. + Optional getSectionPrefix() const; + private: /// Increment the internal refcount of the number of BlockAddresses /// referencing this BasicBlock by \p Amt. Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1804,6 +1804,7 @@ return cast_or_null(getRawUnit()); } void replaceUnit(DICompileUnit *CU) { replaceOperandWith(5, CU); } + DITemplateParameterArray getTemplateParams() const { return cast_or_null(getRawTemplateParams()); } Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -96,6 +96,9 @@ friend class SymbolTableListTraits; + bool BasicBlockSections = false; + bool BasicBlockLabels = false; + /// hasLazyArguments/CheckLazyArguments - The argument list of a function is /// built on demand, so that the list isn't allocated until the first client /// needs it. The hasLazyArguments predicate returns true if the arg list @@ -159,6 +162,18 @@ /// within this function. unsigned getInstructionCount() const; + /// Returns true if this function has basic block sections enabled. + bool getBasicBlockSections() const { return BasicBlockSections; } + + /// Indicates that basic block sections is enabled for this function. + void setBasicBlockSections(bool value) { BasicBlockSections = value; } + + /// Returns true if this function has basic block labels enabled. + bool getBasicBlockLabels() const { return BasicBlockLabels; } + + /// Indicates that basic block labels is enabled for this function. + void setBasicBlockLabels(bool value) { BasicBlockLabels = value; } + /// Returns the FunctionType for me. FunctionType *getFunctionType() const { return cast(getValueType()); Index: llvm/include/llvm/MC/MCAsmInfo.h =================================================================== --- llvm/include/llvm/MC/MCAsmInfo.h +++ llvm/include/llvm/MC/MCAsmInfo.h @@ -400,6 +400,12 @@ // %hi(), and similar unary operators. bool HasMipsExpressions = false; + // If true, then use symbols instead of sections for relocations. This is + // true with basic block sections, as the basic block is relaxed by the + // linker. + bool RelocateWithSymbols = false; + bool RelocateWithSizeRelocs = false; + // If true, emit function descriptor symbol on AIX. bool NeedsFunctionDescriptors = false; @@ -665,6 +671,15 @@ bool canRelaxRelocations() const { return RelaxELFRelocations; } void setRelaxELFRelocations(bool V) { RelaxELFRelocations = V; } bool hasMipsExpressions() const { return HasMipsExpressions; } + bool shouldRelocateWithSymbols() const { return RelocateWithSymbols; } + bool shouldRelocateWithSizeRelocs() const { return RelocateWithSizeRelocs; } + void setRelocateWithSymbols(bool V = true) { + // Relocate with symbols and size relocs. This is currently active + // during basic block sections. If the target does not support size + // relocs, this must be split. + RelocateWithSymbols = V; + RelocateWithSizeRelocs = V; + } bool needsFunctionDescriptors() const { return NeedsFunctionDescriptors; } }; Index: llvm/include/llvm/MC/MCDwarf.h =================================================================== --- llvm/include/llvm/MC/MCDwarf.h +++ llvm/include/llvm/MC/MCDwarf.h @@ -474,6 +474,12 @@ assert(Op == OpRegister); } + long long GetOffsetOrRegister2() const { + if (Operation == OpRegister) + return Register2; + return Offset; + } + public: /// .cfi_def_cfa defines a rule for computing CFA as: take address from /// Register and add Offset to it. @@ -601,6 +607,27 @@ assert(Operation == OpEscape); return StringRef(&Values[0], Values.size()); } + + friend hash_code hash_value(const MCCFIInstruction &Arg) { + return hash_combine(Arg.Label, Arg.Operation, Arg.Register, + Arg.GetOffsetOrRegister2()); + } + + bool operator<(const MCCFIInstruction &Other) const { + return std::make_tuple(Label, Operation, Register, GetOffsetOrRegister2()) < + std::make_tuple(Other.Label, Other.Operation, Other.Register, + Other.GetOffsetOrRegister2()); + } + + bool operator==(const MCCFIInstruction &Other) const { + return !(*this < Other) && !(Other < *this); + } + + MCCFIInstruction StripLabel() const { + MCCFIInstruction Copy = *this; + Copy.Label = nullptr; + return Copy; + } }; struct MCDwarfFrameInfo { Index: llvm/include/llvm/Target/TargetLoweringObjectFile.h =================================================================== --- llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -24,6 +24,7 @@ namespace llvm { class GlobalValue; +class MachineBasicBlock; class MachineModuleInfo; class Mangler; class MCContext; @@ -90,6 +91,21 @@ const Constant *C, unsigned &Align) const; + virtual MCSection * + getSectionForMachineBasicBlock(const Function &F, + const MachineBasicBlock &MBB, + const TargetMachine &TM) const; + + virtual MCSection * + getColdSectionForMachineBasicBlock(const Function &F, + const MachineBasicBlock &MBB, + const TargetMachine &TM) const; + + virtual MCSection * + getEHSectionForMachineBasicBlock(const Function &F, + const MachineBasicBlock &MBB, + const TargetMachine &TM) const; + /// Classify the specified global variable into a set of target independent /// categories embodied in SectionKind. static SectionKind getKindForGlobal(const GlobalObject *GO, Index: llvm/include/llvm/Target/TargetMachine.h =================================================================== --- llvm/include/llvm/Target/TargetMachine.h +++ llvm/include/llvm/Target/TargetMachine.h @@ -242,6 +242,8 @@ bool getUniqueSectionNames() const { return Options.UniqueSectionNames; } + bool getUniqueBBSectionNames() const { return Options.UniqueBBSectionNames; } + /// Return true if data objects should be emitted into their own section, /// corresponds to -fdata-sections. bool getDataSections() const { @@ -254,6 +256,21 @@ return Options.FunctionSections; } + /// If basic blocks should be emitted into their own section, + /// corresponding to -fbasicblock-sections. + llvm::BasicBlockSection::SectionMode getBasicBlockSections() const { + return Options.BasicBlockSections; + } + + bool isFunctionInBasicBlockSectionsList(const StringRef &name) const { + return Options.BasicBlockSectionsList.find(name) != + Options.BasicBlockSectionsList.end(); + } + + SmallSet getBasicBlockSectionsSet(const StringRef &name) const { + return Options.BasicBlockSectionsList.lookup(name); + } + /// Get a \c TargetIRAnalysis appropriate for the target. /// /// This is used to construct the new pass manager's target IR analysis pass, Index: llvm/include/llvm/Target/TargetOptions.h =================================================================== --- llvm/include/llvm/Target/TargetOptions.h +++ llvm/include/llvm/Target/TargetOptions.h @@ -14,6 +14,8 @@ #ifndef LLVM_TARGET_TARGETOPTIONS_H #define LLVM_TARGET_TARGETOPTIONS_H +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/MC/MCTargetOptions.h" namespace llvm { @@ -63,6 +65,16 @@ }; } + namespace BasicBlockSection { + enum SectionMode { + None, // Do not use Basic Block Sections. + All, // Use Basic Block Sections for all functions. + Labels, // Do not use Basic Block Sections but label basic blocks. + Func, // Get list of functions from a file + List // Get list of functions & BBs from a file + }; + } + enum class EABI { Unknown, Default, // Default means not specified @@ -114,9 +126,9 @@ EnableFastISel(false), EnableGlobalISel(false), UseInitArray(false), DisableIntegratedAS(false), RelaxELFRelocations(false), FunctionSections(false), DataSections(false), - UniqueSectionNames(true), TrapUnreachable(false), - NoTrapAfterNoreturn(false), TLSSize(0), EmulatedTLS(false), - ExplicitEmulatedTLS(false), EnableIPRA(false), + UniqueSectionNames(true), UniqueBBSectionNames(false), + TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0), + EmulatedTLS(false), ExplicitEmulatedTLS(false), EnableIPRA(false), EmitStackSizeSection(false), EnableMachineOutliner(false), SupportsDefaultOutlining(false), EmitAddrsig(false), EnableDebugEntryValues(false), ForceDwarfFrameSection(false) {} @@ -224,6 +236,8 @@ unsigned UniqueSectionNames : 1; + unsigned UniqueBBSectionNames : 1; + /// Emit target-specific trap instruction for 'unreachable' IR instructions. unsigned TrapUnreachable : 1; @@ -256,6 +270,11 @@ /// Emit address-significance table. unsigned EmitAddrsig : 1; + /// Emit basic blocks into separate sections. + BasicBlockSection::SectionMode BasicBlockSections = BasicBlockSection::None; + + StringMap> BasicBlockSectionsList; + /// Emit debug info about parameter's entry values. unsigned EnableDebugEntryValues : 1; Index: llvm/include/llvm/Transforms/Utils/ModuleUtils.h =================================================================== --- llvm/include/llvm/Transforms/Utils/ModuleUtils.h +++ llvm/include/llvm/Transforms/Utils/ModuleUtils.h @@ -107,7 +107,10 @@ /// If the module has no strong external symbols (such a module may still have a /// semantic effect if it performs global initialization), we cannot produce a /// unique identifier for this module, so we return the empty string. -std::string getUniqueModuleId(Module *M); +/// +/// If UseModuleId is true, we include the ModuleIdentifier string. This is +/// however not guaranteed to be unique. +std::string getUniqueModuleId(Module *M, bool UseModuleId = false); class CallInst; namespace VFABI { Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -664,7 +664,9 @@ EmitConstantPool(); // Print the 'header' of function. - OutStreamer->SwitchSection(getObjFileLowering().SectionForGlobal(&F, TM)); + MF->setSection(getObjFileLowering().SectionForGlobal(&F, TM)); + OutStreamer->SwitchSection(MF->getSection()); + EmitVisibility(CurrentFnSym, F.getVisibility()); if (MAI->needsFunctionDescriptors() && @@ -1058,6 +1060,19 @@ // Print out code for the function. bool HasAnyRealCode = false; int NumInstsInFunction = 0; + bool emitBasicBlockSections = MF->getBasicBlockSections(); + MachineBasicBlock *EndOfRegularSectionMBB = nullptr; + bool emitBBLabels = MF->getBasicBlockSections() || MF->getBasicBlockLabels(); + if (emitBBLabels) + MF->setBasicBlockLabels(); + if (emitBasicBlockSections) { + MF->sortBasicBlockSections(); + EndOfRegularSectionMBB = + const_cast(MF->front().getSectionEndMBB()); + assert(EndOfRegularSectionMBB->isEndSection() && + "The MBB at the end of the regular section must end a section"); + } + for (auto &MBB : *MF) { // Print a label for the basic block. EmitBasicBlockStart(MBB); @@ -1094,6 +1109,17 @@ break; case TargetOpcode::ANNOTATION_LABEL: case TargetOpcode::EH_LABEL: + if (MBB.isExceptionSection() && MBB.isBeginSection() && + ((*std::prev(MI.getIterator())).getOpcode() == + TargetOpcode::CFI_INSTRUCTION)) { + // Emit a NOP here to avoid zero-offset landing pads with + // basic block sections. + MCInst Noop; + MF->getSubtarget().getInstrInfo()->getNoop(Noop); + OutStreamer->AddComment("avoids zero-offset landing pad"); + OutStreamer->EmitInstruction(Noop, getSubtargetInfo()); + } + LLVM_FALLTHROUGH; case TargetOpcode::GC_LABEL: OutStreamer->EmitLabel(MI.getOperand(0).getMCSymbol()); break; @@ -1137,7 +1163,18 @@ } } } - + if (&MBB != EndOfRegularSectionMBB && + (MF->getBasicBlockLabels() || MBB.isEndSection())) { + // Emit size directive for the size of this basic block. Create a symbol + // for the end of the basic block. + MCSymbol *CurrentBBEnd = OutContext.createTempSymbol(); + const MCExpr *SizeExp = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(CurrentBBEnd, OutContext), + MCSymbolRefExpr::create(MBB.getSymbol(), OutContext), OutContext); + OutStreamer->EmitLabel(CurrentBBEnd); + MBB.setEndMCSymbol(CurrentBBEnd); + OutStreamer->emitELFSize(MBB.getSymbol(), SizeExp); + } EmitBasicBlockEnd(MBB); } @@ -1171,6 +1208,10 @@ } } + // Switch to the original section if basic block sections was used. + if (emitBasicBlockSections) + OutStreamer->SwitchSection(MF->getSection()); + const Function &F = MF->getFunction(); for (const auto &BB : F) { if (!BB.hasAddressTaken()) @@ -1186,7 +1227,7 @@ EmitFunctionBodyEnd(); if (needFuncLabelsForEHOrDebugInfo(*MF, MMI) || - MAI->hasDotTypeDotSizeDirective()) { + MAI->hasDotTypeDotSizeDirective() || emitBasicBlockSections) { // Create a symbol for the end of function. CurrentFnEnd = createTempSymbol("func_end"); OutStreamer->EmitLabel(CurrentFnEnd); @@ -1209,6 +1250,9 @@ HI.Handler->markFunctionEnd(); } + if (emitBasicBlockSections) + EndOfRegularSectionMBB->setEndMCSymbol(CurrentFnEnd); + // Print out jump tables referenced by the function. EmitJumpTableInfo(); @@ -1686,6 +1730,7 @@ CurrentFnSymForSize = CurrentFnSym; CurrentFnBegin = nullptr; CurExceptionSym = nullptr; + ExceptionSymbols.clear(); bool NeedsLocalForSize = MAI->needsLocalForSize(); if (F.hasFnAttribute("patchable-function-entry") || needFuncLabelsForEHOrDebugInfo(MF, MMI) || NeedsLocalForSize || @@ -2933,6 +2978,7 @@ /// MachineBasicBlock, an alignment (if present) and a comment describing /// it if appropriate. void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) { + bool BasicBlockSections = MF->getBasicBlockSections(); // End the previous funclet and start a new one. if (MBB.isEHFuncletEntry()) { for (const HandlerInfo &HI : Handlers) { @@ -2942,9 +2988,11 @@ } // Emit an alignment directive for this block, if needed. - const Align Alignment = MBB.getAlignment(); - if (Alignment != Align::None()) - EmitAlignment(Alignment); + if (MBB.pred_empty() || !BasicBlockSections) { + const Align Alignment = MBB.getAlignment(); + if (Alignment != Align::None()) + EmitAlignment(Alignment); + } // If the block has its address taken, emit any labels that were used to // reference the block. It is possible that there is more than one label @@ -2976,23 +3024,61 @@ emitBasicBlockLoopComments(MBB, MLI, *this); } - // Print the main label for the block. + bool emitBBLabels = BasicBlockSections || MF->getBasicBlockLabels(); if (MBB.pred_empty() || - (isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry() && - !MBB.hasLabelMustBeEmitted())) { + (!emitBBLabels && isBlockOnlyReachableByFallthrough(&MBB) && + !MBB.isEHFuncletEntry() && !MBB.hasLabelMustBeEmitted())) { if (isVerbose()) { // NOTE: Want this comment at start of line, don't emit with AddComment. OutStreamer->emitRawComment(" %bb." + Twine(MBB.getNumber()) + ":", false); } } else { - if (isVerbose() && MBB.hasLabelMustBeEmitted()) + if (isVerbose() && MBB.hasLabelMustBeEmitted()) { OutStreamer->AddComment("Label of block must be emitted"); + } + // With -fbasicblock-sections, a basic block can start a new section. + if (MBB.isExceptionSection()) { + if (MF->front().isExceptionSection()) { + OutStreamer->SwitchSection(MF->getSection()); + } else { + OutStreamer->SwitchSection( + getObjFileLowering().getEHSectionForMachineBasicBlock( + MF->getFunction(), MBB, TM)); + } + } else if (MBB.isColdSection()) { + // Create the cold section here. + OutStreamer->SwitchSection( + getObjFileLowering().getColdSectionForMachineBasicBlock( + MF->getFunction(), MBB, TM)); + } else if (MBB.isBeginSection() && MBB.isEndSection()) { + OutStreamer->SwitchSection( + getObjFileLowering().getSectionForMachineBasicBlock(MF->getFunction(), + MBB, TM)); + } else if (BasicBlockSections) { + OutStreamer->SwitchSection(MF->getSection()); + } OutStreamer->EmitLabel(MBB.getSymbol()); + // With BasicBlockSections, each Basic Block must handle CFI information on + // its own. + if (MBB.isBeginSection()) { + for (const HandlerInfo &HI : Handlers) { + HI.Handler->beginBasicBlock(MBB); + } + } } } -void AsmPrinter::EmitBasicBlockEnd(const MachineBasicBlock &MBB) {} +void AsmPrinter::EmitBasicBlockEnd(const MachineBasicBlock &MBB) { + // Check if CFI information needs to be updated for this MBB with basic block + // sections. + if (MF->getBasicBlockSections() && MBB.isEndSection()) { + for (const HandlerInfo &HI : Handlers) { + HI.Handler->endBasicBlock(MBB); + } + CurExceptionSym = nullptr; + } +} void AsmPrinter::EmitVisibility(MCSymbol *Sym, unsigned Visibility, bool IsDefinition) const { @@ -3020,6 +3106,10 @@ /// the predecessor and this block is a fall-through. bool AsmPrinter:: isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { + // With BasicBlock Sections, no block is a fall through. + if (MBB->isBeginSection()) + return false; + // If this is a landing pad, it isn't a fall through. If it has no preds, // then nothing falls through to it. if (MBB->isEHPad() || MBB->pred_empty()) Index: llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -227,10 +227,15 @@ // doing that violates the ranges that are calculated in the history map. // However, we currently do not emit debug values for constant arguments // directly at the start of the function, so this code is still useful. + // + // If the first mention of an argument is in a unique-section basic block, + // we cannot assign the CurrentFnBegin label, as it lies in a different + // section. For simplicity, we simply ignore such mentions in this code. const DILocalVariable *DIVar = Entries.front().getInstr()->getDebugVariable(); if (DIVar->isParameter() && - getDISubprogram(DIVar->getScope())->describes(&MF->getFunction())) { + getDISubprogram(DIVar->getScope())->describes(&MF->getFunction()) && + Entries.front().getInstr()->getParent()->sameSection(&MF->front())) { if (!IsDescribedByReg(Entries.front().getInstr())) LabelsBeforeInsn[Entries.front().getInstr()] = Asm->getFunctionBegin(); if (Entries.front().getInstr()->getDebugExpression()->isFragment()) { @@ -342,3 +347,17 @@ LabelsBeforeInsn.clear(); LabelsAfterInsn.clear(); } + +void DebugHandlerBase::beginBasicBlock(const MachineBasicBlock &MBB) { + if (!MBB.isBeginSection()) + return; + + PrevLabel = MBB.getSymbol(); +} + +void DebugHandlerBase::endBasicBlock(const MachineBasicBlock &MBB) { + if (!MBB.isEndSection()) + return; + + PrevLabel = nullptr; +} Index: llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h +++ llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h @@ -96,6 +96,8 @@ /// Until the next call, bytes added to the stream will be added to this /// entry. void startEntry(const MCSymbol *BeginSym, const MCSymbol *EndSym) { + assert(&BeginSym->getSection() == &EndSym->getSection() && + "debug_loc entries cannot span across multiple sections"); Entries.push_back({BeginSym, EndSym, DWARFBytes.size(), Comments.size()}); } Index: llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -47,8 +47,10 @@ } void DwarfCFIExceptionBase::endFragment() { - if (shouldEmitCFI) + // With -fbasicblock-sections, this is handled at each basic block. + if (shouldEmitCFI && !Asm->MF->getBasicBlockSections()) { Asm->OutStreamer->EmitCFIEndProc(); + } } DwarfCFIException::DwarfCFIException(AsmPrinter *A) @@ -162,6 +164,9 @@ // Provide LSDA information. if (shouldEmitLSDA) Asm->OutStreamer->EmitCFILsda(ESP(Asm), TLOF.getLSDAEncoding()); + + // Set the exception symbol associated with this basic block. + Asm->setExceptionSym(MBB, ESP(Asm)); } /// endFunction - Gather and emit post-function exception information. @@ -172,3 +177,13 @@ emitExceptionTable(); } + +void DwarfCFIException::beginBasicBlock(const MachineBasicBlock &MBB) { + beginFragment(&MBB, getExceptionSym); +} + +void DwarfCFIException::endBasicBlock(const MachineBasicBlock &MBB) { + if (shouldEmitCFI) { + Asm->OutStreamer->EmitCFIEndProc(); + } +} Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -392,7 +392,22 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) { DIE *SPDie = getOrCreateSubprogramDIE(SP, includeMinimalInlineScopes()); - attachLowHighPC(*SPDie, Asm->getFunctionBegin(), Asm->getFunctionEnd()); + if (!Asm->MF->getBasicBlockSections()) + attachLowHighPC(*SPDie, Asm->getFunctionBegin(), Asm->getFunctionEnd()); + else { + SmallVector BB_List; + BB_List.push_back({Asm->getFunctionBegin(), Asm->getFunctionEnd()}); + // If basic block sections are on, only the entry BB and exception + // handling BBs will be in the [getFunctionBegin(), getFunctionEnd()] + // range. Ranges for the other BBs have to be emitted separately. + for (auto &MBB : *Asm->MF) { + if (!MBB.pred_empty() && MBB.isBeginSection()) { + BB_List.push_back( + {MBB.getSymbol(), MBB.getSectionEndMBB()->getEndMCSymbol()}); + } + } + attachRangesOrLowHighPC(*SPDie, BB_List); + } if (DD->useAppleExtensionAttributes() && !DD->getCurrentFunction()->getTarget().Options.DisableFramePointerElim( *DD->getCurrentFunction())) @@ -521,9 +536,37 @@ DIE &Die, const SmallVectorImpl &Ranges) { SmallVector List; List.reserve(Ranges.size()); - for (const InsnRange &R : Ranges) - List.push_back( - {DD->getLabelBeforeInsn(R.first), DD->getLabelAfterInsn(R.second)}); + for (const InsnRange &R : Ranges) { + auto *BeginLabel = DD->getLabelBeforeInsn(R.first); + auto *EndLabel = DD->getLabelAfterInsn(R.second); + + const auto *BeginMBB = R.first->getParent(); + const auto *EndMBB = R.second->getParent(); + + if (BeginMBB->sameSection(EndMBB) || + Asm->MF->getBasicBlockSections() == llvm::BasicBlockSection::None) { + // Without basic block sections, there is just one continuous range. + // The same holds if EndMBB is in the initial non-unique-section BB range. + List.push_back({BeginLabel, EndLabel}); + continue; + } + + assert(!BeginMBB->sameSection(EndMBB) && + "BeginMBB and EndMBB are in the same section!"); + const auto *MBBInSection = BeginMBB->getSectionEndMBB(); + List.push_back({BeginLabel, MBBInSection->getEndMCSymbol()}); + MBBInSection = MBBInSection->getNextNode(); + while (!MBBInSection->sameSection(EndMBB)) { + assert(MBBInSection->isBeginSection() && + "This should start a new section."); + List.push_back({MBBInSection->getSymbol(), + MBBInSection->getSectionEndMBB()->getEndMCSymbol()}); + MBBInSection = MBBInSection->getSectionEndMBB()->getNextNode(); + } + + assert(MBBInSection->sameSection(EndMBB)); + List.push_back({MBBInSection->getSymbol(), EndLabel}); + } attachRangesOrLowHighPC(Die, std::move(List)); } Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1467,7 +1467,9 @@ const MCSymbol *EndLabel; if (std::next(EI) == Entries.end()) { - EndLabel = Asm->getFunctionEnd(); + const MachineBasicBlock &EndMBB = Asm->MF->back(); + EndLabel = EndMBB.isEndSection() ? EndMBB.getEndMCSymbol() + : Asm->getFunctionEnd(); if (EI->isClobber()) EndMI = EI->getInstr(); } @@ -1894,6 +1896,19 @@ // Add the range of this function to the list of ranges for the CU. TheCU.addRange({Asm->getFunctionBegin(), Asm->getFunctionEnd()}); + // With basic block sections, add all basic block ranges with unique + // sections. + if (MF->getBasicBlockSections()) { + for (auto &MBB : *MF) { + if (MBB.getNumber() == MF->front().getNumber()) + continue; + if (MBB.isBeginSection()) { + TheCU.addRange( + {MBB.getSymbol(), MBB.getSectionEndMBB()->getEndMCSymbol()}); + } + } + } + // Under -gmlt, skip building the subprogram if there are no inlined // subroutines inside it. But with -fdebug-info-for-profiling, the subprogram // is still needed as we need its source location. @@ -2543,6 +2558,19 @@ // * as of October 2018, at least // Ideally/in v5, this could use SectionLabels to reuse existing addresses // in the address pool to minimize object size/relocations. + if (Asm->TM.getBasicBlockSections() != llvm::BasicBlockSection::None && + Asm->TM.getBasicBlockSections() != llvm::BasicBlockSection::Labels) { + // With basic block sections, symbol difference cannot be emitted as + // the can span sections. + Asm->emitInt8(dwarf::DW_LLE_startx_endx); + Asm->EmitULEB128(AddrPool.getIndex(Entry.Begin)); + Asm->EmitULEB128(AddrPool.getIndex(Entry.End)); + } else { + Asm->emitInt8(dwarf::DW_LLE_startx_length); + unsigned idx = AddrPool.getIndex(Entry.Begin); + Asm->EmitULEB128(idx); + Asm->EmitLabelDifference(Entry.End, Entry.Begin, 4); + } Asm->emitInt8(dwarf::DW_LLE_startx_length); unsigned idx = AddrPool.getIndex(Entry.Begin); Asm->EmitULEB128(idx); Index: llvm/lib/CodeGen/AsmPrinter/DwarfException.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfException.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfException.h @@ -66,6 +66,9 @@ void beginFragment(const MachineBasicBlock *MBB, ExceptionSymbolProvider ESP) override; + + void beginBasicBlock(const MachineBasicBlock &MBB) override; + void endBasicBlock(const MachineBasicBlock &MBB) override; }; class LLVM_LIBRARY_VISIBILITY ARMException : public DwarfCFIExceptionBase { Index: llvm/lib/CodeGen/AsmPrinter/EHStreamer.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/EHStreamer.h +++ llvm/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -69,23 +69,45 @@ unsigned Action; }; + /// Structure describing a contiguous range of call-sites which reside + /// in the same function part. + struct CallSiteRange { + // Index of the first call-site entry in the call-site table which + // belongs to this range. + unsigned CallSiteBeginIdx = 0; + // Index just after the last call-site entry in the call-site table which + // belongs to this range. + unsigned CallSiteEndIdx = 0; + // Symbol marking the beginning of the precedure fragment (section). + MCSymbol *FragmentBeginLabel = nullptr; + // Symbol marking the end of the procedure fragment (section). + MCSymbol *FragmentEndLabel = nullptr; + // LSDA symbol for this call-site range. + MCSymbol *ExceptionLabel = nullptr; + // Whether this is the call-site range containing all the landing pads + bool IsLPRange = false; + }; + /// Compute the actions table and gather the first action index for each /// landing pad site. - void computeActionsTable(const SmallVectorImpl &LandingPads, - SmallVectorImpl &Actions, - SmallVectorImpl &FirstActions); + void computeActionsTable( + const SmallVectorImpl &LandingPads, + SmallVectorImpl &Actions, + SmallVectorImpl &FirstActions); void computePadMap(const SmallVectorImpl &LandingPads, RangeMapType &PadMap); - /// Compute the call-site table. The entry for an invoke has a try-range - /// containing the call, a non-zero landing pad and an appropriate action. - /// The entry for an ordinary call has a try-range containing the call and - /// zero for the landing pad and the action. Calls marked 'nounwind' have - /// no entry and must not be contained in the try-range of any entry - they - /// form gaps in the table. Entries must be ordered by try-range address. + /// Compute the call-site table and the call-site ranges. The entry for an + /// invoke has a try-range containing the call, a non-zero landing pad and an + /// appropriate action. The entry for an ordinary call has a try-range + /// containing the call and zero for the landing pad and the action. Calls + /// marked 'nounwind' have no entry and must not be contained in the try-range + /// of any entry - they form gaps in the table. Entries must be ordered by + /// try-range address. virtual void computeCallSiteTable( SmallVectorImpl &CallSites, + SmallVectorImpl &CallSiteRanges, const SmallVectorImpl &LandingPads, const SmallVectorImpl &FirstActions); Index: llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -220,16 +220,36 @@ /// the landing pad and the action. Calls marked 'nounwind' have no entry and /// must not be contained in the try-range of any entry - they form gaps in the /// table. Entries must be ordered by try-range address. -void EHStreamer:: -computeCallSiteTable(SmallVectorImpl &CallSites, - const SmallVectorImpl &LandingPads, - const SmallVectorImpl &FirstActions) { +/// +/// Call-sites are split into one or more call-site ranges associated with +/// different sections of the function. +/// +/// - With -function-sections, all call-sites are grouped into one +/// call-site-range +/// corresponding to the function section. +/// +/// - With -basic-block sections, one call-site range is created for each +/// section, +/// with its FragmentBeginLabel and FragmentEndLabel respectively set to the +/// beginning and ending of the corresponding section and its ExceptionLabel +/// set to the exception symbol dedicated for this section. Later, one LSDA +/// header will be emitted for each call-site range with its call-sites +/// following. The action table and type info table will be shared across +/// all ranges. +void EHStreamer::computeCallSiteTable( + SmallVectorImpl &CallSites, + SmallVectorImpl &CallSiteRanges, + const SmallVectorImpl &LandingPads, + const SmallVectorImpl &FirstActions) { RangeMapType PadMap; computePadMap(LandingPads, PadMap); // The end label of the previous invoke or nounwind try-range. MCSymbol *LastLabel = nullptr; + // Pointer to the current call-site range. + CallSiteRange *CurCSRange = nullptr; + // Whether there is a potentially throwing instruction (currently this means // an ordinary call) between the end of the previous try-range and now. bool SawPotentiallyThrowing = false; @@ -239,8 +259,38 @@ bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; + // All landing pads should reside in one section, and hence in one call-site + // range. + CallSiteRange *LandingPadRange = nullptr; + // Visit all instructions in order of address. for (const auto &MBB : *Asm->MF) { + if (&MBB == &Asm->MF->front() || MBB.isBeginSection()) { + // We start a call-site range upon function entry and at the beginning of + // every basic block section. + CallSiteRanges.push_back(CallSiteRange()); + CurCSRange = &CallSiteRanges.back(); + CurCSRange->FragmentBeginLabel = (&MBB == &Asm->MF->front()) + ? Asm->getFunctionBegin() + : MBB.getSymbol(); + CurCSRange->ExceptionLabel = Asm->getExceptionSym(&MBB); + CurCSRange->CallSiteBeginIdx = CallSites.size(); + PreviousIsInvoke = false; + SawPotentiallyThrowing = false; + LastLabel = nullptr; + } + + if (MBB.isEHPad()) { + // We have found the landing pad range + if (LandingPadRange == nullptr) { + LandingPadRange = CurCSRange; + LandingPadRange->IsLPRange = true; + } else if (LandingPadRange->FragmentBeginLabel != + CurCSRange->FragmentBeginLabel) + report_fatal_error( + "Landing pads reside in different callsite ranges (sections)."); + } + for (const auto &MI : MBB) { if (!MI.isEHLabel()) { if (MI.isCall()) @@ -282,12 +332,8 @@ PreviousIsInvoke = false; } else { // This try-range is for an invoke. - CallSiteEntry Site = { - BeginLabel, - LastLabel, - LandingPad, - FirstActions[P.PadIndex] - }; + CallSiteEntry Site = {BeginLabel, LastLabel, LandingPad, + FirstActions[P.PadIndex]}; // Try to merge with the previous call-site. SJLJ doesn't do this if (PreviousIsInvoke && !IsSJLJ) { @@ -313,14 +359,24 @@ PreviousIsInvoke = true; } } - } - // If some instruction between the previous try-range and the end of the - // function may throw, create a call-site entry with no landing pad for the - // region following the try-range. - if (SawPotentiallyThrowing && !IsSJLJ) { - CallSiteEntry Site = { LastLabel, nullptr, nullptr, 0 }; - CallSites.push_back(Site); + if (&MBB == &Asm->MF->back() || MBB.isEndSection()) { + CurCSRange->FragmentEndLabel = + MBB.isEndSection() ? MBB.getEndMCSymbol() : Asm->getFunctionEnd(); + + // If some instruction between the previous try-range and the end of the + // function may throw, create a call-site entry with no landing pad for + // the region following the try-range. + if (SawPotentiallyThrowing && !IsSJLJ) { + CallSiteEntry Site = {LastLabel, + MBB.isEndSection() ? CurCSRange->FragmentEndLabel + : nullptr, + nullptr, 0}; + CallSites.push_back(Site); + SawPotentiallyThrowing = false; + } + CurCSRange->CallSiteEndIdx = CallSites.size(); + } } } @@ -371,15 +427,29 @@ SmallVector FirstActions; computeActionsTable(LandingPads, Actions, FirstActions); - // Compute the call-site table. + // Compute the call-site table and call-site ranges. SmallVector CallSites; - computeCallSiteTable(CallSites, LandingPads, FirstActions); + SmallVector CallSiteRanges; + computeCallSiteTable(CallSites, CallSiteRanges, LandingPads, FirstActions); + + // If the call-site range table is empty, add a single range containing all + // the call-sites. + if (CallSiteRanges.empty()) { + CallSiteRange CSRange; + CSRange.FragmentBeginLabel = Asm->getFunctionBegin(); + CSRange.FragmentEndLabel = Asm->getFunctionEnd(); + CSRange.ExceptionLabel = Asm->getCurExceptionSym(); + CSRange.CallSiteBeginIdx = 0; + CSRange.CallSiteEndIdx = CallSites.size(); + CallSiteRanges.push_back(CSRange); + } bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm; + unsigned CallSiteEncoding = - IsSJLJ ? static_cast(dwarf::DW_EH_PE_udata4) : - Asm->getObjFileLowering().getCallSiteEncoding(); + IsSJLJ ? static_cast(dwarf::DW_EH_PE_udata4) + : Asm->getObjFileLowering().getCallSiteEncoding(); bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty(); // Type infos. @@ -429,15 +499,10 @@ Asm->EmitAlignment(Align(4)); // Emit the LSDA. - MCSymbol *GCCETSym = - Asm->OutContext.getOrCreateSymbol(Twine("GCC_except_table")+ - Twine(Asm->getFunctionNumber())); + MCSymbol *GCCETSym = Asm->OutContext.getOrCreateSymbol( + Twine("GCC_except_table") + Twine(Asm->getFunctionNumber())); Asm->OutStreamer->EmitLabel(GCCETSym); - Asm->OutStreamer->EmitLabel(Asm->getCurExceptionSym()); - - // Emit the LSDA header. - Asm->EmitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); - Asm->EmitEncodingByte(TTypeEncoding, "@TType"); + MCSymbol *CstEndLabel = Asm->createTempSymbol("cst_end"); MCSymbol *TTBaseLabel = nullptr; if (HaveTTData) { @@ -445,23 +510,34 @@ // here and the amount of padding before the aligned type table. The // assembler must sometimes pad this uleb128 or insert extra padding before // the type table. See PR35809 or GNU as bug 4029. - MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); TTBaseLabel = Asm->createTempSymbol("ttbase"); - Asm->EmitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); - Asm->OutStreamer->EmitLabel(TTBaseRefLabel); } bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); - // Emit the landing pad call site table. - MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); - MCSymbol *CstEndLabel = Asm->createTempSymbol("cst_end"); - Asm->EmitEncodingByte(CallSiteEncoding, "Call site"); - Asm->EmitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); - Asm->OutStreamer->EmitLabel(CstBeginLabel); - // SjLj / Wasm Exception handling if (IsSJLJ || IsWasm) { + Asm->OutStreamer->EmitLabel(Asm->getCurExceptionSym()); + + // Emit the LSDA header. + Asm->EmitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); + Asm->EmitEncodingByte(TTypeEncoding, "@TType"); + + if (HaveTTData) { + // N.B.: There is a dependency loop between the size of the TTBase uleb128 + // here and the amount of padding before the aligned type table. The + // assembler must sometimes pad this uleb128 or insert extra padding + // before the type table. See PR35809 or GNU as bug 4029. + MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); + Asm->EmitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); + Asm->OutStreamer->EmitLabel(TTBaseRefLabel); + } + + // Emit the landing pad call site table. + MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); + Asm->EmitEncodingByte(CallSiteEncoding, "Call site"); + Asm->EmitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); + Asm->OutStreamer->EmitLabel(CstBeginLabel); unsigned idx = 0; for (SmallVectorImpl::const_iterator I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) { @@ -470,7 +546,8 @@ // Index of the call site entry. if (VerboseAsm) { Asm->OutStreamer->AddComment(">> Call Site " + Twine(idx) + " <<"); - Asm->OutStreamer->AddComment(" On exception at call site "+Twine(idx)); + Asm->OutStreamer->AddComment(" On exception at call site " + + Twine(idx)); } Asm->EmitULEB128(idx); @@ -486,6 +563,7 @@ } Asm->EmitULEB128(S.Action); } + Asm->OutStreamer->EmitLabel(CstEndLabel); } else { // Itanium LSDA exception handling @@ -507,62 +585,129 @@ // A missing entry in the call-site table indicates that a call is not // supposed to throw. + CallSiteRange *LandingPadRange = &CallSiteRanges.back(); + + // Find the landing-pad range if more than one call-site ranges exist. + for (auto &CSRange : CallSiteRanges) { + if (CSRange.IsLPRange) { + LandingPadRange = &CSRange; + break; + } + } + + // The call-site table is split into its call-site ranges, each being + // emitted as: + // [ LPStartEncoding | LPStart ] + // [ TypeTableEncoding | TypeTableOffset ] + // [ CallSiteEncoding | CallSiteTableEndOffset ] + // cst_begin -> { call-site entries contained in this range } + // + // and is followed by the next call-site range. + // + // For each call-site range, CallSiteTableEndOffset is computed as the + // difference between cst_begin of that range and the last call-site-table's + // end. This offset is used to find the action table. + unsigned Entry = 0; - for (SmallVectorImpl::const_iterator - I = CallSites.begin(), E = CallSites.end(); I != E; ++I) { - const CallSiteEntry &S = *I; + for (auto &CSRange : CallSiteRanges) { + // The call-site range for each range must be aligned. + Asm->EmitAlignment(Align(4)); + Asm->OutStreamer->EmitLabel(CSRange.ExceptionLabel); + + // Emit the LSDA header. + // If only one call-site range exists, LPStart could be omitted as it is + // the same as the function entry. + if (CallSiteRanges.size() == 1) + Asm->EmitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); + else { + // For more than one call-site range, LPStart must explicitly be + // specified. + Asm->EmitEncodingByte(dwarf::DW_EH_PE_absptr, "@LPStart"); + Asm->OutStreamer->EmitSymbolValue(LandingPadRange->FragmentBeginLabel, + Asm->MAI->getCodePointerSize()); + } + Asm->EmitEncodingByte(TTypeEncoding, "@TType"); + + if (HaveTTData) { + // N.B.: There is a dependency loop between the size of the TTBase + // uleb128 here and the amount of padding before the aligned type table. + // The assembler must sometimes pad this uleb128 or insert extra padding + // before the type table. See PR35809 or GNU as bug 4029. + MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); + Asm->EmitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); + Asm->OutStreamer->EmitLabel(TTBaseRefLabel); + } - MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); - - MCSymbol *BeginLabel = S.BeginLabel; - if (!BeginLabel) - BeginLabel = EHFuncBeginSym; - MCSymbol *EndLabel = S.EndLabel; - if (!EndLabel) - EndLabel = Asm->getFunctionEnd(); - - // Offset of the call site relative to the start of the procedure. - if (VerboseAsm) - Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + " <<"); - Asm->EmitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding); - if (VerboseAsm) - Asm->OutStreamer->AddComment(Twine(" Call between ") + - BeginLabel->getName() + " and " + - EndLabel->getName()); - Asm->EmitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding); - - // Offset of the landing pad relative to the start of the procedure. - if (!S.LPad) { + // Emit the call-site entries in this call-site range. + MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); + Asm->EmitEncodingByte(CallSiteEncoding, "Call site"); + // Emit the difference between the beginning of the call-site entries for + // this range and the end of the whole call-site table (the end of the + // last range's call-site entries). + Asm->EmitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); + Asm->OutStreamer->EmitLabel(CstBeginLabel); + + for (auto callSiteIdx = CSRange.CallSiteBeginIdx; + callSiteIdx != CSRange.CallSiteEndIdx; ++callSiteIdx) { + const CallSiteEntry &S = CallSites[callSiteIdx]; + + MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel; + MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel; + + MCSymbol *BeginLabel = S.BeginLabel; + if (!BeginLabel) + BeginLabel = EHFuncBeginSym; + MCSymbol *EndLabel = S.EndLabel; + if (!EndLabel) + EndLabel = EHFuncEndSym; + + // Offset of the call site relative to the start of the procedure. if (VerboseAsm) - Asm->OutStreamer->AddComment(" has no landing pad"); - Asm->EmitCallSiteValue(0, CallSiteEncoding); - } else { + Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + + " <<"); + Asm->EmitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding); if (VerboseAsm) - Asm->OutStreamer->AddComment(Twine(" jumps to ") + - S.LPad->LandingPadLabel->getName()); - Asm->EmitCallSiteOffset(S.LPad->LandingPadLabel, EHFuncBeginSym, - CallSiteEncoding); - } + Asm->OutStreamer->AddComment(Twine(" Call between ") + + BeginLabel->getName() + " and " + + EndLabel->getName()); + Asm->EmitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding); + + // Offset of the landing pad relative to the start of the landing pad + // fragment. + if (!S.LPad) { + if (VerboseAsm) + Asm->OutStreamer->AddComment(" has no landing pad"); + Asm->EmitCallSiteValue(0, CallSiteEncoding); + } else { + if (VerboseAsm) + Asm->OutStreamer->AddComment(Twine(" jumps to ") + + S.LPad->LandingPadLabel->getName()); + Asm->EmitCallSiteOffset(S.LPad->LandingPadLabel, + LandingPadRange->FragmentBeginLabel, + CallSiteEncoding); + } - // Offset of the first associated action record, relative to the start of - // the action table. This value is biased by 1 (1 indicates the start of - // the action table), and 0 indicates that there are no actions. - if (VerboseAsm) { - if (S.Action == 0) - Asm->OutStreamer->AddComment(" On action: cleanup"); - else - Asm->OutStreamer->AddComment(" On action: " + - Twine((S.Action - 1) / 2 + 1)); + // Offset of the first associated action record, relative to the start + // of the action table. This value is biased by 1 (1 indicates the start + // of the action table), and 0 indicates that there are no actions. + if (VerboseAsm) { + if (S.Action == 0) + Asm->OutStreamer->AddComment(" On action: cleanup"); + else + Asm->OutStreamer->AddComment(" On action: " + + Twine((S.Action - 1) / 2 + 1)); + } + Asm->EmitULEB128(S.Action); } - Asm->EmitULEB128(S.Action); } + Asm->OutStreamer->EmitLabel(CstEndLabel); } - Asm->OutStreamer->EmitLabel(CstEndLabel); // Emit the Action Table. int Entry = 0; - for (SmallVectorImpl::const_iterator - I = Actions.begin(), E = Actions.end(); I != E; ++I) { + for (SmallVectorImpl::const_iterator I = Actions.begin(), + E = Actions.end(); + I != E; ++I) { const ActionEntry &Action = *I; if (VerboseAsm) { Index: llvm/lib/CodeGen/AsmPrinter/WasmException.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/WasmException.h +++ llvm/lib/CodeGen/AsmPrinter/WasmException.h @@ -32,6 +32,7 @@ // Compute the call site table for wasm EH. void computeCallSiteTable( SmallVectorImpl &CallSites, + SmallVectorImpl &CallSiteRanges, const SmallVectorImpl &LandingPads, const SmallVectorImpl &FirstActions) override; }; Index: llvm/lib/CodeGen/AsmPrinter/WasmException.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/WasmException.cpp +++ llvm/lib/CodeGen/AsmPrinter/WasmException.cpp @@ -76,6 +76,7 @@ // information. void WasmException::computeCallSiteTable( SmallVectorImpl &CallSites, + SmallVectorImpl &CallSiteRanges, const SmallVectorImpl &LandingPads, const SmallVectorImpl &FirstActions) { MachineFunction &MF = *Asm->MF; Index: llvm/lib/CodeGen/CFIInstrInserter.cpp =================================================================== --- llvm/lib/CodeGen/CFIInstrInserter.cpp +++ llvm/lib/CodeGen/CFIInstrInserter.cpp @@ -247,6 +247,8 @@ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); bool InsertedCFIInstr = false; + MF.sortBasicBlockSections(); + for (MachineBasicBlock &MBB : MF) { // Skip the first MBB in a function if (MBB.getNumber() == MF.front().getNumber()) continue; @@ -255,11 +257,17 @@ auto MBBI = MBBInfo.MBB->begin(); DebugLoc DL = MBBInfo.MBB->findDebugLoc(MBBI); - if (PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset) { + // If the current MBB will be placed in a unique section, a full DefCfa + // must be emitted. + const bool ForceFullCFA = MBB.isBeginSection(); + + if (PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset || + ForceFullCFA) { // If both outgoing offset and register of a previous block don't match // incoming offset and register of this block, add a def_cfa instruction // with the correct offset and register for this block. - if (PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister) { + if (PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister || + ForceFullCFA) { unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( nullptr, MBBInfo.IncomingCFARegister, getCorrectCFAOffset(&MBB))); BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) @@ -287,6 +295,13 @@ .addCFIIndex(CFIIndex); InsertedCFIInstr = true; } + + if (ForceFullCFA) { + MF.getSubtarget().getFrameLowering()->emitCalleeSavedFrameMoves( + *MBBInfo.MBB, MBBI); + InsertedCFIInstr = true; + } + PrevMBBInfo = &MBBInfo; } return InsertedCFIInstr; Index: llvm/lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- llvm/lib/CodeGen/CodeGenPrepare.cpp +++ llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -441,6 +441,19 @@ BFI.reset(new BlockFrequencyInfo(F, *BPI, *LI)); PSI = &getAnalysis().getPSI(); OptSize = F.hasOptSize(); + + if (TM && TM->getBasicBlockSections() == llvm::BasicBlockSection::All) + F.setBasicBlockSections(true); + + if (TM && + (TM->getBasicBlockSections() == llvm::BasicBlockSection::List || + TM->getBasicBlockSections() == llvm::BasicBlockSection::Func) && + TM->isFunctionInBasicBlockSectionsList(F.getName())) + F.setBasicBlockSections(true); + + if (TM && TM->getBasicBlockSections() == llvm::BasicBlockSection::Labels) + F.setBasicBlockLabels(true); + if (ProfileGuidedSectionPrefix) { if (PSI->isFunctionHotInCallGraph(&F, *BFI)) F.setSectionPrefix(".hot"); Index: llvm/lib/CodeGen/MachineBasicBlock.cpp =================================================================== --- llvm/lib/CodeGen/MachineBasicBlock.cpp +++ llvm/lib/CodeGen/MachineBasicBlock.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include +#include using namespace llvm; #define DEBUG_TYPE "codegen" @@ -61,12 +62,32 @@ const MachineFunction *MF = getParent(); MCContext &Ctx = MF->getContext(); auto Prefix = Ctx.getAsmInfo()->getPrivateLabelPrefix(); + + bool BasicBlockSymbols = + MF->getBasicBlockSections() || MF->getBasicBlockLabels(); + auto Delimiter = BasicBlockSymbols ? "." : "_"; assert(getNumber() >= 0 && "cannot get label for unreachable MBB"); - CachedMCSymbol = Ctx.getOrCreateSymbol(Twine(Prefix) + "BB" + - Twine(MF->getFunctionNumber()) + - "_" + Twine(getNumber())); - } + // With Basic Block Sections, we emit a symbol for every basic block. To + // keep the size of strtab small, we choose a unary encoding which can + // compress the symbol names significantly. The basic blocks for function + // foo are named a.BB.foo, aa.BB.foo, and so on. + if (BasicBlockSymbols) { + auto Iter = MF->getMBBSymbolPrefix().begin(); + if (getNumber() < 0 || + getNumber() >= (int)MF->getMBBSymbolPrefix().size()) + report_fatal_error("Unreachable MBB: " + Twine(getNumber())); + std::string Prefix(Iter + 1, Iter + getNumber() + 1); + std::reverse(Prefix.begin(), Prefix.end()); + CachedMCSymbol = + Ctx.getOrCreateSymbol(Prefix + Twine(Delimiter) + "BB" + + Twine(Delimiter) + Twine(MF->getName())); + } else { + CachedMCSymbol = Ctx.getOrCreateSymbol( + Twine(Prefix) + "BB" + Twine(MF->getFunctionNumber()) + + Twine(Delimiter) + Twine(getNumber())); + } + } return CachedMCSymbol; } @@ -529,6 +550,64 @@ getParent()->splice(++NewBefore->getIterator(), getIterator()); } +// Returns true if this basic block and the Other are in the same section. +bool MachineBasicBlock::sameSection(const MachineBasicBlock *Other) const { + if (this == Other) + return true; + + if ((this->isColdSection() != Other->isColdSection()) || + (this->isExceptionSection() != Other->isExceptionSection())) + return false; + + if ((this->isBeginSection() && this->isEndSection()) || + (Other->isBeginSection() && Other->isEndSection())) + return false; + + return true; +} + +const MachineBasicBlock *MachineBasicBlock::getSectionEndMBB() const { + if (this->isEndSection()) + return this; + auto I = std::next(this->getIterator()); + const MachineFunction *MF = getParent(); + while (I != MF->end()) { + const MachineBasicBlock &MBB = *I; + if (MBB.isEndSection()) + return &MBB; + I = std::next(I); + } + llvm_unreachable("No End Basic Block for this section."); +} + +// Insert unconditional jumps to the basic block to which there is +// a fall through. +void MachineBasicBlock::insertUnconditionalFallthroughBranch() { + MachineBasicBlock *Fallthrough = getFallThrough(); + + if (Fallthrough == nullptr) + return; + + // If this basic block and the Fallthrough basic block are in the same + // section then do not insert the jump. + if (this->sameSection(Fallthrough)) + return; + + const TargetInstrInfo *TII = getParent()->getSubtarget().getInstrInfo(); + SmallVector Cond; + MachineBasicBlock *TBB = nullptr, *FBB = nullptr; + + // If a branch to the fall through block already exists, return. + if (!TII->analyzeBranch(*this, TBB, FBB, Cond) && + (TBB == Fallthrough || FBB == Fallthrough)) { + return; + } + + Cond.clear(); + DebugLoc DL = findBranchDebugLoc(); + TII->insertBranch(*this, Fallthrough, nullptr, Cond, DL); +} + void MachineBasicBlock::updateTerminator() { const TargetInstrInfo *TII = getParent()->getSubtarget().getInstrInfo(); // A block with no successors has no concerns with fall-through edges. Index: llvm/lib/CodeGen/MachineFunction.cpp =================================================================== --- llvm/lib/CodeGen/MachineFunction.cpp +++ llvm/lib/CodeGen/MachineFunction.cpp @@ -33,6 +33,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" @@ -181,6 +182,17 @@ Alignment = std::max(Alignment, STI->getTargetLowering()->getPrefFunctionAlignment()); + if (Target.getBasicBlockSections() == llvm::BasicBlockSection::All || + F.getBasicBlockSections() || + ((Target.getBasicBlockSections() == llvm::BasicBlockSection::List || + Target.getBasicBlockSections() == llvm::BasicBlockSection::Func) && + Target.isFunctionInBasicBlockSectionsList(F.getName()))) + BasicBlockSections = true; + + if (Target.getBasicBlockSections() == llvm::BasicBlockSection::Labels || + F.getBasicBlockLabels()) + BasicBlockLabels = true; + if (AlignAllFunctions) Alignment = Align(1ULL << AlignAllFunctions); @@ -337,6 +349,126 @@ MBBNumbering.resize(BlockNo); } +/// HasEHInfo - Return true is this Machine Basic Block is a landing pad. +// static bool HasEHInfo(const MachineBasicBlock &MBB) { +// if (MBB.isEHPad() || MBB.isEHFuncletEntry()) +// return true; +// for (auto &MI : MBB) { +// if (MI.isEHLabel()) +// return true; +// } +// return false; +//} + +bool MachineFunction::sortBasicBlockSections() { + // This should only be done once no matter how many times it is called. + if (this->BBSectionsSorted || !this->getBasicBlockSections()) + return false; + + DenseMap MBBOrder; + unsigned MBBOrderN = 0; + + SmallSet S = Target.getBasicBlockSectionsSet(F.getName()); + for (auto &MBB : *this) { + // A unique BB section can only be created if this basic block is not + // used for exception table computations. Entry basic block cannot + // a section because the function starts one. + // bool UsesEHInfo = HasEHInfo(MBB); + if (MBB.getNumber() == this->front().getNumber()) { + if (MBB.isEHPad()) + MBB.setExceptionSection(); + continue; + } + // Also, check if this BB is a cold basic block in which case sections + // are not required with the list option. + bool isColdBB = + ((Target.getBasicBlockSections() == llvm::BasicBlockSection::List) && + !S.count(MBB.getNumber())); + if (MBB.isEHPad()) { + MBB.setExceptionSection(); + } else if (isColdBB) { + MBB.setColdSection(); + } else { + MBB.setBeginSection(); + MBB.setEndSection(); + } + MBBOrder[&MBB] = MBBOrderN++; + } + + // With -fbasicblock-sections, fall through blocks must be made + // explicitly reachable. Do this after sections is set as + // unnecessary fallthroughs can be avoided. + for (auto &MBB : *this) { + MBB.insertUnconditionalFallthroughBranch(); + } + + // Order : Entry Block, Cold Section, Other Unique Sections. + auto SectionType = ([&](MachineBasicBlock &X) { + if (X.getNumber() == this->front().getNumber() && !X.isExceptionSection()) + return 0; + if (X.isExceptionSection()) + return 1; + else if (X.isColdSection()) + return 2; + return 3; + }); + + this->sort(([&](MachineBasicBlock &X, MachineBasicBlock &Y) { + auto TypeX = SectionType(X); + auto TypeY = SectionType(Y); + + return (TypeX != TypeY) ? TypeX < TypeY : MBBOrder[&X] < MBBOrder[&Y]; + })); + + // Set begin and end sections for cold basic blocks. With this more sections + // can be added if needed. + MachineBasicBlock *PrevMBB = nullptr; + for (auto &MBB : *this) { + // Entry block + if (MBB.getNumber() == this->front().getNumber()) { + PrevMBB = &MBB; + continue; + } + assert(PrevMBB != nullptr && "First block was not a regular block!"); + int TypeP = SectionType(*PrevMBB); + int TypeT = SectionType(MBB); + if (TypeP != TypeT) { + PrevMBB->setEndSection(); + MBB.setBeginSection(); + } + PrevMBB = &MBB; + } + PrevMBB->setEndSection(); + + this->BBSectionsSorted = true; + return true; +} + +void MachineFunction::setBasicBlockLabels() { + const TargetInstrInfo *TII = getSubtarget().getInstrInfo(); + this->MBBSymbolPrefix.resize(getNumBlockIDs(), 'a'); + for (auto MBBI = begin(), E = end(); MBBI != E; ++MBBI) { + if (MBBI->getNumber() < 0 || MBBI->getNumber() >= (int)getNumBlockIDs()) + report_fatal_error( + "BasicBlock number was out of range: " + Twine(MBBI->getNumber()) + + " [0 -> " + Twine(getNumBlockIDs()) + "]"); + // 'a' - Normal block. + // 'r' - Return block. + // 'l' - Landing Pad. + // 'L' - Return and landing pad. + bool isEHPad = MBBI->isEHPad(); + bool isRetBlock = MBBI->isReturnBlock() && !TII->isTailCall(MBBI->back()); + char type = 'a'; + if (isEHPad && isRetBlock) + type = 'L'; + else if (isEHPad) + type = 'l'; + else if (isRetBlock) + type = 'r'; + MBBSymbolPrefix[MBBI->getNumber()] = type; + } +} + /// Allocate a new MachineInstr. Use this instead of `new MachineInstr'. MachineInstr *MachineFunction::CreateMachineInstr(const MCInstrDesc &MCID, const DebugLoc &DL, Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -21,6 +21,8 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/IR/Comdat.h" @@ -52,8 +54,8 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CodeGen.h" -#include "llvm/Support/Format.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include @@ -751,6 +753,69 @@ return DataRelROSection; } +MCSection *TargetLoweringObjectFileELF::getSectionForMachineBasicBlock( + const Function &F, const MachineBasicBlock &MBB, + const TargetMachine &TM) const { + SmallString<128> Name; + Name = (static_cast(MBB.getParent()->getSection())) + ->getSectionName(); + if (TM.getUniqueBBSectionNames()) { + Name += "."; + Name += MBB.getSymbol()->getName(); + } + unsigned UniqueID = NextUniqueID++; + unsigned Flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; + std::string GroupName = ""; + if (F.hasComdat()) { + Flags |= ELF::SHF_GROUP; + GroupName = F.getComdat()->getName(); + } + return getContext().getELFSection(Name, ELF::SHT_PROGBITS, Flags, 0, + GroupName, UniqueID); +} + +MCSection *TargetLoweringObjectFileELF::getColdSectionForMachineBasicBlock( + const Function &F, const MachineBasicBlock &MBB, + const TargetMachine &TM) const { + SmallString<128> Name; + Name = (static_cast(MBB.getParent()->getSection())) + ->getSectionName(); + + if (!TM.getUniqueSectionNames()) { + Name += "."; + Name += MBB.getParent()->getName(); + } + + Name += ".cold"; + + unsigned Flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; + std::string GroupName = ""; + if (F.hasComdat()) { + Flags |= ELF::SHF_GROUP; + GroupName = F.getComdat()->getName(); + } + return getContext().getELFSection(Name, ELF::SHT_PROGBITS, Flags, 0, + GroupName); +} + +MCSection *TargetLoweringObjectFileELF::getEHSectionForMachineBasicBlock( + const Function &F, const MachineBasicBlock &MBB, + const TargetMachine &TM) const { + SmallString<128> Name; + Name = (static_cast(MBB.getParent()->getSection())) + ->getSectionName(); + Name += ".eh"; + + unsigned Flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; + std::string GroupName = ""; + if (F.hasComdat()) { + Flags |= ELF::SHF_GROUP; + GroupName = F.getComdat()->getName(); + } + return getContext().getELFSection(Name, ELF::SHT_PROGBITS, Flags, 0, + GroupName); +} + static MCSectionELF *getStaticStructorSection(MCContext &Ctx, bool UseInitArray, bool IsCtor, unsigned Priority, const MCSymbol *KeySym) { Index: llvm/lib/IR/BasicBlock.cpp =================================================================== --- llvm/lib/IR/BasicBlock.cpp +++ llvm/lib/IR/BasicBlock.cpp @@ -18,6 +18,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" #include "llvm/IR/Type.h" #include Index: llvm/lib/IR/Globals.cpp =================================================================== --- llvm/lib/IR/Globals.cpp +++ llvm/lib/IR/Globals.cpp @@ -237,6 +237,10 @@ if (const Function *F = dyn_cast(this)) return F->empty() && !F->isMaterializable(); + // A basic block is always defined. + if (dyn_cast(this)) + return false; + // Aliases and ifuncs are always definitions. assert(isa(this)); return false; Index: llvm/lib/IR/Mangler.cpp =================================================================== --- llvm/lib/IR/Mangler.cpp +++ llvm/lib/IR/Mangler.cpp @@ -118,7 +118,11 @@ PrefixTy = Private; } - const DataLayout &DL = GV->getParent()->getDataLayout(); + const DataLayout &DL = + (isa(GV) + ? dyn_cast(GV)->getParent()->getParent()->getDataLayout() + : GV->getParent()->getDataLayout()); + if (!GV->hasName()) { // Get the ID for the global, assigning a new one if we haven't got one // already. Index: llvm/lib/MC/ELFObjectWriter.cpp =================================================================== --- llvm/lib/MC/ELFObjectWriter.cpp +++ llvm/lib/MC/ELFObjectWriter.cpp @@ -39,6 +39,7 @@ #include "llvm/Support/Alignment.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -1321,6 +1322,7 @@ if (!RefA) return false; + const auto &MAI = Asm.getContext().getAsmInfo(); MCSymbolRefExpr::VariantKind Kind = RefA->getKind(); switch (Kind) { default: @@ -1345,6 +1347,12 @@ case MCSymbolRefExpr::VK_PPC_GOT_HI: case MCSymbolRefExpr::VK_PPC_GOT_HA: return true; + + case MCSymbolRefExpr::VK_SIZE: + if (MAI->shouldRelocateWithSymbols()) + return true; + else + break; } // An undefined symbol is not in any section, so the relocation has to point @@ -1413,7 +1421,7 @@ if (TargetObjectWriter->needsRelocateWithSymbol(*Sym, Type)) return true; - return false; + return MAI->shouldRelocateWithSymbols(); } void ELFObjectWriter::recordRelocation(MCAssembler &Asm, Index: llvm/lib/MC/MCDwarf.cpp =================================================================== --- llvm/lib/MC/MCDwarf.cpp +++ llvm/lib/MC/MCDwarf.cpp @@ -29,6 +29,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/ErrorHandling.h" @@ -39,12 +40,18 @@ #include "llvm/Support/raw_ostream.h" #include #include +#include #include #include #include using namespace llvm; +static cl::opt NoDedupFDEToCIE( + "no-dedup-fde-to-cie", + cl::desc("Moves FDE instructions at the beginning of an FDE to CIE"), + cl::init(false), cl::Hidden); + /// Manage the .debug_line_str section contents, if we use it. class llvm::MCDwarfLineStr { MCSymbol *LineStrLabel = nullptr; @@ -847,6 +854,20 @@ MCOS->EmitIntValue(0, 1); } +static const MCExpr *MakeSizeExpr(MCStreamer &MCOS, MCSymbol &Start, + const MCSymbol &End) { + const MCExpr *Range = MakeStartMinusEndExpr(MCOS, Start, End, 0); + + auto MAI = MCOS.getContext().getAsmInfo(); + if (!MAI->shouldRelocateWithSizeRelocs()) + return forceExpAbs(MCOS, Range); + + MCOS.emitELFSize(&Start, Range); + const MCExpr *RelocatableRange = MCSymbolRefExpr::create( + &Start, MCSymbolRefExpr::VK_SIZE, MCOS.getContext()); + return RelocatableRange; +} + // When generating dwarf for assembly source files this emits the data for // .debug_aranges section. This section contains a header and a table of pairs // of PointerSize'ed values for the address and size of section(s) with line @@ -901,17 +922,16 @@ // Now emit the table of pairs of PointerSize'ed values for the section // addresses and sizes. for (MCSection *Sec : Sections) { - const MCSymbol *StartSymbol = Sec->getBeginSymbol(); + MCSymbol *StartSymbol = Sec->getBeginSymbol(); MCSymbol *EndSymbol = Sec->getEndSymbol(context); assert(StartSymbol && "StartSymbol must not be NULL"); assert(EndSymbol && "EndSymbol must not be NULL"); const MCExpr *Addr = MCSymbolRefExpr::create( StartSymbol, MCSymbolRefExpr::VK_None, context); - const MCExpr *Size = MakeStartMinusEndExpr(*MCOS, - *StartSymbol, *EndSymbol, 0); + const MCExpr *Size = MakeSizeExpr(*MCOS, *StartSymbol, *EndSymbol); MCOS->EmitValue(Addr, AddrSize); - emitAbsValue(*MCOS, Size, AddrSize); + MCOS->EmitValue(Size, AddrSize); } // And finally the pair of terminating zeros. @@ -1106,7 +1126,7 @@ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfRangesSection()); for (MCSection *Sec : Sections) { - const MCSymbol *StartSymbol = Sec->getBeginSymbol(); + MCSymbol *StartSymbol = Sec->getBeginSymbol(); MCSymbol *EndSymbol = Sec->getEndSymbol(context); assert(StartSymbol && "StartSymbol must not be NULL"); assert(EndSymbol && "EndSymbol must not be NULL"); @@ -1118,10 +1138,10 @@ MCOS->EmitValue(SectionStartAddr, AddrSize); // Emit a range list entry spanning this section - const MCExpr *SectionSize = MakeStartMinusEndExpr(*MCOS, - *StartSymbol, *EndSymbol, 0); + const MCExpr *SectionSize = MakeSizeExpr(*MCOS, *StartSymbol, *EndSymbol); + MCOS->EmitIntValue(0, AddrSize); - emitAbsValue(*MCOS, SectionSize, AddrSize); + MCOS->EmitValue(SectionSize, AddrSize); } // Emit end of list entry @@ -1316,7 +1336,8 @@ void EmitFDE(const MCSymbol &cieStart, const MCDwarfFrameInfo &frame, bool LastInSection, const MCSymbol &SectionStart); void EmitCFIInstructions(ArrayRef Instrs, - MCSymbol *BaseLabel); + MCSymbol *BaseLabel, bool EmitDeduped, + bool EmitNotDeduped); void EmitCFIInstruction(const MCCFIInstruction &Instr); }; @@ -1457,14 +1478,44 @@ llvm_unreachable("Unhandled case in switch"); } +/// Deduping of FDE to CIE is particularly useful with basic block sections +/// as every basic block gets its own FDE with duplicate CFI instructions. It +/// is useful in general but the opportunities to dedup are lesser. +static bool ShouldBeDeduped(const MCCFIInstruction &Instr, + const MCSymbol *BaseLabel, + const MCObjectStreamer &Streamer) { + if (NoDedupFDEToCIE || + !Streamer.getContext().getAsmInfo()->shouldRelocateWithSymbols()) + return false; + + if (!BaseLabel || !BaseLabel->isDefined() || !BaseLabel->isInSection()) + return false; + + MCSymbol *Label = Instr.getLabel(); + + if (!Label || !Label->isDefined() || !Label->isInSection()) + return false; + + return &Label->getSection() == &BaseLabel->getSection() && + Label->getOffset() == BaseLabel->getOffset(); +} + /// Emit frame instructions to describe the layout of the frame. void FrameEmitterImpl::EmitCFIInstructions(ArrayRef Instrs, - MCSymbol *BaseLabel) { + MCSymbol *BaseLabel, + bool EmitDeduped = true, + bool EmitNotDeduped = true) { + bool InDedupedRange = true; for (const MCCFIInstruction &Instr : Instrs) { MCSymbol *Label = Instr.getLabel(); // Throw out move if the label is invalid. if (Label && !Label->isDefined()) continue; // Not emitted, in dead code. + InDedupedRange &= ShouldBeDeduped(Instr, BaseLabel, Streamer); + if ((InDedupedRange && !EmitDeduped) || + (!InDedupedRange && !EmitNotDeduped)) + continue; + // Advance row if new location. if (BaseLabel && Label) { MCSymbol *ThisSym = Label; @@ -1519,9 +1570,8 @@ Streamer.EmitSymbolValue(Frame.Begin, Size); // Range Length - const MCExpr *Range = MakeStartMinusEndExpr(Streamer, *Frame.Begin, - *Frame.End, 0); - emitAbsValue(Streamer, Range, 4); + const MCExpr *Range = MakeSizeExpr(Streamer, *Frame.Begin, *Frame.End); + Streamer.EmitValue(Range, 4); // Compact Encoding Size = getSizeForEncoding(Streamer, dwarf::DW_EH_PE_udata4); @@ -1661,7 +1711,8 @@ if (!Frame.IsSimple) { const std::vector &Instructions = MAI->getInitialFrameState(); - EmitCFIInstructions(Instructions, nullptr); + EmitCFIInstructions(Instructions, nullptr, true, true); + EmitCFIInstructions(Frame.Instructions, Frame.Begin, true, false); } InitialCFAOffset = CFAOffset; @@ -1712,9 +1763,8 @@ emitFDESymbol(Streamer, *frame.Begin, PCEncoding, IsEH); // PC Range - const MCExpr *Range = - MakeStartMinusEndExpr(Streamer, *frame.Begin, *frame.End, 0); - emitAbsValue(Streamer, Range, PCSize); + const MCExpr *Range = MakeSizeExpr(Streamer, *frame.Begin, *frame.End); + Streamer.EmitValue(Range, PCSize); if (IsEH) { // Augmentation Data Length @@ -1731,7 +1781,7 @@ } // Call Frame Instructions - EmitCFIInstructions(frame.Instructions, frame.Begin); + EmitCFIInstructions(frame.Instructions, frame.Begin, false, true); // Padding // The size of a .eh_frame section has to be a multiple of the alignment @@ -1748,27 +1798,50 @@ struct CIEKey { static const CIEKey getEmptyKey() { return CIEKey(nullptr, 0, -1, false, false, static_cast(INT_MAX), - false); + false, nullptr); } static const CIEKey getTombstoneKey() { return CIEKey(nullptr, -1, 0, false, false, static_cast(INT_MAX), - false); + false, nullptr); + } + + static std::vector + getDedupedInstructions(const std::vector &Instructions, + const MCSymbol *BaseSymbol, + const MCObjectStreamer &Streamer) { + std::vector DedupedInstructions; + for (const auto &Instr : Instructions) { + MCSymbol *Label = Instr.getLabel(); + // Throw out move if the label is invalid. + if (Label && !Label->isDefined()) + continue; // Not emitted, in dead code. + + if (!ShouldBeDeduped(Instr, BaseSymbol, Streamer)) + break; + + DedupedInstructions.push_back(Instr.StripLabel()); + } + return DedupedInstructions; } CIEKey(const MCSymbol *Personality, unsigned PersonalityEncoding, unsigned LSDAEncoding, bool IsSignalFrame, bool IsSimple, - unsigned RAReg, bool IsBKeyFrame) + unsigned RAReg, bool IsBKeyFrame, + const std::vector *DedupedInstructions) : Personality(Personality), PersonalityEncoding(PersonalityEncoding), LsdaEncoding(LSDAEncoding), IsSignalFrame(IsSignalFrame), - IsSimple(IsSimple), RAReg(RAReg), IsBKeyFrame(IsBKeyFrame) {} + IsSimple(IsSimple), RAReg(RAReg), IsBKeyFrame(IsBKeyFrame), + DedupedInstructions(DedupedInstructions) {} - explicit CIEKey(const MCDwarfFrameInfo &Frame) + explicit CIEKey(const MCDwarfFrameInfo &Frame, + const std::vector *DedupedInstructions) : Personality(Frame.Personality), PersonalityEncoding(Frame.PersonalityEncoding), LsdaEncoding(Frame.LsdaEncoding), IsSignalFrame(Frame.IsSignalFrame), IsSimple(Frame.IsSimple), RAReg(Frame.RAReg), - IsBKeyFrame(Frame.IsBKeyFrame) {} + IsBKeyFrame(Frame.IsBKeyFrame), + DedupedInstructions(DedupedInstructions) {} StringRef PersonalityName() const { if (!Personality) @@ -1776,12 +1849,20 @@ return Personality->getName(); } + const std::vector GetDedupedInstructions() const { + if (!DedupedInstructions) + return {}; + return *DedupedInstructions; + } + bool operator<(const CIEKey &Other) const { return std::make_tuple(PersonalityName(), PersonalityEncoding, LsdaEncoding, - IsSignalFrame, IsSimple, RAReg) < + IsSignalFrame, IsSimple, RAReg, + GetDedupedInstructions()) < std::make_tuple(Other.PersonalityName(), Other.PersonalityEncoding, Other.LsdaEncoding, Other.IsSignalFrame, - Other.IsSimple, Other.RAReg); + Other.IsSimple, Other.RAReg, + Other.GetDedupedInstructions()); } const MCSymbol *Personality; @@ -1791,6 +1872,7 @@ bool IsSimple; unsigned RAReg; bool IsBKeyFrame; + const std::vector *DedupedInstructions; }; } // end anonymous namespace @@ -1802,9 +1884,12 @@ static CIEKey getTombstoneKey() { return CIEKey::getTombstoneKey(); } static unsigned getHashValue(const CIEKey &Key) { + const auto &DedupedInstructions = Key.GetDedupedInstructions(); return static_cast(hash_combine( Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding, - Key.IsSignalFrame, Key.IsSimple, Key.RAReg, Key.IsBKeyFrame)); + Key.IsSignalFrame, Key.IsSimple, Key.RAReg, Key.IsBKeyFrame, + hash_combine_range(DedupedInstructions.begin(), + DedupedInstructions.end()))); } static bool isEqual(const CIEKey &LHS, const CIEKey &RHS) { @@ -1813,7 +1898,8 @@ LHS.LsdaEncoding == RHS.LsdaEncoding && LHS.IsSignalFrame == RHS.IsSignalFrame && LHS.IsSimple == RHS.IsSimple && LHS.RAReg == RHS.RAReg && - LHS.IsBKeyFrame == RHS.IsBKeyFrame; + LHS.IsBKeyFrame == RHS.IsBKeyFrame && + LHS.GetDedupedInstructions() == RHS.GetDedupedInstructions(); } }; @@ -1857,8 +1943,14 @@ MCSymbol *SectionStart = Context.createTempSymbol(); Streamer.EmitLabel(SectionStart); + std::map> DedupedInstructions; DenseMap CIEStarts; + for (const auto &Frame : FrameArray) { + DedupedInstructions[Frame.Begin] = CIEKey::getDedupedInstructions( + Frame.Instructions, Frame.Begin, Streamer); + } + const MCSymbol *DummyDebugKey = nullptr; bool CanOmitDwarf = MOFI->getOmitDwarfIfHaveCompactUnwind(); // Sort the FDEs by their corresponding CIE before we emit them. @@ -1867,8 +1959,9 @@ // an FDE refers to a CIE other than the closest previous CIE. std::vector FrameArrayX(FrameArray.begin(), FrameArray.end()); llvm::stable_sort(FrameArrayX, - [](const MCDwarfFrameInfo &X, const MCDwarfFrameInfo &Y) { - return CIEKey(X) < CIEKey(Y); + [&](const MCDwarfFrameInfo &X, const MCDwarfFrameInfo &Y) { + return CIEKey(X, &DedupedInstructions.at(X.Begin)) < + CIEKey(Y, &DedupedInstructions.at(Y.Begin)); }); for (auto I = FrameArrayX.begin(), E = FrameArrayX.end(); I != E;) { const MCDwarfFrameInfo &Frame = *I; @@ -1879,7 +1972,7 @@ // of by the compact unwind encoding. continue; - CIEKey Key(Frame); + CIEKey Key(Frame, &DedupedInstructions.at(Frame.Begin)); const MCSymbol *&CIEStart = IsEH ? CIEStarts[Key] : DummyDebugKey; if (!CIEStart) CIEStart = &Emitter.EmitCIE(Frame); Index: llvm/lib/Target/AArch64/AArch64FrameLowering.h =================================================================== --- llvm/lib/Target/AArch64/AArch64FrameLowering.h +++ llvm/lib/Target/AArch64/AArch64FrameLowering.h @@ -24,8 +24,9 @@ : TargetFrameLowering(StackGrowsDown, Align(16), 0, Align(16), true /*StackRealignable*/) {} - void emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MBBI) const; + void + emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) const override; MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, Index: llvm/lib/Target/TargetLoweringObjectFile.cpp =================================================================== --- llvm/lib/Target/TargetLoweringObjectFile.cpp +++ llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -149,6 +149,10 @@ if (isa(GO)) return SectionKind::getText(); + // Basic blocks are classified as text sections. + if (isa(GO)) + return SectionKind::getText(); + // Global variables require more detailed analysis. const auto *GVar = cast(GO); @@ -302,6 +306,23 @@ return DataSection; } +MCSection *TargetLoweringObjectFile::getSectionForMachineBasicBlock( + const Function &F, const MachineBasicBlock &MBB, + const TargetMachine &TM) const { + return nullptr; +} + +MCSection *TargetLoweringObjectFile::getColdSectionForMachineBasicBlock( + const Function &F, const MachineBasicBlock &MBB, + const TargetMachine &TM) const { + return nullptr; +} + +MCSection *TargetLoweringObjectFile::getEHSectionForMachineBasicBlock( + const Function &F, const MachineBasicBlock &MBB, + const TargetMachine &TM) const { + return nullptr; +} /// getTTypeGlobalReference - Return an MCExpr to use for a /// reference to the specified global variable from exception /// handling information. Index: llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp =================================================================== --- llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp +++ llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp @@ -70,12 +70,12 @@ IsPCRel = true; return RT64_32; case FK_Data_4: - case FK_PCRel_4: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_relax: case X86::reloc_riprel_4byte_relax_rex: case X86::reloc_riprel_4byte_movq_load: return RT64_32; + case FK_PCRel_4: case X86::reloc_branch_4byte_pcrel: Modifier = MCSymbolRefExpr::VK_PLT; return RT64_32; Index: llvm/lib/Target/X86/X86FrameLowering.h =================================================================== --- llvm/lib/Target/X86/X86FrameLowering.h +++ llvm/lib/Target/X86/X86FrameLowering.h @@ -58,6 +58,10 @@ void inlineStackProbe(MachineFunction &MF, MachineBasicBlock &PrologMBB) const override; + void + emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) const override; + void emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL) const; Index: llvm/lib/Target/X86/X86FrameLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86FrameLowering.cpp +++ llvm/lib/Target/X86/X86FrameLowering.cpp @@ -457,6 +457,29 @@ .addCFIIndex(CFIIndex); } +/// Emits Dwarf Info specifying offsets of callee saved registers and +/// frame pointer. +void X86FrameLowering::emitCalleeSavedFrameMoves( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { + emitCalleeSavedFrameMoves(MBB, MBBI, DebugLoc{}); + + MachineFunction &MF = *MBB.getParent(); + if (!hasFP(MF)) + return; + + const MachineModuleInfo &MMI = MF.getMMI(); + const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); + const unsigned FramePtr = TRI->getFrameRegister(MF); + const unsigned MachineFramePtr = + STI.isTarget64BitILP32() ? unsigned(getX86SubSuperRegister(FramePtr, 64)) + : FramePtr; + unsigned DwarfReg = MRI->getDwarfRegNum(MachineFramePtr, true); + // Offset = space for return address + size of the frame pointer itself. + unsigned Offset = (Is64Bit ? 8 : 4) + (Uses64BitFramePtr ? 8 : 4); + BuildCFI(MBB, MBBI, DebugLoc{}, + MCCFIInstruction::createOffset(nullptr, DwarfReg, -Offset)); +} + void X86FrameLowering::emitCalleeSavedFrameMoves( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL) const { Index: llvm/lib/Transforms/Utils/ModuleUtils.cpp =================================================================== --- llvm/lib/Transforms/Utils/ModuleUtils.cpp +++ llvm/lib/Transforms/Utils/ModuleUtils.cpp @@ -250,7 +250,7 @@ }); } -std::string llvm::getUniqueModuleId(Module *M) { +std::string llvm::getUniqueModuleId(Module *M, bool UseModuleId) { MD5 Md5; bool ExportsSymbols = false; auto AddGlobal = [&](GlobalValue &GV) { @@ -271,8 +271,18 @@ for (auto &IF : M->ifuncs()) AddGlobal(IF); - if (!ExportsSymbols) - return ""; + // When UseModuleId is true, we include the module identifier also. Module + // ID helps when there are no globals exported or when multiple definitions + // of the same globals are allowed in different modules (with "-z muldefs"). + // While it is highly likely that Module identifier is unique, it is not + // guaranteed. + if (UseModuleId && !M->getModuleIdentifier().empty()) { + Md5.update(M->getModuleIdentifier()); + Md5.update(ArrayRef{0}); + } else { + if (!ExportsSymbols) + return ""; + } MD5::MD5Result R; Md5.final(R); Index: llvm/test/CodeGen/X86/basicblock-sections.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/basicblock-sections.ll @@ -0,0 +1,36 @@ +; RUN: llc < %s -mtriple=x86_64-pc-linux -function-sections -basicblock-sections=all -unique-bb-section-names | FileCheck %s -check-prefix=LINUX-SECTIONS +; RUN: llc < %s -mtriple=i386-unknown-linux-gnu -function-sections -basicblock-sections=all -unique-bb-section-names | FileCheck %s -check-prefix=LINUX-SECTIONS + +define void @_Z3bazb(i1 zeroext) { + %2 = alloca i8, align 1 + %3 = zext i1 %0 to i8 + store i8 %3, i8* %2, align 1 + %4 = load i8, i8* %2, align 1 + %5 = trunc i8 %4 to i1 + br i1 %5, label %6, label %8 + +6: ; preds = %1 + %7 = call i32 @_Z3barv() + br label %10 + +8: ; preds = %1 + %9 = call i32 @_Z3foov() + br label %10 + +10: ; preds = %8, %6 + ret void +} + +declare i32 @_Z3barv() #1 + +declare i32 @_Z3foov() #1 + + +; LINUX-SECTIONS: .section .text._Z3bazb,"ax",@progbits +; LINUX-SECTIONS: _Z3bazb: +; LINUX-SECTIONS: .section .text._Z3bazb.r.BB._Z3bazb,"ax",@progbits,unique,1 +; LINUX-SECTIONS: r.BB._Z3bazb: +; LINUX-SECTIONS: .size r.BB._Z3bazb, .Ltmp0-r.BB._Z3bazb +; LINUX-SECTIONS: .section .text._Z3bazb.rr.BB._Z3bazb,"ax",@progbits,unique,2 +; LINUX-SECTIONS: rr.BB._Z3bazb: +; LINUX-SECTIONS: .size rr.BB._Z3bazb, .Ltmp1-rr.BB._Z3bazb Index: llvm/test/CodeGen/X86/gcc_except_table_basicblock-sections.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/gcc_except_table_basicblock-sections.ll @@ -0,0 +1,115 @@ +; RUN: llc -basicblock-sections=all -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s +@_ZTIi = external constant i8* + +define i32 @main() uwtable optsize ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; Verify that each basic block section gets its own LSDA exception symbol. +; +; CHECK: main: +; CHECK: .Lfunc_begin0: +; CHECK: .cfi_startproc +; CHECK: .cfi_personality 3, __gxx_personality_v0 +; CHECK: .cfi_lsda 3, .Lexception0 +; CHECK: pushq %rax +; CHECK: .Ltmp0: +; CHECK: callq _Z1fv +; CHECK: .Ltmp1: +; CHECK: jmp r.BB.main +; CHECK: .cfi_endproc + +; CHECK: lr.BB.main: # %lpad +; CHECK: .cfi_startproc +; CHECK: .cfi_personality 3, __gxx_personality_v0 +; CHECK: .cfi_lsda 3, .Lexception1 +; CHECK: nop # avoids zero-offset landing pad +; CHECK: .Ltmp2: +; CHECK: movq %rax, %rdi +; CHECK: callq _Unwind_Resume +; CHECK: .Ltmp3: +; CHECK: .size lr.BB.main, .Ltmp3-lr.BB.main +; CHECK: .cfi_endproc + +; CHECK: r.BB.main: # %try.cont +; CHECK: .cfi_startproc +; CHECK: .cfi_personality 3, __gxx_personality_v0 +; CHECK: .cfi_lsda 3, .Lexception2 +; CHECK: xorl %eax, %eax +; CHECK: popq %rcx +; CHECK: retq +; CHECK: .Ltmp4: +; CHECK: .cfi_endproc + +entry: + invoke void @_Z1fv() optsize + to label %try.cont unwind label %lpad + +lpad: + %0 = landingpad { i8*, i32 } + cleanup + catch i8* bitcast (i8** @_ZTIi to i8*) + br label %eh.resume + +try.cont: + ret i32 0 + +eh.resume: + resume { i8*, i32 } %0 +} + +declare void @_Z1fv() optsize + +declare i32 @__gxx_personality_v0(...) + +; Verify that the exception table gets split across the three basic block sections. +; +; CHECK: GCC_except_table0: +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: .Lexception0: +; CHECK-NEXT: .byte 0 # @LPStart Encoding = absptr +; CHECK-NEXT: .quad lr.BB.main +; CHECK-NEXT: .byte 3 # @TType Encoding = udata4 +; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref0 +; CHECK-NEXT: .Lttbaseref0: +; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 +; CHECK-NEXT: .uleb128 .Lcst_end0-.Lcst_begin0 +; CHECK-NEXT: .Lcst_begin0: +; CHECK-NEXT: .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 1 << +; CHECK-NEXT: .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 +; CHECK-NEXT: .uleb128 .Ltmp2-lr.BB.main # jumps to .Ltmp2 +; CHECK-NEXT: .byte 3 # On action: 2 +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: .Lexception1: +; CHECK-NEXT: .byte 0 # @LPStart Encoding = absptr +; CHECK-NEXT: .quad lr.BB.main +; CHECK-NEXT: .byte 3 # @TType Encoding = udata4 +; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref1 +; CHECK-NEXT: .Lttbaseref1: +; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 +; CHECK-NEXT: .uleb128 .Lcst_end0-.Lcst_begin1 +; CHECK-NEXT: .Lcst_begin1: +; CHECK-NEXT: .uleb128 lr.BB.main-lr.BB.main # >> Call Site 2 << +; CHECK-NEXT: .uleb128 .Ltmp3-lr.BB.main # Call between lr.BB.main and .Ltmp3 +; CHECK-NEXT: .byte 0 # has no landing pad +; CHECK-NEXT: .byte 0 # On action: cleanup +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: .Lexception2: +; CHECK-NEXT: .byte 0 # @LPStart Encoding = absptr +; CHECK-NEXT: .quad lr.BB.main +; CHECK-NEXT: .byte 3 # @TType Encoding = udata4 +; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref2 +; CHECK-NEXT: .Lttbaseref2: +; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 +; CHECK-NEXT: .uleb128 .Lcst_end0-.Lcst_begin2 +; CHECK-NEXT: .Lcst_begin2: +; CHECK-NEXT: .Lcst_end0: +; CHECK-NEXT: .byte 0 # >> Action Record 1 << +; CHECK-NEXT: # Cleanup +; CHECK-NEXT: .byte 0 # No further actions +; CHECK-NEXT: .byte 1 # >> Action Record 2 << +; CHECK-NEXT: # Catch TypeInfo 1 +; CHECK-NEXT: .byte 125 # Continue to action 1 +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: # >> Catch TypeInfos << +; CHECK-NEXT: .long _ZTIi # TypeInfo 1 +; CHECK-NEXT: .Lttbase0: +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: # -- End function Index: llvm/test/DebugInfo/X86/basicblock-sections-cfi.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/basicblock-sections-cfi.ll @@ -0,0 +1,112 @@ +; RUN: llc -O0 %s --basicblock-sections=all -mtriple=x86_64-unknown-linux-gnu -filetype=asm -o - | FileCheck --check-prefix=SECTIONS_CFI %s +; RUN: llc -O0 %s --basicblock-sections=all -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o - | llvm-dwarfdump --debug-frame - | FileCheck --check-prefix=DEBUG_FRAME %s + +; From: +; int foo(int a) { +; if (a > 20) +; return 2; +; else +; return 0; +; } + +; SECTIONS_CFI: _Z3fooi +; SECTIONS_CFI: .cfi_startproc +; SECTIONS_CFI: .cfi_def_cfa_offset +; SECTIONS_CFI: .cfi_def_cfa_register +; SECTIONS_CFI: .cfi_endproc + +; SECTIONS_CFI: a.BB._Z3fooi +; SECTIONS_CFI-NEXT: .cfi_startproc +; SECTIONS_CFI-NEXT: .cfi_def_cfa +; SECTIONS_CFI-NEXT: .cfi_offset +; SECTIONS_CFI: .cfi_endproc + +; SECTIONS_CFI: aa.BB._Z3fooi +; SECTIONS_CFI-NEXT: .cfi_startproc +; SECTIONS_CFI-NEXT: .cfi_def_cfa +; SECTIONS_CFI-NEXT: .cfi_offset +; SECTIONS_CFI: .cfi_endproc + + +; There must be 2 CIEs and 4 FDEs + +; DEBUG_FRAME: .debug_frame contents + +; DEBUG_FRAME: CIE +; DEBUG_FRAME: DW_CFA_def_cfa +; DEBUG_FRAME: DW_CFA_offset + +; DEBUG_FRAME: FDE cie= +; DEBUG_FRAME: DW_CFA_def_cfa_offset +; DEBUG_FRAME: DW_CFA_def_cfa_register + +; DEBUG_FRAME: CIE +; DEBUG_FRAME: DW_CFA_def_cfa +; DEBUG_FRAME: DW_CFA_def_cfa + +; DEBUG_FRAME: FDE cie= + +; DEBUG_FRAME: FDE cie= + +; DEBUG_FRAME: FDE cie= +; DEBUG_FRAME: DW_CFA_def_cfa + + +source_filename = "debuginfo.cc" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local i32 @_Z3fooi(i32 %0) #0 !dbg !7 { + %2 = alloca i32, align 4 + %3 = alloca i32, align 4 + store i32 %0, i32* %3, align 4 + call void @llvm.dbg.declare(metadata i32* %3, metadata !11, metadata !DIExpression()), !dbg !12 + %4 = load i32, i32* %3, align 4, !dbg !13 + %5 = icmp sgt i32 %4, 20, !dbg !15 + br i1 %5, label %6, label %7, !dbg !16 + +6: ; preds = %1 + store i32 2, i32* %2, align 4, !dbg !17 + br label %8, !dbg !17 + +7: ; preds = %1 + store i32 0, i32* %2, align 4, !dbg !18 + br label %8, !dbg !18 + +8: ; preds = %7, %6 + %9 = load i32, i32* %2, align 4, !dbg !19 + ret i32 %9, !dbg !19 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "target-cpu"="x86-64" } + +attributes #1 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 10.0.0 (git@github.com:google/llvm-propeller.git f9421ebf4b3d8b64678bf6c49d1607fdce3f50c5)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "debuginfo.cc", directory: "/g/tmsriram/Projects_2019/github_repo/Examples") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (git@github.com:google/llvm-propeller.git f9421ebf4b3d8b64678bf6c49d1607fdce3f50c5)"} +!7 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!12 = !DILocation(line: 1, column: 13, scope: !7) +!13 = !DILocation(line: 2, column: 7, scope: !14) +!14 = distinct !DILexicalBlock(scope: !7, file: !1, line: 2, column: 7) +!15 = !DILocation(line: 2, column: 9, scope: !14) +!16 = !DILocation(line: 2, column: 7, scope: !7) +!17 = !DILocation(line: 3, column: 5, scope: !14) +!18 = !DILocation(line: 5, column: 5, scope: !14) +!19 = !DILocation(line: 6, column: 1, scope: !7) Index: llvm/test/DebugInfo/X86/basicblock-sections-cfiinstr.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/basicblock-sections-cfiinstr.ll @@ -0,0 +1,143 @@ +; RUN: llc -O3 %s -mtriple=x86_64-unknown-linux-gnu -filetype=asm --basicblock-sections=all -stop-after=cfi-instr-inserter -o - | FileCheck --check-prefix=CFI_INSTR %s + +; CFI_INSTR: _Z7computebiiiiiiiiiiii +; CFI_INSTR: bb.0 +; CFI_INSTR: CFI_INSTRUCTION def_cfa_offset +; CFI_INSTR: bb.1 +; CFI_INSTR: CFI_INSTRUCTION def_cfa $rsp +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR: bb.2 +; CFI_INSTR: CFI_INSTRUCTION def_cfa $rsp +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR: bb.3 +; CFI_INSTR: CFI_INSTRUCTION def_cfa $rsp +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset + +; From: +; int compute(bool k, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int pa, int pb, int pc) { +; int result; +; if (k) +; result = p1 * p2 + p3 / p4 - p5 * p6 + p7 / p8 - p9 * pa + pb / pc; +; else +; result = p1 / p2 - p3 * p4 + p5 / p6 - p7 * p8 + p9 / pa - pb * pc; +; return result; +; } + +; ModuleID = 'use_regs.tmp.bc' +source_filename = "use_regs.cc" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: norecurse nounwind readnone uwtable +define dso_local i32 @_Z7computebiiiiiiiiiiii(i1 zeroext %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9, i32 %10, i32 %11, i32 %12) local_unnamed_addr #0 !dbg !7 { + call void @llvm.dbg.value(metadata i1 %0, metadata !13, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %2, metadata !15, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %3, metadata !16, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %4, metadata !17, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %5, metadata !18, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %6, metadata !19, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %7, metadata !20, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %8, metadata !21, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %9, metadata !22, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %10, metadata !23, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %11, metadata !24, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %12, metadata !25, metadata !DIExpression()), !dbg !27 + br i1 %0, label %14, label %22, !dbg !28 + +14: ; preds = %13 + %15 = mul nsw i32 %2, %1, !dbg !29 + %16 = sdiv i32 %3, %4, !dbg !31 + %.neg28 = mul i32 %6, %5 + %17 = sdiv i32 %7, %8, !dbg !32 + %.neg29 = mul i32 %10, %9 + %18 = sdiv i32 %11, %12, !dbg !33 + %reass.add30 = add i32 %.neg29, %.neg28 + %19 = sub i32 %15, %reass.add30, !dbg !34 + %20 = add i32 %19, %16, !dbg !35 + %21 = add i32 %20, %17, !dbg !36 + br label %28, !dbg !37 + +22: ; preds = %13 + %23 = sdiv i32 %1, %2, !dbg !38 + %.neg = mul i32 %4, %3 + %24 = sdiv i32 %5, %6, !dbg !39 + %.neg25 = mul i32 %8, %7 + %25 = sdiv i32 %9, %10, !dbg !40 + %.neg26 = mul i32 %12, %11 + %reass.add = add i32 %.neg25, %.neg + %reass.add27 = add i32 %reass.add, %.neg26 + %26 = sub i32 %23, %reass.add27, !dbg !41 + %27 = add i32 %26, %24, !dbg !42 + call void @llvm.dbg.value(metadata i32 %29, metadata !26, metadata !DIExpression()), !dbg !27 + br label %28 + +28: ; preds = %22, %14 + %.sink32 = phi i32 [ %25, %22 ], [ %18, %14 ] + %.sink = phi i32 [ %27, %22 ], [ %21, %14 ] + %29 = add i32 %.sink, %.sink32, !dbg !43 + call void @llvm.dbg.value(metadata i32 %29, metadata !26, metadata !DIExpression()), !dbg !27 + ret i32 %29, !dbg !44 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { norecurse nounwind readnone uwtable } +attributes #1 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 10.0.0 (git@github.com:google/llvm-propeller.git e414756c805463af90acd9bff57e6b1c805b7925)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "use_regs.cc", directory: "/g/tmsriram/Projects_2019/github_repo/Examples") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (git@github.com:google/llvm-propeller.git e414756c805463af90acd9bff57e6b1c805b7925)"} +!7 = distinct !DISubprogram(name: "compute", linkageName: "_Z7computebiiiiiiiiiiii", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11, !10, !10, !10, !10, !10, !10, !10, !10, !10, !10, !10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) +!12 = !{!13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26} +!13 = !DILocalVariable(name: "k", arg: 1, scope: !7, file: !1, line: 1, type: !11) +!14 = !DILocalVariable(name: "p1", arg: 2, scope: !7, file: !1, line: 1, type: !10) +!15 = !DILocalVariable(name: "p2", arg: 3, scope: !7, file: !1, line: 1, type: !10) +!16 = !DILocalVariable(name: "p3", arg: 4, scope: !7, file: !1, line: 1, type: !10) +!17 = !DILocalVariable(name: "p4", arg: 5, scope: !7, file: !1, line: 1, type: !10) +!18 = !DILocalVariable(name: "p5", arg: 6, scope: !7, file: !1, line: 1, type: !10) +!19 = !DILocalVariable(name: "p6", arg: 7, scope: !7, file: !1, line: 1, type: !10) +!20 = !DILocalVariable(name: "p7", arg: 8, scope: !7, file: !1, line: 1, type: !10) +!21 = !DILocalVariable(name: "p8", arg: 9, scope: !7, file: !1, line: 1, type: !10) +!22 = !DILocalVariable(name: "p9", arg: 10, scope: !7, file: !1, line: 1, type: !10) +!23 = !DILocalVariable(name: "pa", arg: 11, scope: !7, file: !1, line: 1, type: !10) +!24 = !DILocalVariable(name: "pb", arg: 12, scope: !7, file: !1, line: 1, type: !10) +!25 = !DILocalVariable(name: "pc", arg: 13, scope: !7, file: !1, line: 1, type: !10) +!26 = !DILocalVariable(name: "result", scope: !7, file: !1, line: 2, type: !10) +!27 = !DILocation(line: 0, scope: !7) +!28 = !DILocation(line: 3, column: 7, scope: !7) +!29 = !DILocation(line: 4, column: 17, scope: !30) +!30 = distinct !DILexicalBlock(scope: !7, file: !1, line: 3, column: 7) +!31 = !DILocation(line: 4, column: 27, scope: !30) +!32 = !DILocation(line: 4, column: 47, scope: !30) +!33 = !DILocation(line: 4, column: 67, scope: !30) +!34 = !DILocation(line: 4, column: 32, scope: !30) +!35 = !DILocation(line: 4, column: 42, scope: !30) +!36 = !DILocation(line: 4, column: 52, scope: !30) +!37 = !DILocation(line: 4, column: 5, scope: !30) +!38 = !DILocation(line: 6, column: 17, scope: !30) +!39 = !DILocation(line: 6, column: 37, scope: !30) +!40 = !DILocation(line: 6, column: 57, scope: !30) +!41 = !DILocation(line: 6, column: 42, scope: !30) +!42 = !DILocation(line: 6, column: 52, scope: !30) +!43 = !DILocation(line: 0, scope: !30) +!44 = !DILocation(line: 7, column: 3, scope: !7) Index: llvm/test/DebugInfo/X86/basicblock-sections_1.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/basicblock-sections_1.ll @@ -0,0 +1,82 @@ +; RUN: llc -O0 %s -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t +; llvm-dwarfdump -debug-abbrev %t | FileCheck --check-prefix=NO-NOSECTIONS %s + +; RUN: llc -O0 %s --basicblock-sections=all -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t +; llvm-dwarfdump -debug-abbrev %t | FileCheck --check-prefix=BB-SECTIONS %s +; RUN: llvm-readobj --relocations %t | FileCheck --check-prefix=BB-SECTIONS-RELOCS %s +; From: +; int foo(int a) { +; if (a > 20) +; return 2; +; else +; return 0; +; } + +; NO-SECTIONS: DW_AT_low_pc +; NOSECTIONS: DW_AT_high_pc +; BB-SECTIONS: DW_AT_low_pc +; BB-SECTIONS: DW_AT_ranges +; BB-SECTIONS-RELOCS: R_X86_64_64 a.BB._Z3fooi +; BB-SECTIONS-RELOCS-NEXT: R_X86_64_64 +; BB-SECTIONS-RELOCS-NEXT: R_X86_64_64 aa.BB._Z3fooi +; BB-SECTIONS-RELOCS-NEXT: R_X86_64_64 +; BB-SECTIONS-RELOCS: R_X86_64_SIZE32 + +source_filename = "debuginfo.cc" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local i32 @_Z3fooi(i32 %0) #0 !dbg !7 { + %2 = alloca i32, align 4 + %3 = alloca i32, align 4 + store i32 %0, i32* %3, align 4 + call void @llvm.dbg.declare(metadata i32* %3, metadata !11, metadata !DIExpression()), !dbg !12 + %4 = load i32, i32* %3, align 4, !dbg !13 + %5 = icmp sgt i32 %4, 20, !dbg !15 + br i1 %5, label %6, label %7, !dbg !16 + +6: ; preds = %1 + store i32 2, i32* %2, align 4, !dbg !17 + br label %8, !dbg !17 + +7: ; preds = %1 + store i32 0, i32* %2, align 4, !dbg !18 + br label %8, !dbg !18 + +8: ; preds = %7, %6 + %9 = load i32, i32* %2, align 4, !dbg !19 + ret i32 %9, !dbg !19 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +;attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #0 = { noinline nounwind optnone uwtable } +attributes #1 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 10.0.0 (git@github.com:google/llvm-propeller.git f9421ebf4b3d8b64678bf6c49d1607fdce3f50c5)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "debuginfo.cc", directory: "/g/tmsriram/Projects_2019/github_repo/Examples") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (git@github.com:google/llvm-propeller.git f9421ebf4b3d8b64678bf6c49d1607fdce3f50c5)"} +!7 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!12 = !DILocation(line: 1, column: 13, scope: !7) +!13 = !DILocation(line: 2, column: 7, scope: !14) +!14 = distinct !DILexicalBlock(scope: !7, file: !1, line: 2, column: 7) +!15 = !DILocation(line: 2, column: 9, scope: !14) +!16 = !DILocation(line: 2, column: 7, scope: !7) +!17 = !DILocation(line: 3, column: 5, scope: !14) +!18 = !DILocation(line: 5, column: 5, scope: !14) +!19 = !DILocation(line: 6, column: 1, scope: !7)