Skip to content

Commit 8ac46d6

Browse files
[SPIR-V] Implement builtins for OpIAddCarry/OpISubBorrow and improve/fix type inference (#115192)
This PR is to solve several intertwined issues with type inference while adding support for builtins for OpIAddCarry and OpISubBorrow: * OpIAddCarry and OpISubBorrow generation in a way of supporting SPIR-V friendly builtins `__spirv_...` -- introduces a new element to account for, namely, `ptr sret (%struct) %0` argument that is a place to put a result of the instruction; * fix early definition of SPIR-V types during call lowering -- namely, the goal of the PR is to ensure that correct types are applied to virtual registers which were used as arguments in call lowering and so caused early definition of SPIR-V types; reproducers are attached as a new test cases; * improve parsing of builtin names (e.g., understand a name of a kind `"anon<int, int> __spirv_IAddCarry<int, int>(int, int)"` that was incorrectly parsed as `anon` before the PR); * improve type inference and fix access to erased from parent after visit instructions -- before the PR visiting of instructions in emitintrinsics pass replaced old alloca's, bitcast's, etc. instructions with a newly generated internal SPIR-V intrinsics and after erasing old instructions there were still references to them in a postprocessing working list, while records for newly deduced pointee types were lost; this PR fixes the issue by adding as consistent wrt. internal data structures action `SPIRVEmitIntrinsics::replaceAllUsesWith()` that fixes above mentioned problems; * LLVM IR add/sub instructions result in logical SPIR-V instructions when applied to bool type; * fix validation of pointer types for frexp and lgamma_r, * fix hardcoded reference to AS0 as a Function storage class in lib/Target/SPIRV/SPIRVBuiltins.cpp -- now it's `storageClassToAddressSpace(SPIRV::StorageClass::Function)`, * re-use the same OpTypeStruct for two identical references to struct's in arithmetic with overflow instructions.
1 parent 562d235 commit 8ac46d6

15 files changed

+600
-42
lines changed

llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,14 @@ std::string lookupBuiltinNameHelper(StringRef DemangledCall) {
190190
// Check if the extracted name contains type information between angle
191191
// brackets. If so, the builtin is an instantiated template - needs to have
192192
// the information after angle brackets and return type removed.
193-
if (BuiltinName.find('<') && BuiltinName.back() == '>') {
194-
BuiltinName = BuiltinName.substr(0, BuiltinName.find('<'));
193+
std::size_t Pos1 = BuiltinName.rfind('<');
194+
if (Pos1 != std::string::npos && BuiltinName.back() == '>') {
195+
std::size_t Pos2 = BuiltinName.rfind(' ', Pos1);
196+
if (Pos2 == std::string::npos)
197+
Pos2 = 0;
198+
else
199+
++Pos2;
200+
BuiltinName = BuiltinName.substr(Pos2, Pos1 - Pos2);
195201
BuiltinName = BuiltinName.substr(BuiltinName.find_last_of(' ') + 1);
196202
}
197203

@@ -461,9 +467,11 @@ static Register buildBuiltinVariableLoad(
461467
SPIRVGlobalRegistry *GR, SPIRV::BuiltIn::BuiltIn BuiltinValue, LLT LLType,
462468
Register Reg = Register(0), bool isConst = true, bool hasLinkageTy = true) {
463469
Register NewRegister =
464-
MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
465-
MIRBuilder.getMRI()->setType(NewRegister,
466-
LLT::pointer(0, GR->getPointerSize()));
470+
MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::pIDRegClass);
471+
MIRBuilder.getMRI()->setType(
472+
NewRegister,
473+
LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Function),
474+
GR->getPointerSize()));
467475
SPIRVType *PtrType = GR->getOrCreateSPIRVPointerType(
468476
VariableType, MIRBuilder, SPIRV::StorageClass::Input);
469477
GR->assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
@@ -1556,6 +1564,55 @@ static bool generateWaveInst(const SPIRV::IncomingCall *Call,
15561564
/* isConst= */ false, /* hasLinkageTy= */ false);
15571565
}
15581566

