Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -5222,6 +5222,12 @@ def HLSLGetSpirvSpecConstant : LangBuiltin<"HLSL_LANG">, HLSLScalarTemplate {
let Prototype = "T(unsigned int, T)";
}

def HLSLF16ToF32 : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_f16tof32"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Prototype = "void(...)";
}

// Builtins for XRay.
def XRayCustomEvent : Builtin {
let Spellings = ["__xray_customevent"];
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/CodeGen/CGHLSLBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,22 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getDegreesIntrinsic(),
ArrayRef<Value *>{X}, nullptr, "hlsl.degrees");
}
case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
llvm::Type *Xty = Op0->getType();
llvm::Type *retType = llvm::Type::getFloatTy(this->getLLVMContext());
if (Xty->isVectorTy()) {
auto *XVecTy = E->getArg(0)->getType()->castAs<VectorType>();
retType = llvm::VectorType::get(
retType, ElementCount::getFixed(XVecTy->getNumElements()));
}
if (!E->getArg(0)->getType()->hasUnsignedIntegerRepresentation())
llvm_unreachable(
"f16tof32 operand must have an unsigned int representation");
return Builder.CreateIntrinsic(
retType, CGM.getHLSLRuntime().getLegacyF16ToF32Intrinsic(),
ArrayRef<Value *>{Op0}, nullptr, "hlsl.f16tof32");
}
case Builtin::BI__builtin_hlsl_elementwise_frac: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class CGHLSLRuntime {
flattened_thread_id_in_group)
GENERATE_HLSL_INTRINSIC_FUNCTION(IsInf, isinf)
GENERATE_HLSL_INTRINSIC_FUNCTION(IsNaN, isnan)
GENERATE_HLSL_INTRINSIC_FUNCTION(LegacyF16ToF32, legacyf16tof32)
GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp)
GENERATE_HLSL_INTRINSIC_FUNCTION(Normalize, normalize)
GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt)
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,27 @@ float3 exp2(float3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp2)
float4 exp2(float4);

//===----------------------------------------------------------------------===//
// f16tof32 builtins
//===----------------------------------------------------------------------===//

/// \fn float f16tof32(uint x)
/// \brief Returns the half value stored in the low 16 bits of the uint arg
/// converted to a float.
/// \param x The uint containing two half values.
///
/// The float value of the half value found in the low 16 bits of the \a xi
/// parameter.

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_f16tof32)
float f16tof32(uint);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_f16tof32)
float2 f16tof32(uint2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_f16tof32)
float3 f16tof32(uint3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_f16tof32)
float4 f16tof32(uint4);

//===----------------------------------------------------------------------===//
// firstbithigh builtins
//===----------------------------------------------------------------------===//
Expand Down
57 changes: 45 additions & 12 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2738,6 +2738,23 @@ static bool CheckUnsignedIntRepresentation(Sema *S, SourceLocation Loc,
return false;
}

static bool CheckExpectedBitWidth(Sema *S, CallExpr *TheCall,
unsigned ArgOrdinal, unsigned Width) {
QualType ArgTy = TheCall->getArg(0)->getType();
if (auto *VTy = ArgTy->getAs<VectorType>())
ArgTy = VTy->getElementType();
// ensure arg type has expected bit width
uint64_t ElementBitCount =
S->getASTContext().getTypeSizeInChars(ArgTy).getQuantity() * 8;
if (ElementBitCount != Width) {
S->Diag(TheCall->getArg(0)->getBeginLoc(),
diag::err_integer_incorrect_bit_count)
<< Width << ElementBitCount;
return true;
}
return false;
}

static void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall,
QualType ReturnType) {
auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
Expand Down Expand Up @@ -2897,24 +2914,16 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
CheckUnsignedIntVecRepresentation))
return true;

auto *VTy = TheCall->getArg(0)->getType()->getAs<VectorType>();
// ensure arg integers are 32-bits
uint64_t ElementBitCount = getASTContext()
.getTypeSizeInChars(VTy->getElementType())
.getQuantity() *
8;
if (ElementBitCount != 32) {
SemaRef.Diag(TheCall->getBeginLoc(),
diag::err_integer_incorrect_bit_count)
<< 32 << ElementBitCount;
if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
return true;
}

// ensure both args are vectors of total bit size of a multiple of 64
auto *VTy = TheCall->getArg(0)->getType()->getAs<VectorType>();
int NumElementsArg = VTy->getNumElements();
if (NumElementsArg != 2 && NumElementsArg != 4) {
SemaRef.Diag(TheCall->getBeginLoc(), diag::err_vector_incorrect_bit_count)
<< 1 /*a multiple of*/ << 64 << NumElementsArg * ElementBitCount;
<< 1 /*a multiple of*/ << 64 << NumElementsArg * 32;
return true;
}

