https://github.com/Alexander-Johnston updated https://github.com/llvm/llvm-project/pull/228089
>From d499d664750792c840cf510f4b5ed466d17b25b2 Mon Sep 17 00:00:00 2001 From: Alexander Johnston <[email protected]> Date: Thu, 1 Oct 2026 12:59:05 +0100 Subject: [PATCH 1/3] [HLSL] Add hlsl pack intrinsics to clang --- clang/include/clang/Basic/Builtins.td | 24 +++++++++ clang/include/clang/Basic/HLSLIntrinsics.td | 36 +++++++++++++ clang/lib/CodeGen/CGHLSLBuiltins.cpp | 24 +++++++++ clang/lib/CodeGen/CGHLSLRuntime.h | 4 ++ clang/lib/Sema/SemaHLSL.cpp | 52 +++++++++++++++++++ .../CodeGenHLSL/builtins/pack_clamp_s8.hlsl | 16 ++++++ .../CodeGenHLSL/builtins/pack_clamp_u8.hlsl | 16 ++++++ clang/test/CodeGenHLSL/builtins/pack_s8.hlsl | 16 ++++++ clang/test/CodeGenHLSL/builtins/pack_u8.hlsl | 16 ++++++ .../BuiltIns/pack_clamp_s8-errors.hlsl | 31 +++++++++++ .../BuiltIns/pack_clamp_u8-errors.hlsl | 31 +++++++++++ .../SemaHLSL/BuiltIns/pack_s8-errors.hlsl | 31 +++++++++++ .../SemaHLSL/BuiltIns/pack_u8-errors.hlsl | 31 +++++++++++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 6 +++ llvm/include/llvm/IR/IntrinsicsSPIRV.td | 4 ++ 15 files changed, 338 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/pack_clamp_s8.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/pack_clamp_u8.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/pack_s8.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/pack_u8.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/pack_clamp_s8-errors.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/pack_clamp_u8-errors.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/pack_s8-errors.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/pack_u8-errors.hlsl diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 5480aed3d543972..dfdadc87a6ce02f 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5968,6 +5968,30 @@ def HLSLDdyFine : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLPackU8 : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_pack_u8"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void(...)"; +} + +def HLSLPackS8 : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_pack_s8"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void(...)"; +} + +def HLSLPackClampU8 : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_pack_clamp_u8"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void(...)"; +} + +def HLSLPackClampS8 : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_pack_clamp_s8"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void(...)"; +} + // Builtins for XRay. def XRayCustomEvent : Builtin { let Spellings = ["__xray_customevent"]; diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td index 4be051476395cdc..49e7f83a14472d7 100644 --- a/clang/include/clang/Basic/HLSLIntrinsics.td +++ b/clang/include/clang/Basic/HLSLIntrinsics.td @@ -1927,3 +1927,39 @@ let VaryingLongVector = 1; let IsConvergent = 1; let Availability = SM6_0; } + +def hlsl_pack_u8 : HLSLOneArgBuiltin<"pack_u8", "__builtin_hlsl_pack_u8"> { + let VaryingTypes = [UInt16Ty, UIntTy]; + let VaryingScalar = 0; + let VaryingVecSizes = [4]; + let VaryingMatDims = []; + let ReturnType = UInt8PackedTy; + let Availability = SM6_6; +} + +def hlsl_pack_s8 : HLSLOneArgBuiltin<"pack_s8", "__builtin_hlsl_pack_s8"> { + let VaryingTypes = [Int16Ty, IntTy]; + let VaryingScalar = 0; + let VaryingVecSizes = [4]; + let VaryingMatDims = []; + let ReturnType = Int8PackedTy; + let Availability = SM6_6; +} + +def hlsl_pack_clamp_u8 : HLSLOneArgBuiltin<"pack_clamp_u8", "__builtin_hlsl_pack_clamp_u8"> { + let VaryingTypes = [Int16Ty, IntTy]; + let VaryingScalar = 0; + let VaryingVecSizes = [4]; + let VaryingMatDims = []; + let ReturnType = UInt8PackedTy; + let Availability = SM6_6; +} + +def hlsl_pack_clamp_s8 : HLSLOneArgBuiltin<"pack_clamp_s8", "__builtin_hlsl_pack_clamp_s8"> { + let VaryingTypes = [Int16Ty, IntTy]; + let VaryingScalar = 0; + let VaryingVecSizes = [4]; + let VaryingMatDims = []; + let ReturnType = Int8PackedTy; + let Availability = SM6_6; +} diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index aa26727e8ad17eb..9e75d33f29c3a0a 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -1799,6 +1799,30 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, ArrayRef<Value *>{Op0}, nullptr, "hlsl.ddy.fine"); } + case Builtin::BI__builtin_hlsl_pack_u8: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Intrinsic::ID ID = CGM.getHLSLRuntime().getPackU8Intrinsic(); + return Builder.CreateIntrinsic(/*ReturnType=*/Builder.getInt32Ty(), ID, + {Op0}, nullptr, "hlsl.pack.u8"); + } + case Builtin::BI__builtin_hlsl_pack_s8: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Intrinsic::ID ID = CGM.getHLSLRuntime().getPackS8Intrinsic(); + return Builder.CreateIntrinsic(/*ReturnType=*/Builder.getInt32Ty(), ID, + {Op0}, nullptr, "hlsl.pack.s8"); + } + case Builtin::BI__builtin_hlsl_pack_clamp_u8: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Intrinsic::ID ID = CGM.getHLSLRuntime().getPackClampU8Intrinsic(); + return Builder.CreateIntrinsic(/*ReturnType=*/Builder.getInt32Ty(), ID, + {Op0}, nullptr, "hlsl.pack.clamp.u8"); + } + case Builtin::BI__builtin_hlsl_pack_clamp_s8: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Intrinsic::ID ID = CGM.getHLSLRuntime().getPackClampS8Intrinsic(); + return Builder.CreateIntrinsic(/*ReturnType=*/Builder.getInt32Ty(), ID, + {Op0}, nullptr, "hlsl.pack.clamp.s8"); + } case Builtin::BI__builtin_get_spirv_spec_constant_bool: case Builtin::BI__builtin_get_spirv_spec_constant_short: case Builtin::BI__builtin_get_spirv_spec_constant_ushort: diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 11b3e0220dcfbab..267fce649779780 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -214,6 +214,10 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(DdyCoarse, ddy_coarse) GENERATE_HLSL_INTRINSIC_FUNCTION(DdxFine, ddx_fine) GENERATE_HLSL_INTRINSIC_FUNCTION(DdyFine, ddy_fine) + GENERATE_HLSL_INTRINSIC_FUNCTION(PackS8, pack_s8) + GENERATE_HLSL_INTRINSIC_FUNCTION(PackU8, pack_u8) + GENERATE_HLSL_INTRINSIC_FUNCTION(PackClampS8, pack_clamp_s8) + GENERATE_HLSL_INTRINSIC_FUNCTION(PackClampU8, pack_clamp_u8) //===----------------------------------------------------------------------===// // End of reserved area for HLSL intrinsic getters. diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index d06491b32ea1b2f..db446bee969fc6d 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -4952,6 +4952,58 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { getASTContext().UnsignedIntTy); break; } + case Builtin::BI__builtin_hlsl_pack_u8: { + if (SemaRef.checkArgCount(TheCall, 1)) + return true; + const auto *VecTy = TheCall->getArg(0)->getType()->getAs<VectorType>(); + if (!VecTy || !VecTy->getElementType()->isUnsignedIntegerType() || + (SemaRef.Context.getTypeSize(VecTy->getElementType()) != 16 && + SemaRef.Context.getTypeSize(VecTy->getElementType()) != 32) || + VecTy->getNumElements() != 4) { + SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_builtin_invalid_arg_type) + << 1 << /* vector of */ 4 << /* unsigned integer */ 3 << /* no fp */ 0 + << TheCall->getArg(0)->getType(); + return true; + } + TheCall->setType(getASTContext().UInt8_4PackedTy); + break; + } + case Builtin::BI__builtin_hlsl_pack_clamp_u8: { + if (SemaRef.checkArgCount(TheCall, 1)) + return true; + const auto *VecTy = TheCall->getArg(0)->getType()->getAs<VectorType>(); + if (!VecTy || !VecTy->getElementType()->isSignedIntegerType() || + (SemaRef.Context.getTypeSize(VecTy->getElementType()) != 16 && + SemaRef.Context.getTypeSize(VecTy->getElementType()) != 32) || + VecTy->getNumElements() != 4) { + SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_builtin_invalid_arg_type) + << 1 << /* vector of */ 4 << /* signed integer */ 2 << /* no fp */ 0 + << TheCall->getArg(0)->getType(); + return true; + } + TheCall->setType(getASTContext().UInt8_4PackedTy); + break; + } + case Builtin::BI__builtin_hlsl_pack_s8: + case Builtin::BI__builtin_hlsl_pack_clamp_s8: { + if (SemaRef.checkArgCount(TheCall, 1)) + return true; + const auto *VecTy = TheCall->getArg(0)->getType()->getAs<VectorType>(); + if (!VecTy || !VecTy->getElementType()->isSignedIntegerType() || + (SemaRef.Context.getTypeSize(VecTy->getElementType()) != 16 && + SemaRef.Context.getTypeSize(VecTy->getElementType()) != 32) || + VecTy->getNumElements() != 4) { + SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_builtin_invalid_arg_type) + << 1 << /* vector of */ 4 << /* signed integer */ 2 << /* no fp */ 0 + << TheCall->getArg(0)->getType(); + return true; + } + TheCall->setType(getASTContext().Int8_4PackedTy); + break; + } } return false; } diff --git a/clang/test/CodeGenHLSL/builtins/pack_clamp_s8.hlsl b/clang/test/CodeGenHLSL/builtins/pack_clamp_s8.hlsl new file mode 100644 index 000000000000000..80db19d467f1096 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/pack_clamp_s8.hlsl @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.6-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-int16-type -fnative-half-type -o - | \ +// RUN: FileCheck %s -DCALL=dx +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-int16-type -fnative-half-type -o - | \ +// RUN: FileCheck %s -DCALL=spv + +// CHECK-LABEL: define {{.*}} i32 @_Z8test_u16Dv4_s +// CHECK: [[VAR:%.*]] = call i32 @llvm.[[CALL]].pack.clamp.s8.v4i16(<4 x i16> %{{.*}}) +// CHECK-NEXT: ret i32 [[VAR]] +int8_t4_packed test_u16(int16_t4 val) { return pack_clamp_s8(val); } + +// CHECK-LABEL: define {{.*}} i32 @_Z8test_u32Dv4_i +// CHECK: [[VAR:%.*]] = call i32 @llvm.[[CALL]].pack.clamp.s8.v4i32(<4 x i32> %{{.*}}) +// CHECK-NEXT: ret i32 [[VAR]] +int8_t4_packed test_u32(int4 val) { return pack_clamp_s8(val); } diff --git a/clang/test/CodeGenHLSL/builtins/pack_clamp_u8.hlsl b/clang/test/CodeGenHLSL/builtins/pack_clamp_u8.hlsl new file mode 100644 index 000000000000000..99beb20843ea8e2 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/pack_clamp_u8.hlsl @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.6-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-int16-type -fnative-half-type -o - | \ +// RUN: FileCheck %s -DCALL=dx +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-int16-type -fnative-half-type -o - | \ +// RUN: FileCheck %s -DCALL=spv + +// CHECK-LABEL: define {{.*}} i32 @_Z8test_u16Dv4_s +// CHECK: [[VAR:%.*]] = call i32 @llvm.[[CALL]].pack.clamp.u8.v4i16(<4 x i16> %{{.*}}) +// CHECK-NEXT: ret i32 [[VAR]] +uint8_t4_packed test_u16(int16_t4 val) { return pack_clamp_u8(val); } + +// CHECK-LABEL: define {{.*}} i32 @_Z8test_u32Dv4_i +// CHECK: [[VAR:%.*]] = call i32 @llvm.[[CALL]].pack.clamp.u8.v4i32(<4 x i32> %{{.*}}) +// CHECK-NEXT: ret i32 [[VAR]] +uint8_t4_packed test_u32(int4 val) { return pack_clamp_u8(val); } diff --git a/clang/test/CodeGenHLSL/builtins/pack_s8.hlsl b/clang/test/CodeGenHLSL/builtins/pack_s8.hlsl new file mode 100644 index 000000000000000..4b90a2890a54ba5 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/pack_s8.hlsl @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.6-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-int16-type -fnative-half-type -o - | \ +// RUN: FileCheck %s -DCALL=dx +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-int16-type -fnative-half-type -o - | \ +// RUN: FileCheck %s -DCALL=spv + +// CHECK-LABEL: define {{.*}} i32 @_Z8test_s16Dv4_s +// CHECK: [[VAR:%.*]] = call i32 @llvm.[[CALL]].pack.s8.v4i16(<4 x i16> %{{.*}}) +// CHECK-NEXT: ret i32 [[VAR]] +int8_t4_packed test_s16(int16_t4 val) { return pack_s8(val); } + +// CHECK-LABEL: define {{.*}} i32 @_Z8test_s32Dv4_i +// CHECK: [[VAR:%.*]] = call i32 @llvm.[[CALL]].pack.s8.v4i32(<4 x i32> %{{.*}}) +// CHECK-NEXT: ret i32 [[VAR]] +int8_t4_packed test_s32(int4 val) { return pack_s8(val); } diff --git a/clang/test/CodeGenHLSL/builtins/pack_u8.hlsl b/clang/test/CodeGenHLSL/builtins/pack_u8.hlsl new file mode 100644 index 000000000000000..b4ea9e78b12b424 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/pack_u8.hlsl @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.6-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-int16-type -fnative-half-type -o - | \ +// RUN: FileCheck %s -DCALL=dx +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-int16-type -fnative-half-type -o - | \ +// RUN: FileCheck %s -DCALL=spv + +// CHECK-LABEL: define {{.*}} i32 @_Z8test_u16Dv4_t +// CHECK: [[VAR:%.*]] = call i32 @llvm.[[CALL]].pack.u8.v4i16(<4 x i16> %{{.*}}) +// CHECK-NEXT: ret i32 [[VAR]] +uint8_t4_packed test_u16(uint16_t4 val) { return pack_u8(val); } + +// CHECK-LABEL: define {{.*}} i32 @_Z8test_u32Dv4_j +// CHECK: [[VAR:%.*]] = call i32 @llvm.[[CALL]].pack.u8.v4i32(<4 x i32> %{{.*}}) +// CHECK-NEXT: ret i32 [[VAR]] +uint8_t4_packed test_u32(uint4 val) { return pack_u8(val); } diff --git a/clang/test/SemaHLSL/BuiltIns/pack_clamp_s8-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/pack_clamp_s8-errors.hlsl new file mode 100644 index 000000000000000..e9a0ce049b66377 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/pack_clamp_s8-errors.hlsl @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -fnative-int16-type -emit-llvm-only -disable-llvm-passes -verify + +void test_builtin_no_args() { + __builtin_hlsl_pack_clamp_s8(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +int8_t4_packed test_builtin_extra_args(int32_t4 p0) { + return __builtin_hlsl_pack_clamp_s8(p0, p0); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} +} + +int8_t4_packed test_builtin_64bit_arg(int64_t4 p0) { + return __builtin_hlsl_pack_clamp_s8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'int64_t4' (aka 'vector<int64_t, 4>'))}} +} + +int8_t4_packed test_builtin_float_vec_arg(float32_t4 p0) { + return __builtin_hlsl_pack_clamp_s8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'float32_t4' (aka 'vector<float32_t, 4>'))}} +} + +int8_t4_packed test_builtin_wrong_vec_elems(int32_t3 p0) { + return __builtin_hlsl_pack_clamp_s8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'int32_t3' (aka 'vector<int32_t, 3>'))}} +} + +int8_t4_packed test_builtin_scalar_arg(int p0) { + return __builtin_hlsl_pack_clamp_s8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'int')}} +} diff --git a/clang/test/SemaHLSL/BuiltIns/pack_clamp_u8-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/pack_clamp_u8-errors.hlsl new file mode 100644 index 000000000000000..d4675c0a5968eb6 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/pack_clamp_u8-errors.hlsl @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -fnative-int16-type -emit-llvm-only -disable-llvm-passes -verify + +void test_builtin_no_args() { + __builtin_hlsl_pack_clamp_u8(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +uint8_t4_packed test_builtin_extra_args(int32_t4 p0) { + return __builtin_hlsl_pack_clamp_u8(p0, p0); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} +} + +uint8_t4_packed test_builtin_64bit_arg(int64_t4 p0) { + return __builtin_hlsl_pack_clamp_u8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'int64_t4' (aka 'vector<int64_t, 4>'))}} +} + +uint8_t4_packed test_builtin_float_vec_arg(float32_t4 p0) { + return __builtin_hlsl_pack_clamp_u8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'float32_t4' (aka 'vector<float32_t, 4>'))}} +} + +uint8_t4_packed test_builtin_wrong_vec_elems(int32_t3 p0) { + return __builtin_hlsl_pack_clamp_u8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'int32_t3' (aka 'vector<int32_t, 3>'))}} +} + +uint8_t4_packed test_builtin_scalar_arg(int p0) { + return __builtin_hlsl_pack_clamp_u8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'int')}} +} diff --git a/clang/test/SemaHLSL/BuiltIns/pack_s8-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/pack_s8-errors.hlsl new file mode 100644 index 000000000000000..0f0a5a082ad7ee1 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/pack_s8-errors.hlsl @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -fnative-int16-type -emit-llvm-only -disable-llvm-passes -verify + +void test_builtin_no_args() { + __builtin_hlsl_pack_s8(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +int8_t4_packed test_builtin_extra_args(int32_t4 p0) { + return __builtin_hlsl_pack_s8(p0, p0); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} +} + +int8_t4_packed test_builtin_64bit_arg(int64_t4 p0) { + return __builtin_hlsl_pack_s8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'int64_t4' (aka 'vector<int64_t, 4>'))}} +} + +int8_t4_packed test_builtin_float_vec_arg(float32_t4 p0) { + return __builtin_hlsl_pack_s8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'float32_t4' (aka 'vector<float32_t, 4>'))}} +} + +int8_t4_packed test_builtin_wrong_vec_elems(int32_t3 p0) { + return __builtin_hlsl_pack_s8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'int32_t3' (aka 'vector<int32_t, 3>'))}} +} + +int8_t4_packed test_builtin_scalar_arg(int p0) { + return __builtin_hlsl_pack_s8(p0); + // expected-error@-1 {{1st argument must be a vector of signed integer types (was 'int')}} +} diff --git a/clang/test/SemaHLSL/BuiltIns/pack_u8-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/pack_u8-errors.hlsl new file mode 100644 index 000000000000000..faf493103dae535 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/pack_u8-errors.hlsl @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -fnative-int16-type -emit-llvm-only -disable-llvm-passes -verify + +void test_builtin_no_args() { + __builtin_hlsl_pack_u8(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +uint8_t4_packed test_builtin_extra_args(uint32_t4 p0) { + return __builtin_hlsl_pack_u8(p0, p0); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} +} + +uint8_t4_packed test_builtin_64bit_arg(uint64_t4 p0) { + return __builtin_hlsl_pack_u8(p0); + // expected-error@-1 {{1st argument must be a vector of unsigned integer types (was 'uint64_t4' (aka 'vector<uint64_t, 4>'))}} +} + +uint8_t4_packed test_builtin_float_vec_arg(float32_t4 p0) { + return __builtin_hlsl_pack_u8(p0); + // expected-error@-1 {{1st argument must be a vector of unsigned integer types (was 'float32_t4' (aka 'vector<float32_t, 4>'))}} +} + +uint8_t4_packed test_builtin_wrong_vec_elems(uint32_t3 p0) { + return __builtin_hlsl_pack_u8(p0); + // expected-error@-1 {{1st argument must be a vector of unsigned integer types (was 'uint32_t3' (aka 'vector<uint32_t, 3>'))}} +} + +uint8_t4_packed test_builtin_scalar_arg(uint p0) { + return __builtin_hlsl_pack_u8(p0); + // expected-error@-1 {{1st argument must be a vector of unsigned integer types (was 'uint' (aka 'unsigned int'))}} +} diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index e087216b822da32..68faf4c2e04734d 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -359,4 +359,10 @@ def int_dx_store_output [llvm_i32_ty /*SigElementId*/, llvm_i32_ty /*RowIndex*/, llvm_i8_ty /*ColIndex*/, llvm_any_ty /*Value*/], [IntrConvergent]>; + +def int_dx_pack_u8 : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_vector_int_ty], [IntrNoMem]>; +def int_dx_pack_s8 : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_vector_int_ty], [IntrNoMem]>; +def int_dx_pack_clamp_u8 : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_vector_int_ty], [IntrNoMem]>; +def int_dx_pack_clamp_s8 : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_vector_int_ty], [IntrNoMem]>; + } diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index 25b5a3c38546546..0f4685ca2582ecc 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -375,5 +375,9 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty] def int_spv_unpackhalf2x16 : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [llvm_i32_ty], [IntrNoMem]>; def int_spv_packhalf2x16 : DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty], [IntrNoMem]>; + def int_spv_pack_u8 : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_vector_int_ty], [IntrNoMem]>; + def int_spv_pack_s8 : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_vector_int_ty], [IntrNoMem]>; + def int_spv_pack_clamp_u8 : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_vector_int_ty], [IntrNoMem]>; + def int_spv_pack_clamp_s8 : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_vector_int_ty], [IntrNoMem]>; } >From 8454a247cd45bc96c76dcbfb0673d6d1f7d89275 Mon Sep 17 00:00:00 2001 From: Alexander Johnston <[email protected]> Date: Thu, 1 Oct 2026 12:59:50 +0100 Subject: [PATCH 2/3] [DirectX] Add hlsl pack intrinsics to DirectX backend --- llvm/lib/Target/DirectX/DXIL.td | 9 ++++++ llvm/lib/Target/DirectX/DXILOpLowering.cpp | 34 ++++++++++++++++++++++ llvm/test/CodeGen/DirectX/pack_clamp_s8.ll | 26 +++++++++++++++++ llvm/test/CodeGen/DirectX/pack_clamp_u8.ll | 26 +++++++++++++++++ llvm/test/CodeGen/DirectX/pack_s8.ll | 26 +++++++++++++++++ llvm/test/CodeGen/DirectX/pack_u8.ll | 26 +++++++++++++++++ 6 files changed, 147 insertions(+) create mode 100644 llvm/test/CodeGen/DirectX/pack_clamp_s8.ll create mode 100644 llvm/test/CodeGen/DirectX/pack_clamp_u8.ll create mode 100644 llvm/test/CodeGen/DirectX/pack_s8.ll create mode 100644 llvm/test/CodeGen/DirectX/pack_u8.ll diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td index 5e63e94a1c069ad..be5a7dca7f44f9e 100644 --- a/llvm/lib/Target/DirectX/DXIL.td +++ b/llvm/lib/Target/DirectX/DXIL.td @@ -1560,3 +1560,12 @@ def CreateHandleFromHeap : DXILOp<218, createHandleFromHeap> { let stages = [Stages<DXIL1_6, [all_stages]>]; let attributes = [Attributes<DXIL1_0, [ReadNone]>]; } + +def Pack4x8 : DXILOp<220, pack4x8> { + let Doc = "pack 4 integer values into a single 32 bit value"; + let arguments = [Int8Ty, OverloadTy, OverloadTy, OverloadTy, OverloadTy]; + let overloads = [Overloads<DXIL1_6, [Int16Ty, Int32Ty]>]; + let result = Int32Ty; + let stages = [Stages<DXIL1_6, [all_stages]>]; + let attributes = [Attributes<DXIL1_6, [ReadNone]>]; +} diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index 2807e58942fbd05..0c146d5de56c331 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -1359,6 +1359,30 @@ class OpLowerer { }); } + [[nodiscard]] bool lowerPack(Function &F, uint32_t PackOpCode) { + IRBuilder<> &IRB = OpBuilder.getIRB(); + Type *RetTy = IRB.getInt32Ty(); + return replaceFunction(F, [&](CallInst *CI) -> Error { + IRB.SetInsertPoint(CI); + SmallVector<Value *, 5> Args; + Args.push_back(IRB.getInt8(PackOpCode)); + + // Disassemble the vector to fill args 1-5 of the pack op. + Value *VecArg = CI->getArgOperand(0); + for (int i = 1; i < 5; i++) + Args.push_back(IRB.CreateExtractElement(VecArg, i - 1)); + + Expected<CallInst *> OpCall = + OpBuilder.tryCreateOp(OpCode::Pack4x8, Args, CI->getName(), RetTy); + if (Error E = OpCall.takeError()) + return E; + + CI->replaceAllUsesWith(*OpCall); + CI->eraseFromParent(); + return Error::success(); + }); + } + bool lowerIntrinsics() { bool Updated = false; bool HasErrors = false; @@ -1482,6 +1506,16 @@ class OpLowerer { case Intrinsic::is_fpclass: HasErrors |= lowerIsFPClass(F); break; + case Intrinsic::dx_pack_u8: + case Intrinsic::dx_pack_s8: + HasErrors |= lowerPack(F, 0); + break; + case Intrinsic::dx_pack_clamp_u8: + HasErrors |= lowerPack(F, 1); + break; + case Intrinsic::dx_pack_clamp_s8: + HasErrors |= lowerPack(F, 2); + break; } Updated = true; } diff --git a/llvm/test/CodeGen/DirectX/pack_clamp_s8.ll b/llvm/test/CodeGen/DirectX/pack_clamp_s8.ll new file mode 100644 index 000000000000000..7829991991b0a65 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/pack_clamp_s8.ll @@ -0,0 +1,26 @@ +; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.6-library %s | FileCheck %s + +define noundef i32 @pack_clamp_s8_16(<4 x i16> noundef %a) { +; CHECK: [[one:%.*]] = extractelement <4 x i16> %a, i64 0 +; CHECK: [[two:%.*]] = extractelement <4 x i16> %a, i64 1 +; CHECK: [[three:%.*]] = extractelement <4 x i16> %a, i64 2 +; CHECK: [[four:%.*]] = extractelement <4 x i16> %a, i64 3 +; CHECK: [[packed:%.*]] = call i32 @dx.op.pack4x8.i16(i32 220, i8 2, i16 [[one]], i16 [[two]], i16 [[three]], i16 [[four]]) +; CHECK: ret i32 [[packed]] + %packed = call i32 @llvm.dx.pack.clamp.s8.v4i16(<4 x i16> %a) + ret i32 %packed +} + +define noundef i32 @pack_clamp_s8_32(<4 x i32> noundef %a) { +; CHECK: [[one:%.*]] = extractelement <4 x i32> %a, i64 0 +; CHECK: [[two:%.*]] = extractelement <4 x i32> %a, i64 1 +; CHECK: [[three:%.*]] = extractelement <4 x i32> %a, i64 2 +; CHECK: [[four:%.*]] = extractelement <4 x i32> %a, i64 3 +; CHECK: [[packed:%.*]] = call i32 @dx.op.pack4x8.i32(i32 220, i8 2, i32 [[one]], i32 [[two]], i32 [[three]], i32 [[four]]) +; CHECK: ret i32 [[packed]] + %packed = call i32 @llvm.dx.pack.clamp.s8.v4i32(<4 x i32> %a) + ret i32 %packed +} + +declare i32 @llvm.dx.pack.clamp.s8.v4i16(<4 x i16>) +declare i32 @llvm.dx.pack.clamp.s8.v4i32(<4 x i32>) diff --git a/llvm/test/CodeGen/DirectX/pack_clamp_u8.ll b/llvm/test/CodeGen/DirectX/pack_clamp_u8.ll new file mode 100644 index 000000000000000..b85530b06429dc7 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/pack_clamp_u8.ll @@ -0,0 +1,26 @@ +; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.6-library %s | FileCheck %s + +define noundef i32 @pack_clamp_u8_16(<4 x i16> noundef %a) { +; CHECK: [[one:%.*]] = extractelement <4 x i16> %a, i64 0 +; CHECK: [[two:%.*]] = extractelement <4 x i16> %a, i64 1 +; CHECK: [[three:%.*]] = extractelement <4 x i16> %a, i64 2 +; CHECK: [[four:%.*]] = extractelement <4 x i16> %a, i64 3 +; CHECK: [[packed:%.*]] = call i32 @dx.op.pack4x8.i16(i32 220, i8 1, i16 [[one]], i16 [[two]], i16 [[three]], i16 [[four]]) +; CHECK: ret i32 [[packed]] + %packed = call i32 @llvm.dx.pack.clamp.u8.v4i16(<4 x i16> %a) + ret i32 %packed +} + +define noundef i32 @pack_clamp_u8_32(<4 x i32> noundef %a) { +; CHECK: [[one:%.*]] = extractelement <4 x i32> %a, i64 0 +; CHECK: [[two:%.*]] = extractelement <4 x i32> %a, i64 1 +; CHECK: [[three:%.*]] = extractelement <4 x i32> %a, i64 2 +; CHECK: [[four:%.*]] = extractelement <4 x i32> %a, i64 3 +; CHECK: [[packed:%.*]] = call i32 @dx.op.pack4x8.i32(i32 220, i8 1, i32 [[one]], i32 [[two]], i32 [[three]], i32 [[four]]) +; CHECK: ret i32 [[packed]] + %packed = call i32 @llvm.dx.pack.clamp.u8.v4i32(<4 x i32> %a) + ret i32 %packed +} + +declare i32 @llvm.dx.pack.clamp.u8.v4i16(<4 x i16>) +declare i32 @llvm.dx.pack.clamp.u8.v4i32(<4 x i32>) diff --git a/llvm/test/CodeGen/DirectX/pack_s8.ll b/llvm/test/CodeGen/DirectX/pack_s8.ll new file mode 100644 index 000000000000000..c54798270d1f628 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/pack_s8.ll @@ -0,0 +1,26 @@ +; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.6-library %s | FileCheck %s + +define noundef i32 @pack_s8_16(<4 x i16> noundef %a) { +; CHECK: [[one:%.*]] = extractelement <4 x i16> %a, i64 0 +; CHECK: [[two:%.*]] = extractelement <4 x i16> %a, i64 1 +; CHECK: [[three:%.*]] = extractelement <4 x i16> %a, i64 2 +; CHECK: [[four:%.*]] = extractelement <4 x i16> %a, i64 3 +; CHECK: [[packed:%.*]] = call i32 @dx.op.pack4x8.i16(i32 220, i8 0, i16 [[one]], i16 [[two]], i16 [[three]], i16 [[four]]) +; CHECK: ret i32 [[packed]] + %packed = call i32 @llvm.dx.pack.s8.v4i16(<4 x i16> %a) + ret i32 %packed +} + +define noundef i32 @pack_s8_32(<4 x i32> noundef %a) { +; CHECK: [[one:%.*]] = extractelement <4 x i32> %a, i64 0 +; CHECK: [[two:%.*]] = extractelement <4 x i32> %a, i64 1 +; CHECK: [[three:%.*]] = extractelement <4 x i32> %a, i64 2 +; CHECK: [[four:%.*]] = extractelement <4 x i32> %a, i64 3 +; CHECK: [[packed:%.*]] = call i32 @dx.op.pack4x8.i32(i32 220, i8 0, i32 [[one]], i32 [[two]], i32 [[three]], i32 [[four]]) +; CHECK: ret i32 [[packed]] + %packed = call i32 @llvm.dx.pack.s8.v4i32(<4 x i32> %a) + ret i32 %packed +} + +declare i32 @llvm.dx.pack.s8.v4i16(<4 x i16>) +declare i32 @llvm.dx.pack.s8.v4i32(<4 x i32>) diff --git a/llvm/test/CodeGen/DirectX/pack_u8.ll b/llvm/test/CodeGen/DirectX/pack_u8.ll new file mode 100644 index 000000000000000..bd52047d5748898 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/pack_u8.ll @@ -0,0 +1,26 @@ +; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.6-library %s | FileCheck %s + +define noundef i32 @pack_u8_16(<4 x i16> noundef %a) { +; CHECK: [[one:%.*]] = extractelement <4 x i16> %a, i64 0 +; CHECK: [[two:%.*]] = extractelement <4 x i16> %a, i64 1 +; CHECK: [[three:%.*]] = extractelement <4 x i16> %a, i64 2 +; CHECK: [[four:%.*]] = extractelement <4 x i16> %a, i64 3 +; CHECK: [[packed:%.*]] = call i32 @dx.op.pack4x8.i16(i32 220, i8 0, i16 [[one]], i16 [[two]], i16 [[three]], i16 [[four]]) +; CHECK: ret i32 [[packed]] + %packed = call i32 @llvm.dx.pack.u8.v4i16(<4 x i16> %a) + ret i32 %packed +} + +define noundef i32 @pack_u8_32(<4 x i32> noundef %a) { +; CHECK: [[one:%.*]] = extractelement <4 x i32> %a, i64 0 +; CHECK: [[two:%.*]] = extractelement <4 x i32> %a, i64 1 +; CHECK: [[three:%.*]] = extractelement <4 x i32> %a, i64 2 +; CHECK: [[four:%.*]] = extractelement <4 x i32> %a, i64 3 +; CHECK: [[packed:%.*]] = call i32 @dx.op.pack4x8.i32(i32 220, i8 0, i32 [[one]], i32 [[two]], i32 [[three]], i32 [[four]]) +; CHECK: ret i32 [[packed]] + %packed = call i32 @llvm.dx.pack.u8.v4i32(<4 x i32> %a) + ret i32 %packed +} + +declare i32 @llvm.dx.pack.u8.v4i16(<4 x i16>) +declare i32 @llvm.dx.pack.u8.v4i32(<4 x i32>) >From d347fc7eab301dc09029537407d52fb29aca9652 Mon Sep 17 00:00:00 2001 From: Alexander Johnston <[email protected]> Date: Thu, 1 Oct 2026 13:00:15 +0100 Subject: [PATCH 3/3] [SPIRV] Add hlsl pack intrinsics to SPIRV backend --- .../Target/SPIRV/SPIRVInstructionSelector.cpp | 53 +++++++++++++++++++ .../SPIRV/hlsl-intrinsics/pack_clamp_s8.ll | 44 +++++++++++++++ .../SPIRV/hlsl-intrinsics/pack_clamp_u8.ll | 42 +++++++++++++++ .../CodeGen/SPIRV/hlsl-intrinsics/pack_s8.ll | 28 ++++++++++ .../CodeGen/SPIRV/hlsl-intrinsics/pack_u8.ll | 28 ++++++++++ 5 files changed, 195 insertions(+) create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_clamp_s8.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_clamp_u8.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_s8.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_u8.ll diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 143e1c0e3ef2abb..84eb442bdaeddd9 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -485,6 +485,8 @@ class SPIRVInstructionSelector : public InstructionSelector { MachineInstr &I) const; bool selectDerivativeInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, const unsigned DPdOpCode) const; + bool selectPackInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, + const bool Signed, const bool Clamp) const; // Utilities Register buildI32Constant(uint32_t Val, MachineInstr &I, SPIRVTypeInst ResType = nullptr) const; @@ -5262,6 +5264,49 @@ bool SPIRVInstructionSelector::selectDerivativeInst( return true; } +bool SPIRVInstructionSelector::selectPackInst(Register ResVReg, + SPIRVTypeInst ResType, + MachineInstr &I, + const bool Signed, + const bool Clamp) const { + MachineIRBuilder MIRBuilder(I); + Register SrcReg = I.getOperand(2).getReg(); + SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(SrcReg); + + // pack_clamp_ instructions require SClamp before performing SConvert + // limits are determined by if the pack_clamp is signed or not + if (Clamp) { + const unsigned ElemWidth = GR.getScalarOrVectorBitWidth(SrcType); + APInt Lower = + Signed ? APInt(ElemWidth, -128, true) : APInt::getZero(ElemWidth); + APInt Upper = + Signed ? APInt(ElemWidth, 127, true) : APInt(ElemWidth, 255, true); + bool ZeroAsNull = !STI.isShader(); + Register LowerLimit = + GR.getOrCreateConstVector(Lower, I, SrcType, TII, ZeroAsNull); + Register UpperLimit = + GR.getOrCreateConstVector(Upper, I, SrcType, TII, ZeroAsNull); + + Register ClampedReg = MRI->createVirtualRegister(GR.getRegClass(SrcType)); + if (!selectExtInst(ClampedReg, SrcType, I, CL::s_clamp, GL::SClamp, + /*setMIFlags=*/true, /*useMISrc=*/false, + {SrcReg, LowerLimit, UpperLimit})) + return false; + SrcReg = ClampedReg; + } + + // Narrow to an i8 vector, then bitcast. Convert sign doesn't matter here + SPIRVTypeInst I8Type = GR.getOrCreateSPIRVIntegerType(8, MIRBuilder); + SPIRVTypeInst I8x4Type = + GR.getOrCreateSPIRVVectorType(I8Type, 4, MIRBuilder, true); + Register I8x4Reg = MRI->createVirtualRegister(GR.getRegClass(I8x4Type)); + auto ConvertOpcode = Signed ? SPIRV::OpSConvert : SPIRV::OpUConvert; + if (!selectOpWithSrcs(I8x4Reg, I8x4Type, I, {SrcReg}, ConvertOpcode)) + return false; + + return selectOpWithSrcs(ResVReg, ResType, I, {I8x4Reg}, SPIRV::OpBitcast); +} + bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const { @@ -5853,6 +5898,14 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, MIB.constrainAllUses(TII, TRI, RBI); return true; } + case Intrinsic::spv_pack_u8: + return selectPackInst(ResVReg, ResType, I, false, false); + case Intrinsic::spv_pack_s8: + return selectPackInst(ResVReg, ResType, I, true, false); + case Intrinsic::spv_pack_clamp_u8: + return selectPackInst(ResVReg, ResType, I, false, true); + case Intrinsic::spv_pack_clamp_s8: + return selectPackInst(ResVReg, ResType, I, true, true); default: return diagnoseUnsupported(I, "intrinsic selection not implemented."); } diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_clamp_s8.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_clamp_s8.ll new file mode 100644 index 000000000000000..f6784e076265c89 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_clamp_s8.ll @@ -0,0 +1,44 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %} + +; CHECK: [[import:%.*]] = OpExtInstImport "GLSL.std.450" + +; CHECK-DAG: [[int8:%.*]] = OpTypeInt 8 0 +; CHECK-DAG: [[int8x4:%.*]] = OpTypeVector [[int8]] 4 +; CHECK-DAG: [[int16:%.*]] = OpTypeInt 16 0 +; CHECK-DAG: [[int16x4:%.*]] = OpTypeVector [[int16]] 4 +; CHECK-DAG: [[int32:%.*]] = OpTypeInt 32 0 +; CHECK-DAG: [[int32x4:%.*]] = OpTypeVector [[int32]] 4 + +; 65408 is -128 for SClamp +; CHECK-DAG: [[int16_65408:%.*]] = OpConstant [[int16]] 65408 +; CHECK-DAG: [[int16_65408x4:%.*]] = OpConstantComposite [[int16x4]] [[int16_65408]] [[int16_65408]] [[int16_65408]] [[int16_65408]] +; CHECK-DAG: [[int16_127:%.*]] = OpConstant [[int16]] 127 +; CHECK-DAG: [[int16_127x4:%.*]] = OpConstantComposite [[int16x4]] [[int16_127]] [[int16_127]] [[int16_127]] [[int16_127]] + +; 4294967168 is -128 for SClamp +; CHECK-DAG: [[int32_4294967168:%.*]] = OpConstant [[int32]] 4294967168 +; CHECK-DAG: [[int32_4294967168x4:%.*]] = OpConstantComposite [[int32x4]] [[int32_4294967168]] [[int32_4294967168]] [[int32_4294967168]] [[int32_4294967168]] +; CHECK-DAG: [[int32_127:%.*]] = OpConstant [[int32]] 127 +; CHECK-DAG: [[int32_127x4:%.*]] = OpConstantComposite [[int32x4]] [[int32_127]] [[int32_127]] [[int32_127]] [[int32_127]] + +define noundef i32 @pack_clamp_s8_16(<4 x i16> noundef %a) { +; CHECK: [[in:%.*]] = OpFunctionParameter [[int16x4]] +; CHECK: [[clamped:%.*]] = OpExtInst [[int16x4]] [[import]] SClamp [[in]] [[int16_65408x4]] [[int16_127x4]] +; CHECK: [[converted:%.*]] = OpSConvert [[int8x4]] [[clamped]] +; CHECK: [[cast:%.*]] = OpBitcast [[int32]] [[converted]] + %packed = call i32 @llvm.spv.pack.clamp.s8.v4i16(<4 x i16> %a) + ret i32 %packed +} + +define noundef i32 @pack_clamp_s8_32(<4 x i32> noundef %a) { +; CHECK: [[in:%.*]] = OpFunctionParameter [[int32x4]] +; CHECK: [[clamped:%.*]] = OpExtInst [[int32x4]] [[import]] SClamp [[in]] [[int32_4294967168x4]] [[int32_127x4]] +; CHECK: [[converted:%.*]] = OpSConvert [[int8x4]] [[clamped]] +; CHECK: [[cast:%.*]] = OpBitcast [[int32]] [[converted]] + %packed = call i32 @llvm.spv.pack.clamp.s8.v4i32(<4 x i32> %a) + ret i32 %packed +} + +declare i32 @llvm.spv.pack.clamp.s8.v4i16(<4 x i16>) +declare i32 @llvm.spv.pack.clamp.s8.v4i32(<4 x i32>) diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_clamp_u8.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_clamp_u8.ll new file mode 100644 index 000000000000000..c5234e3283fee70 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_clamp_u8.ll @@ -0,0 +1,42 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %} + +; CHECK: [[import:%.*]] = OpExtInstImport "GLSL.std.450" + +; CHECK-DAG: [[int8:%.*]] = OpTypeInt 8 0 +; CHECK-DAG: [[int8x4:%.*]] = OpTypeVector [[int8]] 4 +; CHECK-DAG: [[int16:%.*]] = OpTypeInt 16 0 +; CHECK-DAG: [[int16x4:%.*]] = OpTypeVector [[int16]] 4 +; CHECK-DAG: [[int32:%.*]] = OpTypeInt 32 0 +; CHECK-DAG: [[int32x4:%.*]] = OpTypeVector [[int32]] 4 + +; CHECK-DAG: [[int16_0:%.*]] = OpConstant [[int16]] 0 +; CHECK-DAG: [[int16_0x4:%.*]] = OpConstantComposite [[int16x4]] [[int16_0]] [[int16_0]] [[int16_0]] [[int16_0]] +; CHECK-DAG: [[int16_255:%.*]] = OpConstant [[int16]] 255 +; CHECK-DAG: [[int16_255x4:%.*]] = OpConstantComposite [[int16x4]] [[int16_255]] [[int16_255]] [[int16_255]] [[int16_255]] + +; CHECK-DAG: [[int32_0:%.*]] = OpConstant [[int32]] 0 +; CHECK-DAG: [[int32_0x4:%.*]] = OpConstantComposite [[int32x4]] [[int32_0]] [[int32_0]] [[int32_0]] [[int32_0]] +; CHECK-DAG: [[int32_255:%.*]] = OpConstant [[int32]] 255 +; CHECK-DAG: [[int32_255x4:%.*]] = OpConstantComposite [[int32x4]] [[int32_255]] [[int32_255]] [[int32_255]] [[int32_255]] + +define noundef i32 @pack_clamp_u8_16(<4 x i16> noundef %a) { +; CHECK: [[in:%.*]] = OpFunctionParameter [[int16x4]] +; CHECK: [[clamped:%.*]] = OpExtInst [[int16x4]] [[import]] SClamp [[in]] [[int16_0x4]] [[int16_255x4]] +; CHECK: [[converted:%.*]] = OpUConvert [[int8x4]] [[clamped]] +; CHECK: [[cast:%.*]] = OpBitcast [[int32]] [[converted]] + %packed = call i32 @llvm.spv.pack.clamp.u8.v4i16(<4 x i16> %a) + ret i32 %packed +} + +define noundef i32 @pack_clamp_u8_32(<4 x i32> noundef %a) { +; CHECK: [[in:%.*]] = OpFunctionParameter [[int32x4]] +; CHECK: [[clamped:%.*]] = OpExtInst [[int32x4]] [[import]] SClamp [[in]] [[int32_0x4]] [[int32_255x4]] +; CHECK: [[converted:%.*]] = OpUConvert [[int8x4]] [[clamped]] +; CHECK: [[cast:%.*]] = OpBitcast [[int32]] [[converted]] + %packed = call i32 @llvm.spv.pack.clamp.u8.v4i32(<4 x i32> %a) + ret i32 %packed +} + +declare i32 @llvm.spv.pack.clamp.u8.v4i16(<4 x i16>) +declare i32 @llvm.spv.pack.clamp.u8.v4i32(<4 x i32>) diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_s8.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_s8.ll new file mode 100644 index 000000000000000..191382e66b6e570 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_s8.ll @@ -0,0 +1,28 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: [[int8:%.*]] = OpTypeInt 8 0 +; CHECK-DAG: [[int8x4:%.*]] = OpTypeVector [[int8]] 4 +; CHECK-DAG: [[int16:%.*]] = OpTypeInt 16 0 +; CHECK-DAG: [[int16x4:%.*]] = OpTypeVector [[int16]] 4 +; CHECK-DAG: [[int32:%.*]] = OpTypeInt 32 0 +; CHECK-DAG: [[int32x4:%.*]] = OpTypeVector [[int32]] 4 + +define noundef i32 @pack_s8_16(<4 x i16> noundef %a) { +; CHECK: [[in:%.*]] = OpFunctionParameter [[int16x4]] +; CHECK: [[converted:%.*]] = OpSConvert [[int8x4]] [[in]] +; CHECK: [[cast:%.*]] = OpBitcast [[int32]] [[converted]] + %packed = call i32 @llvm.spv.pack.s8.v4i16(<4 x i16> %a) + ret i32 %packed +} + +define noundef i32 @pack_s8_32(<4 x i32> noundef %a) { +; CHECK: [[in:%.*]] = OpFunctionParameter [[int32x4]] +; CHECK: [[converted:%.*]] = OpSConvert [[int8x4]] [[in]] +; CHECK: [[cast:%.*]] = OpBitcast [[int32]] [[converted]] + %packed = call i32 @llvm.spv.pack.s8.v4i32(<4 x i32> %a) + ret i32 %packed +} + +declare i32 @llvm.spv.pack.s8.v4i16(<4 x i16>) +declare i32 @llvm.spv.pack.s8.v4i32(<4 x i32>) diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_u8.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_u8.ll new file mode 100644 index 000000000000000..e87e57984d967df --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pack_u8.ll @@ -0,0 +1,28 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: [[int8:%.*]] = OpTypeInt 8 0 +; CHECK-DAG: [[int8x4:%.*]] = OpTypeVector [[int8]] 4 +; CHECK-DAG: [[int16:%.*]] = OpTypeInt 16 0 +; CHECK-DAG: [[int16x4:%.*]] = OpTypeVector [[int16]] 4 +; CHECK-DAG: [[int32:%.*]] = OpTypeInt 32 0 +; CHECK-DAG: [[int32x4:%.*]] = OpTypeVector [[int32]] 4 + +define noundef i32 @pack_u8_16(<4 x i16> noundef %a) { +; CHECK: [[in:%.*]] = OpFunctionParameter [[int16x4]] +; CHECK: [[converted:%.*]] = OpUConvert [[int8x4]] [[in]] +; CHECK: [[cast:%.*]] = OpBitcast [[int32]] [[converted]] + %packed = call i32 @llvm.spv.pack.u8.v4i16(<4 x i16> %a) + ret i32 %packed +} + +define noundef i32 @pack_u8_32(<4 x i32> noundef %a) { +; CHECK: [[in:%.*]] = OpFunctionParameter [[int32x4]] +; CHECK: [[converted:%.*]] = OpUConvert [[int8x4]] [[in]] +; CHECK: [[cast:%.*]] = OpBitcast [[int32]] [[converted]] + %packed = call i32 @llvm.spv.pack.u8.v4i32(<4 x i32> %a) + ret i32 %packed +} + +declare i32 @llvm.spv.pack.u8.v4i16(<4 x i16>) +declare i32 @llvm.spv.pack.u8.v4i32(<4 x i32>) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
