diff --git a/llvm/include/llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h b/llvm/include/llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h new file mode 100644 index 0000000000000..8d569cd95d7f7 --- /dev/null +++ b/llvm/include/llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h @@ -0,0 +1,33 @@ +//===- EmitChangedFuncDebugInfo.h - Emit Additional Debug Info -*- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Emit debug info for changed or new funcs. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H +#define LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class Module; + +// Pass that emits late dwarf. +class EmitChangedFuncDebugInfoPass + : public PassInfoMixin { +public: + EmitChangedFuncDebugInfoPass() = default; + + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 53cf0046bd858..94428e381ddb4 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -351,6 +351,7 @@ #include "llvm/Transforms/Utils/DXILUpgrade.h" #include "llvm/Transforms/Utils/Debugify.h" #include "llvm/Transforms/Utils/DeclareRuntimeLibcalls.h" +#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/FixIrreducible.h" #include "llvm/Transforms/Utils/HelloWorld.h" diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index fea0d255cc91a..04918ed0a48ca 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -135,6 +135,7 @@ #include "llvm/Transforms/Utils/AssumeBundleBuilder.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/CountVisits.h" +#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/ExtraPassManager.h" #include "llvm/Transforms/Utils/InjectTLIMappings.h" @@ -1643,9 +1644,12 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, if (PTO.CallGraphProfile && !LTOPreLink) MPM.addPass(CGProfilePass(isLTOPostLink(LTOPhase))); - // RelLookupTableConverterPass runs later in LTO post-link pipeline. - if (!LTOPreLink) + // RelLookupTableConverterPass and EmitChangedFuncDebugInfoPass run later in + // LTO post-link pipeline. + if (!LTOPreLink) { MPM.addPass(RelLookupTableConverterPass()); + MPM.addPass(EmitChangedFuncDebugInfoPass()); + } return MPM; } diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 1b1652555cd28..db25041963b9f 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -75,6 +75,7 @@ MODULE_PASS("dfsan", DataFlowSanitizerPass()) MODULE_PASS("dot-callgraph", CallGraphDOTPrinterPass()) MODULE_PASS("dxil-upgrade", DXILUpgradePass()) MODULE_PASS("elim-avail-extern", EliminateAvailableExternallyPass()) +MODULE_PASS("emit-changed-func-debuginfo", EmitChangedFuncDebugInfoPass()) MODULE_PASS("extract-blocks", BlockExtractorPass({}, false)) MODULE_PASS("expand-variadics", ExpandVariadicsPass(ExpandVariadicsMode::Disable)) diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp index 262c902d40d2d..87b0d069ec04e 100644 --- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -50,6 +50,7 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" @@ -432,6 +433,16 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM, PromoteMemToReg(Allocas, DT, &AC); } + // If argument(s) are dead (hence removed) or promoted, probably the function + // does not follow standard calling convention anymore. Add DW_CC_nocall to + // DISubroutineType to inform debugger that it may not be safe to call this + // function. + DISubprogram *SP = NF->getSubprogram(); + if (SP) { + auto Temp = SP->getType()->cloneWithCC(llvm::dwarf::DW_CC_nocall); + SP->replaceType(MDNode::replaceWithPermanent(std::move(Temp))); + } + return NF; } diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt index f367ca2fdf56b..72291a0c7d8b0 100644 --- a/llvm/lib/Transforms/Utils/CMakeLists.txt +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt @@ -23,6 +23,7 @@ add_llvm_component_library(LLVMTransformUtils DebugSSAUpdater.cpp DeclareRuntimeLibcalls.cpp DemoteRegToStack.cpp + EmitChangedFuncDebugInfo.cpp DXILUpgrade.cpp EntryExitInstrumenter.cpp EscapeEnumerator.cpp diff --git a/llvm/lib/Transforms/Utils/EmitChangedFuncDebugInfo.cpp b/llvm/lib/Transforms/Utils/EmitChangedFuncDebugInfo.cpp new file mode 100644 index 0000000000000..41ee72a68bfe7 --- /dev/null +++ b/llvm/lib/Transforms/Utils/EmitChangedFuncDebugInfo.cpp @@ -0,0 +1,465 @@ +//==- EmitChangedFuncDebugInfoPass - Emit Additional Debug Info -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements emitting debug info for functions with changed +// signatures or new functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Module.h" +#include "llvm/TargetParser/Triple.h" + +using namespace llvm; + +static cl::opt DisableChangedFuncDBInfo( + "disable-changed-func-dbinfo", cl::Hidden, cl::init(false), + cl::desc("Disable debuginfo emission for changed func signatures")); + +/// ===================== Small helpers ===================== + +/// Strip qualifiers through derived types, but stop when we see the first +/// pointer type. Otherwise return the base non-qualified type. +static DIType *stripToBaseOrFirstPointer(DIType *T) { + while (auto *DT = dyn_cast_or_null(T)) { + if (DT->getTag() == dwarf::DW_TAG_pointer_type) + return DT; + T = DT->getBaseType(); + } + return T; +} + +/// Rebuild a DILocation chain identical to Old, but root it under NewSP via +/// inlinedAt. +static const DILocation *reanchorDILocChain(const DILocation *Old, + DISubprogram *NewSP, + LLVMContext &Ctx) { + // Root location anchored at the new subprogram. + DILocation *Root = DILocation::get(Ctx, 0, 0, NewSP); + + SmallVector Chain; + const DILocation *Cur = Old; + Chain.push_back(Cur); + while ((Cur = Cur->getInlinedAt())) + Chain.push_back(Cur); + + DILocation *Prev = Root; + for (int i = Chain.size() - 1; i >= 0; --i) { + const DILocation *DL = Chain[i]; + Prev = DILocation::get(Ctx, DL->getLine(), DL->getColumn(), DL->getScope(), + Prev, DL->isImplicitCode(), DL->getAtomGroup(), + DL->getAtomRank()); + } + return Prev; +} + +/// Recursively transform every DILocation inside an MD tree. +static Metadata * +mapAllDILocs(Metadata *M, + std::function X, + LLVMContext &Ctx) { + if (auto *DL = dyn_cast(M)) + return const_cast(X(DL)); + + if (auto *N = dyn_cast(M)) { + SmallVector NewOps; + NewOps.reserve(N->getNumOperands()); + for (const MDOperand &Op : N->operands()) + NewOps.push_back(mapAllDILocs(Op.get(), X, Ctx)); + return MDNode::get(Ctx, NewOps); // tag nodes need not be distinct + } + return M; +} + +/// Clone a loop MD node, rewriting all nested DILocations with X. +static MDNode *cloneLoopIDReplacingAllDILocs( + MDNode *OldLoopID, std::function X, + LLVMContext &Ctx) { + SmallVector Ops; + Ops.reserve(OldLoopID->getNumOperands()); + Ops.push_back(nullptr); // placeholder for self + for (unsigned i = 1, e = OldLoopID->getNumOperands(); i < e; ++i) + Ops.push_back(mapAllDILocs(OldLoopID->getOperand(i).get(), X, Ctx)); + MDNode *New = MDNode::getDistinct(Ctx, Ops); + New->replaceOperandWith(0, New); + return New; +} + +/// ===================== Type utilities ===================== + +/// For a struct/union parameter split into fragments, derive an integer DIType +/// for the fragment described by Expr. If a member with matching (offset,size) +/// exists, reuse its base type; otherwise synthesize an int type of BitSize. +static DIType *getIntTypeFromExpr(DIBuilder &DIB, DIExpression *Expr, + DICompositeType *DTy) { + for (auto Op : Expr->expr_ops()) { + if (Op.getOp() != dwarf::DW_OP_LLVM_fragment) + continue; + + uint64_t BitOffset = Op.getArg(0); + uint64_t BitSize = Op.getArg(1); + + for (auto *Element : DTy->getElements()) { + if (auto *Elem = dyn_cast(Element)) { + if (Elem->getSizeInBits() == BitSize && + Elem->getOffsetInBits() == BitOffset) + return Elem->getBaseType(); + } + } + // No matching member; synthesize. + return DIB.createBasicType(("int" + std::to_string(BitSize)).c_str(), + BitSize, dwarf::DW_ATE_signed); + } + return nullptr; +} + +/// Compute the DI type to use for a parameter given its IR Type Ty and original +/// DI type Orig (qualifiers stripped / first pointer returned). +/// Sets NeedSuffix when we “coerce” a composite to a fragment or wrap it in a +/// pointer. +static DIType *computeParamDIType(DIBuilder &DIB, Type *Ty, DIType *Orig, + unsigned PointerBitWidth, DIExpression *Expr, + bool &NeedSuffix) { + NeedSuffix = false; + DIType *Stripped = stripToBaseOrFirstPointer(Orig); + + if (Ty->isIntegerTy()) { + if (auto *Comp = dyn_cast_or_null(Stripped)) { + if (!Ty->isIntegerTy(Comp->getSizeInBits())) { + DIType *Frag = getIntTypeFromExpr(DIB, Expr, Comp); + if (Frag) + NeedSuffix = true; + return Frag; + } + // sizes match -> rare; accept fallthrough + } + unsigned W = cast(Ty)->getBitWidth(); + return DIB.createBasicType(("int" + std::to_string(W)).c_str(), W, + dwarf::DW_ATE_signed); + } + + if (Ty->isPointerTy()) { + if (auto *Comp = dyn_cast_or_null(Stripped)) { + NeedSuffix = true; // struct turned into pointer to struct + return DIB.createPointerType(Comp, PointerBitWidth); + } + if (auto *Der = dyn_cast_or_null(Stripped)) { + if (Der->getTag() == dwarf::DW_TAG_pointer_type) + return Der; // already a pointer in DI + } + // Generic pointer: synthesize pointer to pointer-sized int + DIType *Base = + DIB.createBasicType(("int" + std::to_string(PointerBitWidth)).c_str(), + PointerBitWidth, dwarf::DW_ATE_signed); + return DIB.createPointerType(Base, PointerBitWidth); + } + + if (Ty->isFloatingPointTy()) { + unsigned W = Ty->getScalarSizeInBits(); + return DIB.createBasicType(("float" + std::to_string(W)).c_str(), W, + dwarf::DW_ATE_float); + } + // Default to pointer-sized int + return DIB.createBasicType(("int" + std::to_string(PointerBitWidth)).c_str(), + PointerBitWidth, dwarf::DW_ATE_signed); +} + +/// Synthesize a DI type/name for a parameter we failed to match via dbg +/// records. +static std::pair +fallbackParam(DIBuilder &DIB, Function *F, unsigned Idx, unsigned PtrW) { + Type *Ty = F->getArg(Idx)->getType(); + unsigned W = Ty->isIntegerTy() ? cast(Ty)->getBitWidth() : 32; + DIType *BaseInt = DIB.createBasicType(("int" + std::to_string(W)).c_str(), W, + dwarf::DW_ATE_signed); + DIType *ParamTy = + Ty->isIntegerTy() ? BaseInt : DIB.createPointerType(BaseInt, PtrW); + std::string Name = F->getArg(Idx)->getName().str(); + if (Name.empty()) + Name = "__" + std::to_string(Idx); + return {ParamTy, Name}; +} + +/// Aggregate (struct/union) larger than pointer width? +static bool isLargeByValueAggregate(DIType *T, unsigned PtrW) { + DIType *P = stripToBaseOrFirstPointer(T); + if (auto *Comp = dyn_cast_or_null(P)) + return Comp->getSizeInBits() > PtrW; + return false; +} + +/// ===================== Argument collection ===================== + +/// Scan the entry block’s dbg records to deduce DI type & name for argument +/// Idx. Handles alloca-based byval lowering and the zext(i1)->i8 adjacent-use +/// pattern. Falls back to a synthesized type if no match. +static bool getOneArgDI(Module &M, unsigned Idx, BasicBlock &Entry, + DIBuilder &DIB, Function *F, DISubprogram *OldSP, + DISubprogram *NewSP, + SmallVectorImpl &TypeList, + SmallVectorImpl &ArgList, + unsigned PointerBitWidth) { + for (Instruction &I : Entry) { + for (DbgRecord &DR : I.getDbgRecordRange()) { + auto *DVR = dyn_cast(&DR); + if (!DVR) + continue; + + auto *VAM = dyn_cast_or_null(DVR->getRawLocation()); + if (!VAM) + continue; + + Value *LocV = VAM->getValue(); + if (!LocV) + continue; + + auto *Var = DVR->getVariable(); + if (!Var || !Var->getArg()) + continue; + + // Strip modifiers/pointers as in your original + DIType *DITy = Var->getType(); + while (auto *DTy = dyn_cast(DITy)) { + if (DTy->getTag() == dwarf::DW_TAG_pointer_type) { + DITy = DTy; + break; + } + DITy = DTy->getBaseType(); + } + + // Accept direct match, or special alloca/byval, or the zext(i1)->i8 case. + bool Matched = (LocV == F->getArg(Idx)); + if (!Matched) { + if (isa(LocV)) { + if (Var->getName() != F->getArg(Idx)->getName()) + continue; + Matched = true; + } else if (Instruction *Prev = I.getPrevNode()) { + if (auto *ZExt = dyn_cast(Prev)) + Matched = (ZExt->getOperand(0) == F->getArg(Idx) && LocV == Prev); + if (!Matched) + continue; + } else { + continue; + } + } + + Type *IRTy = F->getArg(Idx)->getType(); + bool NeedSuffix = false; + DIType *ParamType = + computeParamDIType(DIB, IRTy, Var->getType(), PointerBitWidth, + DVR->getExpression(), NeedSuffix); + if (!ParamType) + return false; + + TypeList.push_back(ParamType); + + std::string ArgName = F->getArg(Idx)->getName().str(); + if (ArgName.empty()) { + ArgName = Var->getName().str(); + if (NeedSuffix) + ArgName += "__" + std::to_string(Idx); + } + + auto *NewVar = DIB.createParameterVariable( + NewSP, StringRef(ArgName), Idx + 1, OldSP->getUnit()->getFile(), + OldSP->getLine(), ParamType); + ArgList.push_back(NewVar); + return true; + } + } + + // Fallback (unused/poison argument) + auto [ParamTy, Name] = fallbackParam(DIB, F, Idx, PointerBitWidth); + TypeList.push_back(ParamTy); + auto *NewVar = DIB.createParameterVariable(NewSP, StringRef(Name), Idx + 1, + OldSP->getUnit()->getFile(), + OldSP->getLine(), ParamTy); + ArgList.push_back(NewVar); + return true; +} + +static bool collectReturnAndArgs(Module &M, DIBuilder &DIB, Function *F, + DISubprogram *OldSP, DISubprogram *NewSP, + SmallVectorImpl &TypeList, + SmallVectorImpl &ArgList, + unsigned PointerBitWidth) { + FunctionType *FTy = F->getFunctionType(); + Type *RetTy = FTy->getReturnType(); + + if (RetTy->isVoidTy()) { + TypeList.push_back(nullptr); + } else { + // Non-void return type is assumed unchanged by optimization. + DITypeRefArray TyArray = OldSP->getType()->getTypeArray(); + TypeList.push_back(TyArray[0]); + } + + BasicBlock &Entry = F->getEntryBlock(); + for (unsigned i = 0, n = FTy->getNumParams(); i < n; ++i) { + if (!getOneArgDI(M, i, Entry, DIB, F, OldSP, NewSP, TypeList, ArgList, + PointerBitWidth)) + return false; + } + return true; +} + +/// ===================== Per-function transform ===================== + +static void generateDebugInfo(Module &M, Function *F, + unsigned PointerBitWidth) { + DISubprogram *OldSP = F->getSubprogram(); + DICompileUnit *CU = OldSP->getUnit(); + DIBuilder DIB(M, /*AllowUnresolved=*/false, CU); + + SmallVector TypeList, ArgList; + + // Create a fresh “artificial” subprogram (type/args filled later). + DISubprogram *NewSP = + DIB.createFunction(OldSP->getScope(), // Scope + F->getName(), // Name + F->getName(), // Linkage name + CU->getFile(), // File + OldSP->getLine(), // Line + nullptr, // DISubroutineType + OldSP->getScopeLine(), // ScopeLine + DINode::FlagZero | DINode::FlagArtificial, + DISubprogram::SPFlagDefinition); + + bool Success = collectReturnAndArgs(M, DIB, F, OldSP, NewSP, TypeList, + ArgList, PointerBitWidth); + if (!Success) { + // Cannot decide a signature: mark the old one nocall and bail out. + auto Temp = OldSP->getType()->cloneWithCC(llvm::dwarf::DW_CC_nocall); + OldSP->replaceType(MDNode::replaceWithPermanent(std::move(Temp))); + DIB.finalize(); + return; + } + + // Install new type + retained params. + DITypeRefArray DITypeArray = DIB.getOrCreateTypeArray(TypeList); + auto *SubroutineType = DIB.createSubroutineType(DITypeArray); + NewSP->replaceType(SubroutineType); + NewSP->replaceRetainedNodes(DIB.getOrCreateArray(ArgList)); + F->setSubprogram(NewSP); + + // Reanchor all DILocations (DbgRecord stream + Instruction DebugLoc + + // MD_loop). + LLVMContext &Ctx = M.getContext(); + const auto Reanchor = [&](const DILocation *Old) -> const DILocation * { + return reanchorDILocChain(Old, NewSP, Ctx); + }; + + for (BasicBlock &BB : *F) { + for (Instruction &I : BB) { + for (DbgRecord &DR : I.getDbgRecordRange()) { + if (DebugLoc DL = DR.getDebugLoc()) + DR.setDebugLoc( + DebugLoc(const_cast(Reanchor(DL.get())))); + } + if (DebugLoc DL = I.getDebugLoc()) + I.setDebugLoc(DebugLoc(const_cast(Reanchor(DL.get())))); + if (MDNode *LoopID = I.getMetadata(LLVMContext::MD_loop)) { + MDNode *New = cloneLoopIDReplacingAllDILocs(LoopID, Reanchor, Ctx); + I.setMetadata(LLVMContext::MD_loop, New); + } + } + } + + // Insert dbg.values for the real IR arguments at function entry. + if (unsigned NumArgs = F->getFunctionType()->getNumParams()) { + auto IP = F->getEntryBlock().getFirstInsertionPt(); + const DILocation *Top = DILocation::get(Ctx, 0, 0, NewSP); + for (int i = (int)NumArgs - 1; i >= 0; --i) { + auto *Var = cast(ArgList[i]); + DIB.insertDbgValueIntrinsic(F->getArg(i), Var, DIB.createExpression(), + Top, IP); + } + } + + DIB.finalize(); +} + +/// ===================== Pass driver ===================== + +PreservedAnalyses EmitChangedFuncDebugInfoPass::run(Module &M, + ModuleAnalysisManager &AM) { + if (DisableChangedFuncDBInfo) + return PreservedAnalyses::all(); + + // C-only + for (DICompileUnit *CU : M.debug_compile_units()) { + auto L = CU->getSourceLanguage().getUnversionedName(); + if (L != dwarf::DW_LANG_C && L != dwarf::DW_LANG_C89 && + L != dwarf::DW_LANG_C99 && L != dwarf::DW_LANG_C11 && + L != dwarf::DW_LANG_C17) + return PreservedAnalyses::all(); + } + + Triple T(M.getTargetTriple()); + if (T.isBPF()) // BPF: LLVM emits BTF; skip here for now. + return PreservedAnalyses::all(); + + const unsigned PointerBitWidth = T.getArchPointerBitWidth(); + + SmallVector ChangedFuncs; + for (Function &F : M) { + if (F.isIntrinsic() || F.isDeclaration()) + continue; + DISubprogram *SP = F.getSubprogram(); + if (!SP) + continue; + + DITypeRefArray TyArray = SP->getType()->getTypeArray(); + if (TyArray.size() == 0) + continue; + + // Skip if return is a large aggregate (> pointer size). + { + DIType *RetDI = stripToBaseOrFirstPointer(TyArray[0]); + if (auto *Comp = dyn_cast_or_null(RetDI)) + if (Comp->getSizeInBits() > PointerBitWidth) + continue; + } + + // Skip varargs originals. + if (TyArray.size() > 1 && TyArray[TyArray.size() - 1] == nullptr) + continue; + + // Consider signature "changed" if any arg is a large by-value aggregate. + bool SigChanged = false; + if (!F.getName().contains('.')) { + uint8_t cc = SP->getType()->getCC(); + if (cc != dwarf::DW_CC_nocall) { + for (unsigned i = 1; i < TyArray.size(); ++i) { + if (isLargeByValueAggregate(TyArray[i], PointerBitWidth)) { + SigChanged = true; + break; + } + } + if (!SigChanged) + continue; + } + } + + // Reset CC to DW_CC_normal; we’ll mark the new SP as Artificial. + auto Temp = SP->getType()->cloneWithCC(llvm::dwarf::DW_CC_normal); + SP->replaceType(MDNode::replaceWithPermanent(std::move(Temp))); + + ChangedFuncs.push_back(&F); + } + + for (Function *F : ChangedFuncs) + generateDebugInfo(M, F, PointerBitWidth); + + return ChangedFuncs.empty() ? PreservedAnalyses::all() + : PreservedAnalyses::none(); +} diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll index 94e860b8ce304..650bcd6f0f98d 100644 --- a/llvm/test/Other/new-pm-defaults.ll +++ b/llvm/test/Other/new-pm-defaults.ll @@ -295,6 +295,8 @@ ; CHECK-DEFAULT-NEXT: Running pass: CGProfilePass ; CHECK-DEFAULT-NEXT: Running pass: RelLookupTableConverterPass ; CHECK-LTO-NOT: Running pass: RelLookupTableConverterPass +; CHECK-DEFAULT-NEXT: Running pass: EmitChangedFuncDebugInfoPass +; CHECK-LTO-NOT: Running pass: EmitChangedFuncDebugInfoPass ; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo ; CHECK-LTO-NEXT: Running pass: CanonicalizeAliasesPass ; CHECK-LTO-NEXT: Running pass: NameAnonGlobalPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll index a08a140a35166..b913cd3e2d90b 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll @@ -208,6 +208,7 @@ ; CHECK-POSTLINK-O-NEXT: Running pass: ConstantMergePass ; CHECK-POSTLINK-O-NEXT: Running pass: CGProfilePass ; CHECK-POSTLINK-O-NEXT: Running pass: RelLookupTableConverterPass +; CHECK-POSTLINK-O-NEXT: Running pass: EmitChangedFuncDebugInfoPass ; CHECK-EP-OPT-EARLY-NEXT: Running pass: NoOpModulePass ; CHECK-EP-OPT-LAST-NEXT: Running pass: NoOpModulePass ; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll index d9e2dd37a7985..38e3238b3c170 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll @@ -192,6 +192,7 @@ ; CHECK-O-NEXT: Running pass: ConstantMergePass ; CHECK-O-NEXT: Running pass: CGProfilePass ; CHECK-O-NEXT: Running pass: RelLookupTableConverterPass +; CHECK-O-NEXT: Running pass: EmitChangedFuncDebugInfoPass ; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo ; CHECK-O-NEXT: Running pass: PrintModulePass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll index 2f6fa4b27d354..2ec67d01424e7 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll @@ -201,6 +201,7 @@ ; CHECK-O-NEXT: Running pass: ConstantMergePass ; CHECK-O-NEXT: Running pass: CGProfilePass ; CHECK-O-NEXT: Running pass: RelLookupTableConverterPass +; CHECK-O-NEXT: Running pass: EmitChangedFuncDebugInfoPass ; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo ; CHECK-O-NEXT: Running pass: PrintModulePass diff --git a/llvm/test/Transforms/ArgumentPromotion/dbg.ll b/llvm/test/Transforms/ArgumentPromotion/dbg.ll index 6a14facfb36a2..ce86aaa3884de 100644 --- a/llvm/test/Transforms/ArgumentPromotion/dbg.ll +++ b/llvm/test/Transforms/ArgumentPromotion/dbg.ll @@ -53,7 +53,11 @@ define void @caller(ptr %Y, ptr %P) { !0 = !{i32 2, !"Debug Info Version", i32 3} !1 = !DILocation(line: 8, scope: !2) -!2 = distinct !DISubprogram(name: "test", file: !5, line: 3, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !3, scopeLine: 3, scope: null) +!2 = distinct !DISubprogram(name: "test", file: !5, line: 3, type: !7, isLocal: true, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !3, scopeLine: 3, scope: null) !3 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: LineTablesOnly, file: !5) !5 = !DIFile(filename: "test.c", directory: "") !6 = !DILocation(line: 9, scope: !2) +!7 = !DISubroutineType(types: !8) +!8 = !{null, !9} +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) diff --git a/llvm/test/Transforms/SampleProfile/ctxsplit.ll b/llvm/test/Transforms/SampleProfile/ctxsplit.ll index 46e088a63e941..4acd8b5861c14 100644 --- a/llvm/test/Transforms/SampleProfile/ctxsplit.ll +++ b/llvm/test/Transforms/SampleProfile/ctxsplit.ll @@ -51,9 +51,11 @@ attributes #0 = { "use-sample-profile" } !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{!"clang version 8.0.0 (trunk 345241)"} -!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2) +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !12, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2) !8 = !DISubroutineType(types: !2) !9 = !DILocation(line: 2, column: 3, scope: !7) -!10 = distinct !DISubprogram(name: "goo", scope: !1, file: !1, line: 8, type: !8, isLocal: false, isDefinition: true, scopeLine: 8, isOptimized: true, unit: !0, retainedNodes: !2) +!10 = distinct !DISubprogram(name: "goo", scope: !1, file: !1, line: 8, type: !12, isLocal: false, isDefinition: true, scopeLine: 8, isOptimized: true, unit: !0, retainedNodes: !2) !11 = !DILocation(line: 10, column: 3, scope: !10) - +!12 = !DISubroutineType(types: !13) +!13 = !{!14} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) diff --git a/llvm/test/Transforms/SampleProfile/flattened.ll b/llvm/test/Transforms/SampleProfile/flattened.ll index acc6459c99a33..e92264f693bb8 100644 --- a/llvm/test/Transforms/SampleProfile/flattened.ll +++ b/llvm/test/Transforms/SampleProfile/flattened.ll @@ -31,6 +31,9 @@ entry: !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{!"clang version 8.0.0 (trunk 345241)"} -!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2) +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !10, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2) !8 = !DISubroutineType(types: !2) !9 = !DILocation(line: 2, column: 3, scope: !7) +!10 = !DISubroutineType(types: !11) +!11 = !{!12} +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) diff --git a/llvm/test/Transforms/Util/emit-changed-func-debuginfo-argpromotion.ll b/llvm/test/Transforms/Util/emit-changed-func-debuginfo-argpromotion.ll new file mode 100644 index 0000000000000..690ade65ee6c0 --- /dev/null +++ b/llvm/test/Transforms/Util/emit-changed-func-debuginfo-argpromotion.ll @@ -0,0 +1,104 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -S -mtriple=x86_64-unknown-unknown -passes=emit-changed-func-debuginfo < %s | FileCheck %s + +; Source code: +; // clang -S -emit-llvm -O3 -g test.c -mllvm -disable-changed-func-dbinfo +; __attribute__((noinline)) static int callee(const int *p) { return *p + 42; } +; int caller(void) { +; int x = 100; +; return callee(&x); +; } + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable +define dso_local range(i32 -2147483606, -2147483648) i32 @caller() local_unnamed_addr #0 !dbg !10 { +; CHECK-LABEL: define dso_local range(i32 -2147483606, -2147483648) i32 @caller( +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !dbg [[DBG10:![0-9]+]] { +; CHECK-NEXT: #dbg_value(i32 100, [[META15:![0-9]+]], !DIExpression(), [[META16:![0-9]+]]) +; CHECK-NEXT: [[TMP1:%.*]] = tail call fastcc i32 @callee(i32 100), !dbg [[DBG17:![0-9]+]] +; CHECK-NEXT: ret i32 [[TMP1]], !dbg [[DBG18:![0-9]+]] +; + #dbg_value(i32 100, !15, !DIExpression(), !16) + %1 = tail call fastcc i32 @callee(i32 100), !dbg !17 + ret i32 %1, !dbg !18 +} + +; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable +define internal fastcc range(i32 -2147483606, -2147483648) i32 @callee(i32 %0) unnamed_addr #1 !dbg !19 { +; CHECK-LABEL: define internal fastcc range(i32 -2147483606, -2147483648) i32 @callee( +; CHECK-SAME: i32 [[TMP0:%.*]]) unnamed_addr #[[ATTR1:[0-9]+]] !dbg [[DBG19:![0-9]+]] { +; CHECK-NEXT: #dbg_value(i32 [[TMP0]], [[META24:![0-9]+]], !DIExpression(), [[META25:![0-9]+]]) +; CHECK-NEXT: #dbg_value(ptr poison, [[META26:![0-9]+]], !DIExpression(), [[META33:![0-9]+]]) +; CHECK-NEXT: [[TMP2:%.*]] = add nsw i32 [[TMP0]], 42, !dbg [[DBG34:![0-9]+]] +; CHECK-NEXT: ret i32 [[TMP2]], !dbg [[DBG35:![0-9]+]] +; + #dbg_value(ptr poison, !25, !DIExpression(), !26) + %2 = add nsw i32 %0, 42, !dbg !27 + ret i32 %2, !dbg !28 +} + +attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git (git@github.com:yonghong-song/llvm-project.git 8e5d24efc7dac78e8ba568dfe2fc6cfbe9663b13)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/tests/sig-change/prom", checksumkind: CSK_MD5, checksum: "f42f3fd1477418a2e17b444f656351ff") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 8, !"PIC Level", i32 2} +!6 = !{i32 7, !"PIE Level", i32 2} +!7 = !{i32 7, !"uwtable", i32 2} +!8 = !{i32 7, !"debug-info-assignment-tracking", i1 true} +!9 = !{!"clang version 22.0.0git (git@github.com:yonghong-song/llvm-project.git 8e5d24efc7dac78e8ba568dfe2fc6cfbe9663b13)"} +!10 = distinct !DISubprogram(name: "caller", scope: !1, file: !1, line: 2, type: !11, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14, keyInstructions: true) +!11 = !DISubroutineType(types: !12) +!12 = !{!13} +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!14 = !{!15} +!15 = !DILocalVariable(name: "x", scope: !10, file: !1, line: 3, type: !13) +!16 = !DILocation(line: 0, scope: !10) +!17 = !DILocation(line: 4, column: 10, scope: !10, atomGroup: 3, atomRank: 2) +!18 = !DILocation(line: 4, column: 3, scope: !10, atomGroup: 3, atomRank: 1) +!19 = distinct !DISubprogram(name: "callee", scope: !1, file: !1, line: 1, type: !20, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !24, keyInstructions: true) +!20 = !DISubroutineType(cc: DW_CC_nocall, types: !21) +!21 = !{!13, !22} +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) +!23 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13) +!24 = !{!25} +!25 = !DILocalVariable(name: "p", arg: 1, scope: !19, file: !1, line: 1, type: !22) +!26 = !DILocation(line: 0, scope: !19) +!27 = !DILocation(line: 1, column: 71, scope: !19, atomGroup: 1, atomRank: 2) +!28 = !DILocation(line: 1, column: 61, scope: !19, atomGroup: 1, atomRank: 1) +;. +; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], producer: "{{.*}}clang version {{.*}}", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +; CHECK: [[META1]] = !DIFile(filename: "{{.*}}test.c", directory: {{.*}}) +; CHECK: [[DBG10]] = distinct !DISubprogram(name: "caller", scope: [[META1]], file: [[META1]], line: 2, type: [[META11:![0-9]+]], scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META14:![0-9]+]], keyInstructions: true) +; CHECK: [[META11]] = !DISubroutineType(types: [[META12:![0-9]+]]) +; CHECK: [[META12]] = !{[[META13:![0-9]+]]} +; CHECK: [[META13]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +; CHECK: [[META14]] = !{[[META15]]} +; CHECK: [[META15]] = !DILocalVariable(name: "x", scope: [[DBG10]], file: [[META1]], line: 3, type: [[META13]]) +; CHECK: [[META16]] = !DILocation(line: 0, scope: [[DBG10]]) +; CHECK: [[DBG17]] = !DILocation(line: 4, column: 10, scope: [[DBG10]], atomGroup: 3, atomRank: 2) +; CHECK: [[DBG18]] = !DILocation(line: 4, column: 3, scope: [[DBG10]], atomGroup: 3, atomRank: 1) +; CHECK: [[DBG19]] = distinct !DISubprogram(name: "callee", linkageName: "callee", scope: [[META1]], file: [[META1]], line: 1, type: [[META20:![0-9]+]], scopeLine: 1, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META23:![0-9]+]]) +; CHECK: [[META20]] = !DISubroutineType(types: [[META21:![0-9]+]]) +; CHECK: [[META21]] = !{[[META13]], [[META22:![0-9]+]]} +; CHECK: [[META22]] = !DIBasicType(name: "int32", size: 32, encoding: DW_ATE_signed) +; CHECK: [[META23]] = !{} +; CHECK: [[META24]] = !DILocalVariable(name: "__0", arg: 1, scope: [[DBG19]], file: [[META1]], line: 1, type: [[META22]]) +; CHECK: [[META25]] = !DILocation(line: 0, scope: [[DBG19]]) +; CHECK: [[META26]] = !DILocalVariable(name: "p", arg: 1, scope: [[META27:![0-9]+]], file: [[META1]], line: 1, type: [[META30:![0-9]+]]) +; CHECK: [[META27]] = distinct !DISubprogram(name: "callee", scope: [[META1]], file: [[META1]], line: 1, type: [[META28:![0-9]+]], scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META32:![0-9]+]], keyInstructions: true) +; CHECK: [[META28]] = !DISubroutineType(cc: DW_CC_normal, types: [[META29:![0-9]+]]) +; CHECK: [[META29]] = !{[[META13]], [[META30]]} +; CHECK: [[META30]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META31:![0-9]+]], size: 64) +; CHECK: [[META31]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: [[META13]]) +; CHECK: [[META32]] = !{[[META26]]} +; CHECK: [[META33]] = !DILocation(line: 0, scope: [[META27]], inlinedAt: [[META25]]) +; CHECK: [[DBG34]] = !DILocation(line: 1, column: 71, scope: [[META27]], inlinedAt: [[META25]], atomGroup: 1, atomRank: 2) +; CHECK: [[DBG35]] = !DILocation(line: 1, column: 61, scope: [[META27]], inlinedAt: [[META25]], atomGroup: 1, atomRank: 1) +;. diff --git a/llvm/test/Transforms/Util/emit-changed-func-debuginfo-deadarg.ll b/llvm/test/Transforms/Util/emit-changed-func-debuginfo-deadarg.ll new file mode 100644 index 0000000000000..3f01fb7403a88 --- /dev/null +++ b/llvm/test/Transforms/Util/emit-changed-func-debuginfo-deadarg.ll @@ -0,0 +1,133 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -S -mtriple=x86_64-unknown-unknown -passes=emit-changed-func-debuginfo < %s | FileCheck %s + +; Source code: +; // clang -O2 -S -emit-llvm -g test.c -mllvm -disable-changed-func-dbinfo +; struct t { int a; }; +; char *tar(struct t *a, struct t *d); +; __attribute__((noinline)) static char * foo(struct t *a, struct t *d, int b) +; { +; return tar(a, d); +; } +; char *bar(struct t *a, struct t *d) +; { +; return foo(a, d, 1); +; } + +; Function Attrs: nounwind uwtable +define dso_local ptr @bar(ptr noundef %0, ptr noundef %1) local_unnamed_addr #0 !dbg !10 { +; CHECK-LABEL: define dso_local ptr @bar( +; CHECK-SAME: ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] !dbg [[DBG10:![0-9]+]] { +; CHECK-NEXT: #dbg_value(ptr [[TMP0]], [[META21:![0-9]+]], !DIExpression(), [[META23:![0-9]+]]) +; CHECK-NEXT: #dbg_value(ptr [[TMP1]], [[META22:![0-9]+]], !DIExpression(), [[META23]]) +; CHECK-NEXT: [[TMP3:%.*]] = tail call fastcc ptr @foo(ptr noundef [[TMP0]], ptr noundef [[TMP1]]), !dbg [[DBG24:![0-9]+]] +; CHECK-NEXT: ret ptr [[TMP3]], !dbg [[DBG25:![0-9]+]] +; + #dbg_value(ptr %0, !21, !DIExpression(), !23) + #dbg_value(ptr %1, !22, !DIExpression(), !23) + %3 = tail call fastcc ptr @foo(ptr noundef %0, ptr noundef %1), !dbg !24 + ret ptr %3, !dbg !25 +} + +; Function Attrs: noinline nounwind uwtable +define internal fastcc ptr @foo(ptr noundef %0, ptr noundef %1) unnamed_addr #1 !dbg !26 { +; CHECK-LABEL: define internal fastcc ptr @foo( +; CHECK-SAME: ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) unnamed_addr #[[ATTR1:[0-9]+]] !dbg [[DBG26:![0-9]+]] { +; CHECK-NEXT: #dbg_value(ptr [[TMP0]], [[META28:![0-9]+]], !DIExpression(), [[META29:![0-9]+]]) +; CHECK-NEXT: #dbg_value(ptr [[TMP1]], [[META30:![0-9]+]], !DIExpression(), [[META29]]) +; CHECK-NEXT: #dbg_value(ptr [[TMP0]], [[META31:![0-9]+]], !DIExpression(), [[META38:![0-9]+]]) +; CHECK-NEXT: #dbg_value(ptr [[TMP1]], [[META36:![0-9]+]], !DIExpression(), [[META38]]) +; CHECK-NEXT: #dbg_value(i32 poison, [[META37:![0-9]+]], !DIExpression(), [[META38]]) +; CHECK-NEXT: [[TMP3:%.*]] = tail call ptr @tar(ptr noundef [[TMP0]], ptr noundef [[TMP1]]) #[[ATTR3:[0-9]+]], !dbg [[DBG39:![0-9]+]] +; CHECK-NEXT: ret ptr [[TMP3]], !dbg [[DBG40:![0-9]+]] +; + #dbg_value(ptr %0, !30, !DIExpression(), !33) + #dbg_value(ptr %1, !31, !DIExpression(), !33) + #dbg_value(i32 poison, !32, !DIExpression(), !33) + %3 = tail call ptr @tar(ptr noundef %0, ptr noundef %1) #3, !dbg !34 + ret ptr %3, !dbg !35 +} + +declare !dbg !36 ptr @tar(ptr noundef, ptr noundef) local_unnamed_addr #2 + +attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { noinline nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git (git@github.com:yonghong-song/llvm-project.git 8e5d24efc7dac78e8ba568dfe2fc6cfbe9663b13)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/tests/sig-change/deadarg", checksumkind: CSK_MD5, checksum: "54bc89245cb23f69a8eb94fe2fb50a09") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 8, !"PIC Level", i32 2} +!6 = !{i32 7, !"PIE Level", i32 2} +!7 = !{i32 7, !"uwtable", i32 2} +!8 = !{i32 7, !"debug-info-assignment-tracking", i1 true} +!9 = !{!"clang version 22.0.0git (git@github.com:yonghong-song/llvm-project.git 8e5d24efc7dac78e8ba568dfe2fc6cfbe9663b13)"} +!10 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 7, type: !11, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !20, keyInstructions: true) +!11 = !DISubroutineType(types: !12) +!12 = !{!13, !15, !15} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !1, line: 1, size: 32, elements: !17) +!17 = !{!18} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !16, file: !1, line: 1, baseType: !19, size: 32) +!19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!20 = !{!21, !22} +!21 = !DILocalVariable(name: "a", arg: 1, scope: !10, file: !1, line: 7, type: !15) +!22 = !DILocalVariable(name: "d", arg: 2, scope: !10, file: !1, line: 7, type: !15) +!23 = !DILocation(line: 0, scope: !10) +!24 = !DILocation(line: 9, column: 10, scope: !10, atomGroup: 1, atomRank: 2) +!25 = !DILocation(line: 9, column: 3, scope: !10, atomGroup: 1, atomRank: 1) +!26 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !27, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !29, keyInstructions: true) +!27 = !DISubroutineType(cc: DW_CC_nocall, types: !28) +!28 = !{!13, !15, !15, !19} +!29 = !{!30, !31, !32} +!30 = !DILocalVariable(name: "a", arg: 1, scope: !26, file: !1, line: 3, type: !15) +!31 = !DILocalVariable(name: "d", arg: 2, scope: !26, file: !1, line: 3, type: !15) +!32 = !DILocalVariable(name: "b", arg: 3, scope: !26, file: !1, line: 3, type: !19) +!33 = !DILocation(line: 0, scope: !26) +!34 = !DILocation(line: 5, column: 10, scope: !26, atomGroup: 1, atomRank: 2) +!35 = !DILocation(line: 5, column: 3, scope: !26, atomGroup: 1, atomRank: 1) +!36 = !DISubprogram(name: "tar", scope: !1, file: !1, line: 2, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) +;. +; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], producer: "{{.*}}clang version {{.*}}", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +; CHECK: [[META1]] = !DIFile(filename: "{{.*}}test.c", directory: {{.*}}) +; CHECK: [[DBG10]] = distinct !DISubprogram(name: "bar", scope: [[META1]], file: [[META1]], line: 7, type: [[META11:![0-9]+]], scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META20:![0-9]+]], keyInstructions: true) +; CHECK: [[META11]] = !DISubroutineType(types: [[META12:![0-9]+]]) +; CHECK: [[META12]] = !{[[META13:![0-9]+]], [[META15:![0-9]+]], [[META15]]} +; CHECK: [[META13]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META14:![0-9]+]], size: 64) +; CHECK: [[META14]] = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +; CHECK: [[META15]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META16:![0-9]+]], size: 64) +; CHECK: [[META16]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: [[META1]], line: 1, size: 32, elements: [[META17:![0-9]+]]) +; CHECK: [[META17]] = !{[[META18:![0-9]+]]} +; CHECK: [[META18]] = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: [[META16]], file: [[META1]], line: 1, baseType: [[META19:![0-9]+]], size: 32) +; CHECK: [[META19]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +; CHECK: [[META20]] = !{[[META21]], [[META22]]} +; CHECK: [[META21]] = !DILocalVariable(name: "a", arg: 1, scope: [[DBG10]], file: [[META1]], line: 7, type: [[META15]]) +; CHECK: [[META22]] = !DILocalVariable(name: "d", arg: 2, scope: [[DBG10]], file: [[META1]], line: 7, type: [[META15]]) +; CHECK: [[META23]] = !DILocation(line: 0, scope: [[DBG10]]) +; CHECK: [[DBG24]] = !DILocation(line: 9, column: 10, scope: [[DBG10]], atomGroup: 1, atomRank: 2) +; CHECK: [[DBG25]] = !DILocation(line: 9, column: 3, scope: [[DBG10]], atomGroup: 1, atomRank: 1) +; CHECK: [[DBG26]] = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: [[META1]], file: [[META1]], line: 3, type: [[META11]], scopeLine: 4, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META27:![0-9]+]]) +; CHECK: [[META27]] = !{} +; CHECK: [[META28]] = !DILocalVariable(name: "a", arg: 1, scope: [[DBG26]], file: [[META1]], line: 3, type: [[META15]]) +; CHECK: [[META29]] = !DILocation(line: 0, scope: [[DBG26]]) +; CHECK: [[META30]] = !DILocalVariable(name: "d", arg: 2, scope: [[DBG26]], file: [[META1]], line: 3, type: [[META15]]) +; CHECK: [[META31]] = !DILocalVariable(name: "a", arg: 1, scope: [[META32:![0-9]+]], file: [[META1]], line: 3, type: [[META15]]) +; CHECK: [[META32]] = distinct !DISubprogram(name: "foo", scope: [[META1]], file: [[META1]], line: 3, type: [[META33:![0-9]+]], scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META35:![0-9]+]], keyInstructions: true) +; CHECK: [[META33]] = !DISubroutineType(cc: DW_CC_normal, types: [[META34:![0-9]+]]) +; CHECK: [[META34]] = !{[[META13]], [[META15]], [[META15]], [[META19]]} +; CHECK: [[META35]] = !{[[META31]], [[META36]], [[META37]]} +; CHECK: [[META36]] = !DILocalVariable(name: "d", arg: 2, scope: [[META32]], file: [[META1]], line: 3, type: [[META15]]) +; CHECK: [[META37]] = !DILocalVariable(name: "b", arg: 3, scope: [[META32]], file: [[META1]], line: 3, type: [[META19]]) +; CHECK: [[META38]] = !DILocation(line: 0, scope: [[META32]], inlinedAt: [[META29]]) +; CHECK: [[DBG39]] = !DILocation(line: 5, column: 10, scope: [[META32]], inlinedAt: [[META29]], atomGroup: 1, atomRank: 2) +; CHECK: [[DBG40]] = !DILocation(line: 5, column: 3, scope: [[META32]], inlinedAt: [[META29]], atomGroup: 1, atomRank: 1) +;. diff --git a/llvm/test/Transforms/Util/emit-changed-func-debuginfo-struct-16B.ll b/llvm/test/Transforms/Util/emit-changed-func-debuginfo-struct-16B.ll new file mode 100644 index 0000000000000..579faf43cdf11 --- /dev/null +++ b/llvm/test/Transforms/Util/emit-changed-func-debuginfo-struct-16B.ll @@ -0,0 +1,80 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -S -mtriple=x86_64-unknown-unknown -passes=emit-changed-func-debuginfo < %s | FileCheck %s + +; Source code: +; // clang -O2 -S -emit-llvm -g test1.c -mllvm -disable-changed-func-dbinfo +; struct t { long a; long b; }; +; long foo(struct t arg) { +; return arg.a * arg.b; +; } + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable +define dso_local i64 @foo(i64 %0, i64 %1) local_unnamed_addr #0 !dbg !10 { +; CHECK-LABEL: define dso_local i64 @foo( +; CHECK-SAME: i64 [[TMP0:%.*]], i64 [[TMP1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] !dbg [[DBG10:![0-9]+]] { +; CHECK-NEXT: #dbg_value(i64 [[TMP0]], [[META15:![0-9]+]], !DIExpression(), [[META16:![0-9]+]]) +; CHECK-NEXT: #dbg_value(i64 [[TMP1]], [[META17:![0-9]+]], !DIExpression(), [[META16]]) +; CHECK-NEXT: #dbg_value(i64 [[TMP0]], [[META18:![0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 64), [[META27:![0-9]+]]) +; CHECK-NEXT: #dbg_value(i64 [[TMP1]], [[META18]], !DIExpression(DW_OP_LLVM_fragment, 64, 64), [[META27]]) +; CHECK-NEXT: [[TMP3:%.*]] = mul nsw i64 [[TMP1]], [[TMP0]], !dbg [[DBG28:![0-9]+]] +; CHECK-NEXT: ret i64 [[TMP3]], !dbg [[DBG29:![0-9]+]] +; + #dbg_value(i64 %0, !19, !DIExpression(DW_OP_LLVM_fragment, 0, 64), !20) + #dbg_value(i64 %1, !19, !DIExpression(DW_OP_LLVM_fragment, 64, 64), !20) + %3 = mul nsw i64 %1, %0, !dbg !21 + ret i64 %3, !dbg !22 +} + +attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git (git@github.com:yonghong-song/llvm-project.git 8e5d24efc7dac78e8ba568dfe2fc6cfbe9663b13)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test1.c", directory: "/tmp/home/yhs/tests/sig-change/struct", checksumkind: CSK_MD5, checksum: "bd0d0ce5cc67e004962a79d888a27468") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 8, !"PIC Level", i32 2} +!6 = !{i32 7, !"PIE Level", i32 2} +!7 = !{i32 7, !"uwtable", i32 2} +!8 = !{i32 7, !"debug-info-assignment-tracking", i1 true} +!9 = !{!"clang version 22.0.0git (git@github.com:yonghong-song/llvm-project.git 8e5d24efc7dac78e8ba568dfe2fc6cfbe9663b13)"} +!10 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !11, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !18, keyInstructions: true) +!11 = !DISubroutineType(types: !12) +!12 = !{!13, !14} +!13 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !1, line: 1, size: 128, elements: !15) +!15 = !{!16, !17} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !14, file: !1, line: 1, baseType: !13, size: 64) +!17 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 1, baseType: !13, size: 64, offset: 64) +!18 = !{!19} +!19 = !DILocalVariable(name: "arg", arg: 1, scope: !10, file: !1, line: 2, type: !14) +!20 = !DILocation(line: 0, scope: !10) +!21 = !DILocation(line: 3, column: 16, scope: !10, atomGroup: 1, atomRank: 2) +!22 = !DILocation(line: 3, column: 3, scope: !10, atomGroup: 1, atomRank: 1) +;. +; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], producer: "{{.*}}clang version {{.*}}", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +; CHECK: [[META1]] = !DIFile(filename: "{{.*}}test1.c", directory: {{.*}}) +; CHECK: [[DBG10]] = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: [[META1]], file: [[META1]], line: 2, type: [[META11:![0-9]+]], scopeLine: 2, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META14:![0-9]+]]) +; CHECK: [[META11]] = !DISubroutineType(types: [[META12:![0-9]+]]) +; CHECK: [[META12]] = !{[[META13:![0-9]+]], [[META13]], [[META13]]} +; CHECK: [[META13]] = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) +; CHECK: [[META14]] = !{} +; CHECK: [[META15]] = !DILocalVariable(name: "arg__0", arg: 1, scope: [[DBG10]], file: [[META1]], line: 2, type: [[META13]]) +; CHECK: [[META16]] = !DILocation(line: 0, scope: [[DBG10]]) +; CHECK: [[META17]] = !DILocalVariable(name: "arg__1", arg: 2, scope: [[DBG10]], file: [[META1]], line: 2, type: [[META13]]) +; CHECK: [[META18]] = !DILocalVariable(name: "arg", arg: 1, scope: [[META19:![0-9]+]], file: [[META1]], line: 2, type: [[META22:![0-9]+]]) +; CHECK: [[META19]] = distinct !DISubprogram(name: "foo", scope: [[META1]], file: [[META1]], line: 2, type: [[META20:![0-9]+]], scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META26:![0-9]+]], keyInstructions: true) +; CHECK: [[META20]] = !DISubroutineType(cc: DW_CC_normal, types: [[META21:![0-9]+]]) +; CHECK: [[META21]] = !{[[META13]], [[META22]]} +; CHECK: [[META22]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: [[META1]], line: 1, size: 128, elements: [[META23:![0-9]+]]) +; CHECK: [[META23]] = !{[[META24:![0-9]+]], [[META25:![0-9]+]]} +; CHECK: [[META24]] = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: [[META22]], file: [[META1]], line: 1, baseType: [[META13]], size: 64) +; CHECK: [[META25]] = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: [[META22]], file: [[META1]], line: 1, baseType: [[META13]], size: 64, offset: 64) +; CHECK: [[META26]] = !{[[META18]]} +; CHECK: [[META27]] = !DILocation(line: 0, scope: [[META19]], inlinedAt: [[META16]]) +; CHECK: [[DBG28]] = !DILocation(line: 3, column: 16, scope: [[META19]], inlinedAt: [[META16]], atomGroup: 1, atomRank: 2) +; CHECK: [[DBG29]] = !DILocation(line: 3, column: 3, scope: [[META19]], inlinedAt: [[META16]], atomGroup: 1, atomRank: 1) +;. diff --git a/llvm/test/Transforms/Util/emit-changed-func-debuginfo-struct-large.ll b/llvm/test/Transforms/Util/emit-changed-func-debuginfo-struct-large.ll new file mode 100644 index 0000000000000..1d75d2a567b11 --- /dev/null +++ b/llvm/test/Transforms/Util/emit-changed-func-debuginfo-struct-large.ll @@ -0,0 +1,102 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -S -mtriple=x86_64-unknown-unknown -passes=emit-changed-func-debuginfo < %s | FileCheck %s + +; Source code: +; // clang -O2 -S -emit-llvm -g test2.c -mllvm -disable-changed-func-dbinfo +; struct t { long a; long b; long c;}; +; long foo(struct t arg) { +; return arg.a * arg.c; +; } + +%struct.t = type { i64, i64, i64 } + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable +define dso_local i64 @foo(ptr noundef readonly byval(%struct.t) align 8 captures(none) %0) local_unnamed_addr #0 !dbg !9 { +; CHECK-LABEL: define dso_local i64 @foo( +; CHECK-SAME: ptr noundef readonly byval([[STRUCT_T:%.*]]) align 8 captures(none) [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] !dbg [[DBG9:![0-9]+]] { +; CHECK-NEXT: #dbg_value(ptr [[TMP0]], [[META20:![0-9]+]], !DIExpression(), [[META21:![0-9]+]]) +; CHECK-NEXT: #dbg_declare(ptr [[TMP0]], [[META22:![0-9]+]], !DIExpression(), [[META27:![0-9]+]]) +; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP0]], align 8, !dbg [[DBG28:![0-9]+]], !tbaa [[LONG_TBAA29:![0-9]+]] +; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16, !dbg [[DBG34:![0-9]+]] +; CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8, !dbg [[DBG34]], !tbaa [[LONG_TBAA35:![0-9]+]] +; CHECK-NEXT: [[TMP5:%.*]] = mul nsw i64 [[TMP4]], [[TMP2]], !dbg [[DBG36:![0-9]+]] +; CHECK-NEXT: ret i64 [[TMP5]], !dbg [[DBG37:![0-9]+]] +; + #dbg_declare(ptr %0, !19, !DIExpression(), !20) + %2 = load i64, ptr %0, align 8, !dbg !21, !tbaa !22 + %3 = getelementptr inbounds nuw i8, ptr %0, i64 16, !dbg !27 + %4 = load i64, ptr %3, align 8, !dbg !27, !tbaa !28 + %5 = mul nsw i64 %4, %2, !dbg !29 + ret i64 %5, !dbg !30 +} + +attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7} +!llvm.ident = !{!8} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git (git@github.com:yonghong-song/llvm-project.git 8e5d24efc7dac78e8ba568dfe2fc6cfbe9663b13)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test2.c", directory: "/tmp/home/yhs/tests/sig-change/struct", checksumkind: CSK_MD5, checksum: "d58648f18d3fa35e3d95b364b4a95c4c") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 8, !"PIC Level", i32 2} +!6 = !{i32 7, !"PIE Level", i32 2} +!7 = !{i32 7, !"uwtable", i32 2} +!8 = !{!"clang version 22.0.0git (git@github.com:yonghong-song/llvm-project.git 8e5d24efc7dac78e8ba568dfe2fc6cfbe9663b13)"} +!9 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !10, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !18, keyInstructions: true) +!10 = !DISubroutineType(types: !11) +!11 = !{!12, !13} +!12 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !1, line: 1, size: 192, elements: !14) +!14 = !{!15, !16, !17} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 1, baseType: !12, size: 64) +!16 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !13, file: !1, line: 1, baseType: !12, size: 64, offset: 64) +!17 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !13, file: !1, line: 1, baseType: !12, size: 64, offset: 128) +!18 = !{!19} +!19 = !DILocalVariable(name: "arg", arg: 1, scope: !9, file: !1, line: 2, type: !13) +!20 = !DILocation(line: 2, column: 19, scope: !9) +!21 = !DILocation(line: 3, column: 14, scope: !9) +!22 = !{!23, !24, i64 0} +!23 = !{!"t", !24, i64 0, !24, i64 8, !24, i64 16} +!24 = !{!"long", !25, i64 0} +!25 = !{!"omnipotent char", !26, i64 0} +!26 = !{!"Simple C/C++ TBAA"} +!27 = !DILocation(line: 3, column: 22, scope: !9) +!28 = !{!23, !24, i64 16} +!29 = !DILocation(line: 3, column: 16, scope: !9, atomGroup: 1, atomRank: 2) +!30 = !DILocation(line: 3, column: 3, scope: !9, atomGroup: 1, atomRank: 1) +;. +; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], producer: "{{.*}}clang version {{.*}}", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +; CHECK: [[META1]] = !DIFile(filename: "{{.*}}test2.c", directory: {{.*}}) +; CHECK: [[DBG9]] = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: [[META1]], file: [[META1]], line: 2, type: [[META10:![0-9]+]], scopeLine: 2, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META19:![0-9]+]]) +; CHECK: [[META10]] = !DISubroutineType(types: [[META11:![0-9]+]]) +; CHECK: [[META11]] = !{[[META12:![0-9]+]], [[META13:![0-9]+]]} +; CHECK: [[META12]] = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) +; CHECK: [[META13]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META14:![0-9]+]], size: 64) +; CHECK: [[META14]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: [[META1]], line: 1, size: 192, elements: [[META15:![0-9]+]]) +; CHECK: [[META15]] = !{[[META16:![0-9]+]], [[META17:![0-9]+]], [[META18:![0-9]+]]} +; CHECK: [[META16]] = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: [[META14]], file: [[META1]], line: 1, baseType: [[META12]], size: 64) +; CHECK: [[META17]] = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: [[META14]], file: [[META1]], line: 1, baseType: [[META12]], size: 64, offset: 64) +; CHECK: [[META18]] = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: [[META14]], file: [[META1]], line: 1, baseType: [[META12]], size: 64, offset: 128) +; CHECK: [[META19]] = !{} +; CHECK: [[META20]] = !DILocalVariable(name: "arg__0", arg: 1, scope: [[DBG9]], file: [[META1]], line: 2, type: [[META13]]) +; CHECK: [[META21]] = !DILocation(line: 0, scope: [[DBG9]]) +; CHECK: [[META22]] = !DILocalVariable(name: "arg", arg: 1, scope: [[META23:![0-9]+]], file: [[META1]], line: 2, type: [[META14]]) +; CHECK: [[META23]] = distinct !DISubprogram(name: "foo", scope: [[META1]], file: [[META1]], line: 2, type: [[META24:![0-9]+]], scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META26:![0-9]+]], keyInstructions: true) +; CHECK: [[META24]] = !DISubroutineType(cc: DW_CC_normal, types: [[META25:![0-9]+]]) +; CHECK: [[META25]] = !{[[META12]], [[META14]]} +; CHECK: [[META26]] = !{[[META22]]} +; CHECK: [[META27]] = !DILocation(line: 2, column: 19, scope: [[META23]], inlinedAt: [[META21]]) +; CHECK: [[DBG28]] = !DILocation(line: 3, column: 14, scope: [[META23]], inlinedAt: [[META21]]) +; CHECK: [[LONG_TBAA29]] = !{[[META30:![0-9]+]], [[META31:![0-9]+]], i64 0} +; CHECK: [[META30]] = !{!"t", [[META31]], i64 0, [[META31]], i64 8, [[META31]], i64 16} +; CHECK: [[META31]] = !{!"long", [[META32:![0-9]+]], i64 0} +; CHECK: [[META32]] = !{!"omnipotent char", [[META33:![0-9]+]], i64 0} +; CHECK: [[META33]] = !{!"Simple C/C++ TBAA"} +; CHECK: [[DBG34]] = !DILocation(line: 3, column: 22, scope: [[META23]], inlinedAt: [[META21]]) +; CHECK: [[LONG_TBAA35]] = !{[[META30]], [[META31]], i64 16} +; CHECK: [[DBG36]] = !DILocation(line: 3, column: 16, scope: [[META23]], inlinedAt: [[META21]], atomGroup: 1, atomRank: 2) +; CHECK: [[DBG37]] = !DILocation(line: 3, column: 3, scope: [[META23]], inlinedAt: [[META21]], atomGroup: 1, atomRank: 1) +;.