Expand Down Expand Up @@ -3230,7 +3239,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
// Note these are llvm builtins that we want to catch invalid intrinsic
// generation. Normal handling of these builitns will occur elsewhere.
// generation. Normal handling of these builtins will occur elsewhere.
case Builtin::BI__builtin_elementwise_bitreverse: {
// does not include a check for number of arguments
// because that is done previously
Expand Down Expand Up @@ -3340,6 +3349,30 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
break;
}
case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
if (SemaRef.checkArgCount(TheCall, 1))
return true;
if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
CheckUnsignedIntRepresentation))
return true;
// ensure arg integers are 32 bits
if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
return true;
// check it wasn't a bool type
QualType ArgTy = TheCall->getArg(0)->getType();
if (auto *VTy = ArgTy->getAs<VectorType>())
ArgTy = VTy->getElementType();
if (ArgTy->isBooleanType()) {
SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
diag::err_builtin_invalid_arg_type)
<< 1 << /* scalar or vector of */ 5 << /* unsigned int */ 3
<< /* no fp */ 0 << TheCall->getArg(0)->getType();
return true;
}

SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().FloatTy);
break;
}
}
return false;
}
Expand Down
30 changes: 30 additions & 0 deletions clang/test/CodeGenHLSL/builtins/f16tof32-builtin.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \
// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
// RUN: -o - | FileCheck %s

// CHECK: define hidden noundef nofpclass(nan inf) float
// CHECK: %hlsl.f16tof32 = call reassoc nnan ninf nsz arcp afn float @llvm.dx.legacyf16tof32.i32(i32 %0)
// CHECK: ret float %hlsl.f16tof32
// CHECK: declare float @llvm.dx.legacyf16tof32.i32(i32)
float test_scalar(uint p0) { return __builtin_hlsl_elementwise_f16tof32(p0); }

// CHECK: define hidden noundef nofpclass(nan inf) <2 x float>
// CHECK: %hlsl.f16tof32 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.dx.legacyf16tof32.v2i32(<2 x i32> %0)
// CHECK: ret <2 x float> %hlsl.f16tof32
// CHECK: declare <2 x float> @llvm.dx.legacyf16tof32.v2i32(<2 x i32>)
float2 test_uint2(uint2 p0) { return __builtin_hlsl_elementwise_f16tof32(p0); }

// CHECK: define hidden noundef nofpclass(nan inf) <3 x float> @_Z10test_uint3Dv3_j(<3 x i32> noundef %p0) #0 {
// CHECK: %hlsl.f16tof32 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.dx.legacyf16tof32.v3i32(<3 x i32> %0)
// CHECK: ret <3 x float> %hlsl.f16tof32
// CHECK: declare <3 x float> @llvm.dx.legacyf16tof32.v3i32(<3 x i32>)
float3 test_uint3(uint3 p0) { return __builtin_hlsl_elementwise_f16tof32(p0); }

// CHECK: define hidden noundef nofpclass(nan inf) <4 x float> @_Z10test_uint4Dv4_j(<4 x i32> noundef %p0) #0 {
// CHECK: %hlsl.f16tof32 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.dx.legacyf16tof32.v4i32(<4 x i32> %0)
// CHECK: ret <4 x float> %hlsl.f16tof32
// CHECK: declare <4 x float> @llvm.dx.legacyf16tof32.v4i32(<4 x i32>)
float4 test_uint4(uint4 p0) { return __builtin_hlsl_elementwise_f16tof32(p0); }



30 changes: 30 additions & 0 deletions clang/test/CodeGenHLSL/builtins/f16tof32.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \
// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
// RUN: -o - | FileCheck %s

// CHECK: define hidden noundef nofpclass(nan inf) float
// CHECK: %hlsl.f16tof32 = call reassoc nnan ninf nsz arcp afn float @llvm.dx.legacyf16tof32.i32(i32 %0)
// CHECK: ret float %hlsl.f16tof32
// CHECK: declare float @llvm.dx.legacyf16tof32.i32(i32)
float test_scalar(uint p0) { return f16tof32(p0); }

// CHECK: define hidden noundef nofpclass(nan inf) <2 x float>
// CHECK: %hlsl.f16tof32 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.dx.legacyf16tof32.v2i32(<2 x i32> %0)
// CHECK: ret <2 x float> %hlsl.f16tof32
// CHECK: declare <2 x float> @llvm.dx.legacyf16tof32.v2i32(<2 x i32>)
float2 test_uint2(uint2 p0) { return f16tof32(p0); }

// CHECK: define hidden noundef nofpclass(nan inf) <3 x float> @_Z10test_uint3Dv3_j(<3 x i32> noundef %p0) #0 {
// CHECK: %hlsl.f16tof32 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.dx.legacyf16tof32.v3i32(<3 x i32> %0)
// CHECK: ret <3 x float> %hlsl.f16tof32
// CHECK: declare <3 x float> @llvm.dx.legacyf16tof32.v3i32(<3 x i32>)
float3 test_uint3(uint3 p0) { return f16tof32(p0); }

