Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/Basic/BuiltinsSPIRVVK.td
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ include "clang/Basic/BuiltinsSPIRVBase.td"
def reflect : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
def faceforward : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
def refract : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
def fwidth : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
Intrinsic::spv_global_offset,
ArrayRef<Value *>{EmitScalarExpr(E->getArg(0))}, nullptr,
"spv.global.offset");
case SPIRV::BI__builtin_spirv_fwidth:
return Builder.CreateIntrinsic(
/*ReturnType=*/getTypes().ConvertType(E->getType()),
Intrinsic::spv_fwidth, ArrayRef<Value *>{EmitScalarExpr(E->getArg(0))},
nullptr, "spv.fwidth");
}
return nullptr;
}
12 changes: 12 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,18 @@ constexpr K firstbithigh_impl(T X) {
return FBH;
}

template <typename T> constexpr T fwidth_impl(T input) {
#if (__has_builtin(__builtin_spirv_fwidth))
return __builtin_spirv_fwidth(input);
#else
T derivCoarseX = ddx_coarse(input);
derivCoarseX = abs(derivCoarseX);
T derivCoarseY = ddy_coarse(input);
derivCoarseY = abs(derivCoarseY);
return derivCoarseX + derivCoarseY;
#endif
}

} // namespace __detail
} // namespace hlsl

Expand Down
40 changes: 40 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -666,5 +666,45 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
return __detail::smoothstep_vec_impl(Min, Max, X);
}

//===----------------------------------------------------------------------===//
// fwidth builtin
//===----------------------------------------------------------------------===//

/// \fn T fwidth(T x)
/// \brief Computes the sum of the absolute values of the partial derivatives
/// with regard to the x and y screen space coordinates.
/// \param x [in] The floating-point scalar or vector to process.
///
/// The return value is a floating-point scalar or vector where each element
/// holds the computation of the matching element in the input.

template <typename T>
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
__detail::is_same<half, T>::value,
T> fwidth(T input) {
return __detail::fwidth_impl(input);
}

template <typename T>
const inline __detail::enable_if_t<
__detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
fwidth(T input) {
return __detail::fwidth_impl(input);
}

template <int N>
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
const inline __detail::HLSL_FIXED_VECTOR<half, N> fwidth(
__detail::HLSL_FIXED_VECTOR<half, N> input) {
return __detail::fwidth_impl(input);
}

template <int N>
const inline __detail::HLSL_FIXED_VECTOR<float, N>
fwidth(__detail::HLSL_FIXED_VECTOR<float, N> input) {
return __detail::fwidth_impl(input);
}

} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
18 changes: 18 additions & 0 deletions clang/lib/Sema/SemaSPIRV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,24 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI,
case SPIRV::BI__builtin_spirv_generic_cast_to_ptr_explicit: {
return checkGenericCastToPtr(SemaRef, TheCall);
}
case SPIRV::BI__builtin_spirv_fwidth: {
if (SemaRef.checkArgCount(TheCall, 1))
return true;

// Check if first argument has floating representation
ExprResult A = TheCall->getArg(0);
QualType ArgTyA = A.get()->getType();
if (!ArgTyA->hasFloatingRepresentation()) {
SemaRef.Diag(A.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
<< /* fp */ 1 << ArgTyA;
return true;
}

QualType RetTy = ArgTyA;
TheCall->setType(RetTy);
break;
}
}
return false;
}
Expand Down
118 changes: 118 additions & 0 deletions clang/test/CodeGenHLSL/builtins/fwidth.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s \
// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \
// RUN: FileCheck %s --check-prefixes=CHECK
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-unknown-vulkan1.3-library %s \
// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \
// RUN: FileCheck %s --check-prefixes=CHECK-SPIRV

