@@ -118,52 +118,74 @@ static Type *getPointerUseType(Function *F, Op Opcode, unsigned ArgNo) {
118
118
}
119
119
}
120
120
121
- void SPIRVTypeScavenger::deduceIntrinsicTypes (Function &F, Intrinsic::ID Id) {
122
- static constexpr unsigned Return = ~0U ;
123
- auto AddParameter = [&](unsigned ArgNo, DeducedType Ty) {
124
- if (ArgNo == Return) {
125
- // TODO: Handle return types properly.
126
- } else {
127
- Argument *Arg = F.getArg (ArgNo);
128
- LLVM_DEBUG (dbgs () << " Parameter " << *Arg << " of " << F.getName ()
129
- << " has type " << Ty << " \n " );
130
- DeducedTypes[Arg] = Ty;
121
+ bool SPIRVTypeScavenger::typeIntrinsicCall (
122
+ CallBase &CB, SmallVectorImpl<std::pair<unsigned , DeducedType>> &ArgTys) {
123
+ Function *TargetFn = CB.getCalledFunction ();
124
+ assert (TargetFn && TargetFn->isDeclaration () &&
125
+ " Call is not an intrinsic function call" );
126
+ LLVMContext &Ctx = TargetFn->getContext ();
127
+
128
+ if (auto IntrinID = TargetFn->getIntrinsicID ()) {
129
+ switch (IntrinID) {
130
+ case Intrinsic::memcpy: {
131
+ // First two parameters are pointers, but it may be any pointer type.
132
+ DeducedType MemcpyTy = new DeferredType;
133
+ ArgTys.emplace_back (0 , MemcpyTy);
134
+ ArgTys.emplace_back (1 , MemcpyTy);
135
+ break ;
131
136
}
132
- };
133
- LLVMContext &Ctx = F.getContext ();
137
+ case Intrinsic::memset:
138
+ ArgTys.emplace_back (0 , Type::getInt8Ty (Ctx));
139
+ break ;
140
+ case Intrinsic::lifetime_start:
141
+ case Intrinsic::lifetime_end:
142
+ case Intrinsic::invariant_start:
143
+ // These intrinsics were stored as i8* as typed pointers, and the SPIR-V
144
+ // writer will expect these to be i8*, even if they can be any pointer
145
+ // type.
146
+ ArgTys.emplace_back (1 , Type::getInt8Ty (Ctx));
147
+ break ;
148
+ case Intrinsic::invariant_end:
149
+ // This is like invariant_start with an extra string parameter in the
150
+ // beginning (so the pointer object moves to argument two).
151
+ ArgTys.emplace_back (0 , Type::getInt8Ty (Ctx));
152
+ ArgTys.emplace_back (2 , Type::getInt8Ty (Ctx));
153
+ break ;
154
+ case Intrinsic::var_annotation:
155
+ case Intrinsic::ptr_annotation:
156
+ // The first parameter of these is an i8*.
157
+ ArgTys.emplace_back (0 , Type::getInt8Ty (Ctx));
158
+ [[fallthrough]];
159
+ case Intrinsic::annotation:
160
+ // Second and third parameters are strings, which should be constants
161
+ // for global variables. Nominally, this is i8*, but we specifically
162
+ // *do not* want to insert bitcast instructions (they need to remain
163
+ // global constants).
164
+ break ;
165
+ case Intrinsic::stacksave:
166
+ // TODO: support return type.
167
+ break ;
168
+ case Intrinsic::stackrestore:
169
+ ArgTys.emplace_back (0 , Type::getInt8Ty (Ctx));
170
+ break ;
171
+ case Intrinsic::instrprof_cover:
172
+ case Intrinsic::instrprof_increment:
173
+ case Intrinsic::instrprof_increment_step:
174
+ case Intrinsic::instrprof_value_profile:
175
+ // llvm.instrprof.* intrinsics are not supported
176
+ ArgTys.emplace_back (0 , Type::getInt8Ty (Ctx));
177
+ break ;
178
+ // TODO: handle masked gather/scatter intrinsics. This requires support
179
+ // for vector-of-pointers in the type scavenger.
180
+ default :
181
+ return false ;
182
+ }
183
+ } else if (TargetFn->getName ().startswith (" _Z18__spirv_ocl_printf" )) {
184
+ ArgTys.emplace_back (0 , Type::getInt8Ty (Ctx));
185
+ } else
186
+ return false ;
134
187
135
- switch (Id) {
136
- case Intrinsic::memcpy:
137
- // First parameter is a pointer, but it may be any pointer type.
138
- return ;
139
- case Intrinsic::lifetime_start:
140
- case Intrinsic::lifetime_end:
141
- case Intrinsic::invariant_start:
142
- case Intrinsic::invariant_end:
143
- AddParameter (1 , Type::getInt8Ty (Ctx));
144
- return ;
145
- // Second and third parameters are strings, which mean nothing.
146
- case Intrinsic::annotation:
147
- return ;
148
- case Intrinsic::var_annotation:
149
- case Intrinsic::ptr_annotation:
150
- AddParameter (0 , Type::getInt8Ty (Ctx));
151
- // Second and third parameters are strings, so they can be any type.
152
- return ;
153
- case Intrinsic::stacksave:
154
- AddParameter (Return, Type::getInt8Ty (Ctx));
155
- return ;
156
- case Intrinsic::stackrestore:
157
- AddParameter (0 , Type::getInt8Ty (Ctx));
158
- return ;
159
- // llvm.instrprof.* intrinsics are not supported
160
- case Intrinsic::instrprof_cover:
161
- case Intrinsic::instrprof_increment:
162
- case Intrinsic::instrprof_increment_step:
163
- case Intrinsic::instrprof_value_profile:
164
- AddParameter (0 , Type::getInt8Ty (Ctx));
165
- return ;
166
- }
188
+ return true ;
167
189
}
168
190
169
191
static Type *getParamType (const AttributeList &AL, unsigned ArgNo) {
@@ -222,15 +244,13 @@ void SPIRVTypeScavenger::deduceFunctionType(Function &F) {
222
244
}
223
245
}
224
246
225
- if (auto IntrinID = F.getIntrinsicID ()) {
226
- deduceIntrinsicTypes (F, IntrinID);
227
- }
228
-
229
247
// If the function is a mangled name, try to recover types from the Itanium
230
248
// name mangling.
231
249
if (F.getName ().startswith (" _Z" )) {
232
250
SmallVector<Type *, 8 > ParamTypes;
233
- getParameterTypes (&F, ParamTypes);
251
+ if (!getParameterTypes (&F, ParamTypes)) {
252
+ return ;
253
+ }
234
254
for (Argument *Arg : PointerArgs) {
235
255
if (auto *Ty = dyn_cast<TypedPointerType>(ParamTypes[Arg->getArgNo ()])) {
236
256
DeducedTypes[Arg] = Ty->getElementType ();
@@ -447,15 +467,17 @@ void SPIRVTypeScavenger::correctUseTypes(Instruction &I) {
447
467
// If we have an identified function for the call instruction, map the
448
468
// arguments we pass in to the argument requirements of the function.
449
469
if (Function *F = CB->getCalledFunction ()) {
450
- for (Use &U : CB->args ()) {
451
- // If we're calling a var-arg method, we have more operands than the
452
- // function has parameters. Bail out if we hit that point.
453
- unsigned ArgNo = CB->getArgOperandNo (&U);
454
- if (ArgNo >= F->arg_size ())
455
- break ;
456
- if (U->getType ()->isPointerTy ())
457
- PointerOperands.emplace_back (
458
- U.getOperandNo (), computePointerElementType (F->getArg (ArgNo)));
470
+ if (!F->isDeclaration () || !typeIntrinsicCall (*CB, PointerOperands)) {
471
+ for (Use &U : CB->args ()) {
472
+ // If we're calling a var-arg method, we have more operands than the
473
+ // function has parameters. Bail out if we hit that point.
474
+ unsigned ArgNo = CB->getArgOperandNo (&U);
475
+ if (ArgNo >= F->arg_size ())
476
+ break ;
477
+ if (U->getType ()->isPointerTy ())
478
+ PointerOperands.emplace_back (
479
+ U.getOperandNo (), computePointerElementType (F->getArg (ArgNo)));
480
+ }
459
481
}
460
482
}
461
483
}
0 commit comments