-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[DirectX] Add lowering support for llvm.fsh[l|r].*
#170570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
5441b45
bd36e8b
7f46c8e
2752c8e
3839396
284c45a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| #include "llvm/ADT/STLExtras.h" | ||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/CodeGen/Passes.h" | ||
| #include "llvm/IR/Constants.h" | ||
| #include "llvm/IR/IRBuilder.h" | ||
| #include "llvm/IR/InstrTypes.h" | ||
| #include "llvm/IR/Instruction.h" | ||
|
|
@@ -200,6 +201,8 @@ static bool isIntrinsicExpansion(Function &F) { | |
| case Intrinsic::assume: | ||
| case Intrinsic::abs: | ||
| case Intrinsic::atan2: | ||
| case Intrinsic::fshl: | ||
| case Intrinsic::fshr: | ||
| case Intrinsic::exp: | ||
| case Intrinsic::is_fpclass: | ||
| case Intrinsic::log: | ||
|
|
@@ -656,6 +659,32 @@ static Value *expandAtan2Intrinsic(CallInst *Orig) { | |
| return Result; | ||
| } | ||
|
|
||
| template <bool LeftFunnel> | ||
| static Value *expandFunnelShiftIntrinsic(CallInst *Orig) { | ||
| Type *Ty = Orig->getType(); | ||
| Value *A = Orig->getOperand(0); | ||
| Value *B = Orig->getOperand(1); | ||
| Value *Shift = Orig->getOperand(2); | ||
|
|
||
| IRBuilder<> Builder(Orig); | ||
|
|
||
| unsigned BitWidth = Ty->getScalarSizeInBits(); | ||
| Constant *Mask = ConstantInt::get(Ty, BitWidth - 1); | ||
| Constant *Size = ConstantInt::get(Ty, BitWidth); | ||
|
|
||
| // The shift is not required to be masked as DXIL op will do so automatically | ||
| Value *Left = | ||
| LeftFunnel ? Builder.CreateShl(A, Shift) : Builder.CreateLShr(B, Shift); | ||
|
||
|
|
||
| Value *MaskedShift = Builder.CreateAnd(Shift, Mask); | ||
|
||
| Value *InverseShift = Builder.CreateSub(Size, MaskedShift); | ||
| Value *Right = LeftFunnel ? Builder.CreateLShr(B, InverseShift) | ||
| : Builder.CreateShl(A, InverseShift); | ||
|
||
|
|
||
| Value *Result = Builder.CreateOr(Left, Right); | ||
| return Result; | ||
| } | ||
|
|
||
| static Value *expandPowIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId) { | ||
|
|
||
| Value *X = Orig->getOperand(0); | ||
|
|
@@ -995,6 +1024,12 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) { | |
| case Intrinsic::atan2: | ||
| Result = expandAtan2Intrinsic(Orig); | ||
| break; | ||
| case Intrinsic::fshl: | ||
| Result = expandFunnelShiftIntrinsic<true>(Orig); | ||
| break; | ||
| case Intrinsic::fshr: | ||
| Result = expandFunnelShiftIntrinsic<false>(Orig); | ||
| break; | ||
| case Intrinsic::exp: | ||
| Result = expandExpIntrinsic(Orig); | ||
| break; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| ; RUN: opt -S -dxil-intrinsic-expansion -scalarizer -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s | ||
| ; RUN: opt -S -dxil-intrinsic-expansion -scalarizer -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s | ||
| ; | ||
| ; Make sure dxil operation function calls for funnel shifts left are generated. | ||
|
|
||
| ; CHECK-LABEL: define{{.*}}@fshl_i16( | ||
| ; CHECK-SAME: i16 %[[A:.*]], i16 %[[B:.*]], i16 %[[SHIFT:.*]]) | ||
| define noundef i16 @fshl_i16(i16 %a, i16 %b, i16 %shift) { | ||
| entry: | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: %[[LEFT:.*]] = shl i16 %[[A]], %[[SHIFT]] | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT:.*]] = and i16 %[[SHIFT]], 15 | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT:.*]] = sub i16 16, %[[MASKED_SHIFT]] | ||
| ; CHECK-NEXT: %[[RIGHT:.*]] = lshr i16 %[[B]], %[[INVERSE_SHIFT]] | ||
| ; CHECK-NEXT: %[[RES:.*]] = or i16 %[[LEFT]], %[[RIGHT]] | ||
| ; CHECK-NEXT: ret i16 %[[RES]] | ||
| %fsh = call i16 @llvm.fshl.i16(i16 %a, i16 %b, i16 %shift) | ||
| ret i16 %fsh | ||
| } | ||
|
|
||
| declare i16 @llvm.fshl.i16(i16, i16, i16) | ||
|
|
||
| ; CHECK-LABEL: define{{.*}}@fshl_v1i32( | ||
| ; CHECK-SAME: <1 x i32> %[[A_VEC:.*]], <1 x i32> %[[B_VEC:.*]], <1 x i32> %[[SHIFT_VEC:.*]]) | ||
| define noundef <1 x i32> @fshl_v1i32(<1 x i32> %a, <1 x i32> %b, <1 x i32> %shift) { | ||
| entry: | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: %[[B:.*]] = extractelement <1 x i32> %[[B_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[A:.*]] = extractelement <1 x i32> %[[A_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[SHIFT:.*]] = extractelement <1 x i32> %[[SHIFT_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[LEFT:.*]] = shl i32 %[[A]], %[[SHIFT]] | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT:.*]] = and i32 %[[SHIFT]], 31 | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT:.*]] = sub i32 32, %[[MASKED_SHIFT]] | ||
| ; CHECK-NEXT: %[[RIGHT:.*]] = lshr i32 %[[B]], %[[INVERSE_SHIFT]] | ||
| ; CHECK-NEXT: %[[RES:.*]] = or i32 %[[LEFT]], %[[RIGHT]] | ||
| ; CHECK-NEXT: %[[RES_VEC:.*]] = insertelement <1 x i32> poison, i32 %[[RES]], i64 0 | ||
| ; CHECK-NEXT: ret <1 x i32> %[[RES_VEC]] | ||
| %fsh = call <1 x i32> @llvm.fshl.v1i32(<1 x i32> %a, <1 x i32> %b, <1 x i32> %shift) | ||
| ret <1 x i32> %fsh | ||
| } | ||
|
|
||
| declare <1 x i32> @llvm.fshl.v1i32(<1 x i32>, <1 x i32>, <1 x i32>) | ||
|
|
||
| ; CHECK-LABEL: define{{.*}}@fshl_v1i64( | ||
| ; CHECK-SAME: <3 x i64> %[[A_VEC:.*]], <3 x i64> %[[B_VEC:.*]], <3 x i64> %[[SHIFT_VEC:.*]]) | ||
| define noundef <3 x i64> @fshl_v1i64(<3 x i64> %a, <3 x i64> %b, <3 x i64> %shift) { | ||
| entry: | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: %[[B0:.*]] = extractelement <3 x i64> %[[B_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[B1:.*]] = extractelement <3 x i64> %[[B_VEC]], i64 1 | ||
| ; CHECK-NEXT: %[[B2:.*]] = extractelement <3 x i64> %[[B_VEC]], i64 2 | ||
| ; | ||
| ; CHECK-NEXT: %[[A0:.*]] = extractelement <3 x i64> %[[A_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[SHIFT0:.*]] = extractelement <3 x i64> %[[SHIFT_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[LEFT0:.*]] = shl i64 %[[A0]], %[[SHIFT0]] | ||
| ; | ||
| ; CHECK-NEXT: %[[A1:.*]] = extractelement <3 x i64> %[[A_VEC]], i64 1 | ||
| ; CHECK-NEXT: %[[SHIFT1:.*]] = extractelement <3 x i64> %[[SHIFT_VEC]], i64 1 | ||
| ; CHECK-NEXT: %[[LEFT1:.*]] = shl i64 %[[A1]], %[[SHIFT1]] | ||
| ; | ||
| ; CHECK-NEXT: %[[A2:.*]] = extractelement <3 x i64> %[[A_VEC]], i64 2 | ||
| ; CHECK-NEXT: %[[SHIFT2:.*]] = extractelement <3 x i64> %[[SHIFT_VEC]], i64 2 | ||
| ; CHECK-NEXT: %[[LEFT2:.*]] = shl i64 %[[A2]], %[[SHIFT2]] | ||
| ; | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT0:.*]] = and i64 %[[SHIFT0]], 63 | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT1:.*]] = and i64 %[[SHIFT1]], 63 | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT2:.*]] = and i64 %[[SHIFT2]], 63 | ||
| ; | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT0:.*]] = sub i64 64, %[[MASKED_SHIFT0]] | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT1:.*]] = sub i64 64, %[[MASKED_SHIFT1]] | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT2:.*]] = sub i64 64, %[[MASKED_SHIFT2]] | ||
| ; | ||
| ; CHECK-NEXT: %[[RIGHT0:.*]] = lshr i64 %[[B0]], %[[INVERSE_SHIFT0]] | ||
| ; CHECK-NEXT: %[[RIGHT1:.*]] = lshr i64 %[[B1]], %[[INVERSE_SHIFT1]] | ||
| ; CHECK-NEXT: %[[RIGHT2:.*]] = lshr i64 %[[B2]], %[[INVERSE_SHIFT2]] | ||
| ; | ||
| ; CHECK-NEXT: %[[RES0:.*]] = or i64 %[[LEFT0]], %[[RIGHT0]] | ||
| ; CHECK-NEXT: %[[RES1:.*]] = or i64 %[[LEFT1]], %[[RIGHT1]] | ||
| ; CHECK-NEXT: %[[RES2:.*]] = or i64 %[[LEFT2]], %[[RIGHT2]] | ||
| ; | ||
| ; CHECK-NEXT: %[[INSERT0:.*]] = insertelement <3 x i64> poison, i64 %[[RES0]], i64 0 | ||
| ; CHECK-NEXT: %[[INSERT1:.*]] = insertelement <3 x i64> %[[INSERT0]], i64 %[[RES1]], i64 1 | ||
| ; CHECK-NEXT: %[[RES_VEC:.*]] = insertelement <3 x i64> %[[INSERT1]], i64 %[[RES2]], i64 2 | ||
| ; | ||
| ; CHECK-NEXT: ret <3 x i64> %[[RES_VEC]] | ||
| %fsh = call <3 x i64> @llvm.fshl.v1i64(<3 x i64> %a, <3 x i64> %b, <3 x i64> %shift) | ||
| ret <3 x i64> %fsh | ||
| } | ||
|
|
||
| declare <3 x i64> @llvm.fshl.v1i64(<3 x i64>, <3 x i64>, <3 x i64>) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| ; RUN: opt -S -dxil-intrinsic-expansion -scalarizer -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s | ||
| ; RUN: opt -S -dxil-intrinsic-expansion -scalarizer -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s | ||
| ; | ||
| ; Make sure dxil operation function calls for funnel shifts right are generated. | ||
|
|
||
| ; CHECK-LABEL: define{{.*}}@fshr_i16( | ||
| ; CHECK-SAME: i16 %[[A:.*]], i16 %[[B:.*]], i16 %[[SHIFT:.*]]) | ||
| define noundef i16 @fshr_i16(i16 %a, i16 %b, i16 %shift) { | ||
| entry: | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: %[[LEFT:.*]] = lshr i16 %[[B]], %[[SHIFT]] | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT:.*]] = and i16 %[[SHIFT]], 15 | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT:.*]] = sub i16 16, %[[MASKED_SHIFT]] | ||
| ; CHECK-NEXT: %[[RIGHT:.*]] = shl i16 %[[A]], %[[INVERSE_SHIFT]] | ||
| ; CHECK-NEXT: %[[RES:.*]] = or i16 %[[LEFT]], %[[RIGHT]] | ||
| ; CHECK-NEXT: ret i16 %[[RES]] | ||
| %fsh = call i16 @llvm.fshr.i16(i16 %a, i16 %b, i16 %shift) | ||
| ret i16 %fsh | ||
| } | ||
|
|
||
| declare i16 @llvm.fshr.i16(i16, i16, i16) | ||
|
|
||
| ; CHECK-LABEL: define{{.*}}@fshr_v1i32( | ||
| ; CHECK-SAME: <1 x i32> %[[A_VEC:.*]], <1 x i32> %[[B_VEC:.*]], <1 x i32> %[[SHIFT_VEC:.*]]) | ||
| define noundef <1 x i32> @fshr_v1i32(<1 x i32> %a, <1 x i32> %b, <1 x i32> %shift) { | ||
| entry: | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: %[[A:.*]] = extractelement <1 x i32> %[[A_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[B:.*]] = extractelement <1 x i32> %[[B_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[SHIFT:.*]] = extractelement <1 x i32> %[[SHIFT_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[LEFT:.*]] = lshr i32 %[[B]], %[[SHIFT]] | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT:.*]] = and i32 %[[SHIFT]], 31 | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT:.*]] = sub i32 32, %[[MASKED_SHIFT]] | ||
| ; CHECK-NEXT: %[[RIGHT:.*]] = shl i32 %[[A]], %[[INVERSE_SHIFT]] | ||
| ; CHECK-NEXT: %[[RES:.*]] = or i32 %[[LEFT]], %[[RIGHT]] | ||
| ; CHECK-NEXT: %[[RES_VEC:.*]] = insertelement <1 x i32> poison, i32 %[[RES]], i64 0 | ||
| ; CHECK-NEXT: ret <1 x i32> %[[RES_VEC]] | ||
| %fsh = call <1 x i32> @llvm.fshr.v1i32(<1 x i32> %a, <1 x i32> %b, <1 x i32> %shift) | ||
| ret <1 x i32> %fsh | ||
| } | ||
|
|
||
| declare <1 x i32> @llvm.fshr.v1i32(<1 x i32>, <1 x i32>, <1 x i32>) | ||
|
|
||
| ; CHECK-LABEL: define{{.*}}@fshr_v1i64( | ||
| ; CHECK-SAME: <3 x i64> %[[A_VEC:.*]], <3 x i64> %[[B_VEC:.*]], <3 x i64> %[[SHIFT_VEC:.*]]) | ||
| define noundef <3 x i64> @fshr_v1i64(<3 x i64> %a, <3 x i64> %b, <3 x i64> %shift) { | ||
| entry: | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: %[[A0:.*]] = extractelement <3 x i64> %[[A_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[A1:.*]] = extractelement <3 x i64> %[[A_VEC]], i64 1 | ||
| ; CHECK-NEXT: %[[A2:.*]] = extractelement <3 x i64> %[[A_VEC]], i64 2 | ||
| ; | ||
| ; CHECK-NEXT: %[[B0:.*]] = extractelement <3 x i64> %[[B_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[SHIFT0:.*]] = extractelement <3 x i64> %[[SHIFT_VEC]], i64 0 | ||
| ; CHECK-NEXT: %[[LEFT0:.*]] = lshr i64 %[[B0]], %[[SHIFT0]] | ||
| ; | ||
| ; CHECK-NEXT: %[[B1:.*]] = extractelement <3 x i64> %[[B_VEC]], i64 1 | ||
| ; CHECK-NEXT: %[[SHIFT1:.*]] = extractelement <3 x i64> %[[SHIFT_VEC]], i64 1 | ||
| ; CHECK-NEXT: %[[LEFT1:.*]] = lshr i64 %[[B1]], %[[SHIFT1]] | ||
| ; | ||
| ; CHECK-NEXT: %[[B2:.*]] = extractelement <3 x i64> %[[B_VEC]], i64 2 | ||
| ; CHECK-NEXT: %[[SHIFT2:.*]] = extractelement <3 x i64> %[[SHIFT_VEC]], i64 2 | ||
| ; CHECK-NEXT: %[[LEFT2:.*]] = lshr i64 %[[B2]], %[[SHIFT2]] | ||
| ; | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT0:.*]] = and i64 %[[SHIFT0]], 63 | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT1:.*]] = and i64 %[[SHIFT1]], 63 | ||
| ; CHECK-NEXT: %[[MASKED_SHIFT2:.*]] = and i64 %[[SHIFT2]], 63 | ||
| ; | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT0:.*]] = sub i64 64, %[[MASKED_SHIFT0]] | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT1:.*]] = sub i64 64, %[[MASKED_SHIFT1]] | ||
| ; CHECK-NEXT: %[[INVERSE_SHIFT2:.*]] = sub i64 64, %[[MASKED_SHIFT2]] | ||
| ; | ||
| ; CHECK-NEXT: %[[RIGHT0:.*]] = shl i64 %[[A0]], %[[INVERSE_SHIFT0]] | ||
| ; CHECK-NEXT: %[[RIGHT1:.*]] = shl i64 %[[A1]], %[[INVERSE_SHIFT1]] | ||
| ; CHECK-NEXT: %[[RIGHT2:.*]] = shl i64 %[[A2]], %[[INVERSE_SHIFT2]] | ||
| ; | ||
| ; CHECK-NEXT: %[[RES0:.*]] = or i64 %[[LEFT0]], %[[RIGHT0]] | ||
| ; CHECK-NEXT: %[[RES1:.*]] = or i64 %[[LEFT1]], %[[RIGHT1]] | ||
| ; CHECK-NEXT: %[[RES2:.*]] = or i64 %[[LEFT2]], %[[RIGHT2]] | ||
| ; | ||
| ; CHECK-NEXT: %[[INSERT0:.*]] = insertelement <3 x i64> poison, i64 %[[RES0]], i64 0 | ||
| ; CHECK-NEXT: %[[INSERT1:.*]] = insertelement <3 x i64> %[[INSERT0]], i64 %[[RES1]], i64 1 | ||
| ; CHECK-NEXT: %[[RES_VEC:.*]] = insertelement <3 x i64> %[[INSERT1]], i64 %[[RES2]], i64 2 | ||
| ; | ||
| ; CHECK-NEXT: ret <3 x i64> %[[RES_VEC]] | ||
| %fsh = call <3 x i64> @llvm.fshr.v1i64(<3 x i64> %a, <3 x i64> %b, <3 x i64> %shift) | ||
| ret <3 x i64> %fsh | ||
| } | ||
|
|
||
| declare <3 x i64> @llvm.fshr.v1i64(<3 x i64>, <3 x i64>, <3 x i64>) |
Uh oh!
There was an error while loading. Please reload this page.