// CHECK-LABEL: define {{.*}} half @_ZN4hlsl8__detail11fwidth_implIDhEET_S2_
// CHECK: %hlsl.ddx.coarse = call {{.*}} half @llvm.dx.ddx.coarse.f16(half %{{.*}})
// CHECK: %{{.*}} = call {{.*}} half @llvm.fabs.f16(half %{{.*}})
// CHECK: %hlsl.ddy.coarse = call {{.*}} half @llvm.dx.ddy.coarse.f16(half %{{.*}})
// CHECK: %{{.*}} = call {{.*}} half @llvm.fabs.f16(half %{{.*}})
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
// CHECK: ret half %{{.*}}
// CHECK-LABEL-SPIRV: half @_Z15test_f16_fwidthDh
// CHECK-SPIRV: %spv.fwidth = call {{.*}} half @llvm.spv.fwidth.f16(half %{{.*}})
// CHECK-SPIRV: ret half %spv.fwidth
half test_f16_fwidth(half val) {
return fwidth(val);
}

// CHECK-LABEL: define {{.*}} <2 x half> @_ZN4hlsl8__detail11fwidth_implIDv2_DhEET_S3_
// CHECK: %hlsl.ddx.coarse = call {{.*}} <2 x half> @llvm.dx.ddx.coarse.v2f16(<2 x half> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <2 x half> @llvm.fabs.v2f16(<2 x half> %{{.*}})
// CHECK: %hlsl.ddy.coarse = call {{.*}} <2 x half> @llvm.dx.ddy.coarse.v2f16(<2 x half> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <2 x half> @llvm.fabs.v2f16(<2 x half> %{{.*}})
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
// CHECK: ret <2 x half> %{{.*}}
// CHECK-LABEL-SPIRV: <2 x half> @_Z16test_f16_fwidth2Dv2_Dh
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <2 x half> @llvm.spv.fwidth.v2f16(<2 x half> %{{.*}})
// CHECK-SPIRV: ret <2 x half> %spv.fwidth
half2 test_f16_fwidth2(half2 val) {
return fwidth(val);
}

// CHECK-LABEL: define {{.*}} <3 x half> @_ZN4hlsl8__detail11fwidth_implIDv3_DhEET_S3_
// CHECK: %hlsl.ddx.coarse = call {{.*}} <3 x half> @llvm.dx.ddx.coarse.v3f16(<3 x half> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <3 x half> @llvm.fabs.v3f16(<3 x half> %{{.*}})
// CHECK: %hlsl.ddy.coarse = call {{.*}} <3 x half> @llvm.dx.ddy.coarse.v3f16(<3 x half> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <3 x half> @llvm.fabs.v3f16(<3 x half> %{{.*}})
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
// CHECK: ret <3 x half> %{{.*}}
// CHECK-LABEL-SPIRV: <3 x half> @_Z16test_f16_fwidth3Dv3_Dh
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <3 x half> @llvm.spv.fwidth.v3f16(<3 x half> %{{.*}})
// CHECK-SPIRV: ret <3 x half> %spv.fwidth
half3 test_f16_fwidth3(half3 val) {
return fwidth(val);
}

// CHECK-LABEL: define {{.*}} <4 x half> @_ZN4hlsl8__detail11fwidth_implIDv4_DhEET_S3_
// CHECK: %hlsl.ddx.coarse = call {{.*}} <4 x half> @llvm.dx.ddx.coarse.v4f16(<4 x half> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <4 x half> @llvm.fabs.v4f16(<4 x half> %{{.*}})
// CHECK: %hlsl.ddy.coarse = call {{.*}} <4 x half> @llvm.dx.ddy.coarse.v4f16(<4 x half> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <4 x half> @llvm.fabs.v4f16(<4 x half> %{{.*}})
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
// CHECK: ret <4 x half> %{{.*}}
// CHECK-LABEL-SPIRV: <4 x half> @_Z16test_f16_fwidth4Dv4_Dh
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <4 x half> @llvm.spv.fwidth.v4f16(<4 x half> %{{.*}})
// CHECK-SPIRV: ret <4 x half> %spv.fwidth
half4 test_f16_fwidth4(half4 val) {
return fwidth(val);
}