1567+
// We expect a builtin
1568+
// Name(ptr sret([RetType]) %result, Type %operand1, Type %operand1)
1569+
// where %result is a pointer to where the result of the builtin execution
1570+
// is to be stored, and generate the following instructions:
1571+
// Res = Opcode RetType Operand1 Operand1
1572+
// OpStore RetVariable Res
1573+
static bool generateICarryBorrowInst(const SPIRV::IncomingCall *Call,
1574+
MachineIRBuilder &MIRBuilder,
1575+
SPIRVGlobalRegistry *GR) {
1576+
const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1577+
unsigned Opcode =
1578+
SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
1579+
1580+
Register SRetReg = Call->Arguments[0];
1581+
SPIRVType *PtrRetType = GR->getSPIRVTypeForVReg(SRetReg);
1582+
SPIRVType *RetType = GR->getPointeeType(PtrRetType);
1583+
if (!RetType)
1584+
report_fatal_error("The first parameter must be a pointer");
1585+
if (RetType->getOpcode() != SPIRV::OpTypeStruct)
1586+
report_fatal_error("Expected struct type result for the arithmetic with "
1587+
"overflow builtins");
1588+
1589+
SPIRVType *OpType1 = GR->getSPIRVTypeForVReg(Call->Arguments[1]);
1590+
SPIRVType *OpType2 = GR->getSPIRVTypeForVReg(Call->Arguments[2]);
1591+
if (!OpType1 || !OpType2 || OpType1 != OpType2)
1592+
report_fatal_error("Operands must have the same type");
1593+
if (OpType1->getOpcode() == SPIRV::OpTypeVector)
1594+
switch (Opcode) {
1595+
case SPIRV::OpIAddCarryS:
1596+
Opcode = SPIRV::OpIAddCarryV;
1597+
break;
1598+
case SPIRV::OpISubBorrowS:
1599+
Opcode = SPIRV::OpISubBorrowV;
1600+
break;
1601+
}
1602+
1603+
MachineRegisterInfo *MRI = MIRBuilder.getMRI();
1604+
Register ResReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
1605+
MRI->setRegClass(ResReg, &SPIRV::iIDRegClass);
1606+
GR->assignSPIRVTypeToVReg(RetType, ResReg, MIRBuilder.getMF());
1607+
MIRBuilder.buildInstr(Opcode)
1608+
.addDef(ResReg)
1609+
.addUse(GR->getSPIRVTypeID(RetType))
1610+
.addUse(Call->Arguments[1])
1611+
.addUse(Call->Arguments[2]);
1612+
MIRBuilder.buildInstr(SPIRV::OpStore).addUse(SRetReg).addUse(ResReg);
1613+
return true;
1614+
}
1615+
15591616
static bool generateGetQueryInst(const SPIRV::IncomingCall *Call,
15601617
MachineIRBuilder &MIRBuilder,
15611618
SPIRVGlobalRegistry *GR) {
@@ -2511,6 +2568,8 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
25112568
return generateDotOrFMulInst(Call.get(), MIRBuilder, GR);
25122569
case SPIRV::Wave:
25132570
return generateWaveInst(Call.get(), MIRBuilder, GR);
2571+
case SPIRV::ICarryBorrow:
2572+
return generateICarryBorrowInst(Call.get(), MIRBuilder, GR);
25142573
case SPIRV::GetQuery:
25152574
return generateGetQueryInst(Call.get(), MIRBuilder, GR);
25162575
case SPIRV::ImageSizeQuery:

llvm/lib/Target/SPIRV/SPIRVBuiltins.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def KernelClock : BuiltinGroup;
6363
def CastToPtr : BuiltinGroup;
6464
def Construct : BuiltinGroup;
6565
def CoopMatr : BuiltinGroup;
66+
def ICarryBorrow : BuiltinGroup;
6667

6768
//===----------------------------------------------------------------------===//
6869
// Class defining a demangled builtin record. The information in the record
@@ -628,6 +629,10 @@ defm : DemangledNativeBuiltin<"barrier", OpenCL_std, Barrier, 1, 3, OpControlBar
628629
defm : DemangledNativeBuiltin<"work_group_barrier", OpenCL_std, Barrier, 1, 3, OpControlBarrier>;
629630
defm : DemangledNativeBuiltin<"__spirv_ControlBarrier", OpenCL_std, Barrier, 3, 3, OpControlBarrier>;
630631

632+
// ICarryBorrow builtin record:
633+
defm : DemangledNativeBuiltin<"__spirv_IAddCarry", OpenCL_std, ICarryBorrow, 3, 3, OpIAddCarryS>;
634+
defm : DemangledNativeBuiltin<"__spirv_ISubBorrow", OpenCL_std, ICarryBorrow, 3, 3, OpISubBorrowS>;
635+
631636
// cl_intel_split_work_group_barrier
632637
defm : DemangledNativeBuiltin<"intel_work_group_barrier_arrive", OpenCL_std, Barrier, 1, 2, OpControlBarrierArriveINTEL>;
633638
defm : DemangledNativeBuiltin<"__spirv_ControlBarrierArriveINTEL", OpenCL_std, Barrier, 3, 3, OpControlBarrierArriveINTEL>;

llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -546,12 +546,36 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
546546
ArgVRegs.push_back(ArgReg);
547547
SPIRVType *SpvType = GR->getSPIRVTypeForVReg(ArgReg);
548548
if (!SpvType) {
549-
SpvType = GR->getOrCreateSPIRVType(Arg.Ty, MIRBuilder);
550-
GR->assignSPIRVTypeToVReg(SpvType, ArgReg, MF);
549+
Type *ArgTy = nullptr;
550+
if (auto *PtrArgTy = dyn_cast<PointerType>(Arg.Ty)) {
551+
// If Arg.Ty is an untyped pointer (i.e., ptr [addrspace(...)]) and we
552+
// don't have access to original value in LLVM IR or info about
553+
// deduced pointee type, then we should wait with setting the type for
554+
// the virtual register until pre-legalizer step when we access
555+
// @llvm.spv.assign.ptr.type.p...(...)'s info.
556+
if (Arg.OrigValue)
557+
if (Type *ElemTy = GR->findDeducedElementType(Arg.OrigValue))
558+
ArgTy =
559+
TypedPointerType::get(ElemTy, PtrArgTy->getAddressSpace());
560+
} else {
561+
ArgTy = Arg.Ty;
562+
}
563+
if (ArgTy) {
564+
SpvType = GR->getOrCreateSPIRVType(ArgTy, MIRBuilder);
565+
GR->assignSPIRVTypeToVReg(SpvType, ArgReg, MF);
566+
}
551567
}
552568
if (!MRI->getRegClassOrNull(ArgReg)) {
553-
MRI->setRegClass(ArgReg, GR->getRegClass(SpvType));
554-
MRI->setType(ArgReg, GR->getRegType(SpvType));
569+
// Either we have SpvType created, or Arg.Ty is an untyped pointer and
570+
// we know its virtual register's class and type even if we don't know
571+
// pointee type.
572+
MRI->setRegClass(ArgReg, SpvType ? GR->getRegClass(SpvType)
573+
: &SPIRV::pIDRegClass);
574+
MRI->setType(
575+
ArgReg,
576+
SpvType ? GR->getRegType(SpvType)
577+
: LLT::pointer(cast<PointerType>(Arg.Ty)->getAddressSpace(),
578+
GR->getPointerSize()));
555579
}
556580
}
557581
auto instructionSet = canUseOpenCL ? SPIRV::InstructionSet::OpenCL_std

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ class SPIRVEmitIntrinsics
7676
SPIRV::InstructionSet::InstructionSet InstrSet;
7777

