Skip to content

Commit c8c3975

Browse files
committed
FEAT:
- add function for adding saturation decoration to sat intrinsics - add test for fp to int intrinsic - add legalization for G_FPTOSI_SAT and G_FPTOUI_SAT - add instruction selection logic for G_FPTOSI_SAT and G_FPTOUI_SAT
1 parent 31db7af commit c8c3975

File tree

4 files changed

+250
-0
lines changed

4 files changed

+250
-0
lines changed

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818
#include "SPIRVTargetMachine.h"
1919
#include "SPIRVUtils.h"
2020
#include "llvm/ADT/DenseSet.h"
21+
#include "llvm/ADT/STLExtras.h"
2122
#include "llvm/IR/IRBuilder.h"
2223
#include "llvm/IR/InstIterator.h"
2324
#include "llvm/IR/InstVisitor.h"
2425
#include "llvm/IR/IntrinsicsSPIRV.h"
2526
#include "llvm/IR/TypedPointerType.h"
27+
#include "llvm/Support/Casting.h"
2628

29+
#include <iostream>
2730
#include <queue>
2831
#include <unordered_set>
2932

@@ -1337,6 +1340,24 @@ static void createSaturatedConversionDecoration(Instruction *I,
13371340
createDecorationIntrinsic(I, SaturatedConversionNode, B);
13381341
}
13391342

1343+
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B) {
1344+
// llvm::errs() << "this function is running successfully";
1345+
if (auto *CI = dyn_cast<CallInst>(I)) {
1346+
Function *F = CI->getCalledFunction();
1347+
if (F->isIntrinsic()) {
1348+
StringRef S = F->getName();
1349+
SmallVector<StringRef, 8> Parts;
1350+
S.split(Parts, ".", -1, false);
1351+
1352+
if (Parts.size() > 1) {
1353+
if (std::find(Parts.begin(), Parts.end(), "sat") != Parts.end()) {
1354+
createSaturatedConversionDecoration(I, B);
1355+
}
1356+
}
1357+
}
1358+
}
1359+
}
1360+
13401361
Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
13411362
if (!Call.isInlineAsm())
13421363
return &Call;
@@ -2400,6 +2421,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
24002421
if (isConvergenceIntrinsic(I))
24012422
continue;
24022423

2424+
addSaturatedDecorationToIntrinsic(I, B);
24032425
processInstrAfterVisit(I, B);
24042426
}
24052427

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,10 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
602602
return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
603603
case TargetOpcode::G_FPTOUI:
604604
return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
605+
case TargetOpcode::G_FPTOSI_SAT:
606+
return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
607+
case TargetOpcode::G_FPTOUI_SAT:
608+
return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
605609

606610
case TargetOpcode::G_SITOFP:
607611
return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF);

llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
236236
.legalForCartesianProduct(allIntScalarsAndVectors,
237237
allFloatScalarsAndVectors);
238238