// CHECK-LABEL: define {{.*}} float @_ZN4hlsl8__detail11fwidth_implIfEET_S2_
// CHECK: %hlsl.ddx.coarse = call {{.*}} float @llvm.dx.ddx.coarse.f32(float %{{.*}})
// CHECK: %{{.*}} = call {{.*}} float @llvm.fabs.f32(float %{{.*}})
// CHECK: %hlsl.ddy.coarse = call {{.*}} float @llvm.dx.ddy.coarse.f32(float %{{.*}})
// CHECK: %{{.*}} = call {{.*}} float @llvm.fabs.f32(float %{{.*}})
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
// CHECK: ret float %{{.*}}
// CHECK-LABEL-SPIRV: float @_Z15test_f32_fwidthf
// CHECK-SPIRV: %spv.fwidth = call {{.*}} float @llvm.spv.fwidth.f32(float %{{.*}})
// CHECK-SPIRV: ret float %spv.fwidth
float test_f32_fwidth(float val) {
return fwidth(val);
}

// CHECK-LABEL: define {{.*}} <2 x float> @_ZN4hlsl8__detail11fwidth_implIDv2_fEET_S3_
// CHECK: %hlsl.ddx.coarse = call {{.*}} <2 x float> @llvm.dx.ddx.coarse.v2f32(<2 x float> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <2 x float> @llvm.fabs.v2f32(<2 x float> %{{.*}})
// CHECK: %hlsl.ddy.coarse = call {{.*}} <2 x float> @llvm.dx.ddy.coarse.v2f32(<2 x float> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <2 x float> @llvm.fabs.v2f32(<2 x float> %{{.*}})
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
// CHECK: ret <2 x float> %{{.*}}
// CHECK-LABEL-SPIRV: <2 x float> @_Z16test_f32_fwidth2Dv2_f
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <2 x float> @llvm.spv.fwidth.v2f32(<2 x float> %{{.*}})
// CHECK-SPIRV: ret <2 x float> %spv.fwidth
float2 test_f32_fwidth2(float2 val) {
return fwidth(val);
}

// CHECK-LABEL: define {{.*}} <3 x float> @_ZN4hlsl8__detail11fwidth_implIDv3_fEET_S3_
// CHECK: %hlsl.ddx.coarse = call {{.*}} <3 x float> @llvm.dx.ddx.coarse.v3f32(<3 x float> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <3 x float> @llvm.fabs.v3f32(<3 x float> %{{.*}})
// CHECK: %hlsl.ddy.coarse = call {{.*}} <3 x float> @llvm.dx.ddy.coarse.v3f32(<3 x float> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <3 x float> @llvm.fabs.v3f32(<3 x float> %{{.*}})
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
// CHECK: ret <3 x float> %{{.*}}
// CHECK-LABEL-SPIRV: <3 x float> @_Z16test_f32_fwidth3Dv3_f
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <3 x float> @llvm.spv.fwidth.v3f32(<3 x float> %{{.*}})
// CHECK-SPIRV: ret <3 x float> %spv.fwidth
float3 test_f32_fwidth3(float3 val) {
return fwidth(val);
}

// CHECK-LABEL: define {{.*}} <4 x float> @_ZN4hlsl8__detail11fwidth_implIDv4_fEET_S3_
// CHECK: %hlsl.ddx.coarse = call {{.*}} <4 x float> @llvm.dx.ddx.coarse.v4f32(<4 x float> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}})
// CHECK: %hlsl.ddy.coarse = call {{.*}} <4 x float> @llvm.dx.ddy.coarse.v4f32(<4 x float> %{{.*}})
// CHECK: %{{.*}} = call {{.*}} <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}})
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
// CHECK: ret <4 x float> %{{.*}}
// CHECK-LABEL-SPIRV: <4 x float> @_Z16test_f32_fwidth4Dv4_f
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <4 x float> @llvm.spv.fwidth.v4f32(<4 x float> %{{.*}})
// CHECK-SPIRV: ret <4 x float> %spv.fwidth
float4 test_f32_fwidth4(float4 val) {
return fwidth(val);
}
41 changes: 41 additions & 0 deletions clang/test/CodeGenSPIRV/Builtins/fwidth.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-compute %s -emit-llvm -o - | FileCheck %s