7878
// a register of Instructions that don't have a complete type definition
79-
SmallPtrSet<Value *, 8> UncompleteTypeInfo;
80-
SmallVector<Instruction *> PostprocessWorklist;
79+
DenseMap<Value *, unsigned> UncompleteTypeInfo;
80+
SmallVector<Value *> PostprocessWorklist;
8181

8282
// well known result types of builtins
8383
enum WellKnownTypes { Event };
@@ -147,6 +147,7 @@ class SPIRVEmitIntrinsics
147147
std::unordered_set<Function *> &FVisited);
148148
void replaceWithPtrcasted(Instruction *CI, Type *NewElemTy, Type *KnownElemTy,
149149
CallInst *AssignCI);
150+
void replaceAllUsesWith(Value *Src, Value *Dest, bool DeleteOld = true);
150151

151152
bool runOnFunction(Function &F);
152153
bool postprocessTypes();
@@ -272,6 +273,27 @@ static inline void reportFatalOnTokenType(const Instruction *I) {
272273
false);
273274
}
274275

276+
void SPIRVEmitIntrinsics::replaceAllUsesWith(Value *Src, Value *Dest,
277+
bool DeleteOld) {
278+
Src->replaceAllUsesWith(Dest);
279+
// Update deduced type records
280+
GR->updateIfExistDeducedElementType(Src, Dest, DeleteOld);
281+
GR->updateIfExistAssignPtrTypeInstr(Src, Dest, DeleteOld);
282+
// Update uncomplete type records if any
283+
auto It = UncompleteTypeInfo.find(Src);
284+
if (It == UncompleteTypeInfo.end())
285+
return;
286+
if (DeleteOld) {
287+
unsigned Pos = It->second;
288+
UncompleteTypeInfo.erase(Src);
289+
UncompleteTypeInfo[Dest] = Pos;
290+
PostprocessWorklist[Pos] = Dest;
291+
} else {
292+
UncompleteTypeInfo[Dest] = PostprocessWorklist.size();
293+
PostprocessWorklist.push_back(Dest);
294+
}
295+
}
296+
275297
static bool IsKernelArgInt8(Function *F, StoreInst *SI) {
276298
return SI && F->getCallingConv() == CallingConv::SPIR_KERNEL &&
277299
isPointerTy(SI->getValueOperand()->getType()) &&
@@ -434,7 +456,7 @@ void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,
434456
if (!UnknownElemTypeI8)
435457
return;
436458
if (auto *I = dyn_cast<Instruction>(Op)) {
437-
UncompleteTypeInfo.insert(I);
459+
UncompleteTypeInfo[I] = PostprocessWorklist.size();
438460
PostprocessWorklist.push_back(I);
439461
}
440462
}
@@ -640,7 +662,7 @@ Type *SPIRVEmitIntrinsics::deduceElementType(Value *I, bool UnknownElemTypeI8) {
640662
if (!UnknownElemTypeI8)
641663
return nullptr;
642664
if (auto *Instr = dyn_cast<Instruction>(I)) {
643-
UncompleteTypeInfo.insert(Instr);
665+
UncompleteTypeInfo[Instr] = PostprocessWorklist.size();
644666
PostprocessWorklist.push_back(Instr);
645667
}
646668
return IntegerType::getInt8Ty(I->getContext());
@@ -1062,7 +1084,7 @@ Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
10621084
{I.getOperand(0)->getType()}, {Args});
10631085
// remove switch to avoid its unneeded and undesirable unwrap into branches
10641086
// and conditions
1065-
I.replaceAllUsesWith(NewI);
1087+
replaceAllUsesWith(&I, NewI);
10661088
I.eraseFromParent();
10671089
// insert artificial and temporary instruction to preserve valid CFG,
10681090
// it will be removed after IR translation pass
@@ -1084,7 +1106,7 @@ Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
10841106
for (auto &Op : I.operands())
10851107
Args.push_back(Op);
10861108
auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
1087-
I.replaceAllUsesWith(NewI);
1109+
replaceAllUsesWith(&I, NewI);
10881110
I.eraseFromParent();
10891111
return NewI;
10901112
}
@@ -1099,7 +1121,7 @@ Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
10991121
// such bitcasts do not provide sufficient information, should be just skipped
11001122
// here, and handled in insertPtrCastOrAssignTypeInstr.
11011123
if (isPointerTy(I.getType())) {
1102-
I.replaceAllUsesWith(Source);
1124+
replaceAllUsesWith(&I, Source);
11031125
I.eraseFromParent();
11041126
return nullptr;
11051127
}
@@ -1108,7 +1130,7 @@ Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
11081130
SmallVector<Value *> Args(I.op_begin(), I.op_end());
11091131
auto *NewI = B.CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});
11101132
std::string InstName = I.hasName() ? I.getName().str() : "";
1111-
I.replaceAllUsesWith(NewI);
1133+
replaceAllUsesWith(&I, NewI);
11121134
I.eraseFromParent();
11131135
NewI->setName(InstName);
11141136
return NewI;
@@ -1219,6 +1241,8 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
12191241
SmallVector<Value *, 2> Args = {Pointer, VMD, B.getInt32(AddressSpace)};
12201242
auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
12211243
I->setOperand(OperandToReplace, PtrCastI);
1244+
// We need to set up a pointee type for the newly created spv_ptrcast.
1245+
buildAssignPtr(B, ExpectedElementType, PtrCastI);
12221246
}
12231247

