41
41
#ifndef SPIRVTYPESCAVENGER_H
42
42
#define SPIRVTYPESCAVENGER_H
43
43
44
+ #include " llvm/ADT/IntEqClasses.h"
44
45
#include " llvm/ADT/PointerUnion.h"
45
46
#include " llvm/IR/Instructions.h"
46
47
#include " llvm/IR/Module.h"
47
48
#include " llvm/IR/ValueMap.h"
48
49
49
50
using namespace llvm ;
50
51
51
- // / This class allows for the recovery of pointer element types from LLVM
52
- // / opaque pointer types.
52
+ // / This class allows for the recovery of typed pointer types from LLVM opaque
53
+ // / pointer types. A detailed description of how this algorithm works may be
54
+ // / found in the file comment of SPIRVTypeScavenger.cpp.
53
55
class SPIRVTypeScavenger {
54
- // / A representation of a pointer whose type will be determined by uses. This
55
- // / will include every value that needs to be assigned the same type.
56
- struct DeferredType {
57
- std::vector<Value *> Values;
56
+ // / The mapping from type variables to concrete types.
57
+ std::vector<Type *> TypeVariables;
58
+
59
+ // / The structure storing which type variables have been unified.
60
+ IntEqClasses UnifiedTypeVars;
61
+
62
+ // / Replace all ptr types found within T with new type variables.
63
+ Type *allocateTypeVariable (Type *T);
64
+
65
+ // / Replace all type variables found within T with their concrete types. If
66
+ // / the type variable doesn't have a concrete type yet, the type variable will
67
+ // / be retained.
68
+ Type *substituteTypeVariables (Type *T);
69
+
70
+ // / Try to resolve all type variables into concrete types using knowledge that
71
+ // / T1 and T2 have to be the same type. If T1 and T2 cannot be made the same
72
+ // / type, return false (and callers will know they need to insert synthetic
73
+ // / bitcasts to guarantee equality).
74
+ bool unifyType (Type *T1, Type *T2);
75
+
76
+ // / This stores the Value -> corrected type mapping for the module. It is
77
+ // / expected that all instructions, arguments, and global values will appear
78
+ // / in this mapping, while constants are not expected to be listed here.
79
+ ValueMap<Value *, Type *> DeducedTypes;
80
+
81
+ // / Store associated type variables for certain instructions. In the case
82
+ // / where a return value has an association with an operand, it's necessary
83
+ // / that the type variable used to generate type rules be the same for all
84
+ // / invocations of getTypeRules. This variable allows storage of such
85
+ // / variables.
86
+ ValueMap<Value *, Type *> AssociatedTypeVariables;
87
+
88
+ // / A type rule, which expresses that the given operand of a User must have
89
+ // / the given type (which may contain type variables).
90
+ struct TypeRule {
91
+ unsigned OpNo;
92
+ bool LhsIndirect;
93
+ bool RhsIndirect;
94
+ PointerUnion<Type *, Use *> Target;
95
+ TypeRule (unsigned A, bool AIndirect, Type *B, bool BIndirect)
96
+ : OpNo(A), LhsIndirect(AIndirect), RhsIndirect(BIndirect), Target(B) {}
97
+ TypeRule (unsigned A, bool AIndirect, Use *B, bool BIndirect)
98
+ : OpNo(A), LhsIndirect(AIndirect), RhsIndirect(BIndirect), Target(B) {}
99
+
100
+ // / Establishes typeof(operand) == concrete type
101
+ static TypeRule is (unsigned OpIndex, Type *Ty) {
102
+ return TypeRule (OpIndex, false , Ty, false );
103
+ }
104
+ // / Establishes typeof(operand) == concrete type
105
+ static TypeRule is (Use &U, Type *Ty) {
106
+ return TypeRule::is (U.getOperandNo (), Ty);
107
+ }
108
+ // / Establishes typeof(operand) == typeof(operand)
109
+ static TypeRule is (User &U, unsigned Op1, unsigned Op2) {
110
+ return TypeRule (Op1, false , &U.getOperandUse (Op2), false );
111
+ }
112
+ // / Establishes typedptr(typeof(operand)) == typedptr(typeof(operand))
113
+ // / (this is useful when the address spaces do not need to match).
114
+ static TypeRule isIndirect (User &U, unsigned Op1, unsigned Op2) {
115
+ return TypeRule (Op1, true , &U.getOperandUse (Op2), true );
116
+ }
117
+ // / Establishes typeof(operand) == typedptr(concrete type)
118
+ static TypeRule pointsTo (Use &U, Type *Ty) {
119
+ return TypeRule (U.getOperandNo (), false , Ty, true );
120
+ }
121
+ // / Establishes typeof(operand) == typedptr(concrete type)
122
+ static TypeRule pointsTo (User &U, unsigned OpIndex, Type *Ty) {
123
+ return TypeRule::pointsTo (U.getOperandUse (OpIndex), Ty);
124
+ }
125
+ // / Establishes typeof(mem operand) == typedptr(typeof(val operand))
126
+ static TypeRule pointsTo (User &U, unsigned MemIndex, unsigned ValIndex) {
127
+ return TypeRule (MemIndex, false , &U.getOperandUse (ValIndex), true );
128
+ }
129
+ // / Establishes typeof(operand) == typedptr(typeof(return))
130
+ static TypeRule pointsToReturn (User &U, unsigned OpIndex) {
131
+ return TypeRule (RETURN_OPERAND, true , &U.getOperandUse (OpIndex), false );
132
+ }
133
+ // / Establishes typeof(return) == concrete type
134
+ static TypeRule returns (Type *Ty) {
135
+ return TypeRule (RETURN_OPERAND, false , Ty, false );
136
+ }
137
+ // / Establishes typeof(return) == typedptr(concrete type)
138
+ static TypeRule returnsPointerTo (Type *Ty) {
139
+ return TypeRule (RETURN_OPERAND, false , Ty, true );
140
+ }
141
+ // / Establishes typeof(return) == typeof(operand)
142
+ static TypeRule propagates (Use &U) {
143
+ return TypeRule (RETURN_OPERAND, false , &U, false );
144
+ }
145
+ // / Establishes typeof(return) == typeof(operand)
146
+ static TypeRule propagates (User &U, unsigned OpIndex) {
147
+ return TypeRule::propagates (U.getOperandUse (OpIndex));
148
+ }
149
+ // / Establishes typedptr(typeof(return)) == typedptr(typeof(operand))
150
+ static TypeRule propagatesIndirect (Use &U) {
151
+ return TypeRule (RETURN_OPERAND, true , &U, true );
152
+ }
153
+ // / Establishes typedptr(typeof(return)) == typedptr(typeof(operand))
154
+ static TypeRule propagatesIndirect (User &U, unsigned OpIndex) {
155
+ return TypeRule::propagatesIndirect (U.getOperandUse (OpIndex));
156
+ }
58
157
};
59
158
60
- // / This is called when a deferred type is fixed to a known use.
61
- void fixType (DeferredType &Deferred, Type *AssignedType);
62
-
63
- // / This merges two deferred types into one deferred type.
64
- void mergeType (DeferredType *A, DeferredType *B);
65
-
66
- // / A representation of the possible states of a type internal to this pass:
67
- // / it may be either
68
- // / * Something with a fixed LLVM type (this is a Type *)
69
- // / * A type whose pointer element type is yet unknown (DeferredType *)
70
- // / * A multi-level pointer type (this is a Value *, whose type is what this
71
- // / pointer type will point to). The latter should only exist for
72
- // / pointer operands of memory operations that return ptr.
73
- typedef PointerUnion<Type *, DeferredType *, Value *> DeducedType;
74
- friend llvm::raw_ostream &operator <<(llvm::raw_ostream &OS, DeducedType Ty) {
75
- if (auto *AsTy = dyn_cast<Type *>(Ty))
76
- return OS << *AsTy;
77
- if (auto *AsDeferred = dyn_cast<DeferredType *>(Ty))
78
- return OS << " deferred type for " << *AsDeferred->Values [0 ];
79
- if (auto *AsValue = dyn_cast<Value *>(Ty))
80
- return OS << " points to " << *AsValue;
81
- return OS;
82
- }
159
+ // / This is a value that allows the ability to express the type of a value as
160
+ // / a whole in a typing rule.
161
+ static constexpr unsigned RETURN_OPERAND = ~0U ;
162
+
163
+ // / Turn a type rule into an operand and a type to check for. If the type of
164
+ // / the operand and the type to check against cannot be unified, then a
165
+ // / bitcast will need to be inserted for the use.
166
+ std::pair<Use &, Type *> getTypeCheck (Instruction &I, const TypeRule &Rule);
83
167
84
- // / Compute the pointer element type of a value, solely based on its
85
- // / definition. The value must be pointer-valued.
86
- DeducedType computePointerElementType (Value *V);
168
+ // / Retrieve the list of typing rules for an instruction.
169
+ void getTypeRules (Instruction &I, SmallVectorImpl<TypeRule> &Rules);
87
170
88
- // / This stores the Value -> pointer element type mapping for the module.
89
- ValueMap<Value *, DeducedType> DeducedTypes;
171
+ // / Get the best guess for the type of the value, applying any type rules to
172
+ // / the return value of an instruction that exist. The return type may refer
173
+ // / to type variables that have yet to be resolved, if the type rules are
174
+ // / insufficient to establish a typed pointer type for the instruction.
175
+ Type *getTypeAfterRules (Value *V);
90
176
91
177
// / Enforce that the pointer element types of all operands of the instruction
92
178
// / matches the type that the instruction itself requires. If a pointer
@@ -99,17 +185,21 @@ class SPIRVTypeScavenger {
99
185
// / analysis on the module.
100
186
void deduceFunctionType (Function &F);
101
187
102
- // / This computes the known types of a call to an LLVM intrinsic or specific
103
- // / well-known function name. Returns true if the call filled in type
104
- // / information.
105
- // /
106
- // / The ArgTys parameter contains a list of known type uses for the parameters
107
- // / of the function call. Each element is a pair, with the first being the
108
- // / operand number, and the second indicating either a known type or an
109
- // / unknown type variable (DeferredType).
110
- bool
111
- typeIntrinsicCall (CallBase &CB,
112
- SmallVectorImpl<std::pair<unsigned , DeducedType>> &ArgTys);
188
+ // / This computes known type rules of a call to an LLVM intrinsic or specific
189
+ // / well-known function name. Returns true if the call was known to this
190
+ // / function.
191
+ bool typeIntrinsicCall (CallBase &CB, SmallVectorImpl<TypeRule> &TypeRules);
192
+
193
+ // / Get the type rules for checking argument and return value compatibility
194
+ // / for the function type being called. This is meant to help unify cases
195
+ // / for indirect function calls.
196
+ void typeFunctionParams (CallBase &CB, FunctionType *FT, unsigned ArgStart,
197
+ bool IncludeRet,
198
+ SmallVectorImpl<TypeRule> &TypeRules);
199
+
200
+ // / Compute the type of a global variable or global alias, based on the type
201
+ // / of the initializer (which may be null for global variables).
202
+ void typeGlobalValue (GlobalValue &GV, Constant *Init);
113
203
114
204
// / Compute pointer element types for all pertinent values in the module.
115
205
void typeModule (Module &M);
@@ -119,24 +209,17 @@ class SPIRVTypeScavenger {
119
209
std::vector<Value *> VisitStack;
120
210
121
211
public:
122
- explicit SPIRVTypeScavenger (Module &M) { typeModule (M); }
123
-
124
- // / This type represents the type that a pointer element type of a type. If it
125
- // / is a Type value, then the pointee type represents a pointer to that type.
126
- // / If it is a Value value, then the pointee type is the type of that value
127
- // / (which should be a pointer-typed value.)
128
- typedef PointerUnion<Type *, Value *> PointeeType;
129
-
130
- // / Get the pointer element type of the value.
131
- // / If the type is a multi-level pointer, then PointeeType will be a Value
132
- // / whose pointee type can be recursively queried through this method.
133
- // / Otherwise, it will be a pointer to the Type returned by this method.
134
- PointeeType getPointerElementType (Value *V);
135
-
136
- // / Get the pointer element type of an argument of the given function. Since
137
- // / this type is guaranteed to not be a multi-level pointer type, the result
138
- // / is an LLVM type instead of a PointeeType.
139
- Type *getArgumentPointerElementType (Function *F, unsigned ArgNo);
212
+ explicit SPIRVTypeScavenger (Module &M) : UnifiedTypeVars(1024 ) {
213
+ typeModule (M);
214
+ }
215
+
216
+ // / Get the type of the value, with pointer types replaced with
217
+ // / TypedPointerType types instead.
218
+ Type *getScavengedType (Value *V);
219
+
220
+ // / Get the deduced function type for a function, with pointer types replaced
221
+ // / with TypedPointerTypes (maybe including type variables).
222
+ FunctionType *getFunctionType (Function *F);
140
223
};
141
224
142
225
#endif // SPIRVTYPESCAVENGER_H
0 commit comments