Adding debug support to tinylang – Advanced IR Generation-2


  1. If the type name is simply renamed, then we must map this to a type definition. Here, we need to make use of the scope and line number information:

llvm::DIType *
CGDebugInfo::getAliasType(AliasTypeDeclaration *Ty) {
return DBuilder.createTypedef(
getType(Ty->getType()), Ty->getName(),
CU->getFile(), getLineNumber(Ty->getLocation()),
getScope());
}

  1. Creating the debug information for an array requires specifying the size and the alignment. We can retrieve this data from the DataLayout class. We also need to specify the index range of the array:

llvm::DIType *
CGDebugInfo::getArrayType(ArrayTypeDeclaration *Ty) {
auto *ATy =
llvm::cast(CGM.convertType(Ty));
const llvm::DataLayout &DL =
CGM.getModule()->getDataLayout();
Expr *Nums = Ty->getNums();
uint64_t NumElements =
llvm::cast(Nums)
->getValue()
.getZExtValue();
llvm::SmallVector Subscripts;
Subscripts.push_back(
DBuilder.getOrCreateSubrange(0, NumElements));
return DBuilder.createArrayType(
DL.getTypeSizeInBits(ATy) * 8,
1 << Log2(DL.getABITypeAlign(ATy)), getType(Ty->getType()),
DBuilder.getOrCreateArray(Subscripts));
}

  1. Using all these single methods, we can create a central method to create the metadata for a type. This metadata is also responsible for caching the data:

llvm::DIType *
CGDebugInfo::getType(TypeDeclaration *Ty) {
if (llvm::DIType *T = TypeCache[Ty])
return T;
if (llvm::isa(Ty))
return TypeCache[Ty] = getPervasiveType(Ty);
else if (auto *AliasTy =
llvm::dyn_cast(Ty))
return TypeCache[Ty] = getAliasType(AliasTy);
else if (auto *ArrayTy =
llvm::dyn_cast(Ty))
return TypeCache[Ty] = getArrayType(ArrayTy);
else if (auto *RecordTy =
llvm ::dyn_cast(
Ty))
return TypeCache[Ty] = getRecordType(RecordTy);
llvm::report_fatal_error(“Unsupported type”);
return nullptr;
}

  1. We also need to add a method to emit metadata for global variables:

void CGDebugInfo::emitGlobalVariable(
VariableDeclaration *Decl,
llvm::GlobalVariable *V) {
llvm::DIGlobalVariableExpression *GV =
DBuilder.createGlobalVariableExpression(
getScope(), Decl->getName(), V->getName(),
CU->getFile(),
getLineNumber(Decl->getLocation()),
getType(Decl->getType()), false);
V->addDebugInfo(GV);
}

  1. To emit the debug information for procedures, we need to create the metadata for the procedure type. For this, we need a list of the types of the parameter, with the return type being the first entry. If the procedure has no return type, then we must use an unspecified type; this is called void, similar to how it is in C. If a parameter is a reference, then we need to add the reference type; otherwise, we must add the type to the list:

llvm::DISubroutineType *
CGDebugInfo::getType(ProcedureDeclaration *P) {
llvm::SmallVector Types;
const llvm::DataLayout &DL =
CGM.getModule()->getDataLayout();
// Return type at index 0
if (P->getRetType())
Types.push_back(getType(P->getRetType()));
else
Types.push_back(
DBuilder.createUnspecifiedType(“void”));
for (const auto *FP : P->getFormalParams()) {
llvm::DIType *PT = getType(FP->getType());
if (FP->isVar()) {
llvm::Type *PTy = CGM.convertType(FP->getType());
PT = DBuilder.createReferenceType(
llvm::dwarf::DW_TAG_reference_type, PT,
DL.getTypeSizeInBits(PTy) * 8,
1 << Log2(DL.getABITypeAlign(PTy)));
}
Types.push_back(PT);
}
return DBuilder.createSubroutineType(
DBuilder.getOrCreateTypeArray(Types));
}

  1. For the procedure itself, we can now create the debug information using the procedure type we created in the previous step. A procedure also opens a new scope, so we must push the procedure onto the scope stack. We must also associate the LLVM function object with the new debug information:

void CGDebugInfo::emitProcedure(
ProcedureDeclaration *Decl, llvm::Function *Fn) {
llvm::DISubroutineType *SubT = getType(Decl);
llvm::DISubprogram *Sub = DBuilder.createFunction(
getScope(), Decl->getName(), Fn->getName(),
CU->getFile(), getLineNumber(Decl->getLocation()),
SubT, getLineNumber(Decl->getLocation()),
llvm::DINode::FlagPrototyped,
llvm::DISubprogram::SPFlagDefinition);
openScope(Sub);
Fn->setSubprogram(Sub);
}

Leave a Reply

Your email address will not be published. Required fields are marked *