1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #include "vc/Utils/General/DebugInfo.h"
10 #include "vc/Utils/GenX/TypeSize.h"
11 
12 #include <llvm/IR/DebugInfoMetadata.h>
13 #include <llvm/IR/GlobalVariable.h>
14 #include <llvm/IR/IRBuilder.h>
15 #include <llvm/IR/Intrinsics.h>
16 #include <llvm/IR/Module.h>
17 #include <llvm/Support/Debug.h>
18 
19 #include <llvmWrapper/IR/DerivedTypes.h>
20 
21 #include "Probe/Assertion.h"
22 
23 #define DEBUG_TYPE "VC_DEBUG_INFO_UTILS"
24 
25 using namespace llvm;
26 
checkIfModuleHasDebugInfo(const llvm::Module & M)27 bool vc::DIBuilder::checkIfModuleHasDebugInfo(const llvm::Module &M) {
28   unsigned NumDebugCUs =
29       std::distance(M.debug_compile_units_begin(), M.debug_compile_units_end());
30 
31   if (NumDebugCUs == 0)
32     return false;
33 
34   IGC_ASSERT_MESSAGE(NumDebugCUs == 1,
35                      "only modules with one CU are supported at the moment:");
36   return NumDebugCUs == 1;
37 }
38 
checkIfFunctionHasDebugInfo(const llvm::Function & F)39 bool vc::DIBuilder::checkIfFunctionHasDebugInfo(const llvm::Function &F) {
40   DISubprogram *SP = F.getSubprogram();
41   if (!SP)
42     return false;
43   IGC_ASSERT(checkIfModuleHasDebugInfo(*F.getParent()));
44   return true;
45 }
46 
createDbgDeclareForLocalizedGlobal(llvm::Instruction & Address,const llvm::GlobalVariable & GV,llvm::Instruction & InsertPt)47 llvm::DbgDeclareInst *vc::DIBuilder::createDbgDeclareForLocalizedGlobal(
48     llvm::Instruction &Address, const llvm::GlobalVariable &GV,
49     llvm::Instruction &InsertPt) {
50   auto &Fn = *Address.getFunction();
51 
52   if (!vc::DIBuilder::checkIfFunctionHasDebugInfo(Fn))
53     return nullptr;
54 
55   SmallVector<DIGlobalVariableExpression *, 1> GVEs;
56   GV.getDebugInfo(GVEs);
57   if (GVEs.empty())
58     return nullptr;
59   IGC_ASSERT(GVEs.size() == 1);
60 
61   DIGlobalVariableExpression &GVE = *GVEs.front();
62   const DIGlobalVariable &DIDebugVariable = *GVE.getVariable();
63   DIExpression &DIExpr = *GVE.getExpression();
64 
65   vc::DIBuilder DBuilder(*Address.getModule());
66 
67   auto *DILocalVar = DBuilder.createLocalVariable(
68       Fn.getSubprogram(), DIDebugVariable.getName(), DIDebugVariable.getFile(),
69       0 /*LineNo*/, DIDebugVariable.getType(), 0 /*ArgNo*/,
70       DINode::DIFlags::FlagArtificial, DIDebugVariable.getAlignInBits());
71   auto *DILoc = DBuilder.createLocationForFunctionScope(Fn);
72   return DBuilder.createDbgDeclare(Address, *DILocalVar, DIExpr, *DILoc,
73                                    InsertPt);
74 }
75 
registerNewGlobalVariable(llvm::DIGlobalVariableExpression * NewGV) const76 void vc::DIBuilder::registerNewGlobalVariable(
77     llvm::DIGlobalVariableExpression *NewGV) const {
78   IGC_ASSERT(NewGV);
79   auto *CU = getDICompileUnit();
80   IGC_ASSERT(CU);
81 
82   auto OldGlobals = CU->getGlobalVariables();
83   SmallVector<Metadata *, 4> NewGlobals;
84   std::copy(OldGlobals.begin(), OldGlobals.end(),
85             std::back_inserter(NewGlobals));
86   NewGlobals.push_back(NewGV);
87 
88   CU->replaceGlobalVariables(MDTuple::get(M.getContext(), NewGlobals));
89 }
90 
createLocationForFunctionScope(Function & Fn) const91 DILocation *vc::DIBuilder::createLocationForFunctionScope(Function &Fn) const {
92   IGC_ASSERT(checkIfFunctionHasDebugInfo(Fn));
93   auto *SP = Fn.getSubprogram();
94   auto *DILoc = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);
95   return DILoc;
96 }
97 
getDICompileUnit() const98 llvm::DICompileUnit *vc::DIBuilder::getDICompileUnit() const {
99   IGC_ASSERT_MESSAGE(checkIfModuleHasDebugInfo(M), "debug info required!");
100   return *M.debug_compile_units_begin();
101 }
102 
translateScalarTypeToDIType(Type & Ty) const103 DIType *vc::DIBuilder::translateScalarTypeToDIType(Type &Ty) const {
104   IGC_ASSERT(!Ty.isVectorTy());
105   if (!Ty.isIntegerTy()) {
106     LLVM_DEBUG(dbgs() << "ERROR: could not derive DIType for: " << Ty << "\n");
107     return nullptr;
108   }
109   auto SizeInBits = vc::getTypeSize(&Ty, &M.getDataLayout()).inBits();
110   return DIBasicType::get(
111       M.getContext(), dwarf::DW_TAG_base_type, ("ui" + Twine(SizeInBits)).str(),
112       SizeInBits, 0 /*Align*/, dwarf::DW_ATE_unsigned, DINode::FlagZero);
113 }
114 
translateTypeToDIType(Type & Ty) const115 DIType *vc::DIBuilder::translateTypeToDIType(Type &Ty) const {
116   if (!Ty.isVectorTy())
117     return translateScalarTypeToDIType(Ty);
118 
119   auto *VTy = dyn_cast<IGCLLVM::FixedVectorType>(&Ty);
120   if (!VTy) {
121     LLVM_DEBUG(dbgs() << "ERROR: could not derive DIType for: " << Ty << "\n");
122     return nullptr;
123   }
124   auto *ScalarTy = VTy->getScalarType();
125   auto *ScalarDI = translateScalarTypeToDIType(*ScalarTy);
126   if (!ScalarDI) {
127     LLVM_DEBUG(dbgs() << "ERROR: could not derive element DIType for: " << *VTy
128                       << "\n");
129     return nullptr;
130   }
131 
132   auto &Ctx = M.getContext();
133   auto NumElements = VTy->getNumElements();
134   auto *SubrangeDI = DISubrange::get(Ctx, NumElements, 0 /*Lo*/);
135   auto *Subscripts = MDTuple::get(Ctx, SubrangeDI);
136   auto SizeInBits = vc::getTypeSize(VTy, &M.getDataLayout()).inBits();
137   auto *CompositeTypeDI = DICompositeType::get(
138       Ctx, dwarf::DW_TAG_array_type, "" /*Name*/, nullptr /*File*/, 0 /*Line*/,
139       nullptr /*Scope*/, ScalarDI, SizeInBits, 0 /*AlignInBits*/,
140       0 /*OfffsetInBits*/, DINode::FlagVector, Subscripts, 0, nullptr);
141   return CompositeTypeDI;
142 }
143 
createGlobalVariableExpression(StringRef Name,StringRef LinkageName,DIType * Type) const144 llvm::DIGlobalVariableExpression *vc::DIBuilder::createGlobalVariableExpression(
145     StringRef Name, StringRef LinkageName, DIType *Type) const {
146   auto *CU = getDICompileUnit();
147   IGC_ASSERT(CU);
148   auto &Ctx = M.getContext();
149 
150   auto *GV = DIGlobalVariable::getDistinct(
151       Ctx, cast_or_null<DIScope>(CU), Name, LinkageName, CU->getFile(),
152       0 /*Line No*/, Type, true /*IsLocalToUnit*/, true /*isDefined*/,
153       nullptr /*Decl*/, nullptr /*TemplateParams*/, 0 /*AlignInBits*/);
154   auto *EmptyExpr = DIExpression::get(Ctx, llvm::None);
155   auto *GVE = DIGlobalVariableExpression::get(Ctx, GV, EmptyExpr);
156 
157   // all globals should be registered in DICompileUnit::globals
158   registerNewGlobalVariable(GVE);
159 
160   return GVE;
161 }
162 
163 llvm::DbgDeclareInst *
createDbgDeclare(Value & Address,DILocalVariable & LocalVar,DIExpression & Expr,DILocation & Loc,Instruction & InsertPt) const164 vc::DIBuilder::createDbgDeclare(Value &Address, DILocalVariable &LocalVar,
165                                 DIExpression &Expr, DILocation &Loc,
166                                 Instruction &InsertPt) const {
167   auto &Ctx = M.getContext();
168 
169   Value *DeclareArgs[] = {
170       MetadataAsValue::get(Ctx, ValueAsMetadata::get(&Address)),
171       MetadataAsValue::get(Ctx, &LocalVar), MetadataAsValue::get(Ctx, &Expr)};
172 
173   auto *DbgDeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare);
174   IRBuilder<> Builder(&InsertPt);
175   Builder.SetCurrentDebugLocation(&Loc);
176   auto *DeclareInst = Builder.CreateCall(DbgDeclareFn, DeclareArgs);
177   return cast<DbgDeclareInst>(DeclareInst);
178 }
179 
createLocalVariable(llvm::DILocalScope * Scope,llvm::StringRef Name,llvm::DIFile * File,unsigned LineNo,llvm::DIType * Type,unsigned ArgNo,llvm::DINode::DIFlags Flags,unsigned AlignInBits) const180 llvm::DILocalVariable *vc::DIBuilder::createLocalVariable(
181     llvm::DILocalScope *Scope, llvm::StringRef Name, llvm::DIFile *File,
182     unsigned LineNo, llvm::DIType *Type, unsigned ArgNo,
183     llvm::DINode::DIFlags Flags, unsigned AlignInBits) const {
184   return DILocalVariable::get(M.getContext(), Scope, Name, File, LineNo, Type,
185                               ArgNo, Flags, AlignInBits);
186 }
187