239+
getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
240+
.legalForCartesianProduct(allIntScalarsAndVectors,
241+
allFloatScalarsAndVectors);
242+
239243
getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
240244
.legalForCartesianProduct(allFloatScalarsAndVectors,
241245
allScalarsAndVectors);
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unkown-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unkown-unknown %s -o - -filetype=obj | spirv-val %}
3+
4+
; CHECK: OpDecorate %[[#SAT1:]] SaturatedConversion
5+
; CHECK: OpDecorate %[[#SAT2:]] SaturatedConversion
6+
; CHECK: OpDecorate %[[#SAT3:]] SaturatedConversion
7+
; CHECK: OpDecorate %[[#SAT4:]] SaturatedConversion
8+
; CHECK: OpDecorate %[[#SAT5:]] SaturatedConversion
9+
; CHECK: OpDecorate %[[#SAT6:]] SaturatedConversion
10+
; CHECK: OpDecorate %[[#SAT7:]] SaturatedConversion
11+
; CHECK: OpDecorate %[[#SAT8:]] SaturatedConversion
12+
; CHECK: OpDecorate %[[#SAT9:]] SaturatedConversion
13+
; CHECK: OpDecorate %[[#SAT10:]] SaturatedConversion
14+
; CHECK: OpDecorate %[[#SAT11:]] SaturatedConversion
15+
; CHECK: OpDecorate %[[#SAT12:]] SaturatedConversion
16+
; CHECK: OpDecorate %[[#SAT13:]] SaturatedConversion
17+
; CHECK: OpDecorate %[[#SAT14:]] SaturatedConversion
18+
; CHECK: OpDecorate %[[#SAT15:]] SaturatedConversion
19+
20+
21+
; CHECK: %[[#SAT1:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
22+
define spir_kernel void @testfunction_float_to_signed_i8(float %input) {
23+
entry:
24+
%ptr = alloca i8
25+
%0 = call i8 @llvm.fptosi.sat.i8.f32(float %input)
26+
store i8 %0, i8* %ptr
27+
ret void
28+
}
29+
declare i8 @llvm.fptosi.sat.i8.f32(float)
30+
31+
32+
; CHECK: %[[#SAT2:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
33+
define spir_kernel void @testfunction_float_to_signed_i16(float %input) {
34+
entry:
35+
%ptr = alloca i16
36+
%0 = call i16 @llvm.fptosi.sat.i16.f32(float %input)
37+
store i16 %0, i16* %ptr
38+
ret void
39+
}
40+
declare i16 @llvm.fptosi.sat.i16.f32(float)
41+
42+
;;;;;;; output i32
43+
44+
; CHECK: %[[#SAT3:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
45+
define spir_kernel void @testfunction_float_to_signed_i32(float %input) {
46+
entry:
47+
%ptr = alloca i32
48+
%0 = call i32 @llvm.fptosi.sat.i32.f32(float %input)
49+
store i32 %0, i32* %ptr
50+
ret void
51+
}
52+
declare i32 @llvm.fptosi.sat.i32.f32(float)
53+
54+
;;;;;;; output i64
55+
; CHECK: %[[#SAT4:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
56+
define spir_kernel void @testfunction_float_to_signed_i64(float %input) {
57+
entry:
58+
%ptr = alloca i64
59+
%0 = call i64 @llvm.fptosi.sat.i64.f32(float %input)
60+
store i64 %0, i64* %ptr
61+
ret void
62+
}
63+
declare i64 @llvm.fptosi.sat.i64.f32(float)
64+
65+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
66+
; double input
67+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
68+
69+
;;;;;;; output i8
70+
; CHECK: %[[#SAT5:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
71+
define spir_kernel void @testfunction_double_to_signed_i8(double %input) {
72+
entry:
73+
%ptr = alloca i8
74+
%0 = call i8 @llvm.fptosi.sat.i8.f64(double %input)
75+
store i8 %0, i8* %ptr
76+
ret void
77+
}
78+
declare i8 @llvm.fptosi.sat.i8.f64(double)
79+
80+
81+
; CHECK: %[[#SAT6:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
82+
define spir_kernel void @testfunction_double_to_signed_i16(double %input) {
83+
entry:
84+
%ptr = alloca i16
85+
%0 = call i16 @llvm.fptosi.sat.i16.f64(double %input)
86+
store i16 %0, i16* %ptr
87+
ret void
88+
}
89+
declare i16 @llvm.fptosi.sat.i16.f64(double)
90+
91+
92+
; CHECK: %[[#SAT7:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
93+
define spir_kernel void @testfunction_double_to_signed_i32(double %input) {
94+
entry:
95+
%ptr = alloca i32
96+
%0 = call i32 @llvm.fptosi.sat.i32.f64(double %input)
97+
store i32 %0, i32* %ptr
98+
ret void
99+
}
100+
declare i32 @llvm.fptosi.sat.i32.f64(double)
101+
102+
103+
; CHECK: %[[#SAT8:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
104+
define spir_kernel void @testfunction_double_to_signed_i64(double %input) {
105+
entry:
106+
%ptr = alloca i64
107+
%0 = call i64 @llvm.fptosi.sat.i64.f64(double %input)
108+
store i64 %0, i64* %ptr
109+
ret void
110+
}
111+
declare i64 @llvm.fptosi.sat.i64.f64(double)
112+
113+
114+
115+
116+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
117+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118+
; unsigned output
119+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
120+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
121+
122+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
123+
; float input
124+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
125+
126+
;;;;;;; output i8
127+
; CHECK: %[[#SAT8:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
128+
define spir_kernel void @testfunction_float_to_unsigned_i8(float %input) {
129+
entry:
130+
%ptr = alloca i8
131+
%0 = call i8 @llvm.fptoui.sat.i8.f32(float %input)
132+
store i8 %0, i8* %ptr
133+
ret void
134+
}
135+
declare i8 @llvm.fptoui.sat.i8.f32(float)
136+
137+
;;;;;;; output i16
138+
; CHECK: %[[#SAT9:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
139+
define spir_kernel void @testfunction_float_to_unsigned_i16(float %input) {
140+
entry:
141+
%ptr = alloca i16
142+
%0 = call i16 @llvm.fptoui.sat.i16.f32(float %input)
143+
store i16 %0, i16* %ptr
144+
ret void
145+
}
146+
declare i16 @llvm.fptoui.sat.i16.f32(float)
147+
148+
;;;;;;; output i32
149+
; CHECK: %[[#SAT10:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
150+
define spir_kernel void @testfunction_float_to_unsigned_i32(float %input) {
151+
entry:
152+
%ptr = alloca i32
153+
%0 = call i32 @llvm.fptoui.sat.i32.f32(float %input)
154+
store i32 %0, i32* %ptr
155+
ret void
156+
}
157+
declare i32 @llvm.fptoui.sat.i32.f32(float)
158+
159+
;;;;;;; output i64
160+
; CHECK: %[[#SAT11:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
161+
define spir_kernel void @testfunction_float_to_unsigned_i64(float %input) {
162+
entry:
163+
%ptr = alloca i64
164+
%0 = call i64 @llvm.fptoui.sat.i64.f32(float %input)
165+
store i64 %0, i64* %ptr
166+
ret void
167+
}
168+
declare i64 @llvm.fptoui.sat.i64.f32(float)
169+
170+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
171+
; double input
172+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
173+
174+
;;;;;;; output i8
175+
; CHECK: %[[#SAT12:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
176+
define spir_kernel void @testfunction_double_to_unsigned_i8(double %input) {
177+
entry:
178+
%ptr = alloca i8
179+
%0 = call i8 @llvm.fptoui.sat.i8.f64(double %input)
180+
store i8 %0, i8* %ptr
181+
ret void
182+
}
183+
declare i8 @llvm.fptoui.sat.i8.f64(double)
184+
185+
;;;;;;; output i16
186+
; CHECK: %[[#SAT13:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
187+
define spir_kernel void @testfunction_double_to_unsigned_i16(double %input) {
188+
entry:
189+
%ptr = alloca i16
190+
%0 = call i16 @llvm.fptoui.sat.i16.f64(double %input)
191+
store i16 %0, i16* %ptr
192+
ret void
193+
}
194+
declare i16 @llvm.fptoui.sat.i16.f64(double)
195+
196+
;;;;;;; output i32
197+
; CHECK: %[[#SAT14:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
198+
define spir_kernel void @testfunction_double_to_unsigned_i32(double %input) {
199+
entry:
200+
%ptr = alloca i32
201+
%0 = call i32 @llvm.fptoui.sat.i32.f64(double %input)
202+
store i32 %0, i32* %ptr
203+
ret void
204+
}
205+
declare i32 @llvm.fptoui.sat.i32.f64(double)
206+
207+
;;;;;;; output i64
208+
; CHECK: %[[#SAT15:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
209+
define spir_kernel void @testfunction_double_to_unsigned_i64(double %input) {
210+
entry:
211+
%ptr = alloca i64
212+
%0 = call i64 @llvm.fptoui.sat.i64.f64(double %input)
213+
store i64 %0, i64* %ptr
214+
ret void
215+
}
216+
declare i64 @llvm.fptoui.sat.i64.f64(double)
217+
218+
219+
220+

0 commit comments

Comments
 (0)