Skip to content

Commit d8e5c0b

Browse files
authored
[DXIL] Complete abs lowering (#86158)
This change completes #86155 - `DXIL.td` - lowering `fabs` intrinsic to the float dxil op. - `DXILIntrinsicExpansion.cpp` - Add intrinsic expansion for the abs case.
1 parent 730ca47 commit d8e5c0b

File tree

5 files changed

+129
-0
lines changed

5 files changed

+129
-0
lines changed

llvm/lib/Target/DirectX/DXIL.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ class DXILOpMapping<int opCode, DXILOpClass opClass,
255255
}
256256

257257
// Concrete definition of DXIL Operation mapping to corresponding LLVM intrinsic
258+
def Abs : DXILOpMapping<6, unary, int_fabs,
259+
"Returns the absolute value of the input.">;
258260
def IsInf : DXILOpMapping<9, isSpecialFloat, int_dx_isinf,
259261
"Determines if the specified value is infinite.",
260262
[llvm_i1_ty, llvm_halforfloat_ty]>;

llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ using namespace llvm;
3333

3434
static bool isIntrinsicExpansion(Function &F) {
3535
switch (F.getIntrinsicID()) {
36+
case Intrinsic::abs:
3637
case Intrinsic::exp:
3738
case Intrinsic::dx_any:
3839
case Intrinsic::dx_clamp:
@@ -46,6 +47,26 @@ static bool isIntrinsicExpansion(Function &F) {
4647
return false;
4748
}
4849

50+
static bool expandAbs(CallInst *Orig) {
51+
Value *X = Orig->getOperand(0);
52+
IRBuilder<> Builder(Orig->getParent());
53+
Builder.SetInsertPoint(Orig);
54+
Type *Ty = X->getType();
55+
Type *EltTy = Ty->getScalarType();
56+
Constant *Zero = Ty->isVectorTy()
57+
? ConstantVector::getSplat(
58+
ElementCount::getFixed(
59+
cast<FixedVectorType>(Ty)->getNumElements()),
60+
ConstantInt::get(EltTy, 0))
61+
: ConstantInt::get(EltTy, 0);
62+
auto *V = Builder.CreateSub(Zero, X);
63+
auto *MaxCall =
64+
Builder.CreateIntrinsic(Ty, Intrinsic::smax, {X, V}, nullptr, "dx.max");
65+
Orig->replaceAllUsesWith(MaxCall);
66+
Orig->eraseFromParent();
67+
return true;
68+
}
69+
4970
static bool expandIntegerDot(CallInst *Orig, Intrinsic::ID DotIntrinsic) {
5071
assert(DotIntrinsic == Intrinsic::dx_sdot ||
5172
DotIntrinsic == Intrinsic::dx_udot);
@@ -213,6 +234,8 @@ static bool expandClampIntrinsic(CallInst *Orig, Intrinsic::ID ClampIntrinsic) {
213234

214235
static bool expandIntrinsic(Function &F, CallInst *Orig) {
215236
switch (F.getIntrinsicID()) {
237+
case Intrinsic::abs:
238+
return expandAbs(Orig);
216239
case Intrinsic::exp:
217240
return expandExpIntrinsic(Orig);
218241
case Intrinsic::dx_any:

llvm/test/CodeGen/DirectX/abs-vec.ll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s
2+
3+
; Make sure dxil operation function calls for abs are generated for int vectors.
4+
5+
; CHECK-LABEL: abs_i16Vec2
6+
define noundef <2 x i16> @abs_i16Vec2(<2 x i16> noundef %a) #0 {
7+
entry:
8+
; CHECK: sub <2 x i16> zeroinitializer, %a
9+
; CHECK: call <2 x i16> @llvm.smax.v2i16(<2 x i16> %a, <2 x i16> %{{.*}})
10+
%elt.abs = call <2 x i16> @llvm.abs.v2i16(<2 x i16> %a, i1 false)
11+
ret <2 x i16> %elt.abs
12+
}
13+
14+
; CHECK-LABEL: abs_i32Vec3
15+
define noundef <3 x i32> @abs_i32Vec3(<3 x i32> noundef %a) #0 {
16+
entry:
17+
; CHECK: sub <3 x i32> zeroinitializer, %a
18+
; CHECK: call <3 x i32> @llvm.smax.v3i32(<3 x i32> %a, <3 x i32> %{{.*}})
19+
%elt.abs = call <3 x i32> @llvm.abs.v3i32(<3 x i32> %a, i1 false)
20+
ret <3 x i32> %elt.abs
21+
}
22+
23+
; CHECK-LABEL: abs_i64Vec4
24+
define noundef <4 x i64> @abs_i64Vec4(<4 x i64> noundef %a) #0 {
25+
entry:
26+
; CHECK: sub <4 x i64> zeroinitializer, %a
27+
; CHECK: call <4 x i64> @llvm.smax.v4i64(<4 x i64> %a, <4 x i64> %{{.*}})
28+
%elt.abs = call <4 x i64> @llvm.abs.v4i64(<4 x i64> %a, i1 false)
29+
ret <4 x i64> %elt.abs
30+
}
31+
32+
declare <2 x i16> @llvm.abs.v2i16(<2 x i16>, i1 immarg)
33+
declare <3 x i32> @llvm.abs.v3i32(<3 x i32>, i1 immarg)
34+
declare <4 x i64> @llvm.abs.v4i64(<4 x i64>, i1 immarg)

llvm/test/CodeGen/DirectX/abs.ll

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
2+
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
3+
4+
; Make sure dxil operation function calls for abs are generated for int16_t/int/int64_t.
5+
6+
; CHECK-LABEL: abs_i16
7+
define noundef i16 @abs_i16(i16 noundef %a) {
8+
entry:
9+
; CHECK: sub i16 0, %a
10+
; EXPCHECK: call i16 @llvm.smax.i16(i16 %a, i16 %{{.*}})
11+
; DOPCHECK: call i16 @dx.op.binary.i16(i32 37, i16 %a, i16 %{{.*}})
12+
%elt.abs = call i16 @llvm.abs.i16(i16 %a, i1 false)
13+
ret i16 %elt.abs
14+
}
15+
16+
; CHECK-LABEL: abs_i32
17+
define noundef i32 @abs_i32(i32 noundef %a) {
18+
entry:
19+
; CHECK: sub i32 0, %a
20+
; EXPCHECK: call i32 @llvm.smax.i32(i32 %a, i32 %{{.*}})
21+
; DOPCHECK: call i32 @dx.op.binary.i32(i32 37, i32 %a, i32 %{{.*}})
22+
%elt.abs = call i32 @llvm.abs.i32(i32 %a, i1 false)
23+
ret i32 %elt.abs
24+
}
25+
26+
; CHECK-LABEL: abs_i64
27+
define noundef i64 @abs_i64(i64 noundef %a) {
28+
entry:
29+
; CHECK: sub i64 0, %a
30+
; EXPCHECK: call i64 @llvm.smax.i64(i64 %a, i64 %{{.*}})
31+
; DOPCHECK: call i64 @dx.op.binary.i64(i32 37, i64 %a, i64 %{{.*}})
32+
%elt.abs = call i64 @llvm.abs.i64(i64 %a, i1 false)
33+
ret i64 %elt.abs
34+
}
35+
36+
declare i16 @llvm.abs.i16(i16, i1 immarg)
37+
declare i32 @llvm.abs.i32(i32, i1 immarg)
38+
declare i64 @llvm.abs.i64(i64, i1 immarg)

llvm/test/CodeGen/DirectX/fabs.ll

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
2+
3+
; Make sure dxil operation function calls for abs are generated for float, half, and double.
4+
5+
6+
; CHECK-LABEL: fabs_half
7+
define noundef half @fabs_half(half noundef %a) {
8+
entry:
9+
; CHECK: call half @dx.op.unary.f16(i32 6, half %{{.*}})
10+
%elt.abs = call half @llvm.fabs.f16(half %a)
11+
ret half %elt.abs
12+
}
13+
14+
; CHECK-LABEL: fabs_float
15+
define noundef float @fabs_float(float noundef %a) {
16+
entry:
17+
; CHECK: call float @dx.op.unary.f32(i32 6, float %{{.*}})
18+
%elt.abs = call float @llvm.fabs.f32(float %a)
19+
ret float %elt.abs
20+
}
21+
22+
; CHECK-LABEL: fabs_double
23+
define noundef double @fabs_double(double noundef %a) {
24+
entry:
25+
; CHECK: call double @dx.op.unary.f64(i32 6, double %{{.*}})
26+
%elt.abs = call double @llvm.fabs.f64(double %a)
27+
ret double %elt.abs
28+
}
29+
30+
declare half @llvm.fabs.f16(half)
31+
declare float @llvm.fabs.f32(float)
32+
declare double @llvm.fabs.f64(double)

0 commit comments

Comments
 (0)