12241248
void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
@@ -1331,7 +1355,7 @@ Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {
13311355
SmallVector<Value *> Args(I.op_begin(), I.op_end());
13321356
auto *NewI = B.CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});
13331357
std::string InstName = I.hasName() ? I.getName().str() : "";
1334-
I.replaceAllUsesWith(NewI);
1358+
replaceAllUsesWith(&I, NewI);
13351359
I.eraseFromParent();
13361360
NewI->setName(InstName);
13371361
return NewI;
@@ -1346,7 +1370,7 @@ SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) {
13461370
SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()};
13471371
auto *NewI = B.CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});
13481372
std::string InstName = I.hasName() ? I.getName().str() : "";
1349-
I.replaceAllUsesWith(NewI);
1373+
replaceAllUsesWith(&I, NewI);
13501374
I.eraseFromParent();
13511375
NewI->setName(InstName);
13521376
return NewI;
@@ -1382,7 +1406,7 @@ Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {
13821406
Args.push_back(B.getInt32(Op));
13831407
auto *NewI =
13841408
B.CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args});
1385-
I.replaceAllUsesWith(NewI);
1409+
replaceAllUsesWith(&I, NewI);
13861410
I.eraseFromParent();
13871411
return NewI;
13881412
}
@@ -1443,7 +1467,7 @@ Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) {
14431467
{PtrTy, ArraySize->getType()}, {ArraySize})
14441468
: B.CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {});
14451469
std::string InstName = I.hasName() ? I.getName().str() : "";
1446-
I.replaceAllUsesWith(NewI);
1470+
replaceAllUsesWith(&I, NewI);
14471471
I.eraseFromParent();
14481472
NewI->setName(InstName);
14491473
return NewI;
@@ -1613,7 +1637,7 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
16131637
auto *NewOp =
16141638
buildIntrWithMD(Intrinsic::spv_track_constant,
16151639
{II->getType(), II->getType()}, t->second, I, {}, B);
1616-
I->replaceAllUsesWith(NewOp);
1640+
replaceAllUsesWith(I, NewOp, false);
16171641
NewOp->setArgOperand(0, I);
16181642
}
16191643
bool IsPhi = isa<PHINode>(I), BPrepared = false;

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,15 @@ class SPIRVGlobalRegistry {
180180
auto It = AssignPtrTypeInstr.find(Val);
181181
return It == AssignPtrTypeInstr.end() ? nullptr : It->second;
182182
}
183+
// - Find a record and update its key or add a new record, if found.
184+
void updateIfExistAssignPtrTypeInstr(Value *OldVal, Value *NewVal,
185+
bool DeleteOld) {
186+
if (CallInst *CI = findAssignPtrTypeInstr(OldVal)) {
187+
if (DeleteOld)
188+
AssignPtrTypeInstr.erase(OldVal);
189+
AssignPtrTypeInstr[NewVal] = CI;
190+
}
191+
}
183192