typedef _Float16 half;
typedef half half2 __attribute__((ext_vector_type(2)));
typedef half half3 __attribute__((ext_vector_type(3)));
typedef half half4 __attribute__((ext_vector_type(4)));
typedef float float2 __attribute__((ext_vector_type(2)));
typedef float float3 __attribute__((ext_vector_type(3)));
typedef float float4 __attribute__((ext_vector_type(4)));

// CHECK: [[fwidth0:%.*]] = tail call half @llvm.spv.fwidth.f16(half {{%.*}})
// CHECK: ret half [[fwidth0]]
half test_fwidth_half(half X) { return __builtin_spirv_fwidth(X); }

// CHECK: [[fwidth0:%.*]] = tail call <2 x half> @llvm.spv.fwidth.v2f16(<2 x half> {{%.*}})
// CHECK: ret <2 x half> [[fwidth0]]
half2 test_fwidth_half2(half2 X) { return __builtin_spirv_fwidth(X); }

// CHECK: [[fwidth0:%.*]] = tail call <3 x half> @llvm.spv.fwidth.v3f16(<3 x half> {{%.*}})
// CHECK: ret <3 x half> [[fwidth0]]
half3 test_fwidth_half3(half3 X) { return __builtin_spirv_fwidth(X); }

// CHECK: [[fwidth0:%.*]] = tail call <4 x half> @llvm.spv.fwidth.v4f16(<4 x half> {{%.*}})
// CHECK: ret <4 x half> [[fwidth0]]
half4 test_fwidth_half4(half4 X) { return __builtin_spirv_fwidth(X); }

// CHECK: [[fwidth0:%.*]] = tail call float @llvm.spv.fwidth.f32(float {{%.*}})
// CHECK: ret float [[fwidth0]]
float test_fwidth_float(float X) { return __builtin_spirv_fwidth(X); }

// CHECK: [[fwidth1:%.*]] = tail call <2 x float> @llvm.spv.fwidth.v2f32(<2 x float> {{%.*}})
// CHECK: ret <2 x float> [[fwidth1]]
float2 test_fwidth_float2(float2 X) { return __builtin_spirv_fwidth(X); }

// CHECK: [[fwidth2:%.*]] = tail call <3 x float> @llvm.spv.fwidth.v3f32(<3 x float> {{%.*}})
// CHECK: ret <3 x float> [[fwidth2]]
float3 test_fwidth_float3(float3 X) { return __builtin_spirv_fwidth(X); }

// CHECK: [[fwidth3:%.*]] = tail call <4 x float> @llvm.spv.fwidth.v4f32(<4 x float> {{%.*}})
// CHECK: ret <4 x float> [[fwidth3]]
float4 test_fwidth_float4(float4 X) { return __builtin_spirv_fwidth(X); }
24 changes: 24 additions & 0 deletions clang/test/SemaSPIRV/BuiltIns/fwidth-errors.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_cc1 %s -triple spirv-pc-vulkan-compute -verify

typedef float float2 __attribute__((ext_vector_type(2)));

void test_too_few_arg()
{
return __builtin_spirv_fwidth();
// expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
}

float test_too_many_arg(float p0) {
return __builtin_spirv_fwidth(p0, p0);
// expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
}

float test_int_scalar_inputs(int p0) {
return __builtin_spirv_fwidth(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of floating-point types (was 'int')}}
}

