Enzyme main
Loading...
Searching...
No Matches
RustDebugInfo.cpp
Go to the documentation of this file.
1//===- RustDebugInfo.cpp - Implementaion of Rust Debug Info Parser ---===//
2//
3// Enzyme Project
4//
5// Part of the Enzyme Project, under the Apache License v2.0 with LLVM
6// Exceptions. See https://llvm.org/LICENSE.txt for license information.
7// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8//
9// If using this code in an academic setting, please cite the following:
10// @incollection{enzymeNeurips,
11// title = {Instead of Rewriting Foreign Code for Machine Learning,
12// Automatically Synthesize Fast Gradients},
13// author = {Moses, William S. and Churavy, Valentin},
14// booktitle = {Advances in Neural Information Processing Systems 33},
15// year = {2020},
16// note = {To appear in},
17// }
18//
19//===-------------------------------------------------------------------===//
20//
21// This file implement the Rust debug info parsing function. It will get the
22// description of types from debug info of an instruction and pass it to
23// concrete functions according to the kind of a description and construct
24// the type tree recursively.
25//
26//===-------------------------------------------------------------------===//
27#include "llvm/IR/DIBuilder.h"
28#include "llvm/IR/DataLayout.h"
29#include "llvm/IR/DebugInfo.h"
30#include "llvm/Support/CommandLine.h"
31
32#include "RustDebugInfo.h"
33
34using namespace llvm;
35
36TypeTree parseDIType(DIType &Type, Instruction &I, DataLayout &DL);
37
38TypeTree parseDIType(DIBasicType &Type, Instruction &I, DataLayout &DL) {
39 auto TypeName = Type.getName();
40 TypeTree Result;
41 if (TypeName == "f64") {
42 Result = TypeTree(Type::getDoubleTy(I.getContext())).Only(0, &I);
43 } else if (TypeName == "f32") {
44 Result = TypeTree(Type::getFloatTy(I.getContext())).Only(0, &I);
45 } else if (TypeName == "i8" || TypeName == "i16" || TypeName == "i32" ||
46 TypeName == "i64" || TypeName == "isize" || TypeName == "u8" ||
47 TypeName == "u16" || TypeName == "u32" || TypeName == "u64" ||
48 TypeName == "usize" || TypeName == "i128" || TypeName == "u128") {
50 } else {
52 }
53 return Result;
54}
55
56TypeTree parseDIType(DICompositeType &Type, Instruction &I, DataLayout &DL) {
57 TypeTree Result;
58 if (Type.getTag() == dwarf::DW_TAG_array_type) {
59 DIType *SubType = Type.getBaseType();
60 TypeTree SubTT = parseDIType(*SubType, I, DL);
61 size_t Align = Type.getAlignInBytes();
62 size_t SubSize = SubType->getSizeInBits() / 8;
63 size_t Size = Type.getSizeInBits() / 8;
64 DINodeArray Subranges = Type.getElements();
65 size_t pos = 0;
66 for (auto r : Subranges) {
67 DISubrange *Subrange = dyn_cast<DISubrange>(r);
68 if (auto Count = Subrange->getCount().get<ConstantInt *>()) {
69 int64_t count = Count->getSExtValue();
70 if (count == -1) {
71 break;
72 }
73 for (int64_t i = 0; i < count; i++) {
74 Result |= SubTT.ShiftIndices(DL, 0, Size, pos);
75 size_t tmp = pos + SubSize;
76 if (tmp % Align != 0) {
77 pos = (tmp / Align + 1) * Align;
78 } else {
79 pos = tmp;
80 }
81 }
82 } else {
83 assert(0 && "There shouldn't be non-constant-size arrays in Rust");
84 }
85 }
86 } else if (Type.getTag() == dwarf::DW_TAG_structure_type ||
87 Type.getTag() == dwarf::DW_TAG_union_type) {
88 DINodeArray Elements = Type.getElements();
89 size_t Size = Type.getSizeInBits() / 8;
90 bool firstSubTT = true;
91 for (auto e : Elements) {
92 DIType *SubType = dyn_cast<DIDerivedType>(e);
93 assert(SubType->getTag() == dwarf::DW_TAG_member);
94 TypeTree SubTT = parseDIType(*SubType, I, DL);
95 size_t Offset = SubType->getOffsetInBits() / 8;
96 SubTT = SubTT.ShiftIndices(DL, 0, Size, Offset);
97 if (Type.getTag() == dwarf::DW_TAG_structure_type) {
98 Result |= SubTT;
99 } else {
100 if (firstSubTT) {
101 Result = SubTT;
102 } else {
103 Result &= SubTT;
104 }
105 }
106 if (firstSubTT) {
107 firstSubTT = !firstSubTT;
108 }
109 }
110 } else {
111 assert(0 && "Composite types other than arrays, structs and unions are not "
112 "supported by Rust debug info parser");
113 }
114 return Result;
115}
116
117TypeTree parseDIType(DIDerivedType &Type, Instruction &I, DataLayout &DL) {
118 if (Type.getTag() == dwarf::DW_TAG_pointer_type) {
120 DIType *SubType = Type.getBaseType();
121 TypeTree SubTT = parseDIType(*SubType, I, DL);
122 if (isa<DIBasicType>(SubType)) {
123 Result |= SubTT.ShiftIndices(DL, 0, 1, -1);
124 } else {
125 Result |= SubTT;
126 }
127 return Result.Only(0, &I);
128 } else if (Type.getTag() == dwarf::DW_TAG_member) {
129 DIType *SubType = Type.getBaseType();
130 TypeTree Result = parseDIType(*SubType, I, DL);
131 return Result;
132 } else {
133 assert(0 && "Derived types other than pointers and members are not "
134 "supported by Rust debug info parser");
135 }
136 return {};
137}
138
139TypeTree parseDIType(DIType &Type, Instruction &I, DataLayout &DL) {
140 if (Type.getSizeInBits() == 0) {
141 return TypeTree();
142 }
143
144 if (auto BT = dyn_cast<DIBasicType>(&Type)) {
145 return parseDIType(*BT, I, DL);
146 } else if (auto CT = dyn_cast<DICompositeType>(&Type)) {
147 return parseDIType(*CT, I, DL);
148 } else if (auto DT = dyn_cast<DIDerivedType>(&Type)) {
149 return parseDIType(*DT, I, DL);
150 } else {
151 assert(0 && "Types other than floating-points, integers, arrays, pointers, "
152 "slices, and structs are not supported by debug info parser");
153 }
154 return {};
155}
156
157bool isU8PointerType(DIType &type) {
158 if (type.getTag() == dwarf::DW_TAG_pointer_type) {
159 auto PTy = dyn_cast<DIDerivedType>(&type);
160 DIType *SubType = PTy->getBaseType();
161 if (auto BTy = dyn_cast<DIBasicType>(SubType)) {
162 std::string name = BTy->getName().str();
163 if (name == "u8") {
164 return true;
165 }
166 }
167 }
168 return false;
169}
170
171TypeTree parseDIType(DbgDeclareInst &I, DataLayout &DL) {
172 DIType *type = I.getVariable()->getType();
173
174 // If the type is *u8, do nothing, since the underlying type of data pointed
175 // by a *u8 can be anything
176 if (isU8PointerType(*type)) {
177 return TypeTree();
178 }
179 TypeTree Result = parseDIType(*type, I, DL);
180 return Result;
181}
TypeTree parseDIType(DIType &Type, Instruction &I, DataLayout &DL)
bool isU8PointerType(DIType &type)
Concrete SubType of a given value.
Class representing the underlying types of values as sequences of offsets to a ConcreteType.
Definition TypeTree.h:72
TypeTree Only(int Off, llvm::Instruction *orig) const
Prepend an offset to all mappings.
Definition TypeTree.h:471
TypeTree ShiftIndices(const llvm::DataLayout &dl, const int offset, const int maxSize, size_t addOffset=0) const
Replace mappings in the range in [offset, offset+maxSize] with those in.
Definition TypeTree.h:840