184193
// A registry of mutated values
185194
// (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`):
@@ -214,6 +223,15 @@ class SPIRVGlobalRegistry {
214223
auto It = DeducedElTys.find(Val);
215224
return It == DeducedElTys.end() ? nullptr : It->second;
216225
}
226+
// - Find a record and update its key or add a new record, if found.
227+
void updateIfExistDeducedElementType(Value *OldVal, Value *NewVal,
228+
bool DeleteOld) {
229+
if (Type *Ty = findDeducedElementType(OldVal)) {
230+
if (DeleteOld)
231+
DeducedElTys.erase(OldVal);
232+
DeducedElTys[NewVal] = Ty;
233+
}
234+
}
217235
// - Add a record to the map of deduced composite types.
218236
void addDeducedCompositeType(Value *Val, Type *Ty) {
219237
DeducedNestedTys[Val] = Ty;

llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,17 @@ void SPIRVTargetLowering::finalizeLowering(MachineFunction &MF) const {
414414
validateForwardCalls(STI, MRI, GR, MI);
415415
break;
416416

417+
// ensure that LLVM IR add/sub instructions result in logical SPIR-V
418+
// instructions when applied to bool type
419+
case SPIRV::OpIAddS:
420+
case SPIRV::OpIAddV:
421+
case SPIRV::OpISubS:
422+
case SPIRV::OpISubV:
423+
if (GR.isScalarOrVectorOfType(MI.getOperand(1).getReg(),
424+
SPIRV::OpTypeBool))
425+
MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalNotEqual));
426+
break;
427+
417428
// ensure that LLVM IR bitwise instructions result in logical SPIR-V
418429
// instructions when applied to bool type
419430
case SPIRV::OpBitwiseOrS:
@@ -473,8 +484,11 @@ void SPIRVTargetLowering::finalizeLowering(MachineFunction &MF) const {
473484
MI.getOperand(2).getImm() != SPIRV::InstructionSet::OpenCL_std)
474485
continue;
475486
switch (MI.getOperand(3).getImm()) {
487+
case SPIRV::OpenCLExtInst::frexp:
488+
case SPIRV::OpenCLExtInst::lgamma_r:
476489
case SPIRV::OpenCLExtInst::remquo: {
477-
// The last operand must be of a pointer to the return type.
490+
// The last operand must be of a pointer to i32 or vector of i32
491+
// values.
478492
MachineIRBuilder MIB(MI);
479493
SPIRVType *Int32Type = GR.getOrCreateSPIRVIntegerType(32, MIB);
480494
SPIRVType *RetType = MRI->getVRegDef(MI.getOperand(1).getReg());
@@ -487,8 +501,6 @@ void SPIRVTargetLowering::finalizeLowering(MachineFunction &MF) const {
487501
Int32Type, RetType->getOperand(2).getImm(), MIB));
488502
} break;
489503
case SPIRV::OpenCLExtInst::fract:
490-
case SPIRV::OpenCLExtInst::frexp:
491-
case SPIRV::OpenCLExtInst::lgamma_r:
492504
case SPIRV::OpenCLExtInst::modf:
493505
case SPIRV::OpenCLExtInst::sincos:
494506
// The last operand must be of a pointer to the base type represented

0 commit comments

Comments
 (0)