float test_mismatched_return(float2 p0) {
return __builtin_spirv_fwidth(p0);
// expected-error@-1 {{returning 'float2' (vector of 2 'float' values) from a function with incompatible result type 'float'}}
}
1 change: 1 addition & 0 deletions llvm/include/llvm/IR/IntrinsicsSPIRV.td
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]
def int_spv_discard : DefaultAttrsIntrinsic<[], [], []>;
def int_spv_ddx_coarse : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_ddy_coarse : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_fwidth : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_uclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_sclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_nclamp : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
Expand Down
23 changes: 11 additions & 12 deletions llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
MachineInstr &I) const;
bool selectFrexp(Register ResVReg, const SPIRVType *ResType,
MachineInstr &I) const;
bool selectDpdCoarse(Register ResVReg, const SPIRVType *ResType,
MachineInstr &I, const unsigned DPdOpCode) const;
bool selectDerivativeInst(Register ResVReg, const SPIRVType *ResType,
MachineInstr &I, const unsigned DPdOpCode) const;
// Utilities
std::pair<Register, bool>
buildI32Constant(uint32_t Val, MachineInstr &I,
Expand Down Expand Up @@ -3143,10 +3143,9 @@ bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
return Result;
}

bool SPIRVInstructionSelector::selectDpdCoarse(Register ResVReg,
const SPIRVType *ResType,
MachineInstr &I,
const unsigned DPdOpCode) const {
bool SPIRVInstructionSelector::selectDerivativeInst(
Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
const unsigned DPdOpCode) const {
// TODO: This should check specifically for Fragment Execution Model, but STI
// doesn't provide that information yet. See #167562
errorIfInstrOutsideShader(I);
Expand Down Expand Up @@ -3583,12 +3582,12 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
case Intrinsic::spv_unpackhalf2x16: {
return selectExtInst(ResVReg, ResType, I, GL::UnpackHalf2x16);
}
case Intrinsic::spv_ddx_coarse: {
return selectDpdCoarse(ResVReg, ResType, I, SPIRV::OpDPdxCoarse);
}
case Intrinsic::spv_ddy_coarse: {
return selectDpdCoarse(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
}
case Intrinsic::spv_ddx_coarse:
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxCoarse);
case Intrinsic::spv_ddy_coarse:
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
case Intrinsic::spv_fwidth:
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth);
default: {
std::string DiagMsg;
raw_string_ostream OS(DiagMsg);
Expand Down
20 changes: 17 additions & 3 deletions llvm/test/CodeGen/DirectX/ddx_coarse-errors.ll
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck --check-prefixes=CHECK-TYPE %s
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-compute %s 2>&1 | FileCheck --check-prefixes=CHECK-STAGE %s

; DXIL operation ddx.coarse does not support double overload type
; CHECK: in function ddx.coarse
; CHECK-SAME: Cannot create DerivCoarseX operation: Invalid overload type
; CHECK-TYPE: in function ddx.coarse
; CHECK-TYPE-SAME: Cannot create DerivCoarseX operation: Invalid overload type

; Function Attrs: noinline nounwind optnone
define noundef double @ddx.coarse_double(double noundef %a) #0 {
Expand All @@ -13,3 +14,16 @@ entry:
%dx.ddx.coarse = call double @llvm.dx.ddx.coarse.f64(double %0)
ret double %dx.ddx.coarse
}

; DXIL operation ddx.coarse does not support compute shader stage
; CHECK-STAGE: in function ddx.coarse
; CHECK-STAGE-SAME: Cannot create DerivCoarseX operation: Invalid stage
; Function Attrs: noinline nounwind optnone
define noundef float @ddx.coarse_float(float noundef %a) #0 {
entry:
%a.addr = alloca float, align 8
store float %a, ptr %a.addr, align 8
%0 = load float, ptr %a.addr, align 8
%dx.ddx.coarse = call float @llvm.dx.ddx.coarse.f32(float %0)
ret float %dx.ddx.coarse
}
Loading