// CHECK: define hidden noundef nofpclass(nan inf) <4 x float> @_Z10test_uint4Dv4_j(<4 x i32> noundef %p0) #0 {
// CHECK: %hlsl.f16tof32 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.dx.legacyf16tof32.v4i32(<4 x i32> %0)
// CHECK: ret <4 x float> %hlsl.f16tof32
// CHECK: declare <4 x float> @llvm.dx.legacyf16tof32.v4i32(<4 x i32>)
float4 test_uint4(uint4 p0) { return f16tof32(p0); }



134 changes: 134 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/f16tof32-errors.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify

float builtin_f16tof32_too_few_arg() {
return __builtin_hlsl_elementwise_f16tof32();
// expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
// expected-note@hlsl/hlsl_alias_intrinsics.h:* 4 {{candidate function not viable: requires 1 argument, but 0 were provided}}
}

float builtin_f16tof32_too_many_arg(uint p0) {
return __builtin_hlsl_elementwise_f16tof32(p0, p0);
// expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
// expected-note@hlsl/hlsl_alias_intrinsics.h:* 4 {{candidate function not viable: requires 1 argument, but 2 were provided}}
}

float builtin_f16tof32_bool(bool p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'bool')}}
}

float builtin_f16tof32_bool4(bool4 p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'bool4' (aka 'vector<bool, 4>')}}
}

float builtin_f16tof32_int16_t(int16_t p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'int16_t' (aka 'short'))}}
}

float builtin_f16tof32_int16_t(unsigned short p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{incorrect number of bits in integer (expected 32 bits, have 16)}}
}

float builtin_f16tof32_int(int p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'int')}}
}

float builtin_f16tof32_int64_t(long p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'long')}}
}

float2 builtin_f16tof32_int2_to_float2_promotion(int2 p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'int2' (aka 'vector<int, 2>'))}}
}

float builtin_f16tof32_half(half p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'half')}}
}

float builtin_f16tof32_half4(half4 p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'half4' (aka 'vector<half, 4>'))}}
}

float builtin_f16tof32_float(float p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'float')}}
}

float builtin_f16tof32_double(double p0) {
return __builtin_hlsl_elementwise_f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'double')}}
}

float f16tof32_too_few_arg() {
return f16tof32();
// expected-error@-1 {{no matching function for call to 'f16tof32'}}
}

float f16tof32_too_many_arg(uint p0) {
return f16tof32(p0, p0);
// expected-error@-1 {{no matching function for call to 'f16tof32'}}
}

float f16tof32_bool(bool p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'bool')}}
}

float f16tof32_bool3(bool3 p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'bool3' (aka 'vector<bool, 3>')}}
}


float f16tof32_int16_t(int16_t p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'int16_t' (aka 'short'))}}
}

float f16tof32_int16_t(unsigned short p0) {
return f16tof32(p0);
// expected-error@-1 {{incorrect number of bits in integer (expected 32 bits, have 16)}}
}

float f16tof32_int(int p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'int')}}
}

float f16tof32_int64_t(long p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'long')}}
}

float2 f16tof32_int2_to_float2_promotion(int3 p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'int3' (aka 'vector<int, 3>'))}}
}

float f16tof32_half(half p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'half')}}
}

float f16tof32_half2(half2 p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'half2' (aka 'vector<half, 2>'))}}
}

float f16tof32_float(float p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'float')}}
}

float f16tof32_double(double p0) {
return f16tof32(p0);
// expected-error@-1 {{1st argument must be a scalar or vector of unsigned integer types (was 'double')}}
}
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsDirectX.td
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ def int_dx_isinf : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1
def int_dx_isnan : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>],
[llvm_anyfloat_ty], [IntrNoMem]>;

def int_dx_legacyf16tof32 : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_float_ty>],
[llvm_anyint_ty], [IntrNoMem]>;

def int_dx_lerp : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>,LLVMMatchType<0>],
[IntrNoMem]>;

Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsSPIRV.td
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,8 @@ def int_spv_resource_nonuniformindex
def int_spv_generic_cast_to_ptr_explicit
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [generic_ptr_ty],
[IntrNoMem, NoUndef<RetIndex>]>;

def int_spv_legacyf16tof32 : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_float_ty>],
[llvm_anyint_ty], [IntrNoMem]>;

}
9 changes: 9 additions & 0 deletions llvm/lib/Target/DirectX/DXIL.td
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,15 @@ def WaveActiveOp : DXILOp<119, waveActiveOp> {
let attributes = [Attributes<DXIL1_0, []>];
}

def LegacyF16ToF32 : DXILOp<131, legacyF16ToF32> {
let Doc = "returns the float16 stored in the low-half of the uint converted "
"to a float";
let intrinsics = [IntrinSelect<int_dx_legacyf16tof32>];
let arguments = [Int32Ty];
let result = FloatTy;
let stages = [Stages<DXIL1_0, [all_stages]>];
}

def WaveAllBitCount : DXILOp<135, waveAllOp> {
let Doc = "returns the count of bits set to 1 across the wave";
let intrinsics = [IntrinSelect<int_dx_wave_active_countbits>];
Expand Down
Loading
Loading