Skip to content

Commit fa73cdc

Browse files
improve and fix type deduction
1 parent 15aa918 commit fa73cdc

File tree

2 files changed

+101
-47
lines changed

2 files changed

+101
-47
lines changed

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 92 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class SPIRVEmitIntrinsics
7979
std::unordered_set<Value *> &Visited);
8080

8181
// deduce Types of operands of the Instruction if possible
82-
void deduceOperandElementType(Value *I, DenseMap<Value *, Type *> &Collected);
82+
void deduceOperandElementType(Instruction *I);
8383

8484
void preprocessCompositeConstants(IRBuilder<> &B);
8585
void preprocessUndefs(IRBuilder<> &B);
@@ -275,6 +275,12 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
275275
if (Ty)
276276
break;
277277
}
278+
} else if (auto *Ref = dyn_cast<SelectInst>(I)) {
279+
for (Value *Op : {Ref->getTrueValue(), Ref->getFalseValue()}) {
280+
Ty = deduceElementTypeByUsersDeep(Op, Visited);
281+
if (Ty)
282+
break;
283+
}
278284
}
279285

280286
// remember the found relationship
@@ -374,24 +380,92 @@ Type *SPIRVEmitIntrinsics::deduceElementType(Value *I) {
374380
return IntegerType::getInt8Ty(I->getContext());
375381
}
376382

377-
// Deduce Types of operands of the Instruction if possible.
378-
void SPIRVEmitIntrinsics::deduceOperandElementType(
379-
Value *I, DenseMap<Value *, Type *> &Collected) {
380-
Type *KnownTy = GR->findDeducedElementType(I);
381-
if (!KnownTy)
382-
return;
383-
383+
// If the Instruction has Pointer operands with unresolved types, this function
384+
// tries to deduce them. If the Instruction has Pointer operands with known
385+
// types which differ from expected, this function tries to insert a bitcast to
386+
// resolve the issue.
387+
void SPIRVEmitIntrinsics::deduceOperandElementType(Instruction *I) {
388+
SmallVector<std::pair<Value *, unsigned>> Ops;
389+
Type *KnownElemTy = nullptr;
384390
// look for known basic patterns of type inference
385391
if (auto *Ref = dyn_cast<PHINode>(I)) {
392+
if (!isPointerTy(I->getType()) ||
393+
!(KnownElemTy = GR->findDeducedElementType(I)))
394+
return;
386395
for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {
387396
Value *Op = Ref->getIncomingValue(i);
388-
if (!isUntypedPointerTy(Op->getType()))
389-
continue;
390-
Type *Ty = GR->findDeducedElementType(Op);
391-
if (!Ty) {
392-
Collected[Op] = KnownTy;
393-
GR->addDeducedElementType(Op, KnownTy);
397+
if (isPointerTy(Op->getType()))
398+
Ops.push_back(std::make_pair(Op, i));
399+
}
400+
} else if (auto *Ref = dyn_cast<SelectInst>(I)) {
401+
if (!isPointerTy(I->getType()) ||
402+
!(KnownElemTy = GR->findDeducedElementType(I)))
403+
return;
404+
for (unsigned i = 0; i < Ref->getNumOperands(); i++) {
405+
Value *Op = Ref->getOperand(i);
406+
if (isPointerTy(Op->getType()))
407+
Ops.push_back(std::make_pair(Op, i));
408+
}
409+
} else if (auto *Ref = dyn_cast<ICmpInst>(I)) {
410+
if (!isPointerTy(Ref->getOperand(0)->getType()))
411+
return;
412+
Value *Op0 = Ref->getOperand(0);
413+
Value *Op1 = Ref->getOperand(1);
414+
Type *ElemTy0 = GR->findDeducedElementType(Op0);
415+
Type *ElemTy1 = GR->findDeducedElementType(Op1);
416+
if (ElemTy0) {
417+
KnownElemTy = ElemTy0;
418+
Ops.push_back(std::make_pair(Op1, 1));
419+
} else if (ElemTy1) {
420+
KnownElemTy = ElemTy1;
421+
Ops.push_back(std::make_pair(Op0, 0));
422+
}
423+
}
424+
425+
// There is no enough info to deduce types or all is valid.
426+
if (!KnownElemTy || Ops.size() == 0)
427+
return;
428+
429+
Instruction *User = nullptr;
430+
LLVMContext &Ctx = F->getContext();
431+
IRBuilder<> B(Ctx);
432+
for (auto &OpIt : Ops) {
433+
Value *Op = OpIt.first;
434+
// unsigned i = OpIt.second;
435+
Type *Ty = GR->findDeducedElementType(Op);
436+
if (Ty == KnownElemTy)
437+
continue;
438+
if (Op->use_empty() ||
439+
!(User = dyn_cast<Instruction>(Op->use_begin()->get())))
440+
continue;
441+
442+
setInsertPointSkippingPhis(B, User->getNextNode());
443+
Value *OpTyVal = Constant::getNullValue(KnownElemTy);
444+
Type *OpTy = Op->getType();
445+
if (!Ty) {
446+
GR->addDeducedElementType(Op, KnownElemTy);
447+
// check if there is existing Intrinsic::spv_assign_ptr_type instruction
448+
auto It = AssignPtrTypeInstr.find(Op);
449+
if (It == AssignPtrTypeInstr.end()) {
450+
CallInst *CI =
451+
buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal, Op,
452+
{B.getInt32(getPointerAddressSpace(OpTy))}, B);
453+
AssignPtrTypeInstr[Op] = CI;
454+
} else {
455+
It->second->setArgOperand(
456+
1,
457+
MetadataAsValue::get(
458+
Ctx, MDNode::get(Ctx, ValueAsMetadata::getConstant(OpTyVal))));
394459
}
460+
} else {
461+
SmallVector<Type *, 2> Types = {OpTy, OpTy};
462+
MetadataAsValue *VMD = MetadataAsValue::get(
463+
Ctx, MDNode::get(Ctx, ValueAsMetadata::getConstant(OpTyVal)));
464+
SmallVector<Value *, 2> Args = {Op, VMD,
465+
B.getInt32(getPointerAddressSpace(OpTy))};
466+
CallInst *PtrCastI =
467+
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
468+
I->setOperand(OpIt.second, PtrCastI);
395469
}
396470
}
397471
}
@@ -1145,6 +1219,10 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
11451219
insertAssignTypeIntrs(I, B);
11461220
insertPtrCastOrAssignTypeInstr(I, B);
11471221
}
1222+
1223+
for (auto &I : instructions(Func))
1224+
deduceOperandElementType(&I);
1225+
11481226
for (auto *I : Worklist) {
11491227
TrackConstants = true;
11501228
if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
@@ -1157,36 +1235,6 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
11571235
processInstrAfterVisit(I, B);
11581236
}
11591237

