Skip to content

Commit bde28ae

Browse files
authored
[TIR] Expand debug symbol output for CodeGenLLVM (#16544)
* [TIR] Expand debug symbol output for CodeGenLLVM Prior to this commit, the `CodeGenLLVM` would include DWARF symbols specifying the function signature of each TIR function. This commit expands the information exposed in the debug symbols. * Name functions based on the name of the corresponding TIR function. This is taken either from the `attr::kGlobalSymbol` if present, or the PrimFunc's `GlobalVar` otherwise. * Name function parameter based on their TIR variable name. * Annotate the name, the type signature, and parameter names for the private function produced by the `tir::attr::compute_scope` attribute. * Name local variables based on the name and type of the corresponding TIR variable. * lint fixes * lint fixes * Remove reference to llvm::dwarf::DWARF_VERSION Not available on CI version of llvm * Update number of debug locations * Fix segfault for pointers to custom data types
1 parent a6ab8cb commit bde28ae

File tree

6 files changed

+216
-150
lines changed

6 files changed

+216
-150
lines changed

src/target/llvm/codegen_cpu.cc

Lines changed: 39 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -185,144 +185,58 @@ void CodeGenCPU::Init(const std::string& module_name, LLVMTarget* llvm_target,
185185
InitGlobalContext(dynamic_lookup);
186186
}
187187

188-
llvm::DISubprogram* CodeGenCPU::CreateDebugFunction(const PrimFunc& f) {
189-
#if TVM_LLVM_VERSION >= 50
188+
llvm::DISubprogram* CodeGenCPU::CreateDebugFunction(llvm::StringRef name,
189+
const Array<Type>& param_types,
190+
const Type& return_type) {
191+
#if TVM_LLVM_VERSION < 50
192+
return nullptr;
193+
#else
194+
190195
llvm::SmallVector<llvm::Metadata*, 4> paramTys;
191196

192-
paramTys.push_back(GetDebugType(f->ret_type));
193-
for (const auto& param : f->params) {
194-
paramTys.push_back(GetDebugType(GetType(param)));
197+
paramTys.push_back(GetDebugType(return_type));
198+
for (const auto& param_type : param_types) {
199+
paramTys.push_back(GetDebugType(param_type));
195200
}
196201

197202
auto* DIFunctionTy = dbg_info_->di_builder_->createSubroutineType(
198203
dbg_info_->di_builder_->getOrCreateTypeArray(paramTys));
199204

200205
bool local_to_unit = llvm::GlobalVariable::isLocalLinkage(llvm::GlobalValue::InternalLinkage);
201206

202-
// TODO(driazati): determine the IRModule name instead of hardcoding 'main.tir'
203207
#if TVM_LLVM_VERSION >= 80
204208
auto SPFlags = llvm::DISubprogram::toSPFlags(local_to_unit, /*IsDefinition=*/true,
205209
/*IsOptimized=*/true);
206-
auto* DIFunction = dbg_info_->di_builder_->createFunction(
207-
/*Scope=*/dbg_info_->file_, /*Name=*/"main.tir", /*LinkageName=*/"",
208-
/*File=*/dbg_info_->file_, /*LineNo=*/0, /*Ty=*/DIFunctionTy,
209-
/*ScopeLine=*/0, /*Flags=*/llvm::DINode::FlagZero, /*SPFlags=*/SPFlags);
210210
#else
211+
bool SPFlags = /*IsOptimized=*/true;
212+
#endif
213+
211214
auto* DIFunction = dbg_info_->di_builder_->createFunction(
212-
/*Scope=*/dbg_info_->file_, /*Name=*/"main.tir", /*LinkageName=*/"",
215+
/*Scope=*/dbg_info_->file_, /*Name=*/name, /*LinkageName=*/"",
213216
/*File=*/dbg_info_->file_, /*LineNo=*/0, /*Ty=*/DIFunctionTy,
214-
/*isLocalToUnit=*/local_to_unit, /*isDefinition=*/true, /*ScopeLine=*/0,
215-
/*Flags=*/llvm::DINode::FlagPrototyped, /*isOptimized=*/true);
216-
#endif
217+
/*ScopeLine=*/0, /*Flags=*/llvm::DINode::FlagPrototyped, /*SPFlags=*/SPFlags);
218+
217219
return DIFunction;
218-
#else
219-
return nullptr;
220+
220221
#endif
221222
}
222223

223-
void CodeGenCPU::AddFunction(const GlobalVar& gvar, const PrimFunc& f) {
224-
#if TVM_LLVM_VERSION >= 50
225-
di_subprogram_ = CreateDebugFunction(f);
226-
#endif
227-
EmitDebugLocation(f->span);
228-
CodeGenLLVM::AddFunction(gvar, f);
224+
llvm::DISubprogram* CodeGenCPU::CreateDebugFunction(const GlobalVar& gvar, const PrimFunc& func) {
225+
std::string name = func->GetAttr<String>(tvm::attr::kGlobalSymbol).value_or(gvar->name_hint);
226+
return CreateDebugFunction(name, func->params.Map(GetType), func->ret_type);
227+
}
228+
229+
void CodeGenCPU::AddFunction(const GlobalVar& gvar, const PrimFunc& func) {
230+
di_subprogram_ = CreateDebugFunction(gvar, func);
231+
EmitDebugLocation(func->span);
232+
CodeGenLLVM::AddFunction(gvar, func);
229233
if (f_tvm_register_system_symbol_ != nullptr) {
230-
if (auto global_symbol = f->GetAttr<String>(tvm::attr::kGlobalSymbol)) {
234+
if (auto global_symbol = func->GetAttr<String>(tvm::attr::kGlobalSymbol)) {
231235
export_system_symbols_.emplace_back(
232236
std::make_pair(global_symbol.value().operator std::string(), function_));
233237
}
234238
}
235-
AddDebugInformation(f, function_);
236-
}
237-
238-
// Following Glow |DebugInfo::generateFunctionDebugInfo|, https://git.io/fjadv
239-
void CodeGenCPU::AddDebugInformation(PrimFunc f_tir, llvm::Function* f_llvm) {
240-
#if TVM_LLVM_VERSION >= 50
241-
ICHECK(di_subprogram_);
242-
f_llvm->setSubprogram(di_subprogram_);
243-
ICHECK_EQ(f_llvm->getSubprogram(), di_subprogram_);
244-
245-
IRBuilder builder(&f_llvm->getEntryBlock());
246-
if (!f_llvm->getEntryBlock().empty()) {
247-
builder.SetInsertPoint(&f_llvm->getEntryBlock().front());
248-
}
249-
llvm::DebugLoc DL;
250-
builder.SetCurrentDebugLocation(DL);
251-
llvm::LLVMContext* ctx = llvm_target_->GetContext();
252-
for (size_t i = 0; i < f_llvm->arg_size(); ++i) {
253-
auto* paramAlloca = builder.CreateAlloca(f_llvm->getFunctionType()->getParamType(i));
254-
std::string paramName = "arg" + std::to_string(i + 1);
255-
auto param = dbg_info_->di_builder_->createParameterVariable(
256-
di_subprogram_, paramName, i + 1, dbg_info_->file_, 0,
257-
GetDebugType(GetType(f_tir->params[i]), f_llvm->getFunctionType()->getParamType(i)),
258-
/*alwaysPreserve=*/true);
259-
auto* store = builder.CreateStore(f_llvm->arg_begin() + i, paramAlloca);
260-
auto* di_loc = llvm::DILocation::get(*ctx, 0, 0, di_subprogram_);
261-
dbg_info_->di_builder_->insertDeclare(paramAlloca, param,
262-
dbg_info_->di_builder_->createExpression(),
263-
llvm::DebugLoc(di_loc), store);
264-
}
265-
dbg_info_->di_builder_->finalizeSubprogram(f_llvm->getSubprogram());
266-
auto* scope = f_llvm->getSubprogram();
267-
if (!scope) {
268-
return;
269-
}
270-
271-
for (auto& BB : *f_llvm) {
272-
for (auto& I : BB) {
273-
if (I.getDebugLoc()) {
274-
continue;
275-
}
276-
auto* di_loc = llvm::DILocation::get(*ctx, 0, 0, scope);
277-
I.setDebugLoc(llvm::DebugLoc(di_loc));
278-
}
279-
}
280-
#endif
281-
}
282-
283-
llvm::DIType* CodeGenCPU::GetDebugType(const Type& ty_tir) {
284-
return GetDebugType(ty_tir, GetLLVMType(ty_tir));
285-
}
286-
llvm::DIType* CodeGenCPU::GetDebugType(const Type& ty_tir, llvm::Type* ty_llvm) {
287-
if (ty_llvm == t_void_) {
288-
return nullptr;
289-
290-
} else if (ty_llvm->isPointerTy()) {
291-
auto* ptr_type = ty_tir.as<PointerTypeNode>();
292-
ICHECK(ptr_type != nullptr || GetRuntimeDataType(ty_tir).is_handle())
293-
<< "Got LLVM pointer type from non-pointer IR type: " << ty_tir;
294-
auto* pointee_type = ptr_type != nullptr ? GetDebugType(ptr_type->element_type,
295-
GetLLVMType(ptr_type->element_type))
296-
: nullptr;
297-
return dbg_info_->di_builder_->createPointerType(pointee_type,
298-
ty_llvm->getPrimitiveSizeInBits());
299-
300-
} else if (auto* prim_type = ty_tir.as<PrimTypeNode>()) {
301-
DataType dtype = prim_type->dtype;
302-
auto dwarf_type = [&]() -> llvm::dwarf::TypeKind {
303-
if (dtype.is_bool()) {
304-
return llvm::dwarf::DW_ATE_boolean;
305-
} else if (dtype.is_float()) {
306-
return llvm::dwarf::DW_ATE_float;
307-
} else if (dtype.is_int()) {
308-
return llvm::dwarf::DW_ATE_signed;
309-
} else if (dtype.is_uint()) {
310-
return llvm::dwarf::DW_ATE_unsigned;
311-
} else {
312-
LOG(FATAL) << "No DWARF representation for TIR type " << dtype;
313-
}
314-
}();
315-
316-
return dbg_info_->di_builder_->createBasicType(DLDataType2String(dtype),
317-
dtype.bits() * dtype.lanes(), dwarf_type);
318-
319-
} else {
320-
std::string type_str;
321-
llvm::raw_string_ostream rso(type_str);
322-
ty_llvm->print(rso);
323-
LOG(FATAL) << "Unknown LLVM type:" << rso.str();
324-
}
325-
return nullptr;
239+
AddDebugInformation(function_, func->params.Map(GetType));
326240
}
327241

328242
void CodeGenCPU::AddMainFunction(const std::string& entry_func_name) {
@@ -570,15 +484,18 @@ void CodeGenCPU::CreateComputeScope(const AttrStmtNode* op) {
570484
std::swap(function_, parent_->function_);
571485
std::swap(analyzer_, parent_->analyzer_);
572486
std::swap(var_map_, parent_->var_map_);
487+
std::swap(di_subprogram_, parent_->di_subprogram_);
573488
}
574489

575490
void ExitWithScope() {
576491
std::swap(function_, parent_->function_);
577492
std::swap(analyzer_, parent_->analyzer_);
578493
std::swap(var_map_, parent_->var_map_);
494+
std::swap(di_subprogram_, parent_->di_subprogram_);
579495
}
580496

581497
llvm::Function* function_{nullptr};
498+
llvm::DISubprogram* di_subprogram_{nullptr};
582499
std::unordered_map<const VarNode*, llvm::Value*> var_map_;
583500
std::unique_ptr<arith::Analyzer> analyzer_{std::make_unique<arith::Analyzer>()};
584501
CodeGenCPU* parent_;
@@ -606,6 +523,10 @@ void CodeGenCPU::CreateComputeScope(const AttrStmtNode* op) {
606523
llvm::Function* fcompute = llvm::Function::Create(ftype, llvm::Function::InternalLinkage,
607524
MakeStringRef(value->value), module_.get());
608525
SetTargetAttributes(fcompute);
526+
for (auto it = fcompute->arg_begin(); it != fcompute->arg_end(); it++) {
527+
const Var& var = vargs[std::distance(fcompute->arg_begin(), it)];
528+
it->setName(std::string(var->name_hint));
529+
}
609530

610531
llvm::BasicBlock* compute_call_end = CheckCallSuccess(builder_->CreateCall(fcompute, arg_values));
611532
llvm::LLVMContext* ctx = llvm_target_->GetContext();
@@ -640,11 +561,15 @@ void CodeGenCPU::CreateComputeScope(const AttrStmtNode* op) {
640561
}
641562

642563
function_ = fcompute;
564+
di_subprogram_ = CreateDebugFunction(MakeStringRef(value->value), vargs.Map(GetType),
565+
PrimType(DataType::Int(32)));
643566
auto* compute_entry = llvm::BasicBlock::Create(*ctx, "entry", function_);
644567
builder_->SetInsertPoint(compute_entry);
645568
this->VisitStmt(op->body);
646569
builder_->CreateRet(ConstInt32(0));
647570
builder_->SetInsertPoint(compute_call_end);
571+
572+
AddDebugInformation(fcompute, vargs.Map(GetType));
648573
}
649574

650575
CodeGenLLVM::TypedPointer CodeGenCPU::PackClosureData(const Array<Var>& vfields,

src/target/llvm/codegen_cpu.h

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,11 @@ class CodeGenCPU : public CodeGenLLVM {
165165
// if not directly finalize function and pass on return code.
166166
// return the end block after the check
167167
llvm::BasicBlock* CheckCallSuccess(llvm::Value* retcode);
168-
llvm::DISubprogram* CreateDebugFunction(const PrimFunc& f);
168+
169+
llvm::DISubprogram* CreateDebugFunction(const GlobalVar& gvar, const PrimFunc& f);
170+
llvm::DISubprogram* CreateDebugFunction(llvm::StringRef name, const Array<Type>& param_types,
171+
const Type& return_type);
172+
169173
// Context for injection lookup
170174
llvm::GlobalVariable* gv_mod_ctx_{nullptr};
171175
llvm::GlobalVariable* gv_tvm_func_call_{nullptr};
@@ -189,19 +193,11 @@ class CodeGenCPU : public CodeGenLLVM {
189193
std::vector<std::pair<std::string, llvm::Constant*>> export_system_symbols_;
190194
// List of functions to be registered in the FuncRegistry, if generated.
191195
std::vector<std::pair<std::string, llvm::Function*>> registry_functions_;
192-
// internal debug information, to be populated by
193-
std::unique_ptr<DebugInfo> dbg_info_;
196+
194197
bool target_c_runtime_;
195198
// The system lib prefix if it is not nullopt, then we should do
196199
// system lib registration with the given prefix. The prefix can be ""
197200
Optional<String> system_lib_prefix_;
198-
199-
// Get the DWARF type corresponding to the LLVM type |ty|. The current API in practice only
200-
// generates |int32|, and |int8*|.
201-
llvm::DIType* GetDebugType(const Type& ty_tir);
202-
llvm::DIType* GetDebugType(const Type& ty_tir, llvm::Type* ty_llvm);
203-
// Adds the DWARF debug information for |function| to |dbg_info_|.
204-
void AddDebugInformation(PrimFunc f_tir, llvm::Function* f_llvm);
205201
};
206202

207203
} // namespace codegen

0 commit comments

Comments
 (0)