mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 13:06:06 +00:00
Add step builtins and step HLSL function to DirectX and SPIR-V backend (#106471)
This PR adds the step intrinsic and an HLSL function that uses it. The SPIRV backend is also implemented. Used https://github.com/llvm/llvm-project/pull/102683 as a reference. Fixes https://github.com/llvm/llvm-project/issues/99157
This commit is contained in:
parent
9e2bb418b4
commit
2d47a0baba
@ -4763,6 +4763,7 @@ def HLSLSaturate : LangBuiltin<"HLSL_LANG"> {
|
||||
let Prototype = "void(...)";
|
||||
}
|
||||
|
||||
|
||||
def HLSLSelect : LangBuiltin<"HLSL_LANG"> {
|
||||
let Spellings = ["__builtin_hlsl_select"];
|
||||
let Attributes = [NoThrow, Const];
|
||||
@ -4775,6 +4776,12 @@ def HLSLSign : LangBuiltin<"HLSL_LANG"> {
|
||||
let Prototype = "void(...)";
|
||||
}
|
||||
|
||||
def HLSLStep: LangBuiltin<"HLSL_LANG"> {
|
||||
let Spellings = ["__builtin_hlsl_step"];
|
||||
let Attributes = [NoThrow, Const];
|
||||
let Prototype = "void(...)";
|
||||
}
|
||||
|
||||
// Builtins for XRay.
|
||||
def XRayCustomEvent : Builtin {
|
||||
let Spellings = ["__xray_customevent"];
|
||||
|
@ -18861,6 +18861,16 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
|
||||
|
||||
return SelectVal;
|
||||
}
|
||||
case Builtin::BI__builtin_hlsl_step: {
|
||||
Value *Op0 = EmitScalarExpr(E->getArg(0));
|
||||
Value *Op1 = EmitScalarExpr(E->getArg(1));
|
||||
assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
|
||||
E->getArg(1)->getType()->hasFloatingRepresentation() &&
|
||||
"step operands must have a float representation");
|
||||
return Builder.CreateIntrinsic(
|
||||
/*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(),
|
||||
ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.step");
|
||||
}
|
||||
case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
|
||||
return EmitRuntimeCall(CGM.CreateRuntimeFunction(
|
||||
llvm::FunctionType::get(IntTy, {}, false), "__hlsl_wave_get_lane_index",
|
||||
|
@ -81,6 +81,7 @@ public:
|
||||
GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt)
|
||||
GENERATE_HLSL_INTRINSIC_FUNCTION(Saturate, saturate)
|
||||
GENERATE_HLSL_INTRINSIC_FUNCTION(Sign, sign)
|
||||
GENERATE_HLSL_INTRINSIC_FUNCTION(Step, step)
|
||||
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)
|
||||
GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot)
|
||||
GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot)
|
||||
|
@ -1717,6 +1717,39 @@ float3 sqrt(float3);
|
||||
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt)
|
||||
float4 sqrt(float4);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// step builtins
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \fn T step(T x, T y)
|
||||
/// \brief Returns 1 if the x parameter is greater than or equal to the y
|
||||
/// parameter; otherwise, 0. vector. \param x [in] The first floating-point
|
||||
/// value to compare. \param y [in] The first floating-point value to compare.
|
||||
///
|
||||
/// Step is based on the following formula: (x >= y) ? 1 : 0
|
||||
|
||||
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
|
||||
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_step)
|
||||
half step(half, half);
|
||||
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
|
||||
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_step)
|
||||
half2 step(half2, half2);
|
||||
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
|
||||
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_step)
|
||||
half3 step(half3, half3);
|
||||
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
|
||||
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_step)
|
||||
half4 step(half4, half4);
|
||||
|
||||
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_step)
|
||||
float step(float, float);
|
||||
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_step)
|
||||
float2 step(float2, float2);
|
||||
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_step)
|
||||
float3 step(float3, float3);
|
||||
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_step)
|
||||
float4 step(float4, float4);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// tan builtins
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1747,6 +1747,18 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
|
||||
SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().IntTy);
|
||||
break;
|
||||
}
|
||||
case Builtin::BI__builtin_hlsl_step: {
|
||||
if (SemaRef.checkArgCount(TheCall, 2))
|
||||
return true;
|
||||
if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall))
|
||||
return true;
|
||||
|
||||
ExprResult A = TheCall->getArg(0);
|
||||
QualType ArgTyA = A.get()->getType();
|
||||
// return type is the same as the input type
|
||||
TheCall->setType(ArgTyA);
|
||||
break;
|
||||
}
|
||||
// Note these are llvm builtins that we want to catch invalid intrinsic
|
||||
// generation. Normal handling of these builitns will occur elsewhere.
|
||||
case Builtin::BI__builtin_elementwise_bitreverse: {
|
||||
|
84
clang/test/CodeGenHLSL/builtins/step.hlsl
Normal file
84
clang/test/CodeGenHLSL/builtins/step.hlsl
Normal file
@ -0,0 +1,84 @@
|
||||
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
|
||||
// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
|
||||
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
|
||||
// RUN: --check-prefixes=CHECK,NATIVE_HALF \
|
||||
// RUN: -DFNATTRS=noundef -DTARGET=dx
|
||||
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
|
||||
// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
|
||||
// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
|
||||
// RUN: -DFNATTRS=noundef -DTARGET=dx
|
||||
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
|
||||
// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
|
||||
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
|
||||
// RUN: --check-prefixes=CHECK,NATIVE_HALF \
|
||||
// RUN: -DFNATTRS="spir_func noundef" -DTARGET=spv
|
||||
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
|
||||
// RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
|
||||
// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
|
||||
// RUN: -DFNATTRS="spir_func noundef" -DTARGET=spv
|
||||
|
||||
// NATIVE_HALF: define [[FNATTRS]] half @
|
||||
// NATIVE_HALF: call half @llvm.[[TARGET]].step.f16(half
|
||||
// NO_HALF: call float @llvm.[[TARGET]].step.f32(float
|
||||
// NATIVE_HALF: ret half
|
||||
// NO_HALF: ret float
|
||||
half test_step_half(half p0, half p1)
|
||||
{
|
||||
return step(p0, p1);
|
||||
}
|
||||
// NATIVE_HALF: define [[FNATTRS]] <2 x half> @
|
||||
// NATIVE_HALF: call <2 x half> @llvm.[[TARGET]].step.v2f16(<2 x half>
|
||||
// NO_HALF: call <2 x float> @llvm.[[TARGET]].step.v2f32(<2 x float>
|
||||
// NATIVE_HALF: ret <2 x half> %hlsl.step
|
||||
// NO_HALF: ret <2 x float> %hlsl.step
|
||||
half2 test_step_half2(half2 p0, half2 p1)
|
||||
{
|
||||
return step(p0, p1);
|
||||
}
|
||||
// NATIVE_HALF: define [[FNATTRS]] <3 x half> @
|
||||
// NATIVE_HALF: call <3 x half> @llvm.[[TARGET]].step.v3f16(<3 x half>
|
||||
// NO_HALF: call <3 x float> @llvm.[[TARGET]].step.v3f32(<3 x float>
|
||||
// NATIVE_HALF: ret <3 x half> %hlsl.step
|
||||
// NO_HALF: ret <3 x float> %hlsl.step
|
||||
half3 test_step_half3(half3 p0, half3 p1)
|
||||
{
|
||||
return step(p0, p1);
|
||||
}
|
||||
// NATIVE_HALF: define [[FNATTRS]] <4 x half> @
|
||||
// NATIVE_HALF: call <4 x half> @llvm.[[TARGET]].step.v4f16(<4 x half>
|
||||
// NO_HALF: call <4 x float> @llvm.[[TARGET]].step.v4f32(<4 x float>
|
||||
// NATIVE_HALF: ret <4 x half> %hlsl.step
|
||||
// NO_HALF: ret <4 x float> %hlsl.step
|
||||
half4 test_step_half4(half4 p0, half4 p1)
|
||||
{
|
||||
return step(p0, p1);
|
||||
}
|
||||
|
||||
// CHECK: define [[FNATTRS]] float @
|
||||
// CHECK: call float @llvm.[[TARGET]].step.f32(float
|
||||
// CHECK: ret float
|
||||
float test_step_float(float p0, float p1)
|
||||
{
|
||||
return step(p0, p1);
|
||||
}
|
||||
// CHECK: define [[FNATTRS]] <2 x float> @
|
||||
// CHECK: %hlsl.step = call <2 x float> @llvm.[[TARGET]].step.v2f32(
|
||||
// CHECK: ret <2 x float> %hlsl.step
|
||||
float2 test_step_float2(float2 p0, float2 p1)
|
||||
{
|
||||
return step(p0, p1);
|
||||
}
|
||||
// CHECK: define [[FNATTRS]] <3 x float> @
|
||||
// CHECK: %hlsl.step = call <3 x float> @llvm.[[TARGET]].step.v3f32(
|
||||
// CHECK: ret <3 x float> %hlsl.step
|
||||
float3 test_step_float3(float3 p0, float3 p1)
|
||||
{
|
||||
return step(p0, p1);
|
||||
}
|
||||
// CHECK: define [[FNATTRS]] <4 x float> @
|
||||
// CHECK: %hlsl.step = call <4 x float> @llvm.[[TARGET]].step.v4f32(
|
||||
// CHECK: ret <4 x float> %hlsl.step
|
||||
float4 test_step_float4(float4 p0, float4 p1)
|
||||
{
|
||||
return step(p0, p1);
|
||||
}
|
31
clang/test/SemaHLSL/BuiltIns/step-errors.hlsl
Normal file
31
clang/test/SemaHLSL/BuiltIns/step-errors.hlsl
Normal file
@ -0,0 +1,31 @@
|
||||
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -disable-llvm-passes -verify -verify-ignore-unexpected
|
||||
|
||||
void test_too_few_arg()
|
||||
{
|
||||
return __builtin_hlsl_step();
|
||||
// expected-error@-1 {{too few arguments to function call, expected 2, have 0}}
|
||||
}
|
||||
|
||||
void test_too_many_arg(float2 p0)
|
||||
{
|
||||
return __builtin_hlsl_step(p0, p0, p0);
|
||||
// expected-error@-1 {{too many arguments to function call, expected 2, have 3}}
|
||||
}
|
||||
|
||||
bool builtin_bool_to_float_type_promotion(bool p1)
|
||||
{
|
||||
return __builtin_hlsl_step(p1, p1);
|
||||
// expected-error@-1 {passing 'bool' to parameter of incompatible type 'float'}}
|
||||
}
|
||||
|
||||
bool builtin_step_int_to_float_promotion(int p1)
|
||||
{
|
||||
return __builtin_hlsl_step(p1, p1);
|
||||
// expected-error@-1 {{passing 'int' to parameter of incompatible type 'float'}}
|
||||
}
|
||||
|
||||
bool2 builtin_step_int2_to_float2_promotion(int2 p1)
|
||||
{
|
||||
return __builtin_hlsl_step(p1, p1);
|
||||
// expected-error@-1 {{passing 'int2' (aka 'vector<int, 2>') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}}
|
||||
}
|
@ -87,7 +87,7 @@ def int_dx_umad : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLV
|
||||
def int_dx_normalize : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]>;
|
||||
def int_dx_rcp : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
|
||||
def int_dx_rsqrt : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
|
||||
|
||||
def int_dx_wave_is_first_lane : DefaultAttrsIntrinsic<[llvm_i1_ty], [], [IntrConvergent]>;
|
||||
def int_dx_sign : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_any_ty]>;
|
||||
def int_dx_step : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>]>;
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ let TargetPrefix = "spv" in {
|
||||
def int_spv_normalize : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]>;
|
||||
def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]>;
|
||||
def int_spv_saturate : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
|
||||
def int_spv_step : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [LLVMMatchType<0>, llvm_anyfloat_ty]>;
|
||||
def int_spv_fdot :
|
||||
DefaultAttrsIntrinsic<[LLVMVectorElementType<0>],
|
||||
[llvm_anyfloat_ty, LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>],
|
||||
|
@ -50,6 +50,7 @@ static bool isIntrinsicExpansion(Function &F) {
|
||||
case Intrinsic::dx_sdot:
|
||||
case Intrinsic::dx_udot:
|
||||
case Intrinsic::dx_sign:
|
||||
case Intrinsic::dx_step:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -322,6 +323,28 @@ static Value *expandPowIntrinsic(CallInst *Orig) {
|
||||
return Exp2Call;
|
||||
}
|
||||
|
||||
static Value *expandStepIntrinsic(CallInst *Orig) {
|
||||
|
||||
Value *X = Orig->getOperand(0);
|
||||
Value *Y = Orig->getOperand(1);
|
||||
Type *Ty = X->getType();
|
||||
IRBuilder<> Builder(Orig);
|
||||
|
||||
Constant *One = ConstantFP::get(Ty->getScalarType(), 1.0);
|
||||
Constant *Zero = ConstantFP::get(Ty->getScalarType(), 0.0);
|
||||
Value *Cond = Builder.CreateFCmpOLT(Y, X);
|
||||
|
||||
if (Ty != Ty->getScalarType()) {
|
||||
auto *XVec = dyn_cast<FixedVectorType>(Ty);
|
||||
One = ConstantVector::getSplat(
|
||||
ElementCount::getFixed(XVec->getNumElements()), One);
|
||||
Zero = ConstantVector::getSplat(
|
||||
ElementCount::getFixed(XVec->getNumElements()), Zero);
|
||||
}
|
||||
|
||||
return Builder.CreateSelect(Cond, Zero, One);
|
||||
}
|
||||
|
||||
static Intrinsic::ID getMaxForClamp(Type *ElemTy,
|
||||
Intrinsic::ID ClampIntrinsic) {
|
||||
if (ClampIntrinsic == Intrinsic::dx_uclamp)
|
||||
@ -433,8 +456,9 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) {
|
||||
case Intrinsic::dx_sign:
|
||||
Result = expandSignIntrinsic(Orig);
|
||||
break;
|
||||
case Intrinsic::dx_step:
|
||||
Result = expandStepIntrinsic(Orig);
|
||||
}
|
||||
|
||||
if (Result) {
|
||||
Orig->replaceAllUsesWith(Result);
|
||||
Orig->eraseFromParent();
|
||||
|
@ -263,6 +263,9 @@ private:
|
||||
bool selectSpvThreadId(Register ResVReg, const SPIRVType *ResType,
|
||||
MachineInstr &I) const;
|
||||
|
||||
bool selectStep(Register ResVReg, const SPIRVType *ResType,
|
||||
MachineInstr &I) const;
|
||||
|
||||
bool selectUnmergeValues(MachineInstr &I) const;
|
||||
|
||||
Register buildI32Constant(uint32_t Val, MachineInstr &I,
|
||||
@ -1710,6 +1713,25 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg,
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool SPIRVInstructionSelector::selectStep(Register ResVReg,
|
||||
const SPIRVType *ResType,
|
||||
MachineInstr &I) const {
|
||||
|
||||
assert(I.getNumOperands() == 4);
|
||||
assert(I.getOperand(2).isReg());
|
||||
assert(I.getOperand(3).isReg());
|
||||
MachineBasicBlock &BB = *I.getParent();
|
||||
|
||||
return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
|
||||
.addDef(ResVReg)
|
||||
.addUse(GR.getSPIRVTypeID(ResType))
|
||||
.addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
|
||||
.addImm(GL::Step)
|
||||
.addUse(I.getOperand(2).getReg())
|
||||
.addUse(I.getOperand(3).getReg())
|
||||
.constrainAllUses(TII, TRI, RBI);
|
||||
}
|
||||
|
||||
bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
|
||||
const SPIRVType *ResType,
|
||||
MachineInstr &I) const {
|
||||
@ -2468,6 +2490,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
|
||||
.addUse(GR.getSPIRVTypeID(ResType))
|
||||
.addUse(GR.getOrCreateConstInt(3, I, IntTy, TII));
|
||||
}
|
||||
case Intrinsic::spv_step:
|
||||
return selectStep(ResVReg, ResType, I);
|
||||
default: {
|
||||
std::string DiagMsg;
|
||||
raw_string_ostream OS(DiagMsg);
|
||||
|
78
llvm/test/CodeGen/DirectX/step.ll
Normal file
78
llvm/test/CodeGen/DirectX/step.ll
Normal file
@ -0,0 +1,78 @@
|
||||
; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefix=CHECK
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library < %s | FileCheck %s --check-prefix=CHECK
|
||||
|
||||
; Make sure dxil operation function calls for step are generated for half/float.
|
||||
|
||||
declare half @llvm.dx.step.f16(half, half)
|
||||
declare <2 x half> @llvm.dx.step.v2f16(<2 x half>, <2 x half>)
|
||||
declare <3 x half> @llvm.dx.step.v3f16(<3 x half>, <3 x half>)
|
||||
declare <4 x half> @llvm.dx.step.v4f16(<4 x half>, <4 x half>)
|
||||
|
||||
declare float @llvm.dx.step.f32(float, float)
|
||||
declare <2 x float> @llvm.dx.step.v2f32(<2 x float>, <2 x float>)
|
||||
declare <3 x float> @llvm.dx.step.v3f32(<3 x float>, <3 x float>)
|
||||
declare <4 x float> @llvm.dx.step.v4f32(<4 x float>, <4 x float>)
|
||||
|
||||
define noundef half @test_step_half(half noundef %p0, half noundef %p1) {
|
||||
entry:
|
||||
; CHECK: %0 = fcmp olt half %p1, %p0
|
||||
; CHECK: %1 = select i1 %0, half 0xH0000, half 0xH3C00
|
||||
%hlsl.step = call half @llvm.dx.step.f16(half %p0, half %p1)
|
||||
ret half %hlsl.step
|
||||
}
|
||||
|
||||
define noundef <2 x half> @test_step_half2(<2 x half> noundef %p0, <2 x half> noundef %p1) {
|
||||
entry:
|
||||
; CHECK: %0 = fcmp olt <2 x half> %p1, %p0
|
||||
; CHECK: %1 = select <2 x i1> %0, <2 x half> zeroinitializer, <2 x half> <half 0xH3C00, half 0xH3C00>
|
||||
%hlsl.step = call <2 x half> @llvm.dx.step.v2f16(<2 x half> %p0, <2 x half> %p1)
|
||||
ret <2 x half> %hlsl.step
|
||||
}
|
||||
|
||||
define noundef <3 x half> @test_step_half3(<3 x half> noundef %p0, <3 x half> noundef %p1) {
|
||||
entry:
|
||||
; CHECK: %0 = fcmp olt <3 x half> %p1, %p0
|
||||
; CHECK: %1 = select <3 x i1> %0, <3 x half> zeroinitializer, <3 x half> <half 0xH3C00, half 0xH3C00, half 0xH3C00>
|
||||
%hlsl.step = call <3 x half> @llvm.dx.step.v3f16(<3 x half> %p0, <3 x half> %p1)
|
||||
ret <3 x half> %hlsl.step
|
||||
}
|
||||
|
||||
define noundef <4 x half> @test_step_half4(<4 x half> noundef %p0, <4 x half> noundef %p1) {
|
||||
entry:
|
||||
; CHECK: %0 = fcmp olt <4 x half> %p1, %p0
|
||||
; CHECK: %1 = select <4 x i1> %0, <4 x half> zeroinitializer, <4 x half> <half 0xH3C00, half 0xH3C00, half 0xH3C00, half 0xH3C00>
|
||||
%hlsl.step = call <4 x half> @llvm.dx.step.v4f16(<4 x half> %p0, <4 x half> %p1)
|
||||
ret <4 x half> %hlsl.step
|
||||
}
|
||||
|
||||
define noundef float @test_step_float(float noundef %p0, float noundef %p1) {
|
||||
entry:
|
||||
; CHECK: %0 = fcmp olt float %p1, %p0
|
||||
; CHECK: %1 = select i1 %0, float 0.000000e+00, float 1.000000e+00
|
||||
%hlsl.step = call float @llvm.dx.step.f32(float %p0, float %p1)
|
||||
ret float %hlsl.step
|
||||
}
|
||||
|
||||
define noundef <2 x float> @test_step_float2(<2 x float> noundef %p0, <2 x float> noundef %p1) {
|
||||
entry:
|
||||
; CHECK: %0 = fcmp olt <2 x float> %p1, %p0
|
||||
; CHECK: %1 = select <2 x i1> %0, <2 x float> zeroinitializer, <2 x float> <float 1.000000e+00, float 1.000000e+00>
|
||||
%hlsl.step = call <2 x float> @llvm.dx.step.v2f32(<2 x float> %p0, <2 x float> %p1)
|
||||
ret <2 x float> %hlsl.step
|
||||
}
|
||||
|
||||
define noundef <3 x float> @test_step_float3(<3 x float> noundef %p0, <3 x float> noundef %p1) {
|
||||
entry:
|
||||
; CHECK: %0 = fcmp olt <3 x float> %p1, %p0
|
||||
; CHECK: %1 = select <3 x i1> %0, <3 x float> zeroinitializer, <3 x float> <float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
|
||||
%hlsl.step = call <3 x float> @llvm.dx.step.v3f32(<3 x float> %p0, <3 x float> %p1)
|
||||
ret <3 x float> %hlsl.step
|
||||
}
|
||||
|
||||
define noundef <4 x float> @test_step_float4(<4 x float> noundef %p0, <4 x float> noundef %p1) {
|
||||
entry:
|
||||
; CHECK: %0 = fcmp olt <4 x float> %p1, %p0
|
||||
; CHECK: %1 = select <4 x i1> %0, <4 x float> zeroinitializer, <4 x float> <float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
|
||||
%hlsl.step = call <4 x float> @llvm.dx.step.v4f32(<4 x float> %p0, <4 x float> %p1)
|
||||
ret <4 x float> %hlsl.step
|
||||
}
|
33
llvm/test/CodeGen/SPIRV/hlsl-intrinsics/step.ll
Normal file
33
llvm/test/CodeGen/SPIRV/hlsl-intrinsics/step.ll
Normal file
@ -0,0 +1,33 @@
|
||||
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
|
||||
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
|
||||
|
||||
; Make sure SPIRV operation function calls for step are lowered correctly.
|
||||
|
||||
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
|
||||
; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
|
||||
; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
|
||||
; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
|
||||
|
||||
define noundef <4 x half> @step_half4(<4 x half> noundef %a, <4 x half> noundef %b) {
|
||||
entry:
|
||||
; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]]
|
||||
; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]]
|
||||
; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]]
|
||||
; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Step %[[#arg0]] %[[#arg1]]
|
||||
%hlsl.step = call <4 x half> @llvm.spv.step.v4f16(<4 x half> %a, <4 x half> %b)
|
||||
ret <4 x half> %hlsl.step
|
||||
}
|
||||
|
||||
define noundef <4 x float> @step_float4(<4 x float> noundef %a, <4 x float> noundef %b) {
|
||||
entry:
|
||||
; CHECK: %[[#]] = OpFunction %[[#vec4_float_32]] None %[[#]]
|
||||
; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
|
||||
; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_32]]
|
||||
; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Step %[[#arg0]] %[[#arg1]]
|
||||
%hlsl.step = call <4 x float> @llvm.spv.step.v4f32(<4 x float> %a, <4 x float> %b)
|
||||
ret <4 x float> %hlsl.step
|
||||
}
|
||||
|
||||
declare <4 x half> @llvm.spv.step.v4f16(<4 x half>, <4 x half>)
|
||||
declare <4 x float> @llvm.spv.step.v4f32(<4 x float>, <4 x float>)
|
Loading…
x
Reference in New Issue
Block a user