Skip to content

Commit e8b2018

Browse files
authored
Support llvm.frexp intrinsic translation (#2252)
Map @llvm.frexp intrinsic to OpenCL Extended Instruction frexp builtin. The difference in signatures and return values is covered by extracting/combining values from and into composite type. LLVM IR: { float %fract, i32 %exp } @llvm.frexp.f32.i32(float %val) SPIR-V: { float %fract } ExtInst frexp (float %val, i32 %exp)
1 parent afe1971 commit e8b2018

File tree

3 files changed

+218
-1
lines changed

3 files changed

+218
-1
lines changed

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2123,8 +2123,25 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB,
21232123
return mapValue(V, BM->addUnreachableInst(BB));
21242124

21252125
if (auto *RI = dyn_cast<ReturnInst>(V)) {
2126-
if (auto *RV = RI->getReturnValue())
2126+
if (auto *RV = RI->getReturnValue()) {
2127+
if (auto *II = dyn_cast<IntrinsicInst>(RV)) {
2128+
if (II->getIntrinsicID() == Intrinsic::frexp) {
2129+
// create composite type from the return value and second operand
2130+
auto *FrexpResult = transValue(RV, BB);
2131+
SPIRVValue *IntFromFrexpResult =
2132+
static_cast<SPIRVExtInst *>(FrexpResult)->getArgValues()[1];
2133+
IntFromFrexpResult = BM->addLoadInst(IntFromFrexpResult, {}, BB);
2134+
2135+
std::vector<SPIRVId> Operands = {FrexpResult->getId(),
2136+
IntFromFrexpResult->getId()};
2137+
auto *Compos = BM->addCompositeConstructInst(transType(RV->getType()),
2138+
Operands, BB);
2139+
2140+
return mapValue(V, BM->addReturnValueInst(Compos, BB));
2141+
}
2142+
}
21272143
return mapValue(V, BM->addReturnValueInst(transValue(RV, BB), BB));
2144+
}
21282145
return mapValue(V, BM->addReturnInst(BB));
21292146
}
21302147

@@ -2284,6 +2301,20 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB,
22842301
}
22852302

