diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
| commit | c0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch) | |
| tree | f42add1021b9f2ac6a69ac7cf6c4499962739a45 /llvm/lib/CodeGen/AsmPrinter | |
| parent | 344a3780b2e33f6ca763666c380202b18aab72a3 (diff) | |
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter')
21 files changed, 551 insertions, 304 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp b/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp index db4215e92d44..223840c21d8b 100644 --- a/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp @@ -75,7 +75,6 @@ void ARMException::endFunction(const MachineFunction *MF) { // Emit references to personality. if (Per) { MCSymbol *PerSym = Asm->getSymbol(Per); - Asm->OutStreamer->emitSymbolAttribute(PerSym, MCSA_Global); ATS.emitPersonality(PerSym); } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index e528d33b5f8c..cc848d28a9a7 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -71,7 +71,6 @@ #include "llvm/IR/GCStrategy.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalIFunc.h" -#include "llvm/IR/GlobalIndirectSymbol.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" @@ -102,6 +101,7 @@ #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/SectionKind.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Pass.h" #include "llvm/Remarks/Remark.h" #include "llvm/Remarks/RemarkFormat.h" @@ -115,7 +115,6 @@ #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLoweringObjectFile.h" @@ -275,7 +274,7 @@ bool AsmPrinter::doInitialization(Module &M) { const_cast<TargetLoweringObjectFile &>(getObjFileLowering()) .getModuleMetadata(M); - OutStreamer->InitSections(false); + OutStreamer->initSections(false, *TM.getMCSubtargetInfo()); if (DisableDebugInfoPrinting) MMI->setDebugInfoAvailability(false); @@ -326,16 +325,10 @@ bool AsmPrinter::doInitialization(Module &M) { // Emit module-level inline asm if it exists. if (!M.getModuleInlineAsm().empty()) { - // We're at the module level. Construct MCSubtarget from the default CPU - // and target triple. - std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo( - TM.getTargetTriple().str(), TM.getTargetCPU(), - TM.getTargetFeatureString())); - assert(STI && "Unable to create subtarget info"); OutStreamer->AddComment("Start of file scope inline assembly"); OutStreamer->AddBlankLine(); - emitInlineAsm(M.getModuleInlineAsm() + "\n", - OutContext.getSubtargetCopy(*STI), TM.Options.MCOptions); + emitInlineAsm(M.getModuleInlineAsm() + "\n", *TM.getMCSubtargetInfo(), + TM.Options.MCOptions); OutStreamer->AddComment("End of file scope inline assembly"); OutStreamer->AddBlankLine(); } @@ -1422,7 +1415,7 @@ void AsmPrinter::emitFunctionBody() { }); R << "BasicBlock: " << ore::NV("BasicBlock", MBB.getName()) << "\n"; for (auto &KV : MnemonicVec) { - auto Name = (Twine("INST_") + KV.first.trim()).str(); + auto Name = (Twine("INST_") + getToken(KV.first.trim()).first).str(); R << KV.first << ": " << ore::NV(Name, KV.second) << "\n"; } ORE->emit(R); @@ -1610,14 +1603,13 @@ void AsmPrinter::emitGlobalGOTEquivs() { emitGlobalVariable(GV); } -void AsmPrinter::emitGlobalIndirectSymbol(Module &M, - const GlobalIndirectSymbol& GIS) { - MCSymbol *Name = getSymbol(&GIS); - bool IsFunction = GIS.getValueType()->isFunctionTy(); +void AsmPrinter::emitGlobalAlias(Module &M, const GlobalAlias &GA) { + MCSymbol *Name = getSymbol(&GA); + bool IsFunction = GA.getValueType()->isFunctionTy(); // Treat bitcasts of functions as functions also. This is important at least // on WebAssembly where object and function addresses can't alias each other. if (!IsFunction) - if (auto *CE = dyn_cast<ConstantExpr>(GIS.getIndirectSymbol())) + if (auto *CE = dyn_cast<ConstantExpr>(GA.getAliasee())) if (CE->getOpcode() == Instruction::BitCast) IsFunction = CE->getOperand(0)->getType()->getPointerElementType()->isFunctionTy(); @@ -1627,61 +1619,80 @@ void AsmPrinter::emitGlobalIndirectSymbol(Module &M, // point, all the extra label is emitted, we just have to emit linkage for // those labels. if (TM.getTargetTriple().isOSBinFormatXCOFF()) { - assert(!isa<GlobalIFunc>(GIS) && "IFunc is not supported on AIX."); assert(MAI->hasVisibilityOnlyWithLinkage() && "Visibility should be handled with emitLinkage() on AIX."); - emitLinkage(&GIS, Name); + emitLinkage(&GA, Name); // If it's a function, also emit linkage for aliases of function entry // point. if (IsFunction) - emitLinkage(&GIS, - getObjFileLowering().getFunctionEntryPointSymbol(&GIS, TM)); + emitLinkage(&GA, + getObjFileLowering().getFunctionEntryPointSymbol(&GA, TM)); return; } - if (GIS.hasExternalLinkage() || !MAI->getWeakRefDirective()) + if (GA.hasExternalLinkage() || !MAI->getWeakRefDirective()) OutStreamer->emitSymbolAttribute(Name, MCSA_Global); - else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage()) + else if (GA.hasWeakLinkage() || GA.hasLinkOnceLinkage()) OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference); else - assert(GIS.hasLocalLinkage() && "Invalid alias or ifunc linkage"); + assert(GA.hasLocalLinkage() && "Invalid alias linkage"); // Set the symbol type to function if the alias has a function type. // This affects codegen when the aliasee is not a function. if (IsFunction) - OutStreamer->emitSymbolAttribute(Name, isa<GlobalIFunc>(GIS) - ? MCSA_ELF_TypeIndFunction - : MCSA_ELF_TypeFunction); + OutStreamer->emitSymbolAttribute(Name, MCSA_ELF_TypeFunction); - emitVisibility(Name, GIS.getVisibility()); + emitVisibility(Name, GA.getVisibility()); - const MCExpr *Expr = lowerConstant(GIS.getIndirectSymbol()); + const MCExpr *Expr = lowerConstant(GA.getAliasee()); - if (isa<GlobalAlias>(&GIS) && MAI->hasAltEntry() && isa<MCBinaryExpr>(Expr)) + if (MAI->hasAltEntry() && isa<MCBinaryExpr>(Expr)) OutStreamer->emitSymbolAttribute(Name, MCSA_AltEntry); // Emit the directives as assignments aka .set: OutStreamer->emitAssignment(Name, Expr); - MCSymbol *LocalAlias = getSymbolPreferLocal(GIS); + MCSymbol *LocalAlias = getSymbolPreferLocal(GA); if (LocalAlias != Name) OutStreamer->emitAssignment(LocalAlias, Expr); - if (auto *GA = dyn_cast<GlobalAlias>(&GIS)) { - // If the aliasee does not correspond to a symbol in the output, i.e. the - // alias is not of an object or the aliased object is private, then set the - // size of the alias symbol from the type of the alias. We don't do this in - // other situations as the alias and aliasee having differing types but same - // size may be intentional. - const GlobalObject *BaseObject = GA->getBaseObject(); - if (MAI->hasDotTypeDotSizeDirective() && GA->getValueType()->isSized() && - (!BaseObject || BaseObject->hasPrivateLinkage())) { - const DataLayout &DL = M.getDataLayout(); - uint64_t Size = DL.getTypeAllocSize(GA->getValueType()); - OutStreamer->emitELFSize(Name, MCConstantExpr::create(Size, OutContext)); - } + // If the aliasee does not correspond to a symbol in the output, i.e. the + // alias is not of an object or the aliased object is private, then set the + // size of the alias symbol from the type of the alias. We don't do this in + // other situations as the alias and aliasee having differing types but same + // size may be intentional. + const GlobalObject *BaseObject = GA.getAliaseeObject(); + if (MAI->hasDotTypeDotSizeDirective() && GA.getValueType()->isSized() && + (!BaseObject || BaseObject->hasPrivateLinkage())) { + const DataLayout &DL = M.getDataLayout(); + uint64_t Size = DL.getTypeAllocSize(GA.getValueType()); + OutStreamer->emitELFSize(Name, MCConstantExpr::create(Size, OutContext)); } } +void AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { + assert(!TM.getTargetTriple().isOSBinFormatXCOFF() && + "IFunc is not supported on AIX."); + + MCSymbol *Name = getSymbol(&GI); + + if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) + OutStreamer->emitSymbolAttribute(Name, MCSA_Global); + else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage()) + OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference); + else + assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); + + OutStreamer->emitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction); + emitVisibility(Name, GI.getVisibility()); + + // Emit the directives as assignments aka .set: + const MCExpr *Expr = lowerConstant(GI.getResolver()); + OutStreamer->emitAssignment(Name, Expr); + MCSymbol *LocalAlias = getSymbolPreferLocal(GI); + if (LocalAlias != Name) + OutStreamer->emitAssignment(LocalAlias, Expr); +} + void AsmPrinter::emitRemarksSection(remarks::RemarkStreamer &RS) { if (!RS.needsSection()) return; @@ -1815,6 +1826,11 @@ bool AsmPrinter::doFinalization(Module &M) { } } + // This needs to happen before emitting debug information since that can end + // arbitrary sections. + if (auto *TS = OutStreamer->getTargetStreamer()) + TS->emitConstantPools(); + // Finalize debug and EH information. for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, @@ -1857,11 +1873,11 @@ bool AsmPrinter::doFinalization(Module &M) { AliasStack.push_back(Cur); } for (const GlobalAlias *AncestorAlias : llvm::reverse(AliasStack)) - emitGlobalIndirectSymbol(M, *AncestorAlias); + emitGlobalAlias(M, *AncestorAlias); AliasStack.clear(); } for (const auto &IFunc : M.ifuncs()) - emitGlobalIndirectSymbol(M, IFunc); + emitGlobalIFunc(M, IFunc); GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>(); assert(MI && "AsmPrinter didn't require GCModuleInfo?"); @@ -2455,9 +2471,14 @@ void AsmPrinter::emitAlignment(Align Alignment, const GlobalObject *GV) const { if (Alignment == Align(1)) return; // 1-byte aligned: no need to emit alignment. - if (getCurrentSection()->getKind().isText()) - OutStreamer->emitCodeAlignment(Alignment.value()); - else + if (getCurrentSection()->getKind().isText()) { + const MCSubtargetInfo *STI = nullptr; + if (this->MF) + STI = &getSubtargetInfo(); + else + STI = TM.getMCSubtargetInfo(); + OutStreamer->emitCodeAlignment(Alignment.value(), STI); + } else OutStreamer->emitValueToAlignment(Alignment.value()); } @@ -2513,7 +2534,7 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { OS << "Unsupported expression in static initializer: "; CE->printAsOperand(OS, /*PrintType=*/false, !MF ? nullptr : MF->getFunction().getParent()); - report_fatal_error(OS.str()); + report_fatal_error(Twine(OS.str())); } case Instruction::GetElementPtr: { // Generate a symbolic expression for the byte address @@ -3265,21 +3286,21 @@ void AsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) { // reference the block. It is possible that there is more than one label // here, because multiple LLVM BB's may have been RAUW'd to this block after // the references were generated. + const BasicBlock *BB = MBB.getBasicBlock(); if (MBB.hasAddressTaken()) { - const BasicBlock *BB = MBB.getBasicBlock(); if (isVerbose()) OutStreamer->AddComment("Block address taken"); // MBBs can have their address taken as part of CodeGen without having // their corresponding BB's address taken in IR - if (BB->hasAddressTaken()) + if (BB && BB->hasAddressTaken()) for (MCSymbol *Sym : MMI->getAddrLabelSymbolToEmit(BB)) OutStreamer->emitLabel(Sym); } // Print some verbose block comments. if (isVerbose()) { - if (const BasicBlock *BB = MBB.getBasicBlock()) { + if (BB) { if (BB->hasName()) { BB->printAsOperand(OutStreamer->GetCommentOS(), /*PrintType=*/false, BB->getModule()); @@ -3538,7 +3559,7 @@ void AsmPrinter::emitXRayTable() { // pointers. This should work for both 32-bit and 64-bit platforms. if (FnSledIndex) { OutStreamer->SwitchSection(FnSledIndex); - OutStreamer->emitCodeAlignment(2 * WordSizeBytes); + OutStreamer->emitCodeAlignment(2 * WordSizeBytes, &getSubtargetInfo()); OutStreamer->emitSymbolValue(SledsStart, WordSizeBytes, false); OutStreamer->emitSymbolValue(SledsEnd, WordSizeBytes, false); OutStreamer->SwitchSection(PrevSection); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index 4a93181f5439..ef1abc47701a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -30,10 +30,10 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; @@ -129,13 +129,16 @@ void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, } static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, - MachineModuleInfo *MMI, AsmPrinter *AP, - uint64_t LocCookie, raw_ostream &OS) { + MachineModuleInfo *MMI, const MCAsmInfo *MAI, + AsmPrinter *AP, uint64_t LocCookie, + raw_ostream &OS) { // Switch to the inline assembly variant. OS << "\t.intel_syntax\n\t"; + int CurVariant = -1; // The number of the {.|.|.} region we are in. const char *LastEmitted = AsmStr; // One past the last character emitted. unsigned NumOperands = MI->getNumOperands(); + int AsmPrinterVariant = 1; // X86MCAsmInfo.cpp's AsmWriterFlavorTy::Intel. while (*LastEmitted) { switch (*LastEmitted) { @@ -145,8 +148,8 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' && *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n') ++LiteralEnd; - - OS.write(LastEmitted, LiteralEnd-LastEmitted); + if (CurVariant == -1 || CurVariant == AsmPrinterVariant) + OS.write(LastEmitted, LiteralEnd - LastEmitted); LastEmitted = LiteralEnd; break; } @@ -164,6 +167,27 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, case '$': ++LastEmitted; // Consume second '$' character. break; + case '(': // $( -> same as GCC's { character. + ++LastEmitted; // Consume '(' character. + if (CurVariant != -1) + report_fatal_error("Nested variants found in inline asm string: '" + + Twine(AsmStr) + "'"); + CurVariant = 0; // We're in the first variant now. + break; + case '|': + ++LastEmitted; // Consume '|' character. + if (CurVariant == -1) + OS << '|'; // This is gcc's behavior for | outside a variant. + else + ++CurVariant; // We're in the next variant. + break; + case ')': // $) -> same as GCC's } char. + ++LastEmitted; // Consume ')' character. + if (CurVariant == -1) + OS << '}'; // This is gcc's behavior for } outside a variant. + else + CurVariant = -1; + break; } if (Done) break; @@ -176,16 +200,15 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, // If we have ${:foo}, then this is not a real operand reference, it is a // "magic" string reference, just like in .td files. Arrange to call // PrintSpecial. - if (HasCurlyBraces && LastEmitted[0] == ':') { + if (HasCurlyBraces && *LastEmitted == ':') { ++LastEmitted; const char *StrStart = LastEmitted; const char *StrEnd = strchr(StrStart, '}'); if (!StrEnd) report_fatal_error("Unterminated ${:foo} operand in inline asm" " string: '" + Twine(AsmStr) + "'"); - - std::string Val(StrStart, StrEnd); - AP->PrintSpecial(MI, OS, Val.c_str()); + if (CurVariant == -1 || CurVariant == AsmPrinterVariant) + AP->PrintSpecial(MI, OS, StringRef(StrStart, StrEnd - StrStart)); LastEmitted = StrEnd+1; break; } @@ -201,7 +224,7 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, Twine(AsmStr) + "'"); LastEmitted = IDEnd; - if (Val >= NumOperands-1) + if (Val >= NumOperands - 1) report_fatal_error("Invalid $ operand number in inline asm string: '" + Twine(AsmStr) + "'"); @@ -228,40 +251,50 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, // Okay, we finally have a value number. Ask the target to print this // operand! - unsigned OpNo = InlineAsm::MIOp_FirstOperand; - - bool Error = false; + if (CurVariant == -1 || CurVariant == AsmPrinterVariant) { + unsigned OpNo = InlineAsm::MIOp_FirstOperand; - // Scan to find the machine operand number for the operand. - for (; Val; --Val) { - if (OpNo >= MI->getNumOperands()) break; - unsigned OpFlags = MI->getOperand(OpNo).getImm(); - OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; - } + bool Error = false; - // We may have a location metadata attached to the end of the - // instruction, and at no point should see metadata at any - // other point while processing. It's an error if so. - if (OpNo >= MI->getNumOperands() || - MI->getOperand(OpNo).isMetadata()) { - Error = true; - } else { - unsigned OpFlags = MI->getOperand(OpNo).getImm(); - ++OpNo; // Skip over the ID number. + // Scan to find the machine operand number for the operand. + for (; Val; --Val) { + if (OpNo >= MI->getNumOperands()) + break; + unsigned OpFlags = MI->getOperand(OpNo).getImm(); + OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; + } - if (InlineAsm::isMemKind(OpFlags)) { - Error = AP->PrintAsmMemoryOperand( - MI, OpNo, Modifier[0] ? Modifier : nullptr, OS); + // We may have a location metadata attached to the end of the + // instruction, and at no point should see metadata at any + // other point while processing. It's an error if so. + if (OpNo >= MI->getNumOperands() || MI->getOperand(OpNo).isMetadata()) { + Error = true; } else { - Error = AP->PrintAsmOperand(MI, OpNo, - Modifier[0] ? Modifier : nullptr, OS); + unsigned OpFlags = MI->getOperand(OpNo).getImm(); + ++OpNo; // Skip over the ID number. + + // FIXME: Shouldn't arch-independent output template handling go into + // PrintAsmOperand? + // Labels are target independent. + if (MI->getOperand(OpNo).isBlockAddress()) { + const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress(); + MCSymbol *Sym = AP->GetBlockAddressSymbol(BA); + Sym->print(OS, AP->MAI); + MMI->getContext().registerInlineAsmLabel(Sym); + } else if (InlineAsm::isMemKind(OpFlags)) { + Error = AP->PrintAsmMemoryOperand( + MI, OpNo, Modifier[0] ? Modifier : nullptr, OS); + } else { + Error = AP->PrintAsmOperand(MI, OpNo, + Modifier[0] ? Modifier : nullptr, OS); + } + } + if (Error) { + std::string msg; + raw_string_ostream Msg(msg); + Msg << "invalid operand in inline asm: '" << AsmStr << "'"; + MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); } - } - if (Error) { - std::string msg; - raw_string_ostream Msg(msg); - Msg << "invalid operand in inline asm: '" << AsmStr << "'"; - MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); } break; } @@ -274,10 +307,10 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, MachineModuleInfo *MMI, const MCAsmInfo *MAI, AsmPrinter *AP, uint64_t LocCookie, raw_ostream &OS) { - int CurVariant = -1; // The number of the {.|.|.} region we are in. + int CurVariant = -1; // The number of the {.|.|.} region we are in. const char *LastEmitted = AsmStr; // One past the last character emitted. unsigned NumOperands = MI->getNumOperands(); - int AsmPrinterVariant = MAI->getAssemblerDialect(); + int AsmPrinterVariant = MMI->getTarget().unqualifiedInlineAsmVariant(); if (MAI->getEmitGNUAsmStartIndentationMarker()) OS << '\t'; @@ -291,7 +324,7 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n') ++LiteralEnd; if (CurVariant == -1 || CurVariant == AsmPrinterVariant) - OS.write(LastEmitted, LiteralEnd-LastEmitted); + OS.write(LastEmitted, LiteralEnd - LastEmitted); LastEmitted = LiteralEnd; break; } @@ -311,24 +344,24 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, OS << '$'; ++LastEmitted; // Consume second '$' character. break; - case '(': // $( -> same as GCC's { character. - ++LastEmitted; // Consume '(' character. + case '(': // $( -> same as GCC's { character. + ++LastEmitted; // Consume '(' character. if (CurVariant != -1) report_fatal_error("Nested variants found in inline asm string: '" + Twine(AsmStr) + "'"); - CurVariant = 0; // We're in the first variant now. + CurVariant = 0; // We're in the first variant now. break; case '|': - ++LastEmitted; // consume '|' character. + ++LastEmitted; // Consume '|' character. if (CurVariant == -1) - OS << '|'; // this is gcc's behavior for | outside a variant + OS << '|'; // This is gcc's behavior for | outside a variant. else - ++CurVariant; // We're in the next variant. + ++CurVariant; // We're in the next variant. break; - case ')': // $) -> same as GCC's } char. - ++LastEmitted; // consume ')' character. + case ')': // $) -> same as GCC's } char. + ++LastEmitted; // Consume ')' character. if (CurVariant == -1) - OS << '}'; // this is gcc's behavior for } outside a variant + OS << '}'; // This is gcc's behavior for } outside a variant. else CurVariant = -1; break; @@ -351,9 +384,8 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, if (!StrEnd) report_fatal_error("Unterminated ${:foo} operand in inline asm" " string: '" + Twine(AsmStr) + "'"); - - std::string Val(StrStart, StrEnd); - AP->PrintSpecial(MI, OS, Val.c_str()); + if (CurVariant == -1 || CurVariant == AsmPrinterVariant) + AP->PrintSpecial(MI, OS, StringRef(StrStart, StrEnd - StrStart)); LastEmitted = StrEnd+1; break; } @@ -369,6 +401,10 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, Twine(AsmStr) + "'"); LastEmitted = IDEnd; + if (Val >= NumOperands - 1) + report_fatal_error("Invalid $ operand number in inline asm string: '" + + Twine(AsmStr) + "'"); + char Modifier[2] = { 0, 0 }; if (HasCurlyBraces) { @@ -390,10 +426,6 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, ++LastEmitted; // Consume '}' character. } - if (Val >= NumOperands-1) - report_fatal_error("Invalid $ operand number in inline asm string: '" + - Twine(AsmStr) + "'"); - // Okay, we finally have a value number. Ask the target to print this // operand! if (CurVariant == -1 || CurVariant == AsmPrinterVariant) { @@ -403,7 +435,8 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, // Scan to find the machine operand number for the operand. for (; Val; --Val) { - if (OpNo >= MI->getNumOperands()) break; + if (OpNo >= MI->getNumOperands()) + break; unsigned OpFlags = MI->getOperand(OpNo).getImm(); OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; } @@ -411,12 +444,11 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, // We may have a location metadata attached to the end of the // instruction, and at no point should see metadata at any // other point while processing. It's an error if so. - if (OpNo >= MI->getNumOperands() || - MI->getOperand(OpNo).isMetadata()) { + if (OpNo >= MI->getNumOperands() || MI->getOperand(OpNo).isMetadata()) { Error = true; } else { unsigned OpFlags = MI->getOperand(OpNo).getImm(); - ++OpNo; // Skip over the ID number. + ++OpNo; // Skip over the ID number. // FIXME: Shouldn't arch-independent output template handling go into // PrintAsmOperand? @@ -429,8 +461,6 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, } else if (MI->getOperand(OpNo).isMBB()) { const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol(); Sym->print(OS, AP->MAI); - } else if (Modifier[0] == 'l') { - Error = true; } else if (InlineAsm::isMemKind(OpFlags)) { Error = AP->PrintAsmMemoryOperand( MI, OpNo, Modifier[0] ? Modifier : nullptr, OS); @@ -506,7 +536,7 @@ void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const { if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT) EmitGCCInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS); else - EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS); + EmitMSInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS); // Emit warnings if we use reserved registers on the clobber list, as // that might lead to undefined behaviour. @@ -540,7 +570,7 @@ void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const { "preserved across the asm statement, and clobbering them may " "lead to undefined behaviour."; MMI->getModule()->getContext().diagnose(DiagnosticInfoInlineAsm( - LocCookie, Msg.c_str(), DiagnosticSeverity::DS_Warning)); + LocCookie, Msg, DiagnosticSeverity::DS_Warning)); MMI->getModule()->getContext().diagnose( DiagnosticInfoInlineAsm(LocCookie, Note, DiagnosticSeverity::DS_Note)); } @@ -560,13 +590,13 @@ void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const { /// syntax used is ${:comment}. Targets can override this to add support /// for their own strange codes. void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, - const char *Code) const { - if (!strcmp(Code, "private")) { + StringRef Code) const { + if (Code == "private") { const DataLayout &DL = MF->getDataLayout(); OS << DL.getPrivateGlobalPrefix(); - } else if (!strcmp(Code, "comment")) { + } else if (Code == "comment") { OS << MAI->getCommentString(); - } else if (!strcmp(Code, "uid")) { + } else if (Code == "uid") { // Comparing the address of MI isn't sufficient, because machineinstrs may // be allocated to the same address across functions. @@ -582,7 +612,7 @@ void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, raw_string_ostream Msg(msg); Msg << "Unknown special formatter '" << Code << "' for machine instr: " << *MI; - report_fatal_error(Msg.str()); + report_fatal_error(Twine(Msg.str())); } } diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index bbb0504550c3..85ff84484ced 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -341,7 +341,16 @@ std::string CodeViewDebug::getFullyQualifiedName(const DIScope *Ty) { TypeIndex CodeViewDebug::getScopeIndex(const DIScope *Scope) { // No scope means global scope and that uses the zero index. - if (!Scope || isa<DIFile>(Scope)) + // + // We also use zero index when the scope is a DISubprogram + // to suppress the emission of LF_STRING_ID for the function, + // which can trigger a link-time error with the linker in + // VS2019 version 16.11.2 or newer. + // Note, however, skipping the debug info emission for the DISubprogram + // is a temporary fix. The root issue here is that we need to figure out + // the proper way to encode a function nested in another function + // (as introduced by the Fortran 'contains' keyword) in CodeView. + if (!Scope || isa<DIFile>(Scope) || isa<DISubprogram>(Scope)) return TypeIndex(); assert(!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"); @@ -561,6 +570,44 @@ void CodeViewDebug::emitCodeViewMagicVersion() { OS.emitInt32(COFF::DEBUG_SECTION_MAGIC); } +static SourceLanguage MapDWLangToCVLang(unsigned DWLang) { + switch (DWLang) { + case dwarf::DW_LANG_C: + case dwarf::DW_LANG_C89: + case dwarf::DW_LANG_C99: + case dwarf::DW_LANG_C11: + case dwarf::DW_LANG_ObjC: + return SourceLanguage::C; + case dwarf::DW_LANG_C_plus_plus: + case dwarf::DW_LANG_C_plus_plus_03: + case dwarf::DW_LANG_C_plus_plus_11: + case dwarf::DW_LANG_C_plus_plus_14: + return SourceLanguage::Cpp; + case dwarf::DW_LANG_Fortran77: + case dwarf::DW_LANG_Fortran90: + case dwarf::DW_LANG_Fortran95: + case dwarf::DW_LANG_Fortran03: + case dwarf::DW_LANG_Fortran08: + return SourceLanguage::Fortran; + case dwarf::DW_LANG_Pascal83: + return SourceLanguage::Pascal; + case dwarf::DW_LANG_Cobol74: + case dwarf::DW_LANG_Cobol85: + return SourceLanguage::Cobol; + case dwarf::DW_LANG_Java: + return SourceLanguage::Java; + case dwarf::DW_LANG_D: + return SourceLanguage::D; + case dwarf::DW_LANG_Swift: + return SourceLanguage::Swift; + default: + // There's no CodeView representation for this language, and CV doesn't + // have an "unknown" option for the language field, so we'll use MASM, + // as it's very low level. + return SourceLanguage::Masm; + } +} + void CodeViewDebug::beginModule(Module *M) { // If module doesn't have named metadata anchors or COFF debug section // is not available, skip any debug info related stuff. @@ -574,6 +621,13 @@ void CodeViewDebug::beginModule(Module *M) { TheCPU = mapArchToCVCPUType(Triple(M->getTargetTriple()).getArch()); + // Get the current source language. + NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + const MDNode *Node = *CUs->operands().begin(); + const auto *CU = cast<DICompileUnit>(Node); + + CurrentSourceLanguage = MapDWLangToCVLang(CU->getSourceLanguage()); + collectGlobalVariableInfo(); // Check if we should emit type record hashes. @@ -731,43 +785,6 @@ void CodeViewDebug::emitTypeGlobalHashes() { } } -static SourceLanguage MapDWLangToCVLang(unsigned DWLang) { - switch (DWLang) { - case dwarf::DW_LANG_C: - case dwarf::DW_LANG_C89: - case dwarf::DW_LANG_C99: - case dwarf::DW_LANG_C11: - case dwarf::DW_LANG_ObjC: - return SourceLanguage::C; - case dwarf::DW_LANG_C_plus_plus: - case dwarf::DW_LANG_C_plus_plus_03: - case dwarf::DW_LANG_C_plus_plus_11: - case dwarf::DW_LANG_C_plus_plus_14: - return SourceLanguage::Cpp; - case dwarf::DW_LANG_Fortran77: - case dwarf::DW_LANG_Fortran90: - case dwarf::DW_LANG_Fortran03: - case dwarf::DW_LANG_Fortran08: - return SourceLanguage::Fortran; - case dwarf::DW_LANG_Pascal83: - return SourceLanguage::Pascal; - case dwarf::DW_LANG_Cobol74: - case dwarf::DW_LANG_Cobol85: - return SourceLanguage::Cobol; - case dwarf::DW_LANG_Java: - return SourceLanguage::Java; - case dwarf::DW_LANG_D: - return SourceLanguage::D; - case dwarf::DW_LANG_Swift: - return SourceLanguage::Swift; - default: - // There's no CodeView representation for this language, and CV doesn't - // have an "unknown" option for the language field, so we'll use MASM, - // as it's very low level. - return SourceLanguage::Masm; - } -} - namespace { struct Version { int Part[4]; @@ -797,12 +814,8 @@ void CodeViewDebug::emitCompilerInformation() { MCSymbol *CompilerEnd = beginSymbolRecord(SymbolKind::S_COMPILE3); uint32_t Flags = 0; - NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); - const MDNode *Node = *CUs->operands().begin(); - const auto *CU = cast<DICompileUnit>(Node); - // The low byte of the flags indicates the source language. - Flags = MapDWLangToCVLang(CU->getSourceLanguage()); + Flags = CurrentSourceLanguage; // TODO: Figure out which other flags need to be set. if (MMI->getModule()->getProfileSummary(/*IsCS*/ false) != nullptr) { Flags |= static_cast<uint32_t>(CompileSym3Flags::PGO); @@ -814,6 +827,10 @@ void CodeViewDebug::emitCompilerInformation() { OS.AddComment("CPUType"); OS.emitInt16(static_cast<uint64_t>(TheCPU)); + NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + const MDNode *Node = *CUs->operands().begin(); + const auto *CU = cast<DICompileUnit>(Node); + StringRef CompilerVersion = CU->getProducer(); Version FrontVer = parseVersion(CompilerVersion); OS.AddComment("Frontend version"); @@ -1573,6 +1590,8 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) { return lowerTypeClass(cast<DICompositeType>(Ty)); case dwarf::DW_TAG_union_type: return lowerTypeUnion(cast<DICompositeType>(Ty)); + case dwarf::DW_TAG_string_type: + return lowerTypeString(cast<DIStringType>(Ty)); case dwarf::DW_TAG_unspecified_type: if (Ty->getName() == "decltype(nullptr)") return TypeIndex::NullptrT(); @@ -1617,14 +1636,19 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { const DISubrange *Subrange = cast<DISubrange>(Element); int64_t Count = -1; - // Calculate the count if either LowerBound is absent or is zero and - // either of Count or UpperBound are constant. - auto *LI = Subrange->getLowerBound().dyn_cast<ConstantInt *>(); - if (!Subrange->getRawLowerBound() || (LI && (LI->getSExtValue() == 0))) { - if (auto *CI = Subrange->getCount().dyn_cast<ConstantInt*>()) - Count = CI->getSExtValue(); - else if (auto *UI = Subrange->getUpperBound().dyn_cast<ConstantInt*>()) - Count = UI->getSExtValue() + 1; // LowerBound is zero + + // If Subrange has a Count field, use it. + // Otherwise, if it has an upperboud, use (upperbound - lowerbound + 1), + // where lowerbound is from the LowerBound field of the Subrange, + // or the language default lowerbound if that field is unspecified. + if (auto *CI = Subrange->getCount().dyn_cast<ConstantInt *>()) + Count = CI->getSExtValue(); + else if (auto *UI = Subrange->getUpperBound().dyn_cast<ConstantInt *>()) { + // Fortran uses 1 as the default lowerbound; other languages use 0. + int64_t Lowerbound = (moduleIsInFortran()) ? 1 : 0; + auto *LI = Subrange->getLowerBound().dyn_cast<ConstantInt *>(); + Lowerbound = (LI) ? LI->getSExtValue() : Lowerbound; + Count = UI->getSExtValue() - Lowerbound + 1; } // Forward declarations of arrays without a size and VLAs use a count of -1. @@ -1650,6 +1674,26 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { return ElementTypeIndex; } +// This function lowers a Fortran character type (DIStringType). +// Note that it handles only the character*n variant (using SizeInBits +// field in DIString to describe the type size) at the moment. +// Other variants (leveraging the StringLength and StringLengthExp +// fields in DIStringType) remain TBD. +TypeIndex CodeViewDebug::lowerTypeString(const DIStringType *Ty) { + TypeIndex CharType = TypeIndex(SimpleTypeKind::NarrowCharacter); + uint64_t ArraySize = Ty->getSizeInBits() >> 3; + StringRef Name = Ty->getName(); + // IndexType is size_t, which depends on the bitness of the target. + TypeIndex IndexType = getPointerSizeInBytes() == 8 + ? TypeIndex(SimpleTypeKind::UInt64Quad) + : TypeIndex(SimpleTypeKind::UInt32Long); + + // Create a type of character array of ArraySize. + ArrayRecord AR(CharType, IndexType, ArraySize, Name); + + return TypeTable.writeLeafType(AR); +} + TypeIndex CodeViewDebug::lowerTypeBasic(const DIBasicType *Ty) { TypeIndex Index; dwarf::TypeKind Kind; @@ -1728,9 +1772,14 @@ TypeIndex CodeViewDebug::lowerTypeBasic(const DIBasicType *Ty) { } // Apply some fixups based on the source-level type name. - if (STK == SimpleTypeKind::Int32 && Ty->getName() == "long int") + // Include some amount of canonicalization from an old naming scheme Clang + // used to use for integer types (in an outdated effort to be compatible with + // GCC's debug info/GDB's behavior, which has since been addressed). + if (STK == SimpleTypeKind::Int32 && + (Ty->getName() == "long int" || Ty->getName() == "long")) STK = SimpleTypeKind::Int32Long; - if (STK == SimpleTypeKind::UInt32 && Ty->getName() == "long unsigned int") + if (STK == SimpleTypeKind::UInt32 && (Ty->getName() == "long unsigned int" || + Ty->getName() == "unsigned long")) STK = SimpleTypeKind::UInt32Long; if (STK == SimpleTypeKind::UInt16Short && (Ty->getName() == "wchar_t" || Ty->getName() == "__wchar_t")) @@ -2177,6 +2226,7 @@ void CodeViewDebug::clear() { TypeIndices.clear(); CompleteTypeIndices.clear(); ScopeGlobals.clear(); + CVGlobalVariableOffsets.clear(); } void CodeViewDebug::collectMemberInfo(ClassInfo &Info, @@ -3062,6 +3112,15 @@ void CodeViewDebug::collectGlobalVariableInfo() { const DIGlobalVariable *DIGV = GVE->getVariable(); const DIExpression *DIE = GVE->getExpression(); + if ((DIE->getNumElements() == 2) && + (DIE->getElement(0) == dwarf::DW_OP_plus_uconst)) + // Record the constant offset for the variable. + // + // A Fortran common block uses this idiom to encode the offset + // of a variable from the common block's starting address. + CVGlobalVariableOffsets.insert( + std::make_pair(DIGV, DIE->getElement(1))); + // Emit constant global variables in a global symbol section. if (GlobalMap.count(GVE) == 0 && DIE->isConstant()) { CVGlobalVariable CVGV = {DIGV, DIE}; @@ -3226,7 +3285,11 @@ void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) { if (const auto *MemberDecl = dyn_cast_or_null<DIDerivedType>( DIGV->getRawStaticDataMemberDeclaration())) Scope = MemberDecl->getScope(); - std::string QualifiedName = getFullyQualifiedName(Scope, DIGV->getName()); + // For Fortran, the scoping portion is elided in its name so that we can + // reference the variable in the command line of the VS debugger. + std::string QualifiedName = + (moduleIsInFortran()) ? std::string(DIGV->getName()) + : getFullyQualifiedName(Scope, DIGV->getName()); if (const GlobalVariable *GV = CVGV.GVInfo.dyn_cast<const GlobalVariable *>()) { @@ -3242,7 +3305,13 @@ void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) { OS.AddComment("Type"); OS.emitInt32(getCompleteTypeIndex(DIGV->getType()).getIndex()); OS.AddComment("DataOffset"); - OS.EmitCOFFSecRel32(GVSym, /*Offset=*/0); + + uint64_t Offset = 0; + if (CVGlobalVariableOffsets.find(DIGV) != CVGlobalVariableOffsets.end()) + // Use the offset seen while collecting info on globals. + Offset = CVGlobalVariableOffsets[DIGV]; + OS.EmitCOFFSecRel32(GVSym, Offset); + OS.AddComment("Segment"); OS.EmitCOFFSectionIndex(GVSym); OS.AddComment("Name"); diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index d133474ee5aa..6f88e15ee8fe 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -186,6 +186,13 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { }; FunctionInfo *CurFn = nullptr; + codeview::SourceLanguage CurrentSourceLanguage = + codeview::SourceLanguage::Masm; + + // This map records the constant offset in DIExpression of the + // DIGlobalVariableExpression referencing the DIGlobalVariable. + DenseMap<const DIGlobalVariable *, uint64_t> CVGlobalVariableOffsets; + // Map used to seperate variables according to the lexical scope they belong // in. This is populated by recordLocalVariable() before // collectLexicalBlocks() separates the variables between the FunctionInfo @@ -400,6 +407,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { codeview::TypeIndex lowerType(const DIType *Ty, const DIType *ClassTy); codeview::TypeIndex lowerTypeAlias(const DIDerivedType *Ty); codeview::TypeIndex lowerTypeArray(const DICompositeType *Ty); + codeview::TypeIndex lowerTypeString(const DIStringType *Ty); codeview::TypeIndex lowerTypeBasic(const DIBasicType *Ty); codeview::TypeIndex lowerTypePointer( const DIDerivedType *Ty, @@ -464,6 +472,11 @@ protected: /// Gather post-function debug information. void endFunctionImpl(const MachineFunction *) override; + /// Check if the current module is in Fortran. + bool moduleIsInFortran() { + return CurrentSourceLanguage == codeview::SourceLanguage::Fortran; + } + public: CodeViewDebug(AsmPrinter *AP); diff --git a/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp b/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp index 802f0e880514..5f4ee747fcca 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -93,19 +93,15 @@ void DIEHash::addParentContext(const DIE &Parent) { // Reverse iterate over our list to go from the outermost construct to the // innermost. - for (SmallVectorImpl<const DIE *>::reverse_iterator I = Parents.rbegin(), - E = Parents.rend(); - I != E; ++I) { - const DIE &Die = **I; - + for (const DIE *Die : llvm::reverse(Parents)) { // ... Append the letter "C" to the sequence... addULEB128('C'); // ... Followed by the DWARF tag of the construct... - addULEB128(Die.getTag()); + addULEB128(Die->getTag()); // ... Then the name, taken from the DW_AT_name attribute. - StringRef Name = getDIEStringAttr(Die, dwarf::DW_AT_name); + StringRef Name = getDIEStringAttr(*Die, dwarf::DW_AT_name); LLVM_DEBUG(dbgs() << "... adding context: " << Name << "\n"); if (!Name.empty()) addString(Name); diff --git a/llvm/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp b/llvm/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp index bb24f1414ef1..dd795079ac1a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -252,8 +252,8 @@ void DbgValueHistoryMap::trimLocationRanges( // Now actually remove the entries. Iterate backwards so that our remaining // ToRemove indices are valid after each erase. - for (auto Itr = ToRemove.rbegin(), End = ToRemove.rend(); Itr != End; ++Itr) - HistoryMapEntries.erase(HistoryMapEntries.begin() + *Itr); + for (EntryIndex Idx : llvm::reverse(ToRemove)) + HistoryMapEntries.erase(HistoryMapEntries.begin() + Idx); } } diff --git a/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp b/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp index c81288c0e460..4df34d2c9402 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -174,21 +174,26 @@ uint64_t DebugHandlerBase::getBaseTypeSize(const DIType *Ty) { } bool DebugHandlerBase::isUnsignedDIType(const DIType *Ty) { - // SROA may generate dbg value intrinsics to assign an unsigned value to a - // Fortran CHARACTER(1) type variables. Make them as unsigned. if (isa<DIStringType>(Ty)) { - assert((Ty->getSizeInBits()) == 8 && "Not a valid unsigned type!"); + // Some transformations (e.g. instcombine) may decide to turn a Fortran + // character object into an integer, and later ones (e.g. SROA) may + // further inject a constant integer in a llvm.dbg.value call to track + // the object's value. Here we trust the transformations are doing the + // right thing, and treat the constant as unsigned to preserve that value + // (i.e. avoid sign extension). return true; } - if (auto *CTy = dyn_cast<DICompositeType>(Ty)) { - // FIXME: Enums without a fixed underlying type have unknown signedness - // here, leading to incorrectly emitted constants. - if (CTy->getTag() == dwarf::DW_TAG_enumeration_type) - return false; - // (Pieces of) aggregate types that get hacked apart by SROA may be - // represented by a constant. Encode them as unsigned bytes. - return true; + if (auto *CTy = dyn_cast<DICompositeType>(Ty)) { + if (CTy->getTag() == dwarf::DW_TAG_enumeration_type) { + if (!(Ty = CTy->getBaseType())) + // FIXME: Enums without a fixed underlying type have unknown signedness + // here, leading to incorrectly emitted constants. + return false; + } else + // (Pieces of) aggregate types that get hacked apart by SROA may be + // represented by a constant. Encode them as unsigned bytes. + return true; } if (auto *DTy = dyn_cast<DIDerivedType>(Ty)) { diff --git a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h index 62ebadaf3cbe..d7ab2091967f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -158,7 +158,7 @@ public: friend bool operator<(const DbgValueLoc &, const DbgValueLoc &); #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void dump() const { - for (DbgValueLocEntry DV : ValueLocEntries) + for (const DbgValueLocEntry &DV : ValueLocEntries) DV.dump(); if (Expression) Expression->dump(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index faa14dca1c3f..922c91840520 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -143,8 +143,6 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( auto *GVContext = GV->getScope(); const DIType *GTy = GV->getType(); - // Construct the context before querying for the existence of the DIE in - // case such construction creates the DIE. auto *CB = GVContext ? dyn_cast<DICommonBlock>(GVContext) : nullptr; DIE *ContextDIE = CB ? getOrCreateCommonBlock(CB, GlobalExprs) : getOrCreateContextDIE(GVContext); @@ -183,6 +181,8 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( else addGlobalName(GV->getName(), *VariableDIE, DeclContext); + addAnnotation(*VariableDIE, GV->getAnnotations()); + if (uint32_t AlignInBytes = GV->getAlignInBytes()) addUInt(*VariableDIE, dwarf::DW_AT_alignment, dwarf::DW_FORM_udata, AlignInBytes); @@ -260,14 +260,14 @@ void DwarfCompileUnit::addLocationAttribute( if (Global) { const MCSymbol *Sym = Asm->getSymbol(Global); + unsigned PointerSize = Asm->getDataLayout().getPointerSize(); + assert((PointerSize == 4 || PointerSize == 8) && + "Add support for other sizes if necessary"); if (Global->isThreadLocal()) { if (Asm->TM.useEmulatedTLS()) { // TODO: add debug info for emulated thread local mode. } else { // FIXME: Make this work with -gsplit-dwarf. - unsigned PointerSize = Asm->getDataLayout().getPointerSize(); - assert((PointerSize == 4 || PointerSize == 8) && - "Add support for other sizes if necessary"); // Based on GCC's support for TLS: if (!DD->useSplitDwarf()) { // 1) Start with a constNu of the appropriate pointer size @@ -290,6 +290,24 @@ void DwarfCompileUnit::addLocationAttribute( DD->useGNUTLSOpcode() ? dwarf::DW_OP_GNU_push_tls_address : dwarf::DW_OP_form_tls_address); } + } else if (Asm->TM.getRelocationModel() == Reloc::RWPI || + Asm->TM.getRelocationModel() == Reloc::ROPI_RWPI) { + // Constant + addUInt(*Loc, dwarf::DW_FORM_data1, + PointerSize == 4 ? dwarf::DW_OP_const4u + : dwarf::DW_OP_const8u); + // Relocation offset + addExpr(*Loc, PointerSize == 4 ? dwarf::DW_FORM_data4 + : dwarf::DW_FORM_data8, + Asm->getObjFileLowering().getIndirectSymViaRWPI(Sym)); + // Base register + Register BaseReg = Asm->getObjFileLowering().getStaticBase(); + BaseReg = Asm->TM.getMCRegisterInfo()->getDwarfRegNum(BaseReg, false); + addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + BaseReg); + // Offset from base register + addSInt(*Loc, dwarf::DW_FORM_sdata, 0); + // Operation + addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_plus); } else { DD->addArangeLabel(SymbolCU(this, Sym)); addOpAddress(*Loc, Sym); @@ -331,12 +349,10 @@ void DwarfCompileUnit::addLocationAttribute( DIE *DwarfCompileUnit::getOrCreateCommonBlock( const DICommonBlock *CB, ArrayRef<GlobalExpr> GlobalExprs) { - // Construct the context before querying for the existence of the DIE in case - // such construction creates the DIE. - DIE *ContextDIE = getOrCreateContextDIE(CB->getScope()); - + // Check for pre-existence. if (DIE *NDie = getDIE(CB)) return NDie; + DIE *ContextDIE = getOrCreateContextDIE(CB->getScope()); DIE &NDie = createAndAddDIE(dwarf::DW_TAG_common_block, *ContextDIE, CB); StringRef Name = CB->getName().empty() ? "_BLNK_" : CB->getName(); addString(NDie, dwarf::DW_AT_name, Name); @@ -351,7 +367,8 @@ DIE *DwarfCompileUnit::getOrCreateCommonBlock( void DwarfCompileUnit::addRange(RangeSpan Range) { DD->insertSectionLabel(Range.Begin); - bool SameAsPrevCU = this == DD->getPrevCU(); + auto *PrevCU = DD->getPrevCU(); + bool SameAsPrevCU = this == PrevCU; DD->setPrevCU(this); // If we have no current ranges just add the range and return, otherwise, // check the current section and CU against the previous section and CU we @@ -360,6 +377,9 @@ void DwarfCompileUnit::addRange(RangeSpan Range) { if (CURanges.empty() || !SameAsPrevCU || (&CURanges.back().End->getSection() != &Range.End->getSection())) { + // Before a new range is added, always terminate the prior line table. + if (PrevCU) + DD->terminateLineTable(PrevCU); CURanges.push_back(Range); return; } @@ -470,7 +490,6 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) { addSInt(*Loc, dwarf::DW_FORM_sdata, TI_GLOBAL_RELOC); if (!isDwoUnit()) { addLabel(*Loc, dwarf::DW_FORM_data4, SPSym); - DD->addArangeLabel(SymbolCU(this, SPSym)); } else { // FIXME: when writing dwo, we need to avoid relocations. Probably // the "right" solution is to treat globals the way func and data @@ -961,9 +980,7 @@ sortLocalVars(SmallVectorImpl<DbgVariable *> &Input) { bool visitedAllDependencies = Item.getInt(); WorkList.pop_back(); - // Dependency is in a different lexical scope or a global. - if (!Var) - continue; + assert(Var); // Already handled. if (Visited.count(Var)) @@ -987,8 +1004,10 @@ sortLocalVars(SmallVectorImpl<DbgVariable *> &Input) { // visited again after all of its dependencies are handled. WorkList.push_back({Var, 1}); for (auto *Dependency : dependencies(Var)) { - auto Dep = dyn_cast_or_null<const DILocalVariable>(Dependency); - WorkList.push_back({DbgVar[Dep], 0}); + // Don't add dependency if it is in a different lexical scope or a global. + if (const auto *Dep = dyn_cast<const DILocalVariable>(Dependency)) + if (DbgVariable *Var = DbgVar.lookup(Dep)) + WorkList.push_back({Var, 0}); } } return Result; @@ -1103,9 +1122,10 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE( // shouldn't be found by lookup. AbsDef = &ContextCU->createAndAddDIE(dwarf::DW_TAG_subprogram, *ContextDIE, nullptr); ContextCU->applySubprogramAttributesToDefinition(SP, *AbsDef); - - if (!ContextCU->includeMinimalInlineScopes()) - ContextCU->addUInt(*AbsDef, dwarf::DW_AT_inline, None, dwarf::DW_INL_inlined); + ContextCU->addSInt(*AbsDef, dwarf::DW_AT_inline, + DD->getDwarfVersion() <= 4 ? Optional<dwarf::Form>() + : dwarf::DW_FORM_implicit_const, + dwarf::DW_INL_inlined); if (DIE *ObjectPointer = ContextCU->createAndAddScopeChildren(Scope, *AbsDef)) ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer); } @@ -1162,7 +1182,7 @@ DwarfCompileUnit::getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const { } DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, - DIE *CalleeDIE, + const DISubprogram *CalleeSP, bool IsTail, const MCSymbol *PCAddr, const MCSymbol *CallAddr, @@ -1176,7 +1196,8 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, addAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_target), MachineLocation(CallReg)); } else { - assert(CalleeDIE && "No DIE for call site entry origin"); + DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP); + assert(CalleeDIE && "Could not create DIE for call site entry origin"); addDIEEntry(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_origin), *CalleeDIE); } @@ -1265,6 +1286,16 @@ DIE *DwarfCompileUnit::constructImportedEntityDIE( if (!Name.empty()) addString(*IMDie, dwarf::DW_AT_name, Name); + // This is for imported module with renamed entities (such as variables and + // subprograms). + DINodeArray Elements = Module->getElements(); + for (const auto *Element : Elements) { + if (!Element) + continue; + IMDie->addChild( + constructImportedEntityDIE(cast<DIImportedEntity>(Element))); + } + return IMDie; } @@ -1479,10 +1510,12 @@ void DwarfCompileUnit::applyVariableAttributes(const DbgVariable &Var, if (!Name.empty()) addString(VariableDie, dwarf::DW_AT_name, Name); const auto *DIVar = Var.getVariable(); - if (DIVar) + if (DIVar) { if (uint32_t AlignInBytes = DIVar->getAlignInBytes()) addUInt(VariableDie, dwarf::DW_AT_alignment, dwarf::DW_FORM_udata, AlignInBytes); + addAnnotation(VariableDie, DIVar->getAnnotations()); + } addSourceLine(VariableDie, DIVar); addType(VariableDie, Var.getType()); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 6d8186a5ee2b..6e9261087686 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -249,16 +249,14 @@ public: dwarf::LocationAtom getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const; /// Construct a call site entry DIE describing a call within \p Scope to a - /// callee described by \p CalleeDIE. - /// \p CalleeDIE is a declaration or definition subprogram DIE for the callee. - /// For indirect calls \p CalleeDIE is set to nullptr. + /// callee described by \p CalleeSP. /// \p IsTail specifies whether the call is a tail call. /// \p PCAddr points to the PC value after the call instruction. /// \p CallAddr points to the PC value at the call instruction (or is null). /// \p CallReg is a register location for an indirect call. For direct calls /// the \p CallReg is set to 0. - DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, DIE *CalleeDIE, bool IsTail, - const MCSymbol *PCAddr, + DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP, + bool IsTail, const MCSymbol *PCAddr, const MCSymbol *CallAddr, unsigned CallReg); /// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params /// were collected by the \ref collectCallSiteParameters. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index ee14423ca3d0..047676d4c11e 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -480,7 +480,7 @@ static bool hasObjCCategory(StringRef Name) { if (!isObjCClass(Name)) return false; - return Name.find(") ") != StringRef::npos; + return Name.contains(") "); } static void getObjCClassCategory(StringRef In, StringRef &Class, @@ -587,14 +587,6 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, } } -DIE &DwarfDebug::constructSubprogramDefinitionDIE(const DISubprogram *SP) { - DICompileUnit *Unit = SP->getUnit(); - assert(SP->isDefinition() && "Subprogram not a definition"); - assert(Unit && "Subprogram definition without parent unit"); - auto &CU = getOrCreateDwarfCompileUnit(Unit); - return *CU.getOrCreateSubprogramDIE(SP); -} - /// Represents a parameter whose call site value can be described by applying a /// debug expression to a register in the forwarded register worklist. struct FwdRegParamInfo { @@ -945,7 +937,7 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, continue; unsigned CallReg = 0; - DIE *CalleeDIE = nullptr; + const DISubprogram *CalleeSP = nullptr; const Function *CalleeDecl = nullptr; if (CalleeOp.isReg()) { CallReg = CalleeOp.getReg(); @@ -955,19 +947,7 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, CalleeDecl = dyn_cast<Function>(CalleeOp.getGlobal()); if (!CalleeDecl || !CalleeDecl->getSubprogram()) continue; - const DISubprogram *CalleeSP = CalleeDecl->getSubprogram(); - - if (CalleeSP->isDefinition()) { - // Ensure that a subprogram DIE for the callee is available in the - // appropriate CU. - CalleeDIE = &constructSubprogramDefinitionDIE(CalleeSP); - } else { - // Create the declaration DIE if it is missing. This is required to - // support compilation of old bitcode with an incomplete list of - // retained metadata. - CalleeDIE = CU.getOrCreateSubprogramDIE(CalleeSP); - } - assert(CalleeDIE && "Must have a DIE for the callee"); + CalleeSP = CalleeDecl->getSubprogram(); } // TODO: Omit call site entries for runtime calls (objc_msgSend, etc). @@ -1004,7 +984,7 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, << (IsTail ? " [IsTail]" : "") << "\n"); DIE &CallSiteDIE = CU.constructCallSiteEntryDIE( - ScopeDIE, CalleeDIE, IsTail, PCAddr, CallAddr, CallReg); + ScopeDIE, CalleeSP, IsTail, PCAddr, CallAddr, CallReg); // Optionally emit call-site-param debug info. if (emitDebugEntryValues()) { @@ -1427,6 +1407,10 @@ void DwarfDebug::finalizeModuleInfo() { // Emit all Dwarf sections that should come after the content. void DwarfDebug::endModule() { + // Terminate the pending line table. + if (PrevCU) + terminateLineTable(PrevCU); + PrevCU = nullptr; assert(CurFn == nullptr); assert(CurMI == nullptr); @@ -2102,12 +2086,22 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { static DebugLoc findPrologueEndLoc(const MachineFunction *MF) { // First known non-DBG_VALUE and non-frame setup location marks // the beginning of the function body. - for (const auto &MBB : *MF) - for (const auto &MI : MBB) + DebugLoc LineZeroLoc; + for (const auto &MBB : *MF) { + for (const auto &MI : MBB) { if (!MI.isMetaInstruction() && !MI.getFlag(MachineInstr::FrameSetup) && - MI.getDebugLoc()) - return MI.getDebugLoc(); - return DebugLoc(); + MI.getDebugLoc()) { + // Scan forward to try to find a non-zero line number. The prologue_end + // marks the first breakpoint in the function after the frame setup, and + // a compiler-generated line 0 location is not a meaningful breakpoint. + // If none is found, return the first location after the frame setup. + if (MI.getDebugLoc().getLine()) + return MI.getDebugLoc(); + LineZeroLoc = MI.getDebugLoc(); + } + } + } + return LineZeroLoc; } /// Register a source line with debug info. Returns the unique label that was @@ -2162,24 +2156,42 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) { DwarfCompileUnit &CU = getOrCreateDwarfCompileUnit(SP->getUnit()); + Asm->OutStreamer->getContext().setDwarfCompileUnitID( + getDwarfCompileUnitIDForLineTable(CU)); + + // Record beginning of function. + PrologEndLoc = emitInitialLocDirective( + *MF, Asm->OutStreamer->getContext().getDwarfCompileUnitID()); +} + +unsigned +DwarfDebug::getDwarfCompileUnitIDForLineTable(const DwarfCompileUnit &CU) { // Set DwarfDwarfCompileUnitID in MCContext to the Compile Unit this function // belongs to so that we add to the correct per-cu line table in the // non-asm case. if (Asm->OutStreamer->hasRawTextSupport()) // Use a single line table if we are generating assembly. - Asm->OutStreamer->getContext().setDwarfCompileUnitID(0); + return 0; else - Asm->OutStreamer->getContext().setDwarfCompileUnitID(CU.getUniqueID()); + return CU.getUniqueID(); +} - // Record beginning of function. - PrologEndLoc = emitInitialLocDirective( - *MF, Asm->OutStreamer->getContext().getDwarfCompileUnitID()); +void DwarfDebug::terminateLineTable(const DwarfCompileUnit *CU) { + const auto &CURanges = CU->getRanges(); + auto &LineTable = Asm->OutStreamer->getContext().getMCDwarfLineTable( + getDwarfCompileUnitIDForLineTable(*CU)); + // Add the last range label for the given CU. + LineTable.getMCLineSections().addEndEntry( + const_cast<MCSymbol *>(CURanges.back().End)); } void DwarfDebug::skippedNonDebugFunction() { // If we don't have a subprogram for this function then there will be a hole // in the range information. Keep note of this by setting the previously used // section to nullptr. + // Terminate the pending line table. + if (PrevCU) + terminateLineTable(PrevCU); PrevCU = nullptr; CurFn = nullptr; } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index 6356a65b50d3..4e1a1b1e068d 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -65,19 +65,21 @@ class Module; /// such that it could levarage polymorphism to extract common code for /// DbgVariable and DbgLabel. class DbgEntity { - const DINode *Entity; - const DILocation *InlinedAt; - DIE *TheDIE = nullptr; - unsigned SubclassID; - public: enum DbgEntityKind { DbgVariableKind, DbgLabelKind }; - DbgEntity(const DINode *N, const DILocation *IA, unsigned ID) - : Entity(N), InlinedAt(IA), SubclassID(ID) {} +private: + const DINode *Entity; + const DILocation *InlinedAt; + DIE *TheDIE = nullptr; + const DbgEntityKind SubclassID; + +public: + DbgEntity(const DINode *N, const DILocation *IA, DbgEntityKind ID) + : Entity(N), InlinedAt(IA), SubclassID(ID) {} virtual ~DbgEntity() {} /// Accessors. @@ -85,19 +87,18 @@ public: const DINode *getEntity() const { return Entity; } const DILocation *getInlinedAt() const { return InlinedAt; } DIE *getDIE() const { return TheDIE; } - unsigned getDbgEntityID() const { return SubclassID; } + DbgEntityKind getDbgEntityID() const { return SubclassID; } /// @} void setDIE(DIE &D) { TheDIE = &D; } static bool classof(const DbgEntity *N) { switch (N->getDbgEntityID()) { - default: - return false; case DbgVariableKind: case DbgLabelKind: return true; } + llvm_unreachable("Invalid DbgEntityKind"); } }; @@ -471,9 +472,6 @@ private: /// Construct a DIE for this abstract scope. void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope); - /// Construct a DIE for the subprogram definition \p SP and return it. - DIE &constructSubprogramDefinitionDIE(const DISubprogram *SP); - /// Construct DIEs for call site entries describing the calls in \p MF. void constructCallSiteEntryDIEs(const DISubprogram &SP, DwarfCompileUnit &CU, DIE &ScopeDIE, const MachineFunction &MF); @@ -615,7 +613,7 @@ private: DenseSet<InlinedEntity> &ProcessedVars); /// Build the location list for all DBG_VALUEs in the - /// function that describe the same variable. If the resulting + /// function that describe the same variable. If the resulting /// list has only one entry that is valid for entire variable's /// scope return true. bool buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, @@ -635,6 +633,9 @@ protected: /// Gather and emit post-function debug information. void endFunctionImpl(const MachineFunction *MF) override; + /// Get Dwarf compile unit ID for line table. + unsigned getDwarfCompileUnitIDForLineTable(const DwarfCompileUnit &CU); + void skippedNonDebugFunction() override; public: @@ -781,6 +782,9 @@ public: const DwarfCompileUnit *getPrevCU() const { return PrevCU; } void setPrevCU(const DwarfCompileUnit *PrevCU) { this->PrevCU = PrevCU; } + /// Terminate the line table by adding the last range label. + void terminateLineTable(const DwarfCompileUnit *CU); + /// Returns the entries for the .debug_loc section. const DebugLocStream &getDebugLocs() const { return DebugLocs; } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 344d30fad347..976e35905144 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -186,9 +186,8 @@ int64_t DwarfUnit::getDefaultLowerBound() const { /// Check whether the DIE for this MDNode can be shared across CUs. bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const { - // When the MDNode can be part of the type system (this includes subprogram - // declarations *and* subprogram definitions, even local definitions), the - // DIE must be shared across CUs. + // When the MDNode can be part of the type system, the DIE can be shared + // across CUs. // Combining type units and cross-CU DIE sharing is lower value (since // cross-CU DIE sharing is used in LTO and removes type redundancy at that // level already) but may be implementable for some value in projects @@ -196,7 +195,9 @@ bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const { // together. if (isDwoUnit() && !DD->shareAcrossDWOCUs()) return false; - return (isa<DIType>(D) || isa<DISubprogram>(D)) && !DD->generateTypeUnits(); + return (isa<DIType>(D) || + (isa<DISubprogram>(D) && !cast<DISubprogram>(D)->isDefinition())) && + !DD->generateTypeUnits(); } DIE *DwarfUnit::getDIE(const DINode *D) const { @@ -671,7 +672,7 @@ std::string DwarfUnit::getParentContextString(const DIScope *Context) const { // Reverse iterate over our list to go from the outermost construct to the // innermost. - for (const DIScope *Ctx : make_range(Parents.rbegin(), Parents.rend())) { + for (const DIScope *Ctx : llvm::reverse(Parents)) { StringRef Name = Ctx->getName(); if (Name.empty() && isa<DINamespace>(Ctx)) Name = "(anonymous namespace)"; @@ -753,6 +754,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) { if (!Name.empty()) addString(Buffer, dwarf::DW_AT_name, Name); + addAnnotation(Buffer, DTy->getAnnotations()); + // If alignment is specified for a typedef , create and insert DW_AT_alignment // attribute in DW_TAG_typedef DIE. if (Tag == dwarf::DW_TAG_typedef && DD->getDwarfVersion() >= 5) { @@ -832,6 +835,23 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy) { addFlag(Buffer, dwarf::DW_AT_rvalue_reference); } +void DwarfUnit::addAnnotation(DIE &Buffer, DINodeArray Annotations) { + if (!Annotations) + return; + + for (const Metadata *Annotation : Annotations->operands()) { + const MDNode *MD = cast<MDNode>(Annotation); + const MDString *Name = cast<MDString>(MD->getOperand(0)); + + // Currently, only MDString is supported with btf_decl_tag attribute. + const MDString *Value = cast<MDString>(MD->getOperand(1)); + + DIE &AnnotationDie = createAndAddDIE(dwarf::DW_TAG_LLVM_annotation, Buffer); + addString(AnnotationDie, dwarf::DW_AT_name, Name->getString()); + addString(AnnotationDie, dwarf::DW_AT_const_value, Value->getString()); + } +} + void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { // Add name if not anonymous or intermediate type. StringRef Name = CTy->getName(); @@ -849,7 +869,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { case dwarf::DW_TAG_variant_part: case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_union_type: - case dwarf::DW_TAG_class_type: { + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_namelist: { // Emit the discriminator for a variant part. DIDerivedType *Discriminator = nullptr; if (Tag == dwarf::DW_TAG_variant_part) { @@ -918,6 +939,13 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { DIE &VariantPart = createAndAddDIE(Composite->getTag(), Buffer); constructTypeDIE(VariantPart, Composite); } + } else if (Tag == dwarf::DW_TAG_namelist) { + auto *Var = dyn_cast<DINode>(Element); + auto *VarDIE = getDIE(Var); + if (VarDIE) { + DIE &ItemDie = createAndAddDIE(dwarf::DW_TAG_namelist_item, Buffer); + addDIEEntry(ItemDie, dwarf::DW_AT_namelist_item, *VarDIE); + } } } @@ -960,6 +988,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { if (!Name.empty()) addString(Buffer, dwarf::DW_AT_name, Name); + addAnnotation(Buffer, CTy->getAnnotations()); + if (Tag == dwarf::DW_TAG_enumeration_type || Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { @@ -1196,6 +1226,8 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, if (!SP->getName().empty()) addString(SPDie, dwarf::DW_AT_name, SP->getName()); + addAnnotation(SPDie, SP->getAnnotations()); + if (!SkipSPSourceLocation) addSourceLine(SPDie, SP); @@ -1546,6 +1578,8 @@ DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { if (!Name.empty()) addString(MemberDie, dwarf::DW_AT_name, Name); + addAnnotation(MemberDie, DT->getAnnotations()); + if (DIType *Resolved = DT->getBaseType()) addType(MemberDie, Resolved); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index 4d31dd0daf59..8140279adaef 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -294,6 +294,9 @@ public: void addSectionLabel(DIE &Die, dwarf::Attribute Attribute, const MCSymbol *Label, const MCSymbol *Sec); + /// Add DW_TAG_LLVM_annotation. + void addAnnotation(DIE &Buffer, DINodeArray Annotations); + /// Get context owner's DIE. DIE *createTypeDIE(const DICompositeType *Ty); diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp index e589c2e64abd..150f19324834 100644 --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -812,8 +812,7 @@ void EHStreamer::emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) { Entry = TypeInfos.size(); } - for (const GlobalValue *GV : make_range(TypeInfos.rbegin(), - TypeInfos.rend())) { + for (const GlobalValue *GV : llvm::reverse(TypeInfos)) { if (VerboseAsm) Asm->OutStreamer->AddComment("TypeInfo " + Twine(Entry--)); Asm->emitTTypeReference(GV, TTypeEncoding); diff --git a/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp index 35a830f416f6..9e6f1a537de3 100644 --- a/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp @@ -20,6 +20,8 @@ using namespace llvm; +PseudoProbeHandler::~PseudoProbeHandler() = default; + void PseudoProbeHandler::emitPseudoProbe(uint64_t Guid, uint64_t Index, uint64_t Type, uint64_t Attr, const DILocation *DebugLoc) { @@ -35,7 +37,10 @@ void PseudoProbeHandler::emitPseudoProbe(uint64_t Guid, uint64_t Index, auto Name = SP->getLinkageName(); if (Name.empty()) Name = SP->getName(); - uint64_t CallerGuid = Function::getGUID(Name); + // Use caching to avoid redundant md5 computation for build speed. + uint64_t &CallerGuid = NameGuidMap[Name]; + if (!CallerGuid) + CallerGuid = Function::getGUID(Name); uint64_t CallerProbeId = PseudoProbeDwarfDiscriminator::extractProbeIndex( InlinedAt->getDiscriminator()); ReversedInlineStack.emplace_back(CallerGuid, CallerProbeId); diff --git a/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.h b/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.h index f2026a118bf5..7d5e51218693 100644 --- a/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.h +++ b/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.h @@ -26,9 +26,12 @@ class DILocation; class PseudoProbeHandler : public AsmPrinterHandler { // Target of pseudo probe emission. AsmPrinter *Asm; + // Name to GUID map, used as caching/memoization for speed. + DenseMap<StringRef, uint64_t> NameGuidMap; public: PseudoProbeHandler(AsmPrinter *A) : Asm(A){}; + ~PseudoProbeHandler() override; void emitPseudoProbe(uint64_t Guid, uint64_t Index, uint64_t Type, uint64_t Attr, const DILocation *DebugLoc); diff --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp index 352a33e8639d..a17a2ca2790e 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp @@ -18,16 +18,25 @@ using namespace llvm; void WasmException::endModule() { - // This is the symbol used in 'throw' and 'catch' instruction to denote this - // is a C++ exception. This symbol has to be emitted somewhere once in the - // module. Check if the symbol has already been created, i.e., we have at - // least one 'throw' or 'catch' instruction in the module, and emit the symbol - // only if so. - SmallString<60> NameStr; - Mangler::getNameWithPrefix(NameStr, "__cpp_exception", Asm->getDataLayout()); - if (Asm->OutContext.lookupSymbol(NameStr)) { - MCSymbol *ExceptionSym = Asm->GetExternalSymbolSymbol("__cpp_exception"); - Asm->OutStreamer->emitLabel(ExceptionSym); + // These are symbols used to throw/catch C++ exceptions and C longjmps. These + // symbols have to be emitted somewhere once in the module. Check if each of + // the symbols has already been created, i.e., we have at least one 'throw' or + // 'catch' instruction with the symbol in the module, and emit the symbol only + // if so. + // + // But in dynamic linking, it is in general not possible to come up with a + // module instantiating order in which tag-defining modules are loaded before + // the importing modules. So we make them undefined symbols here, define tags + // in the JS side, and feed them to each importing module. + if (!Asm->isPositionIndependent()) { + for (const char *SymName : {"__cpp_exception", "__c_longjmp"}) { + SmallString<60> NameStr; + Mangler::getNameWithPrefix(NameStr, SymName, Asm->getDataLayout()); + if (Asm->OutContext.lookupSymbol(NameStr)) { + MCSymbol *ExceptionSym = Asm->GetExternalSymbolSymbol(SymName); + Asm->OutStreamer->emitLabel(ExceptionSym); + } + } } } diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp index b30d9cc12abc..ef57031c7294 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -43,6 +43,7 @@ WinException::WinException(AsmPrinter *A) : EHStreamer(A) { // platforms use an imagerel32 relocation to refer to symbols. useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64); isAArch64 = Asm->TM.getTargetTriple().isAArch64(); + isThumb = Asm->TM.getTargetTriple().isThumb(); } WinException::~WinException() {} @@ -330,10 +331,12 @@ const MCExpr *WinException::create32bitRef(const GlobalValue *GV) { } const MCExpr *WinException::getLabel(const MCSymbol *Label) { - if (isAArch64) - return MCSymbolRefExpr::create(Label, MCSymbolRefExpr::VK_COFF_IMGREL32, - Asm->OutContext); - return MCBinaryExpr::createAdd(create32bitRef(Label), + return MCSymbolRefExpr::create(Label, MCSymbolRefExpr::VK_COFF_IMGREL32, + Asm->OutContext); +} + +const MCExpr *WinException::getLabelPlusOne(const MCSymbol *Label) { + return MCBinaryExpr::createAdd(getLabel(Label), MCConstantExpr::create(1, Asm->OutContext), Asm->OutContext); } @@ -561,8 +564,8 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() { /// struct Table { /// int NumEntries; /// struct Entry { -/// imagerel32 LabelStart; -/// imagerel32 LabelEnd; +/// imagerel32 LabelStart; // Inclusive +/// imagerel32 LabelEnd; // Exclusive /// imagerel32 FilterOrFinally; // One means catch-all. /// imagerel32 LabelLPad; // Zero means __finally. /// } Entries[NumEntries]; @@ -664,7 +667,7 @@ void WinException::emitSEHActionsForRange(const WinEHFuncInfo &FuncInfo, AddComment("LabelStart"); OS.emitValue(getLabel(BeginLabel), 4); AddComment("LabelEnd"); - OS.emitValue(getLabel(EndLabel), 4); + OS.emitValue(getLabelPlusOne(EndLabel), 4); AddComment(UME.IsFinally ? "FinallyFunclet" : UME.Filter ? "FilterFunction" : "CatchAll"); OS.emitValue(FilterOrFinally, 4); @@ -949,8 +952,15 @@ void WinException::computeIP2StateTable( if (!ChangeLabel) ChangeLabel = StateChange.PreviousEndLabel; // Emit an entry indicating that PCs after 'Label' have this EH state. + // NOTE: On ARM architectures, the StateFromIp automatically takes into + // account that the return address is after the call instruction (whose EH + // state we should be using), but on other platforms we need to +1 to the + // label so that we are using the correct EH state. + const MCExpr *LabelExpression = (isAArch64 || isThumb) + ? getLabel(ChangeLabel) + : getLabelPlusOne(ChangeLabel); IPToStateTable.push_back( - std::make_pair(getLabel(ChangeLabel), StateChange.NewState)); + std::make_pair(LabelExpression, StateChange.NewState)); // FIXME: assert that NewState is between CatchLow and CatchHigh. } } diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.h b/llvm/lib/CodeGen/AsmPrinter/WinException.h index feea05ba63ad..638589adf0dd 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinException.h +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.h @@ -39,6 +39,9 @@ class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer { /// True if we are generating exception handling on Windows for ARM64. bool isAArch64 = false; + /// True if we are generating exception handling on Windows for ARM (Thumb). + bool isThumb = false; + /// Pointer to the current funclet entry BB. const MachineBasicBlock *CurrentFuncletEntry = nullptr; @@ -77,6 +80,7 @@ class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer { const MCExpr *create32bitRef(const MCSymbol *Value); const MCExpr *create32bitRef(const GlobalValue *GV); const MCExpr *getLabel(const MCSymbol *Label); + const MCExpr *getLabelPlusOne(const MCSymbol *Label); const MCExpr *getOffset(const MCSymbol *OffsetOf, const MCSymbol *OffsetFrom); const MCExpr *getOffsetPlusOne(const MCSymbol *OffsetOf, const MCSymbol *OffsetFrom); |