1160-
for (auto &I : instructions(Func)) {
1161-
Type *ITy = I.getType();
1162-
if (!isPointerTy(ITy))
1163-
continue;
1164-
DenseMap<Value *, Type *> CollectedTys;
1165-
deduceOperandElementType(&I, CollectedTys);
1166-
Instruction *User;
1167-
LLVMContext &Ctx = F->getContext();
1168-
for (const auto &Rec : CollectedTys) {
1169-
if (Rec.first->use_empty() ||
1170-
!(User = dyn_cast<Instruction>(Rec.first->use_begin()->get())))
1171-
continue;
1172-
Type *OpTy = Rec.first->getType();
1173-
Value *OpTyVal = Constant::getNullValue(Rec.second);
1174-
// check if there is existing Intrinsic::spv_assign_ptr_type instruction
1175-
auto It = AssignPtrTypeInstr.find(Rec.first);
1176-
if (It == AssignPtrTypeInstr.end()) {
1177-
setInsertPointSkippingPhis(B, User->getNextNode());
1178-
buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal,
1179-
Rec.first, {B.getInt32(getPointerAddressSpace(OpTy))},
1180-
B);
1181-
} else {
1182-
It->second->setArgOperand(
1183-
1,
1184-
MetadataAsValue::get(
1185-
Ctx, MDNode::get(Ctx, ValueAsMetadata::getConstant(OpTyVal))));
1186-
}
1187-
}
1188-
}
1189-
11901238
// check if function parameter types are set
11911239
if (!F->isIntrinsic())
11921240
processParamTypes(F, B);

llvm/test/CodeGen/SPIRV/instructions/select-phi.ll

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --translator-compatibility-mode %s -o - -filetype=obj | spirv-val %}
23
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
34

5+
; CHECK-DAG: %[[Char:.*]] = OpTypeInt 8 0
46
; CHECK-DAG: %[[Long:.*]] = OpTypeInt 32 0
57
; CHECK-DAG: %[[Array:.*]] = OpTypeArray %[[Long]] %[[#]]
68
; CHECK-DAG: %[[Struct:.*]] = OpTypeStruct %[[Array]]
79
; CHECK-DAG: %[[StructPtr:.*]] = OpTypePointer Function %[[Struct]]
10+
; CHECK-DAG: %[[CharPtr:.*]] = OpTypePointer Function %[[Char]]
811

912
; CHECK: %[[Branch1:.*]] = OpLabel
1013
; CHECK: %[[Res1:.*]] = OpVariable %[[StructPtr]] Function
1114
; CHECK: OpBranchConditional %[[#]] %[[#]] %[[Branch2:.*]]
12-
; CHECK: %[[Res2:.*]] = OpInBoundsPtrAccessChain %[[StructPtr]] %[[#]] %[[#]]
15+
; CHECK: %[[Res2:.*]] = OpInBoundsPtrAccessChain %[[CharPtr]] %[[#]] %[[#]]
16+
; CHECK: %[[Res2Casted:.*]] = OpBitcast %[[StructPtr]] %[[Res2]]
1317
; CHECK: OpBranchConditional %[[#]] %[[#]] %[[BranchSelect:.*]]
14-
; CHECK: %[[SelectRes:.*]] = OpSelect %[[StructPtr]] %[[#]] %[[#]] %[[#]]
18+
; CHECK: %[[SelectRes:.*]] = OpSelect %[[CharPtr]] %[[#]] %[[#]] %[[#]]
19+
; CHECK: %[[SelectResCasted:.*]] = OpBitcast %[[StructPtr]] %[[SelectRes]]
1520
; CHECK: OpLabel
16-
; CHECK: OpPhi %[[StructPtr]] %[[Res1]] %[[Branch1]] %[[Res2]] %[[Branch2]] %[[SelectRes]] %[[BranchSelect]]
21+
; CHECK: OpPhi %[[StructPtr]] %[[Res1]] %[[Branch1]] %[[Res2Casted]] %[[Branch2]] %[[SelectResCasted]] %[[BranchSelect]]
1722

1823
%struct = type { %array }
1924
%array = type { [1 x i64] }
@@ -48,5 +53,6 @@ exit: ; preds = %sw2, %sw1, %entry
4853
%cmp = xor i1 %r4, %expected
4954
%frombool6.i = zext i1 %cmp to i8
5055
store i8 %frombool6.i, ptr addrspace(1) %add.ptr.i, align 1
56+
%r5 = icmp eq ptr %add.ptr, %retval.0
5157
ret void
5258
}

0 commit comments

Comments
 (0)