22862303
if (auto *Ext = dyn_cast<ExtractValueInst>(V)) {
2304+
if (auto *II = dyn_cast<IntrinsicInst>(Ext->getAggregateOperand())) {
2305+
if (II->getIntrinsicID() == Intrinsic::frexp) {
2306+
unsigned Idx = Ext->getIndices()[0];
2307+
auto *Val = transValue(II, BB);
2308+
if (Idx == 0)
2309+
return mapValue(V, Val);
2310+
2311+
// Idx = 1
2312+
SPIRVValue *IntFromFrexpResult =
2313+
static_cast<SPIRVExtInst *>(Val)->getArgValues()[1];
2314+
IntFromFrexpResult = BM->addLoadInst(IntFromFrexpResult, {}, BB);
2315+
return mapValue(V, IntFromFrexpResult);
2316+
}
2317+
}
22872318
return mapValue(V, BM->addCompositeExtractInst(
22882319
transScavengedType(Ext),
22892320
transValue(Ext->getAggregateOperand(), BB),
@@ -3641,6 +3672,7 @@ bool LLVMToSPIRVBase::isKnownIntrinsic(Intrinsic::ID Id) {
36413672
case Intrinsic::fabs:
36423673
case Intrinsic::floor:
36433674
case Intrinsic::fma:
3675+
case Intrinsic::frexp:
36443676
case Intrinsic::log:
36453677
case Intrinsic::log10:
36463678
case Intrinsic::log2:
@@ -3751,6 +3783,8 @@ static SPIRVWord getBuiltinIdForIntrinsic(Intrinsic::ID IID) {
37513783
return OpenCLLIB::Floor;
37523784
case Intrinsic::fma:
37533785
return OpenCLLIB::Fma;
3786+
case Intrinsic::frexp:
3787+
return OpenCLLIB::Frexp;
37543788
case Intrinsic::log:
37553789
return OpenCLLIB::Log;
37563790
case Intrinsic::log10:
@@ -3926,6 +3960,28 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
39263960
return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops,
39273961
BB);
39283962
}
3963+
case Intrinsic::frexp: {
3964+
if (!checkTypeForSPIRVExtendedInstLowering(II, BM))
3965+
break;
3966+
SPIRVWord ExtOp = getBuiltinIdForIntrinsic(IID);
3967+
3968+
SPIRVType *FTy = transType(II->getType()->getStructElementType(0));
3969+
SPIRVTypePointer *ITy = static_cast<SPIRVTypePointer *>(transPointerType(
3970+
II->getType()->getStructElementType(1), SPIRAS_Private));
3971+
3972+
unsigned BitWidth = ITy->getElementType()->getBitWidth();
3973+
BM->getErrorLog().checkError(BitWidth == 32, SPIRVEC_InvalidBitWidth,
3974+
std::to_string(BitWidth));
3975+
3976+
SPIRVValue *IntVal =
3977+
BM->addVariable(ITy, false, spv::internal::LinkageTypeInternal, nullptr,
3978+
"", ITy->getStorageClass(), BB);
3979+
3980+
std::vector<SPIRVValue *> Ops{transValue(II->getArgOperand(0), BB), IntVal};
3981+
3982+
return BM->addExtInst(FTy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops,
3983+
BB);
3984+
}
39293985
// Binary FP intrinsics
39303986
case Intrinsic::copysign:
39313987
case Intrinsic::pow:

test/llvm-intrinsics/frexp.ll

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -spirv-text
3+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
4+
; RUN: llvm-spirv %t.bc -o %t.spv
5+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
6+
; RUN: llvm-dis %t.rev.bc
7+
; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM
8+
9+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
10+
target triple = "spir64-unknown-unknown"
11+
12+
; CHECK-SPIRV: ExtInstImport [[#ExtInstSetId:]] "OpenCL.std"
13+
14+
; CHECK-SPIRV: TypeInt [[#TypeInt:]] 32
15+
; CHECK-SPIRV: TypeFloat [[#TypeFloat:]] 32
16+
; CHECK-SPIRV: TypeStruct [[#TypeStrFloatInt:]] [[#TypeFloat]] [[#TypeInt]]
17+
; CHECK-SPIRV: TypePointer [[#TypeIntPtr:]] 7 [[#TypeInt]]
18+
19+
; CHECK-SPIRV: TypeFloat [[#TypeDouble:]] 64
20+
; CHECK-SPIRV: TypeStruct [[#TypeStrDoubleInt:]] [[#TypeDouble]] [[#TypeInt]]
21+
22+
; CHECK-SPIRV: TypeVector [[#VecFloat2:]] [[#TypeFloat]] 2
23+
; CHECK-SPIRV: TypeVector [[#VecInt2:]] [[#TypeInt]] 2
24+
; CHECK-SPIRV: TypeStruct [[#TypeStrFloatIntVec2:]] [[#VecFloat2]] [[#VecInt2]]
25+
26+
; CHECK-SPIRV: TypeVector [[#VecFloat4:]] [[#TypeFloat]] 4
27+
; CHECK-SPIRV: TypeVector [[#VecInt4:]] [[#TypeInt]] 4
28+
; CHECK-SPIRV: TypeStruct [[#TypeStrFloatIntVec4:]] [[#VecFloat4]] [[#VecInt4]]
29+
30+
; CHECK-SPIRV: TypeVector [[#VecDouble2:]] [[#TypeDouble]] 2
31+
; CHECK-SPIRV: TypeStruct [[#TypeStrDoubleIntVec2:]] [[#VecDouble2]] [[#VecInt2]]
32+
33+
; CHECK-SPIRV: Constant [[#TypeFloat]] [[#NegatedZeroConst:]] 2147483648
34+
; CHECK-SPIRV: Undef [[#TypeDouble]] [[#UndefDouble:]]
35+
; CHECK-SPIRV: ConstantNull [[#VecFloat2]] [[#NullVecFloat2:]]
36+
; CHECK-SPIRV: Constant [[#TypeFloat]] [[#ZeroConstFloat:]] 0
37+
; CHECK-SPIRV: ConstantComposite [[#VecFloat2]] [[#ZeroesCompositeFloat:]] [[#ZeroConstFloat]] [[#NegatedZeroConst]]
38+
39+
; CHECK-LLVM: %[[StrTypeFloatInt:[a-z0-9.]+]] = type { float, i32 }
40+
; CHECK-LLVM: %[[StrTypeDoubleInt:[a-z0-9.]+]] = type { double, i32 }
41+
; CHECK-LLVM: %[[StrTypeFloatIntVec2:[a-z0-9.]+]] = type { <2 x float>, <2 x i32> }
42+
; CHECK-LLVM: %[[StrTypeFloatIntVec4:[a-z0-9.]+]] = type { <4 x float>, <4 x i32> }
43+
; CHECK-LLVM: %[[StrTypeDoubleIntVec2:[a-z0-9.]+]] = type { <2 x double>, <2 x i32> }
44+
45+
declare { float, i32 } @llvm.frexp.f32.i32(float)
46+
declare { double, i32 } @llvm.frexp.f64.i32(double)
47+
declare { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float>)
48+
declare { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float>)
49+
declare { <2 x double>, <2 x i32> } @llvm.frexp.v2f64.v2i32(<2 x double>)
50+
51+
; CHECK-SPIRV: Function [[#TypeStrFloatInt:]]
52+
; CHECK-SPIRV: Variable [[#TypeIntPtr]] [[#IntVar:]] 7
53+
; CHECK-SPIRV: ExtInst [[#TypeFloat]] [[#FrexpId:]] [[#ExtInstSetId]] frexp [[#NegatedZeroConst]] [[#IntVar]]
54+
; CHECK-SPIRV: Load [[#]] [[#LoadId:]] [[#]]
55+
; CHECK-SPIRV: CompositeConstruct [[#TypeStrFloatInt]] [[#ComposConstr:]] [[#FrexpId]] [[#LoadId]]
56+
; CHECK-SPIRV: ReturnValue [[#ComposConstr]]
57+
58+
; CHECK-LLVM: %[[#IntVar:]] = alloca i32
59+
; CHECK-LLVM: %[[Frexp:[a-z0-9]+]] = call spir_func float @_Z5frexpfPi(float -0.000000e+00, ptr %[[#IntVar]])
60+
; CHECK-LLVM: %[[#LoadIntVar:]] = load i32, ptr %[[#IntVar]]
61+
; CHECK-LLVM: %[[#AllocaStrFloatInt:]] = alloca %[[StrTypeFloatInt]]
62+
; CHECK-LLVM: %[[GEPFloat:[a-z0-9]+]] = getelementptr inbounds %structtype, ptr %[[#AllocaStrFloatInt]], i32 0, i32 0
63+
; CHECK-LLVM: store float %[[Frexp]], ptr %[[GEPFloat]]
64+
; CHECK-LLVM: %[[GEPInt:[a-z0-9]+]] = getelementptr inbounds %structtype, ptr %[[#AllocaStrFloatInt]], i32 0, i32 1
65+
; CHECK-LLVM: store i32 %[[#LoadIntVar]], ptr %[[GEPInt]]
66+
; CHECK-LLVM: %[[LoadStrFloatInt:[a-z0-9]+]] = load %[[StrTypeFloatInt]], ptr %[[#AllocaStrFloatInt]]
67+
; CHECK-LLVM: ret %[[StrTypeFloatInt]] %[[LoadStrFloatInt]]
68+
define { float, i32 } @frexp_negzero() {
69+
%ret = call { float, i32 } @llvm.frexp.f32.i32(float -0.0)
70+
ret { float, i32 } %ret
71+
}
72+
73+
; CHECK-SPIRV: ExtInst [[#TypeDouble]] [[#]] [[#ExtInstSetId]] frexp [[#UndefDouble]] [[#]]
74+
; CHECK-LLVM: call spir_func double @_Z5frexpdPi(double undef, ptr %[[#]])
75+
; CHECK-LLVM: ret %[[StrTypeDoubleInt]]
76+
define { double, i32 } @frexp_undef() {
77+
%ret = call { double, i32 } @llvm.frexp.f64.i32(double undef)
78+
ret { double, i32 } %ret
79+
}
80+
81+
; CHECK-SPIRV: ExtInst [[#VecFloat2]] [[#]] [[#ExtInstSetId]] frexp [[#NullVecFloat2]] [[#]]
82+
; CHECK-LLVM: call spir_func <2 x float> @_Z5frexpDv2_fPDv2_i(<2 x float> zeroinitializer, ptr %[[#]])
83+
; CHECK-LLVM: ret %[[StrTypeFloatIntVec2]]
84+
define { <2 x float>, <2 x i32> } @frexp_zero_vector() {
85+
%ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> zeroinitializer)
86+
ret { <2 x float>, <2 x i32> } %ret
87+
}
88+
89+
; CHECK-SPIRV: ExtInst [[#VecFloat2]] [[#]] [[#ExtInstSetId]] frexp [[#ZeroesCompositeFloat]] [[#]]
90+
; CHECK-LLVM: call spir_func <2 x float> @_Z5frexpDv2_fPDv2_i(<2 x float> <float 0.000000e+00, float -0.000000e+00>, ptr %[[#]])
91+
; CHECK-LLVM: ret %[[StrTypeFloatIntVec2]]
92+
define { <2 x float>, <2 x i32> } @frexp_zero_negzero_vector() {
93+
%ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> <float 0.0, float -0.0>)
94+
ret { <2 x float>, <2 x i32> } %ret
95+
}
96+
97+
; CHECK-SPIRV: ExtInst [[#VecFloat4]] [[#]] [[#ExtInstSetId]] frexp [[#]] [[#]]
98+
; CHECK-LLVM: call spir_func <4 x float> @_Z5frexpDv4_fPDv4_i(<4 x float> <float 1.600000e+01, float -3.200000e+01, float undef, float 9.999000e+03>, ptr %[[#]])
99+
; CHECK-LLVM: ret %[[StrTypeFloatIntVec4]]
100+
define { <4 x float>, <4 x i32> } @frexp_nonsplat_vector() {
101+
%ret = call { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float> <float 16.0, float -32.0, float undef, float 9999.0>)
102+
ret { <4 x float>, <4 x i32> } %ret
103+
}
104+
105+
; CHECK-SPIRV: ExtInst [[#TypeFloat]] [[#]] [[#ExtInstSetId]] frexp [[#]] [[#]]
106+
; CHECK-SPIRV: ExtInst [[#TypeFloat]] [[#]] [[#ExtInstSetId]] frexp [[#]] [[#]]
107+
; CHECK-LLVM: %[[#IntVar1:]] = alloca i32
108+
; CHECK-LLVM: %[[Frexp0:[a-z0-9.]+]] = call spir_func float @_Z5frexpfPi(float %x, ptr %[[#IntVar1]])
109+
; CHECK-LLVM: %[[#IntVar2:]] = alloca i32
110+
; CHECK-LLVM: %[[Frexp1:[a-z0-9.]+]] = call spir_func float @_Z5frexpfPi(float %[[Frexp0]], ptr %[[#IntVar2]])
111+
; CHECK-LLVM: %[[#LoadIntVar:]] = load i32, ptr %[[#IntVar2]]
112+
; CHECK-LLVM: %[[#AllocaStrFloatInt:]] = alloca %[[StrTypeFloatInt]]
113+
; CHECK-LLVM: %[[GEPFloat:[a-z0-9]+]] = getelementptr inbounds %structtype, ptr %[[#AllocaStrFloatInt]], i32 0, i32 0
114+
; CHECK-LLVM: store float %[[Frexp1]], ptr %[[GEPFloat]]
115+
; CHECK-LLVM: %[[GEPInt:[a-z0-9]+]] = getelementptr inbounds %structtype, ptr %[[#AllocaStrFloatInt]], i32 0, i32 1
116+
; CHECK-LLVM: store i32 %[[#LoadIntVar]], ptr %[[GEPInt]]
117+
; CHECK-LLVM: %[[LoadStrFloatInt:[a-z0-9]+]] = load %[[StrTypeFloatInt]], ptr %[[#AllocaStrFloatInt]]
118+
; CHECK-LLVM: ret %[[StrTypeFloatInt]] %[[LoadStrFloatInt]]
119+
define { float, i32 } @frexp_frexp(float %x) {
120+
%frexp0 = call { float, i32 } @llvm.frexp.f32.i32(float %x)
121+
%frexp0.0 = extractvalue { float, i32 } %frexp0, 0
122+
%frexp1 = call { float, i32 } @llvm.frexp.f32.i32(float %frexp0.0)
123+
ret { float, i32 } %frexp1
124+
}
125+
126+
; CHECK-SPIRV: ExtInst [[#VecDouble2]] [[#]] [[#ExtInstSetId]] frexp [[#]] [[#]]
127+
; CHECK-SPIRV: ExtInst [[#VecDouble2]] [[#]] [[#ExtInstSetId]] frexp [[#]] [[#]]
128+
; CHECK-LLVM: %[[Frexp0:[a-z0-9.]+]] = call spir_func <2 x double> @_Z5frexpDv2_dPDv2_i(<2 x double> %x, ptr %[[#]])
129+
; CHECK-LLVM: call spir_func <2 x double> @_Z5frexpDv2_dPDv2_i(<2 x double> %[[Frexp0]], ptr %[[#]])
130+
; CHECK-LLVM: ret %[[StrTypeDoubleIntVec2]]
131+
define { <2 x double>, <2 x i32> } @frexp_frexp_vector(<2 x double> %x) {
132+
%frexp0 = call { <2 x double>, <2 x i32> } @llvm.frexp.v2f64.v2i32(<2 x double> %x)
133+
%frexp0.0 = extractvalue { <2 x double>, <2 x i32> } %frexp0, 0
134+
%frexp1 = call { <2 x double>, <2 x i32> } @llvm.frexp.v2f64.v2i32(<2 x double> %frexp0.0)
135+
ret { <2 x double>, <2 x i32> } %frexp1
136+
}
137+
138+
; CHECK-SPIRV: ExtInst [[#TypeFloat]] [[#]] [[#ExtInstSetId]] frexp [[#]] [[#]]
139+
; CHECK-LLVM: %[[#IntVar:]] = alloca i32
140+
; CHECK-LLVM: %[[Frexp:[a-z0-9.]+]] = call spir_func float @_Z5frexpfPi(float %x, ptr %[[#IntVar]])
141+
; CHECK-LLVM: %[[LoadVar:[a-z0-9.]+]] = load i32, ptr %[[#IntVar]]
142+
; CHECK-LLVM: ret i32 %[[LoadVar]]
143+
define i32 @frexp_frexp_get_int(float %x) {
144+
%frexp0 = call { float, i32 } @llvm.frexp.f32.i32(float %x)
145+
%frexp0.0 = extractvalue { float, i32 } %frexp0, 1
146+
ret i32 %frexp0.0
147+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: not llvm-spirv %t.bc 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
3+
4+
; CHECK-ERROR: InvalidBitWidth: Invalid bit width in input: 16
5+
6+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
7+
target triple = "spir64-unknown-unknown"
8+
9+
declare { <2 x float>, <2 x i16> } @llvm.frexp.v2f32.v2i16(<2 x float>)
10+
11+
define { <2 x float>, <2 x i16> } @frexp_zero_vector() {
12+
%ret = call { <2 x float>, <2 x i16> } @llvm.frexp.v2f32.v2i16(<2 x float> zeroinitializer)
13+
ret { <2 x float>, <2 x i16> } %ret
14+
}

0 commit comments

Comments
 (0)