https://github.com/huangjd updated https://github.com/llvm/llvm-project/pull/81545
>From f2c82758e1cba7773e41d941d2812c829c339675 Mon Sep 17 00:00:00 2001 From: William Huang <williamjhu...@google.com> Date: Mon, 12 Feb 2024 02:27:13 -0500 Subject: [PATCH 1/3] Add option to generate additional info for expression containing pointer of pointers. Such expression does correspond to a variable in the source code thus does not have a debug location. However the user may want to collect sampling counter for memory accesses to analyze usage frequency of class members. By enabling -fdebug_info_for_pointer_type a psuedo variable and its debug info is generated in place whenever there's an intermediate expression with pointer access. --- clang/include/clang/Basic/DebugOptions.def | 4 ++ clang/include/clang/Driver/Options.td | 4 ++ clang/lib/CodeGen/CGDebugInfo.cpp | 16 +++++ clang/lib/CodeGen/CGDebugInfo.h | 6 ++ clang/lib/CodeGen/CGDecl.cpp | 4 ++ clang/lib/CodeGen/CGExpr.cpp | 79 ++++++++++++++++++++++ clang/lib/CodeGen/CodeGenFunction.h | 5 ++ clang/lib/Driver/ToolChains/Clang.cpp | 3 + 8 files changed, 121 insertions(+) diff --git a/clang/include/clang/Basic/DebugOptions.def b/clang/include/clang/Basic/DebugOptions.def index 7cd3edf08a17ea..6dd09f46842077 100644 --- a/clang/include/clang/Basic/DebugOptions.def +++ b/clang/include/clang/Basic/DebugOptions.def @@ -129,6 +129,10 @@ DEBUGOPT(CodeViewCommandLine, 1, 0) /// Whether emit extra debug info for sample pgo profile collection. DEBUGOPT(DebugInfoForProfiling, 1, 0) +/// Whether to generate pseudo variables and their debug info for intermediate +/// pointer accesses. +DEBUGOPT(DebugInfoForPointerType, 1, 0) + /// Whether to emit .debug_gnu_pubnames section instead of .debug_pubnames. DEBUGOPT(DebugNameTable, 2, 0) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 7f4fa33748faca..96b22d3f7640dd 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1675,6 +1675,10 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling", PosFlag<SetTrue, [], [ClangOption, CC1Option], "Emit extra debug info to make sample profile more accurate">, NegFlag<SetFalse>>; +def fdebug_info_for_pointer_type : Flag<["-"], "fdebug-info-for-pointer-type">, + Group<f_Group>, Visibility<[ClangOption, CC1Option]>, + HelpText<"Generate pseudo variables and their debug info for intermediate pointer accesses">, + MarshallingInfoFlag<CodeGenOpts<"DebugInfoForPointerType">>; def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">, Group<f_Group>, Visibility<[ClangOption, CLOption]>, HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">; diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 0f3f684d61dc94..6ce40da22dc97d 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -5636,6 +5636,22 @@ void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var, Var->addDebugInfo(GVE); } +void CGDebugInfo::EmitPseudoVariable(llvm::AllocaInst *Alloca, QualType Ty, + SourceLocation Loc) { + llvm::DIFile *Unit = getOrCreateFile(Loc); + unsigned Line = getLineNumber(Loc); + unsigned Column = getColumnNumber(Loc); + llvm::DILocalVariable *D = DBuilder.createAutoVariable( + LexicalBlockStack.back(), Alloca->getName(), getOrCreateFile(Loc), Line, + getOrCreateType(Ty, Unit)); + llvm::DILocation *DIL = + llvm::DILocation::get(CGM.getLLVMContext(), Line, Column, + LexicalBlockStack.back(), CurInlinedAt); + SmallVector<uint64_t> Expr; + DBuilder.insertDeclare(Alloca, D, DBuilder.createExpression(Expr), DIL, + Alloca->getParent()); +} + void CGDebugInfo::EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl GD) { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 7b60e94555d060..a2c484f50b2bc5 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -529,6 +529,12 @@ class CGDebugInfo { /// Emit information about an external variable. void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); + /// Emit debug information for a pseudo variable assigned to the value of an + /// intermediate expression, so that a performance counter can track the usage + /// of a specific expression of interest. + void EmitPseudoVariable(llvm::AllocaInst *Alloca, QualType Ty, + SourceLocation Loc); + /// Emit information about global variable alias. void EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl Decl); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index bbe14ef4c17244..5f7b2529179003 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -793,6 +793,10 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime(); if (!lifetime) { llvm::Value *value = EmitScalarExpr(init); + if (CGM.getCodeGenOpts().getDebugInfo() > + llvm::codegenoptions::DebugLineTablesOnly && + CGM.getCodeGenOpts().DebugInfoForPointerType) + value = UnemitPseudoVariable(value); if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D)); EmitNullabilityCheck(lvalue, value, init->getExprLoc()); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index c5f6b6d3a99f0b..b979c0830c5b34 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -951,6 +951,58 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, return nullptr; } +/// When a pseudo variable is created for %1, it generates these instructions +/// in sequence and return %2: +/// %pseudo = alloca Ty +/// call void @llvm.dbg.declare(metadata ptr %pseudo, metadata, metadata) +/// store Ty %1, ptr %pseudo +/// %2 = load ptr, ptr %pseudo +/// To undo, we detect and remove this sequence, and replace %2 back to %1. +llvm::Value *CodeGenFunction::UnemitPseudoVariable(llvm::Value *V) { + if (!getDebugInfo()) + return V; + + if (llvm::LoadInst *Load = dyn_cast<llvm::LoadInst>(V)) { + llvm::Value *PseudoVar = Load->getPointerOperand(); + if (llvm::StoreInst *Store = + dyn_cast<llvm::StoreInst>(Load->getPrevNode())) { + if (Store->getPointerOperand() != PseudoVar) + return V; + llvm::Value *OriginalValue = Store->getValueOperand(); + if (llvm::CallInst *DbgCall = + dyn_cast<llvm::CallInst>(Store->getPrevNode())) { + if (DbgCall->getCalledFunction() != + llvm::Intrinsic::getDeclaration(&CGM.getModule(), + llvm::Intrinsic::dbg_declare) || + DbgCall->getNumOperands() != 4) + return V; + for (int i = 0; i < 3; i++) { + if (!isa<llvm::MetadataAsValue>(DbgCall->getArgOperand(i))) + return V; + } + if (llvm::MetadataAsValue *Metadata = + dyn_cast<llvm::MetadataAsValue>(DbgCall->getOperand(0))) { + if (llvm::ValueAsMetadata *Value = + dyn_cast<llvm::ValueAsMetadata>(Metadata->getMetadata())) { + if (Value->getValue() != PseudoVar) + return V; + if (llvm::AllocaInst *Alloca = + dyn_cast<llvm::AllocaInst>(DbgCall->getPrevNode())) { + V->replaceAllUsesWith(OriginalValue); + Load->eraseFromParent(); + Store->eraseFromParent(); + DbgCall->eraseFromParent(); + Alloca->eraseFromParent(); + return OriginalValue; + } + } + } + } + } + } + return V; +} + namespace { /// \p StructAccessBase returns the base \p Expr of a field access. It returns @@ -2015,6 +2067,29 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, llvm::MDNode::get(getLLVMContext(), std::nullopt)); } + // if -g2 or above and -fdebug-info-for-pointer-type are enabled, emit + // additional debug info for loads in an intermediate expression, which allows + // a performance counter to deduce the type of the value being loaded, even if + // it does not correspond to a variable in the source code. + // Since there is no variable correspond to an intermediate expression, we + // create a pseudo variable for it and emit its debug info, as if the + // expression were written in SSA form. + if (CGM.getCodeGenOpts().getDebugInfo() > llvm::codegenoptions::DebugLineTablesOnly && + CGM.getCodeGenOpts().DebugInfoForPointerType) { + if (CGDebugInfo *DI = getDebugInfo()) + // We only generate this debug info if loading from GEP, not from other + // cases such as loading a function argument. + if (isa<llvm::GetElementPtrInst>(Load->getOperand(0))) { + const llvm::DebugLoc &DebugLoc = Load->getDebugLoc(); + llvm::AllocaInst *PseudoVar = Builder.CreateAlloca( + Load->getType(), nullptr, Twine("pseudo_").concat(Twine(DebugLoc.getLine())).concat("_").concat(Twine(DebugLoc.getCol()))); + DI->EmitPseudoVariable(PseudoVar, Ty, Loc); + Address PseudoVarAddr(PseudoVar, Load->getType(), Addr.getAlignment()); + Builder.CreateStore(Load, PseudoVarAddr); + Load = Builder.CreateLoad(PseudoVarAddr); + } + } + return EmitFromMemory(Load, Ty); } @@ -5569,6 +5644,10 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { } RValue RV = EmitAnyExpr(E->getRHS()); + if (CGM.getCodeGenOpts().getDebugInfo() > llvm::codegenoptions::DebugLineTablesOnly && + CGM.getCodeGenOpts().DebugInfoForPointerType) + if (isa<DeclRefExpr>(E->getLHS()) && RV.isScalar()) + RV = RValue::get(UnemitPseudoVariable(RV.getScalarVal())); LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); if (RV.isScalar()) EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc()); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 143ad64e8816b1..36a572ace2ef64 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3104,6 +3104,11 @@ class CodeGenFunction : public CodeGenTypeCache { /// Get the record field index as represented in debug info. unsigned getDebugInfoFIndex(const RecordDecl *Rec, unsigned FieldIndex); + /// When the result of EmitLoadOfScalar is immediately assigned to a declared + /// variable, the pseudo variable emitted for it (when the flag + /// -fdebug-info-for-pointer-type is specified) should be undone since there + /// is already a debug value emitted for the declared variable. + llvm::Value *UnemitPseudoVariable(llvm::Value *V); //===--------------------------------------------------------------------===// // Declaration Emission diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index bcba7cbbdb58c2..7882c4f1225f1f 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4256,6 +4256,9 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, // decision should be made in the driver as well though. llvm::DebuggerKind DebuggerTuning = TC.getDefaultDebuggerTuning(); + if (Args.hasArg(options::OPT_fdebug_info_for_pointer_type)) + CmdArgs.push_back("-fdebug-info-for-pointer-type"); + bool SplitDWARFInlining = Args.hasFlag(options::OPT_fsplit_dwarf_inlining, options::OPT_fno_split_dwarf_inlining, false); >From 95235b97774f8700ee9108e057ac360e86c79597 Mon Sep 17 00:00:00 2001 From: William Huang <williamjhu...@google.com> Date: Wed, 6 Mar 2024 05:59:07 -0500 Subject: [PATCH 2/3] Code cleanup --- clang/lib/CodeGen/CGDebugInfo.cpp | 9 ++++ clang/lib/CodeGen/CGDebugInfo.h | 7 +++ clang/lib/CodeGen/CGDecl.cpp | 5 +- clang/lib/CodeGen/CGExpr.cpp | 80 ++++++++++++++----------------- 4 files changed, 52 insertions(+), 49 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 6ce40da22dc97d..7aa96332e495b3 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -5652,6 +5652,15 @@ void CGDebugInfo::EmitPseudoVariable(llvm::AllocaInst *Alloca, QualType Ty, Alloca->getParent()); } +llvm::MDNode *CGDebugInfo::GetPseudoVariableAnnotation() { + if (!PseudoVariableAnnotation) + PseudoVariableAnnotation = + llvm::MDNode::get(CGM.getLLVMContext(), + llvm::MDString::get(CGM.getLLVMContext(), + "fdebug-info-for-pointer-type")); + return PseudoVariableAnnotation; +} + void CGDebugInfo::EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl GD) { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index a2c484f50b2bc5..047095073c6965 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -170,6 +170,9 @@ class CGDebugInfo { /// The key is coroutine real parameters, value is DIVariable in LLVM IR. Param2DILocTy ParamDbgMappings; + /// Cached object for GetPseudoVariableAnnotation(). + llvm::MDNode *PseudoVariableAnnotation = nullptr; + /// Helper functions for getOrCreateType. /// @{ /// Currently the checksum of an interface includes the number of @@ -535,6 +538,10 @@ class CGDebugInfo { void EmitPseudoVariable(llvm::AllocaInst *Alloca, QualType Ty, SourceLocation Loc); + /// Get the special annotation tag that indicates the instruction is + /// associated with EmitPseudoVariable. + llvm::MDNode *GetPseudoVariableAnnotation(); + /// Emit information about global variable alias. void EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl Decl); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 5f7b2529179003..04cd0eaddb83ad 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -793,10 +793,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime(); if (!lifetime) { llvm::Value *value = EmitScalarExpr(init); - if (CGM.getCodeGenOpts().getDebugInfo() > - llvm::codegenoptions::DebugLineTablesOnly && - CGM.getCodeGenOpts().DebugInfoForPointerType) - value = UnemitPseudoVariable(value); + value = UnemitPseudoVariable(value); if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D)); EmitNullabilityCheck(lvalue, value, init->getExprLoc()); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index b979c0830c5b34..43c962da7a3e3e 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -957,45 +957,26 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, /// call void @llvm.dbg.declare(metadata ptr %pseudo, metadata, metadata) /// store Ty %1, ptr %pseudo /// %2 = load ptr, ptr %pseudo -/// To undo, we detect and remove this sequence, and replace %2 back to %1. +/// To undo, we detect and remove this sequence, and replace %2 back with %1. llvm::Value *CodeGenFunction::UnemitPseudoVariable(llvm::Value *V) { - if (!getDebugInfo()) - return V; - - if (llvm::LoadInst *Load = dyn_cast<llvm::LoadInst>(V)) { - llvm::Value *PseudoVar = Load->getPointerOperand(); - if (llvm::StoreInst *Store = - dyn_cast<llvm::StoreInst>(Load->getPrevNode())) { - if (Store->getPointerOperand() != PseudoVar) - return V; - llvm::Value *OriginalValue = Store->getValueOperand(); - if (llvm::CallInst *DbgCall = - dyn_cast<llvm::CallInst>(Store->getPrevNode())) { - if (DbgCall->getCalledFunction() != - llvm::Intrinsic::getDeclaration(&CGM.getModule(), - llvm::Intrinsic::dbg_declare) || - DbgCall->getNumOperands() != 4) - return V; - for (int i = 0; i < 3; i++) { - if (!isa<llvm::MetadataAsValue>(DbgCall->getArgOperand(i))) - return V; - } - if (llvm::MetadataAsValue *Metadata = - dyn_cast<llvm::MetadataAsValue>(DbgCall->getOperand(0))) { - if (llvm::ValueAsMetadata *Value = - dyn_cast<llvm::ValueAsMetadata>(Metadata->getMetadata())) { - if (Value->getValue() != PseudoVar) - return V; - if (llvm::AllocaInst *Alloca = - dyn_cast<llvm::AllocaInst>(DbgCall->getPrevNode())) { - V->replaceAllUsesWith(OriginalValue); - Load->eraseFromParent(); - Store->eraseFromParent(); - DbgCall->eraseFromParent(); - Alloca->eraseFromParent(); - return OriginalValue; - } + if (CGDebugInfo *DI = getDebugInfo()) { + if (llvm::LoadInst *Load = dyn_cast<llvm::LoadInst>(V)) { + if (llvm::MDNode *Tag = + Load->getMetadata(llvm::LLVMContext::MD_annotation)) { + if (Tag == DI->GetPseudoVariableAnnotation()) { + llvm::Value *PseudoVar = Load->getPointerOperand(); + llvm::AllocaInst *Alloca = dyn_cast<llvm::AllocaInst>(PseudoVar); + llvm::StoreInst *Store = + dyn_cast_if_present<llvm::StoreInst>(Load->getPrevNode()); + assert(Store && Store->getPointerOperand() == PseudoVar); + llvm::Value *OriginalValue = Store->getValueOperand(); + V->replaceAllUsesWith(OriginalValue); + assert(Store->getPrevNode()->getPrevNode() == PseudoVar); + auto It = Load->getIterator(); + for (int i = 0; i < 4; i++) { + (It--)->eraseFromParent(); } + return OriginalValue; } } } @@ -2074,20 +2055,31 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, // Since there is no variable correspond to an intermediate expression, we // create a pseudo variable for it and emit its debug info, as if the // expression were written in SSA form. - if (CGM.getCodeGenOpts().getDebugInfo() > llvm::codegenoptions::DebugLineTablesOnly && + if (CGM.getCodeGenOpts().getDebugInfo() > + llvm::codegenoptions::DebugLineTablesOnly && CGM.getCodeGenOpts().DebugInfoForPointerType) { - if (CGDebugInfo *DI = getDebugInfo()) + if (CGDebugInfo *DI = getDebugInfo()) { // We only generate this debug info if loading from GEP, not from other // cases such as loading a function argument. if (isa<llvm::GetElementPtrInst>(Load->getOperand(0))) { const llvm::DebugLoc &DebugLoc = Load->getDebugLoc(); - llvm::AllocaInst *PseudoVar = Builder.CreateAlloca( - Load->getType(), nullptr, Twine("pseudo_").concat(Twine(DebugLoc.getLine())).concat("_").concat(Twine(DebugLoc.getCol()))); + llvm::AllocaInst *PseudoVar = + Builder.CreateAlloca(Load->getType(), nullptr, + Twine("pseudo_") + .concat(Twine(DebugLoc.getLine())) + .concat("_") + .concat(Twine(DebugLoc.getCol()))); DI->EmitPseudoVariable(PseudoVar, Ty, Loc); Address PseudoVarAddr(PseudoVar, Load->getType(), Addr.getAlignment()); Builder.CreateStore(Load, PseudoVarAddr); Load = Builder.CreateLoad(PseudoVarAddr); + // Set a special metadata tag to this instruction, in the case we need + // to revert it because there is already a destination variable for the + // load. + Load->setMetadata(llvm::LLVMContext::MD_annotation, + DI->GetPseudoVariableAnnotation()); } + } } return EmitFromMemory(Load, Ty); @@ -5644,10 +5636,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { } RValue RV = EmitAnyExpr(E->getRHS()); - if (CGM.getCodeGenOpts().getDebugInfo() > llvm::codegenoptions::DebugLineTablesOnly && - CGM.getCodeGenOpts().DebugInfoForPointerType) - if (isa<DeclRefExpr>(E->getLHS()) && RV.isScalar()) - RV = RValue::get(UnemitPseudoVariable(RV.getScalarVal())); + if (isa<DeclRefExpr>(E->getLHS()) && RV.isScalar()) + RV = RValue::get(UnemitPseudoVariable(RV.getScalarVal())); LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); if (RV.isScalar()) EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc()); >From 37d3c1b74d1931819de211bbdb9ff07bf7c092d7 Mon Sep 17 00:00:00 2001 From: William Huang <williamjhu...@google.com> Date: Wed, 13 Mar 2024 18:07:42 -0400 Subject: [PATCH 3/3] Rewrite code to emit debug info for pointer instead of pointee, as requested by kernel dev. --- clang/lib/CodeGen/CGDebugInfo.cpp | 68 ++++++++++++++++++++++------ clang/lib/CodeGen/CGDebugInfo.h | 17 +++---- clang/lib/CodeGen/CGDecl.cpp | 1 - clang/lib/CodeGen/CGExpr.cpp | 69 ----------------------------- clang/lib/CodeGen/CGExprScalar.cpp | 19 +++++++- clang/lib/CodeGen/CodeGenFunction.h | 5 --- llvm/include/llvm/IR/DIBuilder.h | 2 + 7 files changed, 79 insertions(+), 102 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 7aa96332e495b3..1aaed9e9f15eb7 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -5636,29 +5636,69 @@ void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var, Var->addDebugInfo(GVE); } -void CGDebugInfo::EmitPseudoVariable(llvm::AllocaInst *Alloca, QualType Ty, +void CGDebugInfo::EmitPseudoVariable(CGBuilderTy &Builder, + llvm::Instruction *Value, QualType Ty, SourceLocation Loc) { + // Only when -g2 or above is specified, debug info for variables will be + // generated. + if (CGM.getCodeGenOpts().getDebugInfo() <= + llvm::codegenoptions::DebugLineTablesOnly) + return; + llvm::DIFile *Unit = getOrCreateFile(Loc); + llvm::DIType *Type = getOrCreateType(Ty, Unit); + + // Check if Value is already a declared variable and has debug info, in this + // case we have nothing to do. Clang emits declared variable as alloca, and + // it is loaded upon use, so we identify such pattern here. + if (llvm::LoadInst *Load = dyn_cast<llvm::LoadInst>(Value)) { + llvm::Value *Var = Load->getPointerOperand(); + if (llvm::Metadata *MDValue = llvm::ValueAsMetadata::getIfExists(Var)) { + if (llvm::Value *DbgValue = llvm::MetadataAsValue::getIfExists( + CGM.getLLVMContext(), MDValue)) { + for (llvm::User *U : DbgValue->users()) { + if (llvm::CallInst *DbgDeclare = dyn_cast<llvm::CallInst>(U)) { + if (DbgDeclare->getCalledFunction() == DBuilder.GetDeclareFn() && + DbgDeclare->getArgOperand(0) == DbgValue) { + // There can be implicit type cast applied on a variable if it is + // an opaque ptr, in this case its debug info may not match the + // actual type of object being used as in the next instruction, so + // we will need to emit a pseudo variable for type-casted value. + llvm::DILocalVariable *MDNode = dyn_cast<llvm::DILocalVariable>( + dyn_cast<llvm::MetadataAsValue>(DbgDeclare->getOperand(1)) + ->getMetadata()); + if (MDNode->getType() == Type) + return; + } + } + } + } + } + } + + // Insert a sequence of instructions to materialize Value on the stack. + auto SaveInsertionPoint = Builder.saveIP(); + Builder.SetInsertPoint(++(Value->getIterator())); + llvm::AllocaInst *PseudoVar = Builder.CreateAlloca(Value->getType()); + Address PseudoVarAddr(PseudoVar, Value->getType(), + CharUnits::fromQuantity(PseudoVar->getAlign())); + llvm::LoadInst *Load = Builder.CreateLoad(PseudoVarAddr); + Value->replaceAllUsesWith(Load); + Builder.SetInsertPoint(Load); + Builder.CreateStore(Value, PseudoVarAddr); + + // Emit debug info for materialized Value. unsigned Line = getLineNumber(Loc); unsigned Column = getColumnNumber(Loc); llvm::DILocalVariable *D = DBuilder.createAutoVariable( - LexicalBlockStack.back(), Alloca->getName(), getOrCreateFile(Loc), Line, - getOrCreateType(Ty, Unit)); + LexicalBlockStack.back(), "pseudo_var", Unit, Line, Type); llvm::DILocation *DIL = llvm::DILocation::get(CGM.getLLVMContext(), Line, Column, LexicalBlockStack.back(), CurInlinedAt); SmallVector<uint64_t> Expr; - DBuilder.insertDeclare(Alloca, D, DBuilder.createExpression(Expr), DIL, - Alloca->getParent()); -} - -llvm::MDNode *CGDebugInfo::GetPseudoVariableAnnotation() { - if (!PseudoVariableAnnotation) - PseudoVariableAnnotation = - llvm::MDNode::get(CGM.getLLVMContext(), - llvm::MDString::get(CGM.getLLVMContext(), - "fdebug-info-for-pointer-type")); - return PseudoVariableAnnotation; + DBuilder.insertDeclare(PseudoVar, D, DBuilder.createExpression(Expr), DIL, + Load); + Builder.restoreIP(SaveInsertionPoint); } void CGDebugInfo::EmitGlobalAlias(const llvm::GlobalValue *GV, diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 047095073c6965..6452861a1be104 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -170,9 +170,6 @@ class CGDebugInfo { /// The key is coroutine real parameters, value is DIVariable in LLVM IR. Param2DILocTy ParamDbgMappings; - /// Cached object for GetPseudoVariableAnnotation(). - llvm::MDNode *PseudoVariableAnnotation = nullptr; - /// Helper functions for getOrCreateType. /// @{ /// Currently the checksum of an interface includes the number of @@ -532,15 +529,11 @@ class CGDebugInfo { /// Emit information about an external variable. void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); - /// Emit debug information for a pseudo variable assigned to the value of an - /// intermediate expression, so that a performance counter can track the usage - /// of a specific expression of interest. - void EmitPseudoVariable(llvm::AllocaInst *Alloca, QualType Ty, - SourceLocation Loc); - - /// Get the special annotation tag that indicates the instruction is - /// associated with EmitPseudoVariable. - llvm::MDNode *GetPseudoVariableAnnotation(); + /// Emit a pseudo variable and debug info for an intermediate value if it does + /// not correspond to a variable in the source code, so that a profiler can + /// track more accurate usage of certain instructions of interest. + void EmitPseudoVariable(CGBuilderTy &Builder, llvm::Instruction *Value, + QualType Ty, SourceLocation Loc); /// Emit information about global variable alias. void EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl Decl); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 04cd0eaddb83ad..bbe14ef4c17244 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -793,7 +793,6 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime(); if (!lifetime) { llvm::Value *value = EmitScalarExpr(init); - value = UnemitPseudoVariable(value); if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D)); EmitNullabilityCheck(lvalue, value, init->getExprLoc()); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 43c962da7a3e3e..c5f6b6d3a99f0b 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -951,39 +951,6 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, return nullptr; } -/// When a pseudo variable is created for %1, it generates these instructions -/// in sequence and return %2: -/// %pseudo = alloca Ty -/// call void @llvm.dbg.declare(metadata ptr %pseudo, metadata, metadata) -/// store Ty %1, ptr %pseudo -/// %2 = load ptr, ptr %pseudo -/// To undo, we detect and remove this sequence, and replace %2 back with %1. -llvm::Value *CodeGenFunction::UnemitPseudoVariable(llvm::Value *V) { - if (CGDebugInfo *DI = getDebugInfo()) { - if (llvm::LoadInst *Load = dyn_cast<llvm::LoadInst>(V)) { - if (llvm::MDNode *Tag = - Load->getMetadata(llvm::LLVMContext::MD_annotation)) { - if (Tag == DI->GetPseudoVariableAnnotation()) { - llvm::Value *PseudoVar = Load->getPointerOperand(); - llvm::AllocaInst *Alloca = dyn_cast<llvm::AllocaInst>(PseudoVar); - llvm::StoreInst *Store = - dyn_cast_if_present<llvm::StoreInst>(Load->getPrevNode()); - assert(Store && Store->getPointerOperand() == PseudoVar); - llvm::Value *OriginalValue = Store->getValueOperand(); - V->replaceAllUsesWith(OriginalValue); - assert(Store->getPrevNode()->getPrevNode() == PseudoVar); - auto It = Load->getIterator(); - for (int i = 0; i < 4; i++) { - (It--)->eraseFromParent(); - } - return OriginalValue; - } - } - } - } - return V; -} - namespace { /// \p StructAccessBase returns the base \p Expr of a field access. It returns @@ -2048,40 +2015,6 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, llvm::MDNode::get(getLLVMContext(), std::nullopt)); } - // if -g2 or above and -fdebug-info-for-pointer-type are enabled, emit - // additional debug info for loads in an intermediate expression, which allows - // a performance counter to deduce the type of the value being loaded, even if - // it does not correspond to a variable in the source code. - // Since there is no variable correspond to an intermediate expression, we - // create a pseudo variable for it and emit its debug info, as if the - // expression were written in SSA form. - if (CGM.getCodeGenOpts().getDebugInfo() > - llvm::codegenoptions::DebugLineTablesOnly && - CGM.getCodeGenOpts().DebugInfoForPointerType) { - if (CGDebugInfo *DI = getDebugInfo()) { - // We only generate this debug info if loading from GEP, not from other - // cases such as loading a function argument. - if (isa<llvm::GetElementPtrInst>(Load->getOperand(0))) { - const llvm::DebugLoc &DebugLoc = Load->getDebugLoc(); - llvm::AllocaInst *PseudoVar = - Builder.CreateAlloca(Load->getType(), nullptr, - Twine("pseudo_") - .concat(Twine(DebugLoc.getLine())) - .concat("_") - .concat(Twine(DebugLoc.getCol()))); - DI->EmitPseudoVariable(PseudoVar, Ty, Loc); - Address PseudoVarAddr(PseudoVar, Load->getType(), Addr.getAlignment()); - Builder.CreateStore(Load, PseudoVarAddr); - Load = Builder.CreateLoad(PseudoVarAddr); - // Set a special metadata tag to this instruction, in the case we need - // to revert it because there is already a destination variable for the - // load. - Load->setMetadata(llvm::LLVMContext::MD_annotation, - DI->GetPseudoVariableAnnotation()); - } - } - } - return EmitFromMemory(Load, Ty); } @@ -5636,8 +5569,6 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { } RValue RV = EmitAnyExpr(E->getRHS()); - if (isa<DeclRefExpr>(E->getLHS()) && RV.isScalar()) - RV = RValue::get(UnemitPseudoVariable(RV.getScalarVal())); LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); if (RV.isScalar()) EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc()); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 181b15e9c7d0a7..0d64607bac399a 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1787,7 +1787,24 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { } } - return EmitLoadOfLValue(E); + llvm::Value *Result = EmitLoadOfLValue(E); + + // If -fdebug-info-for-pointer-type is specified, emit a pseudo variable and + // its debug info for the pointer, even if there is no variable associated + // with the pointer's expression. + if (CGF.CGM.getCodeGenOpts().DebugInfoForPointerType && CGF.getDebugInfo()) { + if (llvm::LoadInst *Load = dyn_cast<llvm::LoadInst>(Result)) { + if (llvm::GetElementPtrInst *GEP = + dyn_cast<llvm::GetElementPtrInst>(Load->getPointerOperand())) { + if (llvm::Instruction *Pointer = + dyn_cast<llvm::Instruction>(GEP->getPointerOperand())) { + CGF.getDebugInfo()->EmitPseudoVariable( + Builder, Pointer, E->getBase()->getType(), E->getExprLoc()); + } + } + } + } + return Result; } Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 36a572ace2ef64..143ad64e8816b1 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3104,11 +3104,6 @@ class CodeGenFunction : public CodeGenTypeCache { /// Get the record field index as represented in debug info. unsigned getDebugInfoFIndex(const RecordDecl *Rec, unsigned FieldIndex); - /// When the result of EmitLoadOfScalar is immediately assigned to a declared - /// variable, the pseudo variable emitted for it (when the flag - /// -fdebug-info-for-pointer-type is specified) should be undone since there - /// is already a debug value emitted for the declared variable. - llvm::Value *UnemitPseudoVariable(llvm::Value *V); //===--------------------------------------------------------------------===// // Declaration Emission diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index edec161b397155..e420f73e152907 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -1024,6 +1024,8 @@ namespace llvm { N->replaceAllUsesWith(Replacement); return Replacement; } + + Function *GetDeclareFn() { return DeclareFn; } }; // Create wrappers for C Binding types (see CBindingWrapping.h). _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits