Skip to content

Commit df39701

Browse files
jcranmer-intelKornevNikita
authored andcommitted
Improvements to the type scavenger. (#1775)
The main improvement is to enable intrinsics with more complex typing rules to be described. For example, memcpy's requirement that its two pointer arguments have the same type. There is still a larger rewrite of the type scavenger to use TypedPointerType coming down the line. However, this rewrite also needs opaque types to represent the deferred type concept, which is why it hasn't been done yet. This is an intermediate step in the rewrite which better supports some of the other intrinsics with current issues. Original commit: KhronosGroup/SPIRV-LLVM-Translator@df51179
1 parent 3549f63 commit df39701

File tree

3 files changed

+100
-69
lines changed

3 files changed

+100
-69
lines changed

llvm-spirv/lib/SPIRV/SPIRVTypeScavenger.cpp

Lines changed: 80 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -118,52 +118,74 @@ static Type *getPointerUseType(Function *F, Op Opcode, unsigned ArgNo) {
118118
}
119119
}
120120

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;
131136
}
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;
134187

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;
167189
}
168190

169191
static Type *getParamType(const AttributeList &AL, unsigned ArgNo) {
@@ -222,15 +244,13 @@ void SPIRVTypeScavenger::deduceFunctionType(Function &F) {
222244
}
223245
}
224246

225-
if (auto IntrinID = F.getIntrinsicID()) {
226-
deduceIntrinsicTypes(F, IntrinID);
227-
}
228-
229247
// If the function is a mangled name, try to recover types from the Itanium
230248
// name mangling.
231249
if (F.getName().startswith("_Z")) {
232250
SmallVector<Type *, 8> ParamTypes;
233-
getParameterTypes(&F, ParamTypes);
251+
if (!getParameterTypes(&F, ParamTypes)) {
252+
return;
253+
}
234254
for (Argument *Arg : PointerArgs) {
235255
if (auto *Ty = dyn_cast<TypedPointerType>(ParamTypes[Arg->getArgNo()])) {
236256
DeducedTypes[Arg] = Ty->getElementType();
@@ -447,15 +467,17 @@ void SPIRVTypeScavenger::correctUseTypes(Instruction &I) {
447467
// If we have an identified function for the call instruction, map the
448468
// arguments we pass in to the argument requirements of the function.
449469
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+
}
459481
}
460482
}
461483
}

llvm-spirv/lib/SPIRV/SPIRVTypeScavenger.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#define SPIRVTYPESCAVENGER_H
4343

4444
#include "llvm/ADT/PointerUnion.h"
45+
#include "llvm/IR/Instructions.h"
4546
#include "llvm/IR/Module.h"
4647
#include "llvm/IR/ValueMap.h"
4748

@@ -98,9 +99,17 @@ class SPIRVTypeScavenger {
9899
/// analysis on the module.
99100
void deduceFunctionType(Function &F);
100101

101-
/// This assigns known pointer element types for parameters of LLVM
102-
/// intrinsics.
103-
void deduceIntrinsicTypes(Function &F, Intrinsic::ID Id);
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);
104113

105114
/// Compute pointer element types for all pertinent values in the module.
106115
void typeModule(Module &M);

llvm-spirv/test/transcoding/multiple_user_semantic.ll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,25 @@
1212

1313
; CHECK-SPIRV-DAG: Name [[#ClassMember:]] "class.Sample"
1414
; CHECK-SPIRV-DAG: Decorate [[#Var:]] UserSemantic "var_annotation_a"
15-
; CHECK-SPIRV-DAG: Decorate [[#Var]] UserSemantic "var_annotation_b"
15+
; CHECK-SPIRV-DAG: Decorate [[#Var]] UserSemantic "var_annotation_b2"
1616
; CHECK-SPIRV-DAG: MemberDecorate [[#ClassMember]] 0 UserSemantic "class_annotation_a"
17-
; CHECK-SPIRV-DAG: MemberDecorate [[#ClassMember]] 0 UserSemantic "class_annotation_b"
17+
; CHECK-SPIRV-DAG: MemberDecorate [[#ClassMember]] 0 UserSemantic "class_annotation_b2"
1818
; CHECK-SPIRV: Variable [[#]] [[#Var]] [[#]]
1919

2020
; CHECK-LLVM: @[[StrStructA:[0-9_.]+]] = {{.*}}"class_annotation_a\00"
21-
; CHECK-LLVM: @[[StrStructB:[0-9_.]+]] = {{.*}}"class_annotation_b\00"
21+
; CHECK-LLVM: @[[StrStructB:[0-9_.]+]] = {{.*}}"class_annotation_b2\00"
2222
; CHECK-LLVM: @[[StrA:[0-9_.]+]] = {{.*}}"var_annotation_a\00"
23-
; CHECK-LLVM: @[[StrB:[0-9_.]+]] = {{.*}}"var_annotation_b\00"
23+
; CHECK-LLVM: @[[StrB:[0-9_.]+]] = {{.*}}"var_annotation_b2\00"
2424
; CHECK-LLVM: %[[#StructMember:]] = alloca %class.Sample, align 4
2525
; CHECK-LLVM: %[[#GEP1:]] = getelementptr inbounds %class.Sample, %class.Sample* %[[#StructMember]], i32 0, i32 0
2626
; CHECK-LLVM: call i32* @llvm.ptr.annotation.p0i32.p0i8(i32* %[[#GEP1:]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructA]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
2727
; CHECK-LLVM: %[[#GEP2:]] = getelementptr inbounds %class.Sample, %class.Sample* %[[#StructMember]], i32 0, i32 0
28-
; CHECK-LLVM: call i32* @llvm.ptr.annotation.p0i32.p0i8(i32* %[[#GEP2]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
28+
; CHECK-LLVM: call i32* @llvm.ptr.annotation.p0i32.p0i8(i32* %[[#GEP2]], i8* getelementptr inbounds ([20 x i8], [20 x i8]* @[[StrStructB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
2929
; CHECK-LLVM: [[#Var:]] = alloca i32, align 4
3030
; CHECK-LLVM: [[#Bitcast1:]] = bitcast i32* %[[#Var]] to i8*
3131
; CHECK-LLVM: call void @llvm.var.annotation.p0i8.p0i8(i8* %[[#Bitcast1]], i8* getelementptr inbounds ([17 x i8], [17 x i8]* @[[StrA]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
3232
; CHECK-LLVM: [[#Bitcast2:]] = bitcast i32* %[[#Var]] to i8*
33-
; CHECK-LLVM: call void @llvm.var.annotation.p0i8.p0i8(i8* %[[#Bitcast2]], i8* getelementptr inbounds ([17 x i8], [17 x i8]* @[[StrB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
33+
; CHECK-LLVM: call void @llvm.var.annotation.p0i8.p0i8(i8* %[[#Bitcast2]], i8* getelementptr inbounds ([18 x i8], [18 x i8]* @[[StrB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
3434

3535

3636
source_filename = "llvm-link"
@@ -41,9 +41,9 @@ target triple = "spir64"
4141

4242
@.str = private unnamed_addr constant [19 x i8] c"class_annotation_a\00", section "llvm.metadata"
4343
@.str.1 = private unnamed_addr constant [17 x i8] c"/app/example.cpp\00", section "llvm.metadata"
44-
@.str.2 = private unnamed_addr constant [19 x i8] c"class_annotation_b\00", section "llvm.metadata"
44+
@.str.2 = private unnamed_addr constant [20 x i8] c"class_annotation_b2\00", section "llvm.metadata"
4545
@.str.3 = private unnamed_addr constant [17 x i8] c"var_annotation_a\00", section "llvm.metadata"
46-
@.str.4 = private unnamed_addr constant [17 x i8] c"var_annotation_b\00", section "llvm.metadata"
46+
@.str.4 = private unnamed_addr constant [18 x i8] c"var_annotation_b2\00", section "llvm.metadata"
4747

4848
define spir_func void @test() {
4949
%1 = alloca %class.Sample, align 4

0 commit comments

Comments
 (0)