[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -19108,6 +19108,21 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +IntegerType *Int1Ty = +llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && + "wave_active_any_true operand must be a bool"); + +llvm::FunctionType *FT = V-FEXrt wrote: I originally had something like this ```hlsl case Builtin::BI__builtin_hlsl_wave_active_any_true: { Value *Op = EmitScalarExpr(E->getArg(0)); return Builder.CreateIntrinsic( Op->getType(), CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic(), Op, nullptr, "hlsl.wave.activeanytrue" ); } ``` but that was failing with a convergence error `Cannot mix controlled and uncontrolled convergence in the same function.`. I also though I tried `Intrinsic::getOrInsertDeclaration` but I can't remember what happened with that. I'll give it another try https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt created https://github.com/llvm/llvm-project/pull/115902 Resolves https://github.com/llvm/llvm-project/issues/99160 - [x] Implement `WaveActiveAnyTrue` clang builtin, - [x] Link `WaveActiveAnyTrue` clang builtin with `hlsl_intrinsics.h` - [x] Add sema checks for `WaveActiveAnyTrue` to `CheckHLSLBuiltinFunctionCall` in `SemaChecking.cpp` - [x] Add codegen for `WaveActiveAnyTrue` to `EmitHLSLBuiltinExpr` in `CGBuiltin.cpp` - [x] Add codegen tests to `clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl` - [x] Add sema tests to `clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl` - [x] Create the `int_dx_WaveActiveAnyTrue` intrinsic in `IntrinsicsDirectX.td` - [x] Create the `DXILOpMapping` of `int_dx_WaveActiveAnyTrue` to `113` in `DXIL.td` - [x] Create the `WaveActiveAnyTrue.ll` and `WaveActiveAnyTrue_errors.ll` tests in `llvm/test/CodeGen/DirectX/` - [x] Create the `int_spv_WaveActiveAnyTrue` intrinsic in `IntrinsicsSPIRV.td` - [x] In SPIRVInstructionSelector.cpp create the `WaveActiveAnyTrue` lowering and map it to `int_spv_WaveActiveAnyTrue` in `SPIRVInstructionSelector::selectIntrinsic`. - [x] Create SPIR-V backend test case in `llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll` >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 1/3] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRu
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 1/3] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which evalua
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -0,0 +1,17 @@ +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32v1.3-vulkan-unknown %s -o - | FileCheck %s V-FEXrt wrote: do you mean `-mtriple=spirv32v1.5-unknown-unknown`? I couldn't get any other variant of the `spirv` part to work https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 1/4] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which evalua
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify + +bool test_too_few_arg() { + return __builtin_hlsl_wave_active_any_true(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +bool test_too_many_arg(bool p0) { + return __builtin_hlsl_wave_active_any_true(p0, p0); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} +} + +struct Foo +{ + int a; +}; + +bool test_type_check_2(Foo p0) { V-FEXrt wrote: Delete the `_2` from the function name https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt edited https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -93,6 +93,7 @@ def int_dx_rsqrt : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>] def int_dx_wave_active_countbits : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i1_ty], [IntrConvergent, IntrNoMem]>; def int_dx_wave_getlaneindex : DefaultAttrsIntrinsic<[llvm_i32_ty], [], [IntrConvergent, IntrNoMem]>; def int_dx_wave_is_first_lane : DefaultAttrsIntrinsic<[llvm_i1_ty], [], [IntrConvergent]>; +def int_dx_wave_activeanytrue : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_i1_ty], [IntrConvergent]>; V-FEXrt wrote: I don't feel strongly either way, and I'm happy to rename but doesn't `wave.anyactivetrue` match the proposal as much as `wave.any` does while being more explicit? https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 1/5] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which evalua
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 1/6] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which evalua
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -17,12 +17,10 @@ double test_int_builtin(double p0) { double2 test_int_builtin_2(double2 p0) { return __builtin_hlsl_elementwise_firstbithigh(p0); - // expected-error@-1 {{1st argument must be a vector of integers - // (was 'double2' (aka 'vector'))}} + // expected-error@-1 {{1st argument must be a vector of integers (was 'double2' (aka 'vector'))}} } float test_int_builtin_3(float p0) { return __builtin_hlsl_elementwise_firstbithigh(p0); - // expected-error@-1 {{1st argument must be a vector of integers - // (was 'float')}} + // expected-error@-1 {{1st argument must be a vector of integers (was 'double')}} V-FEXrt wrote: The test framework doesn't actually assert these lines when split. I had to unsplit them which raised a test failure that was then fixed https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -1949,24 +1949,36 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg, return Result; } +bool SPIRVInstructionSelector::selectWaveOpInst(Register ResVReg, +const SPIRVType *ResType, +MachineInstr &I, +unsigned Opcode) const { + MachineBasicBlock &BB = *I.getParent(); + SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); + + auto BMI = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) + .addDef(ResVReg) + .addUse(GR.getSPIRVTypeID(ResType)) + .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, +IntTy, TII)); + + for (unsigned j = 2; j < I.getNumOperands(); j++) { V-FEXrt wrote: I'm a die hard vim user >.< But I do already have clangd setup and I think I can set that up to do the same https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt edited https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -0,0 +1,17 @@ +; RUN: llc -verify-machineinstrs -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 %} + +; CHECK-DAG: %[[#bool:]] = OpTypeBool +; CHECK-DAG: %[[#uint:]] = OpTypeInt 32 0 +; CHECK-DAG: %[[#scope:]] = OpConstant %[[#uint]] 3 + +; CHECK-LABEL: Begin function test_wave_any +define i1 @test_wave_any(i1 %p1) { +entry: +; CHECK: %[[#param:]] = OpFunctionParameter %[[#bool]] +; CHECK: %{{.+}} = OpGroupNonUniformAny %[[#bool]] %[[#scope]] %[[#param]] + %ret = call i1 @llvm.spv.wave.any(i1 %p1) V-FEXrt wrote: This [similar commit](https://github.com/llvm/llvm-project/pull/111010/commits/484b2089ae9f0a0fae09b6d68b70171f1007bade#diff-bac84b1c33bc0aee1edd39550243c6e3c5606b6b8538b2f424a55ce3c9977244) (from which I was basing my changes) seems to have intentionally removed the convergence intrinsics generated by the frontend. Should we mirror that or should convergence be added back in to that test? cc @inbelic https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -2848,7 +2819,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, case Intrinsic::spv_wave_active_countbits: return selectWaveActiveCountBits(ResVReg, ResType, I); case Intrinsic::spv_wave_any: -return selectWaveActiveAnyTrue(ResVReg, ResType, I); +return selectWaveNOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAny); case Intrinsic::spv_wave_is_first_lane: { SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); V-FEXrt wrote: Maybe, I'm reading the diff wrong, but I think I already did that? https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -2848,7 +2819,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, case Intrinsic::spv_wave_active_countbits: return selectWaveActiveCountBits(ResVReg, ResType, I); case Intrinsic::spv_wave_any: -return selectWaveActiveAnyTrue(ResVReg, ResType, I); +return selectWaveNOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAny); case Intrinsic::spv_wave_is_first_lane: { SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); V-FEXrt wrote: ohhh I see. Certainly reading the diff wrong! Will fix it up :) https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -1949,6 +1952,23 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg, return Result; } +bool SPIRVInstructionSelector::selectWaveActiveAnyTrue(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I) const { + assert(I.getNumOperands() == 3); + assert(I.getOperand(2).isReg()); + + MachineBasicBlock &BB = *I.getParent(); + SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); + + return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpGroupNonUniformAny)) V-FEXrt wrote: Okay, done! Please take a look! https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -1949,6 +1952,23 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg, return Result; } +bool SPIRVInstructionSelector::selectWaveActiveAnyTrue(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I) const { + assert(I.getNumOperands() == 3); + assert(I.getOperand(2).isReg()); + + MachineBasicBlock &BB = *I.getParent(); + SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); + + return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpGroupNonUniformAny)) V-FEXrt wrote: https://github.com/llvm/llvm-project/pull/115902/commits/8733a1b619dff0c8bcf86316c02252f2c4f5a6b6 https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -2826,6 +2843,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, return selectExtInst(ResVReg, ResType, I, CL::s_clamp, GL::SClamp); case Intrinsic::spv_wave_active_countbits: return selectWaveActiveCountBits(ResVReg, ResType, I); + case Intrinsic::spv_wave_any: +return selectWaveActiveAnyTrue(ResVReg, ResType, I); V-FEXrt wrote: no reason. Its just left over from previous commits. Give me a sec https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -86,6 +86,7 @@ let TargetPrefix = "spv" in { def int_spv_dot4add_i8packed : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; def int_spv_dot4add_u8packed : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; def int_spv_wave_active_countbits : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i1_ty], [IntrConvergent, IntrNoMem]>; + def int_spv_wave_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_i1_ty], [IntrConvergent, IntrNoMem]>; V-FEXrt wrote: @inbelic says its fine to keep here https://github.com/llvm/llvm-project/pull/115902#discussion_r1849054561 https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 01/15] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which eval
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -1949,24 +1955,48 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg, return Result; } +bool SPIRVInstructionSelector::selectWaveNOpInst(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I, + unsigned Opcode, + unsigned OperandCount) const { + assert(I.getNumOperands() == OperandCount); V-FEXrt wrote: I was just blindly refactoring, but one could argue that asserting the expected `OperandCount` is safer from a "is this doing what I expect" angle https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -1949,24 +1955,48 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg, return Result; } +bool SPIRVInstructionSelector::selectWaveNOpInst(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I, + unsigned Opcode, + unsigned OperandCount) const { + assert(I.getNumOperands() == OperandCount); V-FEXrt wrote: Especially since the value is statically known for each opcode https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 01/18] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which eval
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -2206,6 +2206,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) V-FEXrt wrote: I was just kind of following what others had done. But imo its worth keeping if for nothing else besides the documentation https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -1949,6 +1952,23 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg, return Result; } +bool SPIRVInstructionSelector::selectWaveActiveAnyTrue(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I) const { + assert(I.getNumOperands() == 3); + assert(I.getOperand(2).isReg()); + + MachineBasicBlock &BB = *I.getParent(); + SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); + + return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpGroupNonUniformAny)) V-FEXrt wrote: > If it is easy to write a generic with a different number of operands then we > could also look at the other wave intriniscs This should be farily reasonable to do. I'll take a look https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -1949,24 +1955,48 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg, return Result; } +bool SPIRVInstructionSelector::selectWaveNOpInst(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I, + unsigned Opcode, + unsigned OperandCount) const { + assert(I.getNumOperands() == OperandCount); + for (unsigned j = 2; j < OperandCount; j++) { +assert(I.getOperand(j).isReg()); + } + + MachineBasicBlock &BB = *I.getParent(); + SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); + + auto BMI = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) + .addDef(ResVReg) + .addUse(GR.getSPIRVTypeID(ResType)) + .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, +IntTy, TII)); + + for (unsigned j = 2; j < OperandCount; j++) { +BMI.addUse(I.getOperand(j).getReg()); + } + + return BMI.constrainAllUses(TII, TRI, RBI); +} + +bool SPIRVInstructionSelector::selectWaveActiveAnyTrue(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I) const { + return selectWaveNOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAny, 3); V-FEXrt wrote: N/A after removing `OperandCount` https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 01/16] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which eval
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -1949,24 +1955,48 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg, return Result; } +bool SPIRVInstructionSelector::selectWaveNOpInst(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I, + unsigned Opcode, + unsigned OperandCount) const { + assert(I.getNumOperands() == OperandCount); V-FEXrt wrote: https://github.com/llvm/llvm-project/pull/115902/commits/42d24e47bfd0d635119bfa858bdf01b14238fe8c https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -2826,6 +2843,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, return selectExtInst(ResVReg, ResType, I, CL::s_clamp, GL::SClamp); case Intrinsic::spv_wave_active_countbits: return selectWaveActiveCountBits(ResVReg, ResType, I); + case Intrinsic::spv_wave_any: +return selectWaveActiveAnyTrue(ResVReg, ResType, I); V-FEXrt wrote: https://github.com/llvm/llvm-project/pull/115902/commits/42d24e47bfd0d635119bfa858bdf01b14238fe8c https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
https://github.com/V-FEXrt created https://github.com/llvm/llvm-project/pull/116858 Closes https://github.com/llvm/llvm-project/issues/99116 - [x] Implement firstbitlow clang builtin, - [x] Link firstbitlow clang builtin with hlsl_intrinsics.h - [x] Add sema checks for firstbitlow to CheckHLSLBuiltinFunctionCall in SemaChecking.cpp - [x] Add codegen for firstbitlow to EmitHLSLBuiltinExpr in CGBuiltin.cpp - [x] Add codegen tests to clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl - [x] Add sema tests to clang/test/SemaHLSL/BuiltIns/firstbitlow-errors.hlsl - [x] Create the int_dx_firstbitlow intrinsic in IntrinsicsDirectX.td - [x] Create the DXILOpMapping of int_dx_firstbitlow to 32 in DXIL.td - [x] Create the firstbitlow.ll and firstbitlow_errors.ll tests in llvm/test/CodeGen/DirectX/ - [x] Create the int_spv_firstbitlow intrinsic in IntrinsicsSPIRV.td - [x] In SPIRVInstructionSelector.cpp create the firstbitlow lowering and map it to int_spv_firstbitlow in SPIRVInstructionSelector::selectIntrinsic. - [x] Create SPIR-V backend test case in llvm/test/CodeGen/SPIRV/hlsl-intrinsics/firstbitlow.ll >From 49021b33222e0553a3ea52d9802bf133cfa97700 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 14 Nov 2024 11:53:39 -0700 Subject: [PATCH 1/3] [HLSL] Implement elementwise firstbitlow builtin --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 9 +- clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 72 clang/lib/Sema/SemaHLSL.cpp | 3 +- .../CodeGenHLSL/builtins/firstbitlow.hlsl | 153 .../BuiltIns/firstbithigh-errors.hlsl | 6 +- .../SemaHLSL/BuiltIns/firstbitlow-errors.hlsl | 26 +++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 2 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 13 ++ .../DirectX/DirectXTargetTransformInfo.cpp| 1 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 169 ++ llvm/test/CodeGen/DirectX/firstbitlow.ll | 47 + .../test/CodeGen/DirectX/firstbitlow_error.ll | 10 ++ .../SPIRV/hlsl-intrinsics/firstbitlow.ll | 104 +++ 16 files changed, 617 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/firstbitlow-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow.ll create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow_error.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/firstbitlow.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index e866605ac05c09..afe0a311f236d8 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4810,6 +4810,12 @@ def HLSLFirstBitHigh : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLFirstBitLow : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_firstbitlow"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + def HLSLFrac : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_frac"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 9e0c0bff0125c0..a65b96684f18eb 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18956,7 +18956,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, "hlsl.dot4add.u8packed"); } case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: { - Value *X = EmitScalarExpr(E->getArg(0)); return Builder.CreateIntrinsic( @@ -18964,6 +18963,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, getFirstBitHighIntrinsic(CGM.getHLSLRuntime(), E->getArg(0)->getType()), ArrayRef{X}, nullptr, "hlsl.firstbithigh"); } + case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: { +Value *X = EmitScalarExpr(E->getArg(0)); + +return Builder.CreateIntrinsic( +/*ReturnType=*/ConvertType(E->getType()), +CGM.getHLSLRuntime().getFirstBitLowIntrinsic(), ArrayRef{X}, +nullptr, "hlsl.firstbitlow"); + } case Builtin::BI__builtin_hlsl_lerp: { Value *X = EmitScalarExpr(E->getArg(0)); Value *Y = EmitScalarExpr(E->getArg(1)); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 381a5959ec098e..c9eb1b08ff6ba6 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -96,6 +96,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitUHigh, firstbituhigh) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitSHigh, firstbitshigh) + GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitLow, firstbitlow)
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -finclude-default-header -fnative-half-type -triple \ +// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -finclude-default-header -fnative-half-type -triple \ +// RUN: spirv-pc-vulkan-compute %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV + +// Test basic lowering to runtime function call for int values. + +// CHECK-LABEL: test V-FEXrt wrote: ah yeah, good point https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 01/12] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which eval
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 01/11] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which eval
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 1/9] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which evalua
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 01/11] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which eval
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 1/8] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which evalua
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 1/8] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which evalua
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -93,6 +93,7 @@ def int_dx_rsqrt : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>] def int_dx_wave_active_countbits : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i1_ty], [IntrConvergent, IntrNoMem]>; def int_dx_wave_getlaneindex : DefaultAttrsIntrinsic<[llvm_i32_ty], [], [IntrConvergent, IntrNoMem]>; def int_dx_wave_is_first_lane : DefaultAttrsIntrinsic<[llvm_i1_ty], [], [IntrConvergent]>; +def int_dx_wave_activeanytrue : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_i1_ty], [IntrConvergent]>; V-FEXrt wrote: Oh it does and I just fully missed that. Sounds good thanks! https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
@@ -2848,7 +2819,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, case Intrinsic::spv_wave_active_countbits: return selectWaveActiveCountBits(ResVReg, ResType, I); case Intrinsic::spv_wave_any: -return selectWaveActiveAnyTrue(ResVReg, ResType, I); +return selectWaveNOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAny); case Intrinsic::spv_wave_is_first_lane: { SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); V-FEXrt wrote: https://github.com/llvm/llvm-project/pull/115902/commits/ee787874ed394763a7028182df4f1bfeb8cb37cb https://github.com/llvm/llvm-project/pull/115902 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 01/13] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which eval
[clang] [llvm] [HLSL] Implement `WaveActiveAllTrue` Intrinsic (PR #117245)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/117245 >From 1156d98a0ba25a92b4edbacb7c17e5ad6bb2b522 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 21 Nov 2024 08:42:31 -0700 Subject: [PATCH 1/2] [HLSL] Implement WaveActiveAllTrue Intrinsic --- clang/include/clang/Basic/Builtins.td | 6 ++ clang/lib/CodeGen/CGBuiltin.cpp | 10 + clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 .../builtins/WaveActiveAllTrue.hlsl | 17 +++ .../BuiltIns/WaveActiveAllTrue-errors.hlsl| 21 +++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 8 +++ .../Target/SPIRV/SPIRVInstructionSelector.cpp | 2 ++ .../test/CodeGen/DirectX/WaveActiveAllTrue.ll | 10 + .../hlsl-intrinsics/WaveActiveAllTrue.ll | 21 +++ 12 files changed, 107 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAllTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAllTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAllTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 32a09e2ceb3857..d64a66fc9d9cf7 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4762,6 +4762,12 @@ def HLSLAsDouble : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLWaveActiveAllTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_all_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_any_true"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c2e983eebebc10..06d7aaf9badc07 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19419,6 +19419,16 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_all_true: { +Value *Op = EmitScalarExpr(E->getArg(0)); +llvm::Type *Ty = Op->getType(); +assert(Ty->isIntegerTy(1) && + "Intrinsic WaveActiveAllTrue operand must be a bool"); + +Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAllTrueIntrinsic(); +return EmitRuntimeCall( +Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID), {Op}); + } case Builtin::BI__builtin_hlsl_wave_active_any_true: { Value *Op = EmitScalarExpr(E->getArg(0)); assert(Op->getType()->isIntegerTy(1) && diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index bb120c8b5e9e60..1260bb4bc9001b 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -91,6 +91,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddI8Packed, dot4add_i8packed) GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddU8Packed, dot4add_u8packed) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAllTrue, wave_all) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_any) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveCountBits, wave_active_countbits) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 1126e13600f8af..b745997f1d5a2b 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2241,6 +2241,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in all active lanes in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in all lanes. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_all_true) +__attribute__((convergent)) bool WaveActiveAllTrue(bool Val); + /// \brief Returns true if the expression is true in any active lane in the /// current wave. /// diff --git a/clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl b/clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl new file mode 100644 index 00..df530a9cee561a --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -finclude-default-header -fnative-half-type -triple \ +// RUN: dxil-pc-shadermodel6.3-co
[clang] [llvm] [HLSL] Implement `WaveActiveAllTrue` Intrinsic (PR #117245)
@@ -0,0 +1,21 @@ +; RUN: llc -verify-machineinstrs -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 %} + +; CHECK-DAG: %[[#bool:]] = OpTypeBool +; CHECK-DAG: %[[#uint:]] = OpTypeInt 32 0 +; CHECK-DAG: %[[#scope:]] = OpConstant %[[#uint]] 3 +; CHECK-DAG: OpCapability GroupNonUniformVote + +; CHECK-LABEL: Begin function test_wave_all +define i1 @test_wave_all(i1 %p1) #0 { +entry: +; CHECK: %[[#param:]] = OpFunctionParameter %[[#bool]] +; CHECK: %{{.+}} = OpGroupNonUniformAll %[[#bool]] %[[#scope]] %[[#param]] + %0 = call token @llvm.experimental.convergence.entry() V-FEXrt wrote: @Keenuts requested they be included here https://github.com/llvm/llvm-project/pull/115902#discussion_r1850647413 https://github.com/llvm/llvm-project/pull/117245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -0,0 +1,219 @@ +; RUN: llc -verify-machineinstrs -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 %} + +; CHECK-DAG: [[glsl_450_ext:%.+]] = OpExtInstImport "GLSL.std.450" +; CHECK-DAG: OpMemoryModel Logical GLSL450 +; CHECK-DAG: [[u32_t:%.+]] = OpTypeInt 32 0 +; CHECK-DAG: [[u32x2_t:%.+]] = OpTypeVector [[u32_t]] 2 +; CHECK-DAG: [[u32x3_t:%.+]] = OpTypeVector [[u32_t]] 3 +; CHECK-DAG: [[u32x4_t:%.+]] = OpTypeVector [[u32_t]] 4 +; CHECK-DAG: [[const_0:%.*]] = OpConstant [[u32_t]] 0 +; CHECK-DAG: [[const_0x2:%.*]] = OpConstantComposite [[u32x2_t]] [[const_0]] [[const_0]] +; CHECK-DAG: [[const_1:%.*]] = OpConstant [[u32_t]] 1 +; CHECK-DAG: [[const_32:%.*]] = OpConstant [[u32_t]] 32 +; CHECK-DAG: [[const_32x2:%.*]] = OpConstantComposite [[u32x2_t]] [[const_32]] [[const_32]] +; CHECK-DAG: [[const_neg1:%.*]] = OpConstant [[u32_t]] 4294967295 +; CHECK-DAG: [[const_neg1x2:%.*]] = OpConstantComposite [[u32x2_t]] [[const_neg1]] [[const_neg1]] +; CHECK-DAG: [[u16_t:%.+]] = OpTypeInt 16 0 +; CHECK-DAG: [[u16x2_t:%.+]] = OpTypeVector [[u16_t]] 2 +; CHECK-DAG: [[u16x3_t:%.+]] = OpTypeVector [[u16_t]] 3 +; CHECK-DAG: [[u16x4_t:%.+]] = OpTypeVector [[u16_t]] 4 +; CHECK-DAG: [[u64_t:%.+]] = OpTypeInt 64 0 +; CHECK-DAG: [[u64x2_t:%.+]] = OpTypeVector [[u64_t]] 2 +; CHECK-DAG: [[u64x3_t:%.+]] = OpTypeVector [[u64_t]] 3 +; CHECK-DAG: [[u64x4_t:%.+]] = OpTypeVector [[u64_t]] 4 +; CHECK-DAG: [[bool_t:%.+]] = OpTypeBool +; CHECK-DAG: [[boolx2_t:%.+]] = OpTypeVector [[bool_t]] 2 + +; CHECK-LABEL: Begin function firstbitlow_i32 +define noundef i32 @firstbitlow_i32(i32 noundef %a) { +entry: +; CHECK: [[a:%.+]] = OpFunctionParameter [[u32_t]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32_t]] [[glsl_450_ext]] FindILsb [[a]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call i32 @llvm.spv.firstbitlow.i32(i32 %a) + ret i32 %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v2xi32 +define noundef <2 x i32> @firstbitlow_v2xi32(<2 x i32> noundef %a) { +entry: +; CHECK: [[a:%.+]] = OpFunctionParameter [[u32x2_t]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x2_t]] [[glsl_450_ext]] FindILsb [[a]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <2 x i32> @llvm.spv.firstbitlow.v2i32(<2 x i32> %a) + ret <2 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v3xi32 +define noundef <3 x i32> @firstbitlow_v3xi32(<3 x i32> noundef %a) { +entry: +; CHECK: [[a:%.+]] = OpFunctionParameter [[u32x3_t]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x3_t]] [[glsl_450_ext]] FindILsb [[a]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <3 x i32> @llvm.spv.firstbitlow.v3i32(<3 x i32> %a) + ret <3 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v4xi32 +define noundef <4 x i32> @firstbitlow_v4xi32(<4 x i32> noundef %a) { +entry: +; CHECK: [[a:%.+]] = OpFunctionParameter [[u32x4_t]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x4_t]] [[glsl_450_ext]] FindILsb [[a]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <4 x i32> @llvm.spv.firstbitlow.v4i32(<4 x i32> %a) + ret <4 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_i16 +define noundef i32 @firstbitlow_i16(i16 noundef %a) { +entry: +; CHECK: [[a16:%.+]] = OpFunctionParameter [[u16_t]] +; CHECK: [[a32:%.+]] = OpUConvert [[u32_t]] [[a16]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32_t]] [[glsl_450_ext]] FindILsb [[a32]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call i32 @llvm.spv.firstbitlow.i16(i16 %a) + ret i32 %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v2i16 +define noundef <2 x i32> @firstbitlow_v2i16(<2 x i16> noundef %a) { +entry: +; CHECK: [[a16:%.+]] = OpFunctionParameter [[u16x2_t]] +; CHECK: [[a32:%.+]] = OpUConvert [[u32x2_t]] [[a16]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x2_t]] [[glsl_450_ext]] FindILsb [[a32]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <2 x i32> @llvm.spv.firstbitlow.v2i16(<2 x i16> %a) + ret <2 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v3xi16 +define noundef <3 x i32> @firstbitlow_v3xi16(<3 x i16> noundef %a) { +entry: +; CHECK: [[a16:%.+]] = OpFunctionParameter [[u16x3_t]] +; CHECK: [[a32:%.+]] = OpUConvert [[u32x3_t]] [[a16]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x3_t]] [[glsl_450_ext]] FindILsb [[a32]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <3 x i32> @llvm.spv.firstbitlow.v3i16(<3 x i16> %a) + ret <3 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v4xi16 +define noundef <4 x i32> @firstbitlow_v4xi16(<4 x i16> noundef %a) { +entry: +; CHECK: [[a16:%.+]] = OpFunctionParameter [[u16x4_t]] +; CHECK: [[a32:%.+]] = OpUConvert [[u32x4_t]] [[a16]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x4_t]] [[glsl_450_ext]] FindILsb [[a32]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <4 x i32> @llvm.spv.firstbitlow.v4i16(<4 x i1
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
https://github.com/V-FEXrt edited https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3166,109 +3171,228 @@ bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + bool ZeroAsNull = STI.isOpenCLEnv(); + Register ConstIntZero = + GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); + Register ConstIntOne = + GR.getOrCreateConstInt(1, I, BaseType, TII, ZeroAsNull); + + // SPIRV doesn't support vectors with more than 4 components. Since the + // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only + // operate on vectors with 2 or less components. When largers vectors are + // seen. Split them, recurse, then recombine them. + if (ComponentCount > 2) { +unsigned LeftComponentCount = ComponentCount / 2; V-FEXrt wrote: Can you give an example? I'm pretty sure the splitting will never create a vector too large (but the merging back together certainly can) Example: Given `u64x12` the call stack becomes ```c++ selectFirstBitSet64(u64x12); // Top selectFirstBitSet64Overflow(u64x12); // Top selectFirstBitSet64(u64x6); // Top.Left selectFirstBitSet64Overflow(u64x6); // Top.Left selectFirstBitSet64(u64x3); // Top.Left.Left selectFirstBitSet64Overflow(u64x3); // Top.Left.Left selectFirstBitSet64(u64); // Top.Left.Left.Left selectFirstBitSet64(u64x2); // Top.Left.Left.Right selectFirstBitSet64Overflow(u64x3); // Top.Left.Right selectFirstBitSet64(u64); // Top.Left.Right.Left selectFirstBitSet64(u64x2); // Top.Left.Right.Right selectFirstBitSet64Overflow(u64x6); // Top.Right selectFirstBitSet64(u64x3); // Top.Right.Left selectFirstBitSet64Overflow(u64x3); // Top.Right.Left selectFirstBitSet64(u64); // Top.Right.Left.Left selectFirstBitSet64(u64x2); // Top.Right.Left.Right selectFirstBitSet64Overflow(u64x3); // Top.Right.Right selectFirstBitSet64(u64); // Top.Right.Right.Left selectFirstBitSet64(u64x2); // Top.Right.Right.Right ``` https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement `WaveActiveAllTrue` Intrinsic (PR #117245)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/117245 >From 1156d98a0ba25a92b4edbacb7c17e5ad6bb2b522 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 21 Nov 2024 08:42:31 -0700 Subject: [PATCH 1/2] [HLSL] Implement WaveActiveAllTrue Intrinsic --- clang/include/clang/Basic/Builtins.td | 6 ++ clang/lib/CodeGen/CGBuiltin.cpp | 10 + clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 .../builtins/WaveActiveAllTrue.hlsl | 17 +++ .../BuiltIns/WaveActiveAllTrue-errors.hlsl| 21 +++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 8 +++ .../Target/SPIRV/SPIRVInstructionSelector.cpp | 2 ++ .../test/CodeGen/DirectX/WaveActiveAllTrue.ll | 10 + .../hlsl-intrinsics/WaveActiveAllTrue.ll | 21 +++ 12 files changed, 107 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAllTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAllTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAllTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 32a09e2ceb3857..d64a66fc9d9cf7 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4762,6 +4762,12 @@ def HLSLAsDouble : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLWaveActiveAllTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_all_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_any_true"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c2e983eebebc10..06d7aaf9badc07 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19419,6 +19419,16 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_all_true: { +Value *Op = EmitScalarExpr(E->getArg(0)); +llvm::Type *Ty = Op->getType(); +assert(Ty->isIntegerTy(1) && + "Intrinsic WaveActiveAllTrue operand must be a bool"); + +Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAllTrueIntrinsic(); +return EmitRuntimeCall( +Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID), {Op}); + } case Builtin::BI__builtin_hlsl_wave_active_any_true: { Value *Op = EmitScalarExpr(E->getArg(0)); assert(Op->getType()->isIntegerTy(1) && diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index bb120c8b5e9e60..1260bb4bc9001b 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -91,6 +91,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddI8Packed, dot4add_i8packed) GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddU8Packed, dot4add_u8packed) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAllTrue, wave_all) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_any) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveCountBits, wave_active_countbits) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 1126e13600f8af..b745997f1d5a2b 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2241,6 +2241,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in all active lanes in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in all lanes. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_all_true) +__attribute__((convergent)) bool WaveActiveAllTrue(bool Val); + /// \brief Returns true if the expression is true in any active lane in the /// current wave. /// diff --git a/clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl b/clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl new file mode 100644 index 00..df530a9cee561a --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -finclude-default-header -fnative-half-type -triple \ +// RUN: dxil-pc-shadermodel6.3-co
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3166,109 +3171,228 @@ bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + bool ZeroAsNull = STI.isOpenCLEnv(); + Register ConstIntZero = + GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); + Register ConstIntOne = + GR.getOrCreateConstInt(1, I, BaseType, TII, ZeroAsNull); + + // SPIRV doesn't support vectors with more than 4 components. Since the + // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only + // operate on vectors with 2 or less components. When largers vectors are + // seen. Split them, recurse, then recombine them. + if (ComponentCount > 2) { +unsigned LeftComponentCount = ComponentCount / 2; V-FEXrt wrote: Actually one thing I was considering was to just explicitly handle the vec3 and vec4 cases then assert for anything higher but they are equally as messy while being strictly less general https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3166,109 +3171,228 @@ bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + bool ZeroAsNull = STI.isOpenCLEnv(); + Register ConstIntZero = + GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); + Register ConstIntOne = + GR.getOrCreateConstInt(1, I, BaseType, TII, ZeroAsNull); + + // SPIRV doesn't support vectors with more than 4 components. Since the + // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only + // operate on vectors with 2 or less components. When largers vectors are + // seen. Split them, recurse, then recombine them. + if (ComponentCount > 2) { +unsigned LeftComponentCount = ComponentCount / 2; V-FEXrt wrote: I tried to write it to handle that case. It should just keep recursing and splitting the vectors in half until its under 2 components. I do think we are strictly limited by SPIRV here though. Say hlsl supported u64x8, we still have to accept the vec8 in as a parameter and return a vec8 out. Both of which would require invalid SPIRV https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/116858 >From a63e05d2e090edf7834fb62296bccd071a8e38b8 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 14 Nov 2024 11:53:39 -0700 Subject: [PATCH 1/7] [HLSL] Implement elementwise firstbitlow builtin --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 9 +- clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 72 clang/lib/Sema/SemaHLSL.cpp | 3 +- .../CodeGenHLSL/builtins/firstbitlow.hlsl | 153 .../BuiltIns/firstbithigh-errors.hlsl | 6 +- .../SemaHLSL/BuiltIns/firstbitlow-errors.hlsl | 26 +++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 13 ++ .../DirectX/DirectXTargetTransformInfo.cpp| 1 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 169 ++ llvm/test/CodeGen/DirectX/firstbitlow.ll | 47 + .../test/CodeGen/DirectX/firstbitlow_error.ll | 10 ++ .../SPIRV/hlsl-intrinsics/firstbitlow.ll | 104 +++ 16 files changed, 616 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/firstbitlow-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow.ll create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow_error.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/firstbitlow.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 32a09e2ceb3857..a4fb671e479307 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4834,6 +4834,12 @@ def HLSLFirstBitHigh : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLFirstBitLow : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_firstbitlow"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + def HLSLFrac : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_frac"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c2e983eebebc10..cbd4c931b05b05 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19255,7 +19255,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, "hlsl.dot4add.u8packed"); } case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: { - Value *X = EmitScalarExpr(E->getArg(0)); return Builder.CreateIntrinsic( @@ -19263,6 +19262,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, getFirstBitHighIntrinsic(CGM.getHLSLRuntime(), E->getArg(0)->getType()), ArrayRef{X}, nullptr, "hlsl.firstbithigh"); } + case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: { +Value *X = EmitScalarExpr(E->getArg(0)); + +return Builder.CreateIntrinsic( +/*ReturnType=*/ConvertType(E->getType()), +CGM.getHLSLRuntime().getFirstBitLowIntrinsic(), ArrayRef{X}, +nullptr, "hlsl.firstbitlow"); + } case Builtin::BI__builtin_hlsl_lerp: { Value *X = EmitScalarExpr(E->getArg(0)); Value *Y = EmitScalarExpr(E->getArg(1)); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index bb120c8b5e9e60..df285e185173dc 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -97,6 +97,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitUHigh, firstbituhigh) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitSHigh, firstbitshigh) + GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitLow, firstbitlow) GENERATE_HLSL_INTRINSIC_FUNCTION(NClamp, nclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(SClamp, sclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 1126e13600f8af..c132c300da27a4 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -1121,6 +1121,78 @@ uint3 firstbithigh(uint64_t3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) uint4 firstbithigh(uint64_t4); +//===--===// +// firstbitlow builtins +//===--===// + +/// \fn T firstbitlow(T Val) +/// \brief Returns the location of the first set bit starting from the lowest +/// order bit and working upward, per component. +/// \param Val the input value. + +#ifdef __HLSL_ENABLE_16_BIT +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_fir
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3166,109 +3171,228 @@ bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + bool ZeroAsNull = STI.isOpenCLEnv(); + Register ConstIntZero = + GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); + Register ConstIntOne = + GR.getOrCreateConstInt(1, I, BaseType, TII, ZeroAsNull); + + // SPIRV doesn't support vectors with more than 4 components. Since the + // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only + // operate on vectors with 2 or less components. When largers vectors are + // seen. Split them, recurse, then recombine them. + if (ComponentCount > 2) { +unsigned LeftComponentCount = ComponentCount / 2; V-FEXrt wrote: Ah yep. :/ I was hoping it was clean and only `SrcReg` `ResReg` were "bad" but nope. Probably just go with the assert that its never larger than `u64x4` for now. https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3139,136 +3151,269 @@ Register SPIRVInstructionSelector::buildPointerToResource( return AcReg; } -bool SPIRVInstructionSelector::selectFirstBitHigh16(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; - // zero or sign extend +bool SPIRVInstructionSelector::selectFirstBitSet16( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +unsigned ExtendOpcode, unsigned BitSetOpcode) const { Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); - bool Result = - selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, Opcode); - return Result && selectFirstBitHigh32(ResVReg, ResType, I, ExtReg, IsSigned); + bool Result = selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, + ExtendOpcode); + + return Result && + selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode); } -bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -Register SrcReg, -bool IsSigned) const { - unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb; +bool SPIRVInstructionSelector::selectFirstBitSet32( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode) const { return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) .addDef(ResVReg) .addUse(GR.getSPIRVTypeID(ResType)) .addImm(static_cast(SPIRV::InstructionSet::GLSL_std_450)) - .addImm(Opcode) + .addImm(BitSetOpcode) .addUse(SrcReg) .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + bool ZeroAsNull = STI.isOpenCLEnv(); + Register ConstIntZero = + GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); + unsigned LeftComponentCount = ComponentCount / 2; + unsigned RightComponentCount = ComponentCount - LeftComponentCount; + bool LeftIsVector = LeftComponentCount > 1; + + // Split the SrcReg in half into 2 smaller vec registers + // (ie i64x4 -> i64x2, i64x2) MachineIRBuilder MIRBuilder(I); - SPIRVType *postCastT = - GR.getOrCreateSPIRVVectorType(baseType, 2 * count, MIRBuilder); - Register bitcastReg = MRI->createVirtualRegister(GR.getRegClass(postCastT)); + SPIRVType *OpType = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); + SPIRVType *LeftOpType; + SPIRVType *LeftResType; + if (LeftIsVector) { +LeftOpType = +GR.getOrCreateSPIRVVectorType(OpType, LeftComponentCount, MIRBuilder); +LeftResType = +GR.getOrCreateSPIRVVectorType(BaseType, LeftComponentCount, MIRBuilder); + } else { +LeftOpType = OpType; +LeftResType = BaseType; + } + + SPIRVType *RightOpType = + GR.getOrCreateSPIRVVectorType(OpType, RightComponentCount, MIRBuilder); + SPIRVType *RightResType = + GR.getOrCreateSPIRVVectorType(BaseType, RightComponentCount, MIRBuilder); + + Register LeftSideIn = MRI->createVirtualRegister(GR.getRegClass(LeftOpType)); + Register RightSideIn = + MRI->createVirtualRegister(GR.getRegClass(RightOpType)); + + bool Result; + + // Extract the left half from the SrcReg into LeftSideIn + // accounting for the special case when it only has one element + if (LeftIsVector) { +auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), + TII.get(SPIRV::OpVectorShuffle)) + .addDef(LeftSideIn) + .addUse(GR.getSPIRVTypeID(LeftOpType)) + .addUse(SrcReg) + // Per the spec, repeat the vector if only one vec is needed + .addUse(SrcReg); + +for (unsigned J = 0; J < LeftComponentCo
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3139,136 +3151,269 @@ Register SPIRVInstructionSelector::buildPointerToResource( return AcReg; } -bool SPIRVInstructionSelector::selectFirstBitHigh16(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; - // zero or sign extend +bool SPIRVInstructionSelector::selectFirstBitSet16( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +unsigned ExtendOpcode, unsigned BitSetOpcode) const { Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); - bool Result = - selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, Opcode); - return Result && selectFirstBitHigh32(ResVReg, ResType, I, ExtReg, IsSigned); + bool Result = selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, + ExtendOpcode); + + return Result && + selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode); } -bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -Register SrcReg, -bool IsSigned) const { - unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb; +bool SPIRVInstructionSelector::selectFirstBitSet32( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode) const { return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) .addDef(ResVReg) .addUse(GR.getSPIRVTypeID(ResType)) .addImm(static_cast(SPIRV::InstructionSet::GLSL_std_450)) - .addImm(Opcode) + .addImm(BitSetOpcode) .addUse(SrcReg) .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + bool ZeroAsNull = STI.isOpenCLEnv(); + Register ConstIntZero = + GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); + unsigned LeftComponentCount = ComponentCount / 2; + unsigned RightComponentCount = ComponentCount - LeftComponentCount; + bool LeftIsVector = LeftComponentCount > 1; + + // Split the SrcReg in half into 2 smaller vec registers + // (ie i64x4 -> i64x2, i64x2) MachineIRBuilder MIRBuilder(I); - SPIRVType *postCastT = - GR.getOrCreateSPIRVVectorType(baseType, 2 * count, MIRBuilder); - Register bitcastReg = MRI->createVirtualRegister(GR.getRegClass(postCastT)); + SPIRVType *OpType = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); + SPIRVType *LeftOpType; + SPIRVType *LeftResType; + if (LeftIsVector) { +LeftOpType = +GR.getOrCreateSPIRVVectorType(OpType, LeftComponentCount, MIRBuilder); +LeftResType = +GR.getOrCreateSPIRVVectorType(BaseType, LeftComponentCount, MIRBuilder); + } else { +LeftOpType = OpType; +LeftResType = BaseType; + } + + SPIRVType *RightOpType = + GR.getOrCreateSPIRVVectorType(OpType, RightComponentCount, MIRBuilder); + SPIRVType *RightResType = + GR.getOrCreateSPIRVVectorType(BaseType, RightComponentCount, MIRBuilder); + + Register LeftSideIn = MRI->createVirtualRegister(GR.getRegClass(LeftOpType)); + Register RightSideIn = + MRI->createVirtualRegister(GR.getRegClass(RightOpType)); + + bool Result; + + // Extract the left half from the SrcReg into LeftSideIn + // accounting for the special case when it only has one element + if (LeftIsVector) { +auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), + TII.get(SPIRV::OpVectorShuffle)) + .addDef(LeftSideIn) + .addUse(GR.getSPIRVTypeID(LeftOpType)) + .addUse(SrcReg) + // Per the spec, repeat the vector if only one vec is needed + .addUse(SrcReg); + +for (unsigned J = 0; J < LeftComponentCo
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 01/18] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which eval
[clang] [llvm] [HLSL] Implement WaveActiveAnyTrue intrinsic (PR #115902)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/115902 >From 845256b2ed971a4e42f7f871e8b51e711486261a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 11 Nov 2024 16:34:23 -0700 Subject: [PATCH 01/19] [HLSL] Implement WaveActiveAnyTrue intrinsic --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 13 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 +++ clang/lib/Sema/SemaHLSL.cpp | 6 + .../builtins/WaveActiveAnyTrue.hlsl | 17 + .../BuiltIns/WaveActiveAnyTrue-errors.hlsl| 21 llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 10 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 +++ .../test/CodeGen/DirectX/WaveActiveAnyTrue.ll | 10 .../hlsl-intrinsics/WaveActiveAnyTrue.ll | 17 + 13 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAnyTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAnyTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAnyTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAnyTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9bd67e0cefebc3..496b6739724295 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4744,6 +4744,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_any_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_count_bits"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 65d7f5c54a1913..c4a6a9abee63cc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18960,6 +18960,19 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_any_true: { +// Assert Op->getType() == Bool + +// FIXME: PR Question: Can this be simpler? Looks like Int1Ty isn't predefined +IntegerType* Int1Ty = llvm::Type::getInt1Ty(CGM.getTypes().getLLVMContext()); +Value *Op = EmitScalarExpr(E->getArg(0)); +assert(Op->getType() == Int1Ty && "wave_active_any_true operand must be a bool"); + +// FIXME: PR Question: Re Style SingleRef vs {SingleRef} vs ArrayRef{SingleRef} +llvm::FunctionType *FT = llvm::FunctionType::get(Int1Ty, {Int1Ty}, /*isVarArg=*/false); +llvm::StringRef Name = Intrinsic::getName(CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic()); +return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, /*Local=*/false, /*AssumeConvergent=*/true), {Op}, "hlsl.wave.activeanytrue"); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in // defined in SPIRVBuiltins.td. So instead we manually get the matching name diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index cd533cad84e9fb..c3b689ea44fcb8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -89,6 +89,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_activeanytrue) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 8ade4b27f360fb..90991e95d6565a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2096,6 +2096,15 @@ float4 trunc(float4); // Wave* builtins //===--===// +/// \brief Returns true if the expression is true in any active lane in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in any lane. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_any_true) +__attribute__((convergent)) bool WaveActiveAnyTrue(bool Val); + /// \brief Counts the number of boolean variables which eval
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3158,6 +3172,166 @@ bool SPIRVInstructionSelector::selectFirstBitHigh(Register ResVReg, } } +bool SPIRVInstructionSelector::selectFirstBitLow16(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I) const { + // OpUConvert treats the operand bits as an unsigned i16 and zero extends it + // to an unsigned i32. As this leaves all the least significant bits unchanged + // the first set bit from the LSB side doesn't change. + Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); + bool Result = selectNAryOpWithSrcs( + ExtReg, ResType, I, {I.getOperand(2).getReg()}, SPIRV::OpUConvert); + return Result && selectFirstBitLow32(ResVReg, ResType, I, ExtReg); +} + +bool SPIRVInstructionSelector::selectFirstBitLow32(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I, + Register SrcReg) const { + return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) + .addDef(ResVReg) + .addUse(GR.getSPIRVTypeID(ResType)) + .addImm(static_cast(SPIRV::InstructionSet::GLSL_std_450)) + .addImm(GL::FindILsb) + .addUse(SrcReg) + .constrainAllUses(TII, TRI, RBI); +} + +bool SPIRVInstructionSelector::selectFirstBitLow64(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I) const { + Register OpReg = I.getOperand(2).getReg(); + + // 1. Split int64 into 2 pieces using a bitcast + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + MachineIRBuilder MIRBuilder(I); + SPIRVType *PostCastType = + GR.getOrCreateSPIRVVectorType(BaseType, 2 * ComponentCount, MIRBuilder); + Register BitcastReg = + MRI->createVirtualRegister(GR.getRegClass(PostCastType)); + bool Result = + selectUnOpWithSrc(BitcastReg, PostCastType, I, OpReg, SPIRV::OpBitcast); + + // 2. Find the first set bit from the LSB side for all the pieces in #1 + Register FBLReg = MRI->createVirtualRegister(GR.getRegClass(PostCastType)); + Result = Result && selectFirstBitLow32(FBLReg, PostCastType, I, BitcastReg); + + // 3. Split result vector into high bits and low bits + Register HighReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); + Register LowReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); + + bool ZeroAsNull = STI.isOpenCLEnv(); + bool IsScalarRes = ResType->getOpcode() != SPIRV::OpTypeVector; + if (IsScalarRes) { +// if scalar do a vector extract +Result = +Result && +selectNAryOpWithSrcs( +HighReg, ResType, I, +{FBLReg, GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull)}, +SPIRV::OpVectorExtractDynamic); +Result = +Result && +selectNAryOpWithSrcs( +LowReg, ResType, I, +{FBLReg, GR.getOrCreateConstInt(1, I, ResType, TII, ZeroAsNull)}, +SPIRV::OpVectorExtractDynamic); + } else { +// if vector do a shufflevector +auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), + TII.get(SPIRV::OpVectorShuffle)) + .addDef(HighReg) + .addUse(GR.getSPIRVTypeID(ResType)) + .addUse(FBLReg) + // Per the spec, repeat the vector if only one vec is needed + .addUse(FBLReg); + +// high bits are stored in even indexes. Extract them from FBLReg +for (unsigned j = 0; j < ComponentCount * 2; j += 2) { + MIB.addImm(j); +} +Result = Result && MIB.constrainAllUses(TII, TRI, RBI); + +MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), + TII.get(SPIRV::OpVectorShuffle)) + .addDef(LowReg) + .addUse(GR.getSPIRVTypeID(ResType)) + .addUse(FBLReg) + // Per the spec, repeat the vector if only one vec is needed + .addUse(FBLReg); + +// low bits are stored in odd indexes. Extract them from FBLReg +for (unsigned j = 1; j < ComponentCount * 2; j += 2) { + MIB.addImm(j); +} +Result = Result && MIB.constrainAllUses(TII, TRI, RBI); + } + + // 4. Check the result. When low bits == -1 use high, otherwise use low V-FEXrt wrote: I couldn't figure out how to make the swapping work since the shared function is actually what assigns High/Low, but I added a flag to the shared function to swap the regs. Lmk if that's good enough or if there is something I'm missing! https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.o
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/116858 >From eeb864972c48625fa56b96e6b018affe04d84e00 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 14 Nov 2024 11:53:39 -0700 Subject: [PATCH 1/4] [HLSL] Implement elementwise firstbitlow builtin --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 9 +- clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 72 clang/lib/Sema/SemaHLSL.cpp | 3 +- .../CodeGenHLSL/builtins/firstbitlow.hlsl | 153 .../BuiltIns/firstbithigh-errors.hlsl | 6 +- .../SemaHLSL/BuiltIns/firstbitlow-errors.hlsl | 26 +++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 2 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 13 ++ .../DirectX/DirectXTargetTransformInfo.cpp| 1 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 169 ++ llvm/test/CodeGen/DirectX/firstbitlow.ll | 47 + .../test/CodeGen/DirectX/firstbitlow_error.ll | 10 ++ .../SPIRV/hlsl-intrinsics/firstbitlow.ll | 104 +++ 16 files changed, 617 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/firstbitlow-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow.ll create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow_error.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/firstbitlow.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 290feb58754adb..7132c8f816dbc0 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4822,6 +4822,12 @@ def HLSLFirstBitHigh : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLFirstBitLow : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_firstbitlow"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + def HLSLFrac : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_frac"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 4b96bdb709c777..cca840f908cfec 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19119,7 +19119,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, "hlsl.dot4add.u8packed"); } case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: { - Value *X = EmitScalarExpr(E->getArg(0)); return Builder.CreateIntrinsic( @@ -19127,6 +19126,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, getFirstBitHighIntrinsic(CGM.getHLSLRuntime(), E->getArg(0)->getType()), ArrayRef{X}, nullptr, "hlsl.firstbithigh"); } + case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: { +Value *X = EmitScalarExpr(E->getArg(0)); + +return Builder.CreateIntrinsic( +/*ReturnType=*/ConvertType(E->getType()), +CGM.getHLSLRuntime().getFirstBitLowIntrinsic(), ArrayRef{X}, +nullptr, "hlsl.firstbitlow"); + } case Builtin::BI__builtin_hlsl_lerp: { Value *X = EmitScalarExpr(E->getArg(0)); Value *Y = EmitScalarExpr(E->getArg(1)); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index a8e0ed42b79a35..3c3841998938da 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -97,6 +97,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitUHigh, firstbituhigh) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitSHigh, firstbitshigh) + GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitLow, firstbitlow) GENERATE_HLSL_INTRINSIC_FUNCTION(NClamp, nclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(SClamp, sclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index a484d04155d6b2..e0df7cf71af1cc 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -1103,6 +1103,78 @@ uint3 firstbithigh(uint64_t3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) uint4 firstbithigh(uint64_t4); +//===--===// +// firstbitlow builtins +//===--===// + +/// \fn T firstbitlow(T Val) +/// \brief Returns the location of the first set bit starting from the lowest +/// order bit and working upward, per component. +/// \param Val the input value. + +#ifdef __HLSL_ENABLE_16_BIT +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_fir
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/116858 >From eeb864972c48625fa56b96e6b018affe04d84e00 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 14 Nov 2024 11:53:39 -0700 Subject: [PATCH 1/5] [HLSL] Implement elementwise firstbitlow builtin --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 9 +- clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 72 clang/lib/Sema/SemaHLSL.cpp | 3 +- .../CodeGenHLSL/builtins/firstbitlow.hlsl | 153 .../BuiltIns/firstbithigh-errors.hlsl | 6 +- .../SemaHLSL/BuiltIns/firstbitlow-errors.hlsl | 26 +++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 2 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 13 ++ .../DirectX/DirectXTargetTransformInfo.cpp| 1 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 169 ++ llvm/test/CodeGen/DirectX/firstbitlow.ll | 47 + .../test/CodeGen/DirectX/firstbitlow_error.ll | 10 ++ .../SPIRV/hlsl-intrinsics/firstbitlow.ll | 104 +++ 16 files changed, 617 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/firstbitlow-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow.ll create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow_error.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/firstbitlow.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 290feb58754adb..7132c8f816dbc0 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4822,6 +4822,12 @@ def HLSLFirstBitHigh : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLFirstBitLow : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_firstbitlow"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + def HLSLFrac : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_frac"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 4b96bdb709c777..cca840f908cfec 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19119,7 +19119,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, "hlsl.dot4add.u8packed"); } case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: { - Value *X = EmitScalarExpr(E->getArg(0)); return Builder.CreateIntrinsic( @@ -19127,6 +19126,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, getFirstBitHighIntrinsic(CGM.getHLSLRuntime(), E->getArg(0)->getType()), ArrayRef{X}, nullptr, "hlsl.firstbithigh"); } + case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: { +Value *X = EmitScalarExpr(E->getArg(0)); + +return Builder.CreateIntrinsic( +/*ReturnType=*/ConvertType(E->getType()), +CGM.getHLSLRuntime().getFirstBitLowIntrinsic(), ArrayRef{X}, +nullptr, "hlsl.firstbitlow"); + } case Builtin::BI__builtin_hlsl_lerp: { Value *X = EmitScalarExpr(E->getArg(0)); Value *Y = EmitScalarExpr(E->getArg(1)); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index a8e0ed42b79a35..3c3841998938da 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -97,6 +97,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitUHigh, firstbituhigh) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitSHigh, firstbitshigh) + GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitLow, firstbitlow) GENERATE_HLSL_INTRINSIC_FUNCTION(NClamp, nclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(SClamp, sclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index a484d04155d6b2..e0df7cf71af1cc 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -1103,6 +1103,78 @@ uint3 firstbithigh(uint64_t3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) uint4 firstbithigh(uint64_t4); +//===--===// +// firstbitlow builtins +//===--===// + +/// \fn T firstbitlow(T Val) +/// \brief Returns the location of the first set bit starting from the lowest +/// order bit and working upward, per component. +/// \param Val the input value. + +#ifdef __HLSL_ENABLE_16_BIT +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_fir
[clang] [llvm] [HLSL] Implement `WaveActiveAllTrue` Intrinsic (PR #117245)
https://github.com/V-FEXrt created https://github.com/llvm/llvm-project/pull/117245 Resolves https://github.com/llvm/llvm-project/issues/99161 - [x] Implement `WaveActiveAllTrue` clang builtin, - [x] Link `WaveActiveAllTrue` clang builtin with `hlsl_intrinsics.h` - [x] Add sema checks for `WaveActiveAllTrue` to `CheckHLSLBuiltinFunctionCall` in `SemaChecking.cpp` - [x] Add codegen for `WaveActiveAllTrue` to `EmitHLSLBuiltinExpr` in `CGBuiltin.cpp` - [x] Add codegen tests to `clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl` - [x] Add sema tests to `clang/test/SemaHLSL/BuiltIns/WaveActiveAllTrue-errors.hlsl` - [x] Create the `int_dx_WaveActiveAllTrue` intrinsic in `IntrinsicsDirectX.td` - [x] Create the `DXILOpMapping` of `int_dx_WaveActiveAllTrue` to `114` in `DXIL.td` - [x] Create the `WaveActiveAllTrue.ll` and `WaveActiveAllTrue_errors.ll` tests in `llvm/test/CodeGen/DirectX/` - [x] Create the `int_spv_WaveActiveAllTrue` intrinsic in `IntrinsicsSPIRV.td` - [x] In SPIRVInstructionSelector.cpp create the `WaveActiveAllTrue` lowering and map it to `int_spv_WaveActiveAllTrue` in `SPIRVInstructionSelector::selectIntrinsic`. - [x] Create SPIR-V backend test case in `llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAllTrue.ll` >From 73afef24940e4d0978220063df87d3ebda8da615 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 21 Nov 2024 08:42:31 -0700 Subject: [PATCH] [HLSL] Implement WaveActiveAllTrue Intrinsic --- clang/include/clang/Basic/Builtins.td | 6 ++ clang/lib/CodeGen/CGBuiltin.cpp | 10 + clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 9 .../builtins/WaveActiveAllTrue.hlsl | 17 +++ .../BuiltIns/WaveActiveAllTrue-errors.hlsl| 21 +++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 1 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 8 +++ .../Target/SPIRV/SPIRVInstructionSelector.cpp | 2 ++ .../test/CodeGen/DirectX/WaveActiveAllTrue.ll | 10 + .../hlsl-intrinsics/WaveActiveAllTrue.ll | 21 +++ 12 files changed, 107 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/WaveActiveAllTrue-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/WaveActiveAllTrue.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WaveActiveAllTrue.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 290feb58754adb..8aa5719d736f94 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4750,6 +4750,12 @@ def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Prototype = "bool(...)"; } +def HLSLWaveActiveAllTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_all_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_any_true"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index ff7132fd8bc1e7..522a6ce3b999e3 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19282,6 +19282,16 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_all_true: { +Value *Op = EmitScalarExpr(E->getArg(0)); +llvm::Type *Ty = Op->getType(); +assert(Ty->isIntegerTy(1) && + "Intrinsic WaveActiveAllTrue operand must be a bool"); + +Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAllTrueIntrinsic(); +return EmitRuntimeCall( +Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID), {Op}); + } case Builtin::BI__builtin_hlsl_wave_active_any_true: { Value *Op = EmitScalarExpr(E->getArg(0)); assert(Op->getType()->isIntegerTy(1) && diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index a8e0ed42b79a35..29c0fe1acabccc 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -91,6 +91,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddI8Packed, dot4add_i8packed) GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddU8Packed, dot4add_u8packed) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAllTrue, wave_all) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_any) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveCountBits, wave_active_countbits) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib
[clang] [llvm] [HLSL] Implement `WaveActiveAllTrue` Intrinsic (PR #117245)
@@ -861,6 +861,14 @@ def CreateHandleFromBinding : DXILOp<217, createHandleFromBinding> { let stages = [Stages]; } +def WaveActiveAllTrue : DXILOp<334, waveAllTrue> { V-FEXrt wrote: Crossed wires with SPIRV. This should be 114 not 334 https://github.com/llvm/llvm-project/pull/117245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/116858 >From eeb864972c48625fa56b96e6b018affe04d84e00 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 14 Nov 2024 11:53:39 -0700 Subject: [PATCH 1/6] [HLSL] Implement elementwise firstbitlow builtin --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 9 +- clang/lib/CodeGen/CGHLSLRuntime.h | 1 + clang/lib/Headers/hlsl/hlsl_intrinsics.h | 72 clang/lib/Sema/SemaHLSL.cpp | 3 +- .../CodeGenHLSL/builtins/firstbitlow.hlsl | 153 .../BuiltIns/firstbithigh-errors.hlsl | 6 +- .../SemaHLSL/BuiltIns/firstbitlow-errors.hlsl | 26 +++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 2 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + llvm/lib/Target/DirectX/DXIL.td | 13 ++ .../DirectX/DirectXTargetTransformInfo.cpp| 1 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 169 ++ llvm/test/CodeGen/DirectX/firstbitlow.ll | 47 + .../test/CodeGen/DirectX/firstbitlow_error.ll | 10 ++ .../SPIRV/hlsl-intrinsics/firstbitlow.ll | 104 +++ 16 files changed, 617 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/firstbitlow-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow.ll create mode 100644 llvm/test/CodeGen/DirectX/firstbitlow_error.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/firstbitlow.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 290feb58754adb..7132c8f816dbc0 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4822,6 +4822,12 @@ def HLSLFirstBitHigh : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLFirstBitLow : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_firstbitlow"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + def HLSLFrac : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_frac"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 4b96bdb709c777..cca840f908cfec 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19119,7 +19119,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, "hlsl.dot4add.u8packed"); } case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: { - Value *X = EmitScalarExpr(E->getArg(0)); return Builder.CreateIntrinsic( @@ -19127,6 +19126,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, getFirstBitHighIntrinsic(CGM.getHLSLRuntime(), E->getArg(0)->getType()), ArrayRef{X}, nullptr, "hlsl.firstbithigh"); } + case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: { +Value *X = EmitScalarExpr(E->getArg(0)); + +return Builder.CreateIntrinsic( +/*ReturnType=*/ConvertType(E->getType()), +CGM.getHLSLRuntime().getFirstBitLowIntrinsic(), ArrayRef{X}, +nullptr, "hlsl.firstbitlow"); + } case Builtin::BI__builtin_hlsl_lerp: { Value *X = EmitScalarExpr(E->getArg(0)); Value *Y = EmitScalarExpr(E->getArg(1)); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index a8e0ed42b79a35..3c3841998938da 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -97,6 +97,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitUHigh, firstbituhigh) GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitSHigh, firstbitshigh) + GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitLow, firstbitlow) GENERATE_HLSL_INTRINSIC_FUNCTION(NClamp, nclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(SClamp, sclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index a484d04155d6b2..e0df7cf71af1cc 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -1103,6 +1103,78 @@ uint3 firstbithigh(uint64_t3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_firstbithigh) uint4 firstbithigh(uint64_t4); +//===--===// +// firstbitlow builtins +//===--===// + +/// \fn T firstbitlow(T Val) +/// \brief Returns the location of the first set bit starting from the lowest +/// order bit and working upward, per component. +/// \param Val the input value. + +#ifdef __HLSL_ENABLE_16_BIT +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_fir
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -0,0 +1,168 @@ +; RUN: llc -verify-machineinstrs -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 %} + +; CHECK-DAG: [[glsl_450_ext:%.+]] = OpExtInstImport "GLSL.std.450" +; CHECK-DAG: OpMemoryModel Logical GLSL450 +; CHECK-DAG: [[u32_t:%.+]] = OpTypeInt 32 0 +; CHECK-DAG: [[u32x2_t:%.+]] = OpTypeVector [[u32_t]] 2 +; CHECK-DAG: [[u32x3_t:%.+]] = OpTypeVector [[u32_t]] 3 +; CHECK-DAG: [[u32x4_t:%.+]] = OpTypeVector [[u32_t]] 4 +; CHECK-DAG: [[const_0:%.*]] = OpConstant [[u32_t]] 0 +; CHECK-DAG: [[const_0x2:%.*]] = OpConstantComposite [[u32x2_t]] [[const_0]] [[const_0]] +; CHECK-DAG: [[const_0x3:%.*]] = OpConstantComposite [[u32x3_t]] [[const_0]] [[const_0]] [[const_0]] +; CHECK-DAG: [[const_1:%.*]] = OpConstant [[u32_t]] 1 +; CHECK-DAG: [[const_32:%.*]] = OpConstant [[u32_t]] 32 +; CHECK-DAG: [[const_32x2:%.*]] = OpConstantComposite [[u32x2_t]] [[const_32]] [[const_32]] +; CHECK-DAG: [[const_32x3:%.*]] = OpConstantComposite [[u32x3_t]] [[const_32]] [[const_32]] [[const_32]] +; CHECK-DAG: [[const_neg1:%.*]] = OpConstant [[u32_t]] 4294967295 +; CHECK-DAG: [[const_neg1x2:%.*]] = OpConstantComposite [[u32x2_t]] [[const_neg1]] [[const_neg1]] +; CHECK-DAG: [[const_neg1x3:%.*]] = OpConstantComposite [[u32x3_t]] [[const_neg1]] [[const_neg1]] [[const_neg1]] +; CHECK-DAG: [[u16_t:%.+]] = OpTypeInt 16 0 +; CHECK-DAG: [[u16x2_t:%.+]] = OpTypeVector [[u16_t]] 2 +; CHECK-DAG: [[u16x3_t:%.+]] = OpTypeVector [[u16_t]] 3 +; CHECK-DAG: [[u16x4_t:%.+]] = OpTypeVector [[u16_t]] 4 +; CHECK-DAG: [[u64_t:%.+]] = OpTypeInt 64 0 +; CHECK-DAG: [[u64x2_t:%.+]] = OpTypeVector [[u64_t]] 2 +; CHECK-DAG: [[u64x3_t:%.+]] = OpTypeVector [[u64_t]] 3 +; CHECK-DAG: [[bool_t:%.+]] = OpTypeBool +; CHECK-DAG: [[boolx2_t:%.+]] = OpTypeVector [[bool_t]] 2 +; CHECK-DAG: [[boolx3_t:%.+]] = OpTypeVector [[bool_t]] 3 + +; CHECK-LABEL: Begin function firstbitlow_i32 +define noundef i32 @firstbitlow_i32(i32 noundef %a) { +entry: +; CHECK: [[a:%.+]] = OpFunctionParameter [[u32_t]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32_t]] [[glsl_450_ext]] FindILsb [[a]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call i32 @llvm.spv.firstbitlow.i32(i32 %a) + ret i32 %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v2xi32 +define noundef <2 x i32> @firstbitlow_v2xi32(<2 x i32> noundef %a) { +entry: +; CHECK: [[a:%.+]] = OpFunctionParameter [[u32x2_t]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x2_t]] [[glsl_450_ext]] FindILsb [[a]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <2 x i32> @llvm.spv.firstbitlow.v2i32(<2 x i32> %a) + ret <2 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v3xi32 +define noundef <3 x i32> @firstbitlow_v3xi32(<3 x i32> noundef %a) { +entry: +; CHECK: [[a:%.+]] = OpFunctionParameter [[u32x3_t]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x3_t]] [[glsl_450_ext]] FindILsb [[a]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <3 x i32> @llvm.spv.firstbitlow.v3i32(<3 x i32> %a) + ret <3 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v4xi32 +define noundef <4 x i32> @firstbitlow_v4xi32(<4 x i32> noundef %a) { +entry: +; CHECK: [[a:%.+]] = OpFunctionParameter [[u32x4_t]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x4_t]] [[glsl_450_ext]] FindILsb [[a]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <4 x i32> @llvm.spv.firstbitlow.v4i32(<4 x i32> %a) + ret <4 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_i16 +define noundef i32 @firstbitlow_i16(i16 noundef %a) { +entry: +; CHECK: [[a16:%.+]] = OpFunctionParameter [[u16_t]] +; CHECK: [[a32:%.+]] = OpUConvert [[u32_t]] [[a16]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32_t]] [[glsl_450_ext]] FindILsb [[a32]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call i32 @llvm.spv.firstbitlow.i16(i16 %a) + ret i32 %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v2i16 +define noundef <2 x i32> @firstbitlow_v2i16(<2 x i16> noundef %a) { +entry: +; CHECK: [[a16:%.+]] = OpFunctionParameter [[u16x2_t]] +; CHECK: [[a32:%.+]] = OpUConvert [[u32x2_t]] [[a16]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x2_t]] [[glsl_450_ext]] FindILsb [[a32]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <2 x i32> @llvm.spv.firstbitlow.v2i16(<2 x i16> %a) + ret <2 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v3xi16 +define noundef <3 x i32> @firstbitlow_v3xi16(<3 x i16> noundef %a) { +entry: +; CHECK: [[a16:%.+]] = OpFunctionParameter [[u16x3_t]] +; CHECK: [[a32:%.+]] = OpUConvert [[u32x3_t]] [[a16]] +; CHECK: [[ret:%.+]] = OpExtInst [[u32x3_t]] [[glsl_450_ext]] FindILsb [[a32]] +; CHECK: OpReturnValue [[ret]] + %elt.firstbitlow = call <3 x i32> @llvm.spv.firstbitlow.v3i16(<3 x i16> %a) + ret <3 x i32> %elt.firstbitlow +} + +; CHECK-LABEL: Begin function firstbitlow_v4xi16 +define noundef <4 x i32> @firstbitlow_v4xi16(
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3178,98 +3178,74 @@ bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( Register ResVReg, const SPIRVType *ResType, MachineInstr &I, Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + // SPIR-V only allow vecs of size 2,3,4. Calling with a larger vec requires + // creating a param reg and return reg with an invalid vec size. If that is + // resolved then this function is valid for vectors of any component size. unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); - bool ZeroAsNull = STI.isOpenCLEnv(); - Register ConstIntZero = - GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); - unsigned LeftComponentCount = ComponentCount / 2; - unsigned RightComponentCount = ComponentCount - LeftComponentCount; - bool LeftIsVector = LeftComponentCount > 1; + assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops"); - // Split the SrcReg in half into 2 smaller vec registers - // (ie i64x4 -> i64x2, i64x2) + bool ZeroAsNull = STI.isOpenCLEnv(); MachineIRBuilder MIRBuilder(I); - SPIRVType *OpType = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); - SPIRVType *LeftVecOpType; - SPIRVType *LeftVecResType; - if (LeftIsVector) { -LeftVecOpType = -GR.getOrCreateSPIRVVectorType(OpType, LeftComponentCount, MIRBuilder); -LeftVecResType = -GR.getOrCreateSPIRVVectorType(BaseType, LeftComponentCount, MIRBuilder); - } else { -LeftVecOpType = OpType; -LeftVecResType = BaseType; - } - - SPIRVType *RightVecOpType = - GR.getOrCreateSPIRVVectorType(OpType, RightComponentCount, MIRBuilder); - SPIRVType *RightVecResType = - GR.getOrCreateSPIRVVectorType(BaseType, RightComponentCount, MIRBuilder); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + SPIRVType *I64Type = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); + SPIRVType *I64x2Type = GR.getOrCreateSPIRVVectorType(I64Type, 2, MIRBuilder); + SPIRVType *Vec2ResType = + GR.getOrCreateSPIRVVectorType(BaseType, 2, MIRBuilder); - Register LeftSideIn = - MRI->createVirtualRegister(GR.getRegClass(LeftVecOpType)); - Register RightSideIn = - MRI->createVirtualRegister(GR.getRegClass(RightVecOpType)); + std::vector PartialRegs; - bool Result; + // Loops 0, 2, 4, ... but stops one loop early when ComponentCount is odd + unsigned CurrentComponent = 0; + for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) { +Register SubVecReg = MRI->createVirtualRegister(GR.getRegClass(I64x2Type)); - // Extract the left half from the SrcReg into LeftSideIn - // accounting for the special case when it only has one element - if (LeftIsVector) { auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle)) - .addDef(LeftSideIn) - .addUse(GR.getSPIRVTypeID(LeftVecOpType)) + .addDef(SubVecReg) + .addUse(GR.getSPIRVTypeID(I64x2Type)) .addUse(SrcReg) // Per the spec, repeat the vector if only one vec is needed .addUse(SrcReg); -for (unsigned J = 0; J < LeftComponentCount; J++) { - MIB.addImm(J); -} +MIB.addImm(CurrentComponent); +MIB.addImm(CurrentComponent + 1); -Result = MIB.constrainAllUses(TII, TRI, RBI); - } else { -Result = -selectOpWithSrcs(LeftSideIn, LeftVecOpType, I, {SrcReg, ConstIntZero}, - SPIRV::OpVectorExtractDynamic); - } +if (!MIB.constrainAllUses(TII, TRI, RBI)) + return false; - // Extract the right half from the SrcReg into RightSideIn. - // Right will always be a vector since the only time one element is left is - // when Component == 3, and in that case Left is one element. - auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), - TII.get(SPIRV::OpVectorShuffle)) - .addDef(RightSideIn) - .addUse(GR.getSPIRVTypeID(RightVecOpType)) - .addUse(SrcReg) - // Per the spec, repeat the vector if only one vec is needed - .addUse(SrcReg); +Register SubVecBitSetReg = V-FEXrt wrote: uhh I think so? Its hard to give this thing a precise name. This is the register that holds the firstbitlow/high result for each of the sub/split vectors extracted from the input vector https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3178,98 +3178,74 @@ bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( Register ResVReg, const SPIRVType *ResType, MachineInstr &I, Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + // SPIR-V only allow vecs of size 2,3,4. Calling with a larger vec requires + // creating a param reg and return reg with an invalid vec size. If that is + // resolved then this function is valid for vectors of any component size. unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); - bool ZeroAsNull = STI.isOpenCLEnv(); - Register ConstIntZero = - GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); - unsigned LeftComponentCount = ComponentCount / 2; - unsigned RightComponentCount = ComponentCount - LeftComponentCount; - bool LeftIsVector = LeftComponentCount > 1; + assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops"); - // Split the SrcReg in half into 2 smaller vec registers - // (ie i64x4 -> i64x2, i64x2) + bool ZeroAsNull = STI.isOpenCLEnv(); MachineIRBuilder MIRBuilder(I); - SPIRVType *OpType = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); - SPIRVType *LeftVecOpType; - SPIRVType *LeftVecResType; - if (LeftIsVector) { -LeftVecOpType = -GR.getOrCreateSPIRVVectorType(OpType, LeftComponentCount, MIRBuilder); -LeftVecResType = -GR.getOrCreateSPIRVVectorType(BaseType, LeftComponentCount, MIRBuilder); - } else { -LeftVecOpType = OpType; -LeftVecResType = BaseType; - } - - SPIRVType *RightVecOpType = - GR.getOrCreateSPIRVVectorType(OpType, RightComponentCount, MIRBuilder); - SPIRVType *RightVecResType = - GR.getOrCreateSPIRVVectorType(BaseType, RightComponentCount, MIRBuilder); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + SPIRVType *I64Type = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); + SPIRVType *I64x2Type = GR.getOrCreateSPIRVVectorType(I64Type, 2, MIRBuilder); + SPIRVType *Vec2ResType = + GR.getOrCreateSPIRVVectorType(BaseType, 2, MIRBuilder); - Register LeftSideIn = - MRI->createVirtualRegister(GR.getRegClass(LeftVecOpType)); - Register RightSideIn = - MRI->createVirtualRegister(GR.getRegClass(RightVecOpType)); + std::vector PartialRegs; - bool Result; + // Loops 0, 2, 4, ... but stops one loop early when ComponentCount is odd + unsigned CurrentComponent = 0; + for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) { +Register SubVecReg = MRI->createVirtualRegister(GR.getRegClass(I64x2Type)); - // Extract the left half from the SrcReg into LeftSideIn - // accounting for the special case when it only has one element - if (LeftIsVector) { auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle)) - .addDef(LeftSideIn) - .addUse(GR.getSPIRVTypeID(LeftVecOpType)) + .addDef(SubVecReg) + .addUse(GR.getSPIRVTypeID(I64x2Type)) .addUse(SrcReg) // Per the spec, repeat the vector if only one vec is needed .addUse(SrcReg); -for (unsigned J = 0; J < LeftComponentCount; J++) { - MIB.addImm(J); -} +MIB.addImm(CurrentComponent); +MIB.addImm(CurrentComponent + 1); -Result = MIB.constrainAllUses(TII, TRI, RBI); - } else { -Result = -selectOpWithSrcs(LeftSideIn, LeftVecOpType, I, {SrcReg, ConstIntZero}, - SPIRV::OpVectorExtractDynamic); - } +if (!MIB.constrainAllUses(TII, TRI, RBI)) + return false; - // Extract the right half from the SrcReg into RightSideIn. - // Right will always be a vector since the only time one element is left is - // when Component == 3, and in that case Left is one element. - auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), - TII.get(SPIRV::OpVectorShuffle)) - .addDef(RightSideIn) - .addUse(GR.getSPIRVTypeID(RightVecOpType)) - .addUse(SrcReg) - // Per the spec, repeat the vector if only one vec is needed - .addUse(SrcReg); +Register SubVecBitSetReg = V-FEXrt wrote: Do you have a name in mind? Would love to have something better. If not I can basically just add the above as a comment https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3178,98 +3178,74 @@ bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( Register ResVReg, const SPIRVType *ResType, MachineInstr &I, Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + // SPIR-V only allow vecs of size 2,3,4. Calling with a larger vec requires + // creating a param reg and return reg with an invalid vec size. If that is + // resolved then this function is valid for vectors of any component size. unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); - bool ZeroAsNull = STI.isOpenCLEnv(); - Register ConstIntZero = - GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); - unsigned LeftComponentCount = ComponentCount / 2; - unsigned RightComponentCount = ComponentCount - LeftComponentCount; - bool LeftIsVector = LeftComponentCount > 1; + assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops"); - // Split the SrcReg in half into 2 smaller vec registers - // (ie i64x4 -> i64x2, i64x2) + bool ZeroAsNull = STI.isOpenCLEnv(); MachineIRBuilder MIRBuilder(I); - SPIRVType *OpType = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); - SPIRVType *LeftVecOpType; - SPIRVType *LeftVecResType; - if (LeftIsVector) { -LeftVecOpType = -GR.getOrCreateSPIRVVectorType(OpType, LeftComponentCount, MIRBuilder); -LeftVecResType = -GR.getOrCreateSPIRVVectorType(BaseType, LeftComponentCount, MIRBuilder); - } else { -LeftVecOpType = OpType; -LeftVecResType = BaseType; - } - - SPIRVType *RightVecOpType = - GR.getOrCreateSPIRVVectorType(OpType, RightComponentCount, MIRBuilder); - SPIRVType *RightVecResType = - GR.getOrCreateSPIRVVectorType(BaseType, RightComponentCount, MIRBuilder); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + SPIRVType *I64Type = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); + SPIRVType *I64x2Type = GR.getOrCreateSPIRVVectorType(I64Type, 2, MIRBuilder); + SPIRVType *Vec2ResType = + GR.getOrCreateSPIRVVectorType(BaseType, 2, MIRBuilder); - Register LeftSideIn = - MRI->createVirtualRegister(GR.getRegClass(LeftVecOpType)); - Register RightSideIn = - MRI->createVirtualRegister(GR.getRegClass(RightVecOpType)); + std::vector PartialRegs; - bool Result; + // Loops 0, 2, 4, ... but stops one loop early when ComponentCount is odd + unsigned CurrentComponent = 0; + for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) { V-FEXrt wrote: The 2 case is avoided in `selectFirstBitSet64` ```c++ if (ComponentCount > 2) { return selectFirstBitSet64Overflow(ResVReg, ResType, I, SrcReg, BitSetOpcode, SwapPrimarySide); } ``` I didn't want to artificially not support/special case size 2 since it makes the code more complicated and it's already handled by the caller https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
https://github.com/V-FEXrt edited https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL][SPIRV][DXIL] Implement `WaveActiveMax` intrinsic (PR #123428)
@@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ +// RUN: spirv-pc-vulkan-compute %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV + +// Test basic lowering to runtime function call. + +// CHECK-LABEL: test_int +int test_int(int expr) { + // CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.reduce.max.i32([[TY]] %[[#]]) + // CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.reduce.max.i32([[TY]] %[[#]]) + // CHECK: ret [[TY]] %[[RET]] + return WaveActiveMax(expr); +} + +// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.reduce.max.i32([[TY]]) #[[#attr:]] +// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.reduce.max.i32([[TY]]) #[[#attr:]] + +// CHECK-LABEL: test_uint64_t +uint64_t test_uint64_t(uint64_t expr) { + // CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.reduce.umax.i64([[TY]] %[[#]]) + // CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.reduce.umax.i64([[TY]] %[[#]]) + // CHECK: ret [[TY]] %[[RET]] + return WaveActiveMax(expr); +} + +// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.reduce.umax.i64([[TY]]) #[[#attr:]] +// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.reduce.umax.i64([[TY]]) #[[#attr:]] + +// Test basic lowering to runtime function call with array and float value. + +// CHECK-LABEL: test_floatv4 +float4 test_floatv4(float4 expr) { + // CHECK-SPIRV: %[[RET1:.*]] = call reassoc nnan ninf nsz arcp afn spir_func [[TY1:.*]] @llvm.spv.wave.reduce.max.v4f32([[TY1]] %[[#]] + // CHECK-DXIL: %[[RET1:.*]] = call reassoc nnan ninf nsz arcp afn [[TY1:.*]] @llvm.dx.wave.reduce.max.v4f32([[TY1]] %[[#]]) + // CHECK: ret [[TY1]] %[[RET1]] + return WaveActiveMax(expr); +} + +// CHECK-DXIL: declare [[TY1]] @llvm.dx.wave.reduce.max.v4f32([[TY1]]) #[[#attr]] +// CHECK-SPIRV: declare spir_func [[TY1]] @llvm.spv.wave.reduce.max.v4f32([[TY1]]) #[[#attr]] + +// CHECK: attributes #[[#attr]] = {{{.*}} convergent {{.*}}} + V-FEXrt wrote: oh wait nvm, I got confused. This is the post function stuff I think https://github.com/llvm/llvm-project/pull/123428 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL][SPIRV][DXIL] Implement `WaveActiveMax` intrinsic (PR #123428)
@@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ +// RUN: spirv-pc-vulkan-compute %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV + +// Test basic lowering to runtime function call. + +// CHECK-LABEL: test_int +int test_int(int expr) { + // CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.reduce.max.i32([[TY]] %[[#]]) + // CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.reduce.max.i32([[TY]] %[[#]]) + // CHECK: ret [[TY]] %[[RET]] + return WaveActiveMax(expr); +} + +// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.reduce.max.i32([[TY]]) #[[#attr:]] +// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.reduce.max.i32([[TY]]) #[[#attr:]] + +// CHECK-LABEL: test_uint64_t +uint64_t test_uint64_t(uint64_t expr) { + // CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.reduce.umax.i64([[TY]] %[[#]]) + // CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.reduce.umax.i64([[TY]] %[[#]]) + // CHECK: ret [[TY]] %[[RET]] + return WaveActiveMax(expr); +} + +// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.reduce.umax.i64([[TY]]) #[[#attr:]] +// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.reduce.umax.i64([[TY]]) #[[#attr:]] + +// Test basic lowering to runtime function call with array and float value. + +// CHECK-LABEL: test_floatv4 +float4 test_floatv4(float4 expr) { + // CHECK-SPIRV: %[[RET1:.*]] = call reassoc nnan ninf nsz arcp afn spir_func [[TY1:.*]] @llvm.spv.wave.reduce.max.v4f32([[TY1]] %[[#]] + // CHECK-DXIL: %[[RET1:.*]] = call reassoc nnan ninf nsz arcp afn [[TY1:.*]] @llvm.dx.wave.reduce.max.v4f32([[TY1]] %[[#]]) + // CHECK: ret [[TY1]] %[[RET1]] + return WaveActiveMax(expr); +} + +// CHECK-DXIL: declare [[TY1]] @llvm.dx.wave.reduce.max.v4f32([[TY1]]) #[[#attr]] +// CHECK-SPIRV: declare spir_func [[TY1]] @llvm.spv.wave.reduce.max.v4f32([[TY1]]) #[[#attr]] + +// CHECK: attributes #[[#attr]] = {{{.*}} convergent {{.*}}} + V-FEXrt wrote: Is this leftover cruft? https://github.com/llvm/llvm-project/pull/123428 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,133 @@ +//=== ParseHLSLRootSignatureTest.cpp - Parse Root Signature tests -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" + +#include "clang/Parse/ParseHLSLRootSignature.h" +#include "gtest/gtest.h" + +using namespace llvm::hlsl::root_signature; +using namespace clang; + +namespace { + +// The test fixture. +class ParseHLSLRootSignatureTest : public ::testing::Test { +protected: + ParseHLSLRootSignatureTest() + : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), +Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), +SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) { +TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; +Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); + } + + std::unique_ptr CreatePP(StringRef Source, + TrivialModuleLoader &ModLoader) { +std::unique_ptr Buf = +llvm::MemoryBuffer::getMemBuffer(Source); +SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); + +HeaderSearch HeaderInfo(std::make_shared(), SourceMgr, +Diags, LangOpts, Target.get()); +std::unique_ptr PP = std::make_unique( +std::make_shared(), Diags, LangOpts, SourceMgr, +HeaderInfo, ModLoader, +/*IILookup =*/nullptr, +/*OwnsHeaderSearch =*/false); +PP->Initialize(*Target); +PP->EnterMainSourceFile(); +return PP; + } + + void CheckTokens(SmallVector &Computed, + SmallVector &Expected) { +ASSERT_EQ(Computed.size(), Expected.size()); +for (unsigned I = 0, E = Expected.size(); I != E; ++I) { + ASSERT_EQ(Computed[I].Kind, Expected[I]); +} + } + + FileSystemOptions FileMgrOpts; + FileManager FileMgr; + IntrusiveRefCntPtr DiagID; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + LangOptions LangOpts; + std::shared_ptr TargetOpts; + IntrusiveRefCntPtr Target; +}; + +TEST_F(ParseHLSLRootSignatureTest, LexValidTokensTest) { + const llvm::StringLiteral Source = R"cc( +-42 + +b0 t43 u987 s234 + +(),|= + +DescriptorTable + +CBV SRV UAV Sampler +space visibility flags +numDescriptors offset + +DESCRIPTOR_RANGE_OFFSET_APPEND + +DATA_VOLATILE +DATA_STATIC_WHILE_SET_AT_EXECUTE +DATA_STATIC +DESCRIPTORS_VOLATILE +DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS + +shader_visibility_all +shader_visibility_vertex +shader_visibility_hull +shader_visibility_domain +shader_visibility_geometry +shader_visibility_pixel +shader_visibility_amplification +shader_visibility_mesh + +42 +42 + )cc"; + + TrivialModuleLoader ModLoader; + auto PP = CreatePP(Source, ModLoader); + auto TokLoc = SourceLocation(); + + RootSignatureLexer Lexer(Source, TokLoc, *PP); + + SmallVector Tokens = { + RootSignatureToken() // invalid token for completeness + }; + ASSERT_FALSE(Lexer.Lex(Tokens)); V-FEXrt wrote: No, I'm happy to punt it https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,153 @@ +#include "clang/Parse/ParseHLSLRootSignature.h" + +namespace llvm { +namespace hlsl { +namespace root_signature { + +// Lexer Definitions + +static bool IsNumberChar(char C) { + // TODO: extend for float support with or without hexadecimal/exponent V-FEXrt wrote: Yep that would be great! https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,133 @@ +//=== ParseHLSLRootSignatureTest.cpp - Parse Root Signature tests -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" + +#include "clang/Parse/ParseHLSLRootSignature.h" +#include "gtest/gtest.h" + +using namespace llvm::hlsl::root_signature; +using namespace clang; + +namespace { + +// The test fixture. +class ParseHLSLRootSignatureTest : public ::testing::Test { +protected: + ParseHLSLRootSignatureTest() + : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), +Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), +SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) { +TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; +Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); + } + + std::unique_ptr CreatePP(StringRef Source, + TrivialModuleLoader &ModLoader) { +std::unique_ptr Buf = +llvm::MemoryBuffer::getMemBuffer(Source); +SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); + +HeaderSearch HeaderInfo(std::make_shared(), SourceMgr, +Diags, LangOpts, Target.get()); +std::unique_ptr PP = std::make_unique( +std::make_shared(), Diags, LangOpts, SourceMgr, +HeaderInfo, ModLoader, +/*IILookup =*/nullptr, +/*OwnsHeaderSearch =*/false); +PP->Initialize(*Target); +PP->EnterMainSourceFile(); +return PP; + } + + void CheckTokens(SmallVector &Computed, + SmallVector &Expected) { +ASSERT_EQ(Computed.size(), Expected.size()); +for (unsigned I = 0, E = Expected.size(); I != E; ++I) { + ASSERT_EQ(Computed[I].Kind, Expected[I]); +} + } + + FileSystemOptions FileMgrOpts; + FileManager FileMgr; + IntrusiveRefCntPtr DiagID; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + LangOptions LangOpts; + std::shared_ptr TargetOpts; + IntrusiveRefCntPtr Target; +}; + +TEST_F(ParseHLSLRootSignatureTest, LexValidTokensTest) { + const llvm::StringLiteral Source = R"cc( +-42 + +b0 t43 u987 s234 + +(),|= + +DescriptorTable + +CBV SRV UAV Sampler +space visibility flags +numDescriptors offset + +DESCRIPTOR_RANGE_OFFSET_APPEND + +DATA_VOLATILE +DATA_STATIC_WHILE_SET_AT_EXECUTE +DATA_STATIC +DESCRIPTORS_VOLATILE +DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS + +shader_visibility_all +shader_visibility_vertex +shader_visibility_hull +shader_visibility_domain +shader_visibility_geometry +shader_visibility_pixel +shader_visibility_amplification +shader_visibility_mesh + +42 +42 + )cc"; + + TrivialModuleLoader ModLoader; + auto PP = CreatePP(Source, ModLoader); + auto TokLoc = SourceLocation(); + + RootSignatureLexer Lexer(Source, TokLoc, *PP); + + SmallVector Tokens = { + RootSignatureToken() // invalid token for completeness + }; + ASSERT_FALSE(Lexer.Lex(Tokens)); V-FEXrt wrote: Would be nice to see a more robust set of failure tests https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,133 @@ +//=== ParseHLSLRootSignatureTest.cpp - Parse Root Signature tests -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" + +#include "clang/Parse/ParseHLSLRootSignature.h" +#include "gtest/gtest.h" + +using namespace llvm::hlsl::root_signature; +using namespace clang; + +namespace { + +// The test fixture. +class ParseHLSLRootSignatureTest : public ::testing::Test { +protected: + ParseHLSLRootSignatureTest() + : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), +Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), +SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) { +TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; +Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); + } + + std::unique_ptr CreatePP(StringRef Source, + TrivialModuleLoader &ModLoader) { +std::unique_ptr Buf = +llvm::MemoryBuffer::getMemBuffer(Source); +SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); + +HeaderSearch HeaderInfo(std::make_shared(), SourceMgr, +Diags, LangOpts, Target.get()); +std::unique_ptr PP = std::make_unique( +std::make_shared(), Diags, LangOpts, SourceMgr, +HeaderInfo, ModLoader, +/*IILookup =*/nullptr, +/*OwnsHeaderSearch =*/false); +PP->Initialize(*Target); +PP->EnterMainSourceFile(); +return PP; + } + + void CheckTokens(SmallVector &Computed, + SmallVector &Expected) { +ASSERT_EQ(Computed.size(), Expected.size()); +for (unsigned I = 0, E = Expected.size(); I != E; ++I) { + ASSERT_EQ(Computed[I].Kind, Expected[I]); +} + } + + FileSystemOptions FileMgrOpts; + FileManager FileMgr; + IntrusiveRefCntPtr DiagID; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + LangOptions LangOpts; + std::shared_ptr TargetOpts; + IntrusiveRefCntPtr Target; +}; + +TEST_F(ParseHLSLRootSignatureTest, LexValidTokensTest) { + const llvm::StringLiteral Source = R"cc( +-42 + +b0 t43 u987 s234 + +(),|= + +DescriptorTable + +CBV SRV UAV Sampler +space visibility flags +numDescriptors offset + +DESCRIPTOR_RANGE_OFFSET_APPEND + +DATA_VOLATILE +DATA_STATIC_WHILE_SET_AT_EXECUTE +DATA_STATIC +DESCRIPTORS_VOLATILE +DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS + +shader_visibility_all +shader_visibility_vertex +shader_visibility_hull +shader_visibility_domain +shader_visibility_geometry +shader_visibility_pixel +shader_visibility_amplification +shader_visibility_mesh + +42 +42 + )cc"; + + TrivialModuleLoader ModLoader; + auto PP = CreatePP(Source, ModLoader); + auto TokLoc = SourceLocation(); + + RootSignatureLexer Lexer(Source, TokLoc, *PP); + + SmallVector Tokens = { + RootSignatureToken() // invalid token for completeness + }; + ASSERT_FALSE(Lexer.Lex(Tokens)); + + SmallVector Expected = { V-FEXrt wrote: Its probably my unfamiliarity with the code but I can't see how this is actually building up the list of expected tokens. Importing the `.def` file here _seems_ strange https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
https://github.com/V-FEXrt approved this pull request. Personally happy with the code at a high level, though it would be best to have someone with domain knowledge also approve https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,153 @@ +#include "clang/Parse/ParseHLSLRootSignature.h" + +namespace llvm { +namespace hlsl { +namespace root_signature { + +// Lexer Definitions + +static bool IsNumberChar(char C) { + // TODO: extend for float support with or without hexadecimal/exponent V-FEXrt wrote: I'm personally not a big fan of untracked TODOs in code. They quickly fall out of context and never get resolved. Would be good to make sure this is tracked as part of an issue if it isn't resolved before merge https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3181,136 +3193,250 @@ Register SPIRVInstructionSelector::buildPointerToResource( return AcReg; } -bool SPIRVInstructionSelector::selectFirstBitHigh16(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; - // zero or sign extend +bool SPIRVInstructionSelector::selectFirstBitSet16( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +unsigned ExtendOpcode, unsigned BitSetOpcode) const { Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); - bool Result = - selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, Opcode); - return Result && selectFirstBitHigh32(ResVReg, ResType, I, ExtReg, IsSigned); + bool Result = selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, + ExtendOpcode); + + return Result && + selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode); } -bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -Register SrcReg, -bool IsSigned) const { - unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb; +bool SPIRVInstructionSelector::selectFirstBitSet32( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode) const { return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) .addDef(ResVReg) .addUse(GR.getSPIRVTypeID(ResType)) .addImm(static_cast(SPIRV::InstructionSet::GLSL_std_450)) - .addImm(Opcode) + .addImm(BitSetOpcode) .addUse(SrcReg) .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + + // SPIR-V only allow vecs of size 2,3,4. Calling with a larger vec requires + // creating a param reg and return reg with an invalid vec size. If that is + // resolved then this function is valid for vectors of any component size. + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops"); + + bool ZeroAsNull = STI.isOpenCLEnv(); V-FEXrt wrote: I see, yeah I don't know. Maybe @spall has context here? A lot of this code was originally pulled from her PR https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,130 @@ +//=== ParseHLSLRootSignatureTest.cpp - Parse Root Signature tests -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" + +#include "clang/Parse/ParseHLSLRootSignature.h" +#include "gtest/gtest.h" + +using namespace llvm::hlsl::root_signature; +using namespace clang; + +namespace { + +// The test fixture. +class ParseHLSLRootSignatureTest : public ::testing::Test { +protected: + ParseHLSLRootSignatureTest() + : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), +Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), +SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) { +TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; +Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); + } + + Preprocessor *CreatePP(StringRef Source, TrivialModuleLoader &ModLoader) { +std::unique_ptr Buf = +llvm::MemoryBuffer::getMemBuffer(Source); +SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); + +HeaderSearch HeaderInfo(std::make_shared(), SourceMgr, +Diags, LangOpts, Target.get()); +Preprocessor *PP = +new Preprocessor(std::make_shared(), Diags, V-FEXrt wrote: imo unless you have a strong reason for it, you should _really_ avoid new/delete and instead use C++ smart pointers for allocating/freeing heap memory. It takes care of the memory management for you and prevents accidental memory leaks. In this case, `std::unique_ptr` would work perfectly https://en.cppreference.com/w/cpp/memory/unique_ptr https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,152 @@ +#include "clang/Parse/ParseHLSLRootSignature.h" + +namespace llvm { +namespace hlsl { +namespace root_signature { + +// Lexer Definitions + +static bool IsPreprocessorNumberChar(char C) { + // TODO: extend for float support with or without hexadecimal/exponent + return isdigit(C); // integer support +} + +bool RootSignatureLexer::LexNumber(RootSignatureToken &Result) { + // NumericLiteralParser does not handle the sign so we will manually apply it + Result.Signed = Buffer.front() == '-'; + if (Result.Signed) +AdvanceBuffer(); + + // Retrieve the possible number + StringRef NumSpelling = Buffer.take_while(IsPreprocessorNumberChar); + + // Parse the numeric value and so semantic checks on its specification + clang::NumericLiteralParser Literal(NumSpelling, SourceLoc, + PP.getSourceManager(), PP.getLangOpts(), + PP.getTargetInfo(), PP.getDiagnostics()); + if (Literal.hadError) +return true; // Error has already been reported so just return + + // Retrieve the number value to store into the token + if (Literal.isIntegerLiteral()) { +Result.Kind = TokenKind::int_literal; + +APSInt X = APSInt(32, Result.Signed); +if (Literal.GetIntegerValue(X)) + return true; // TODO: Report overflow error + +X = Result.Signed ? -X : X; +Result.IntLiteral = (uint32_t)X.getZExtValue(); + } else { +return true; // TODO: report unsupported number literal specification + } + + AdvanceBuffer(NumSpelling.size()); + return false; +} + +bool RootSignatureLexer::Lex(SmallVector &Tokens) { + // Discard any leading whitespace + AdvanceBuffer(Buffer.take_while(isspace).size()); + + while (!Buffer.empty()) { +RootSignatureToken Result; +if (LexToken(Result)) + return true; + +// Successfully Lexed the token so we can store it +Tokens.push_back(Result); + +// Discard any trailing whitespace +AdvanceBuffer(Buffer.take_while(isspace).size()); + } + + return false; +} + +bool RootSignatureLexer::LexToken(RootSignatureToken &Result) { + // Record where this token is in the text for usage in parser diagnostics + Result.TokLoc = SourceLoc; + + char C = Buffer.front(); + + // Punctuators + switch (C) { +#define PUNCTUATOR(X, Y) \ + case Y: { \ +Result.Kind = TokenKind::pu_##X; \ +AdvanceBuffer(); \ +return false; \ + } +#include "clang/Parse/HLSLRootSignatureTokenKinds.def" V-FEXrt wrote: Is there a particular reason you define `PUNCTUATOR` both here and in the `.def` file? It makes the `.def` file harder to follow since the `#define PUNCTUATOR` there isn't actually used https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,152 @@ +#include "clang/Parse/ParseHLSLRootSignature.h" + +namespace llvm { +namespace hlsl { +namespace root_signature { + +// Lexer Definitions + +static bool IsPreprocessorNumberChar(char C) { + // TODO: extend for float support with or without hexadecimal/exponent + return isdigit(C); // integer support +} + +bool RootSignatureLexer::LexNumber(RootSignatureToken &Result) { + // NumericLiteralParser does not handle the sign so we will manually apply it + Result.Signed = Buffer.front() == '-'; + if (Result.Signed) +AdvanceBuffer(); + + // Retrieve the possible number + StringRef NumSpelling = Buffer.take_while(IsPreprocessorNumberChar); + + // Parse the numeric value and so semantic checks on its specification + clang::NumericLiteralParser Literal(NumSpelling, SourceLoc, + PP.getSourceManager(), PP.getLangOpts(), + PP.getTargetInfo(), PP.getDiagnostics()); + if (Literal.hadError) +return true; // Error has already been reported so just return + + // Retrieve the number value to store into the token + if (Literal.isIntegerLiteral()) { +Result.Kind = TokenKind::int_literal; + +APSInt X = APSInt(32, Result.Signed); +if (Literal.GetIntegerValue(X)) + return true; // TODO: Report overflow error + +X = Result.Signed ? -X : X; +Result.IntLiteral = (uint32_t)X.getZExtValue(); + } else { +return true; // TODO: report unsupported number literal specification + } + + AdvanceBuffer(NumSpelling.size()); + return false; +} + +bool RootSignatureLexer::Lex(SmallVector &Tokens) { + // Discard any leading whitespace + AdvanceBuffer(Buffer.take_while(isspace).size()); + + while (!Buffer.empty()) { +RootSignatureToken Result; +if (LexToken(Result)) + return true; + +// Successfully Lexed the token so we can store it +Tokens.push_back(Result); + +// Discard any trailing whitespace +AdvanceBuffer(Buffer.take_while(isspace).size()); + } + + return false; +} + +bool RootSignatureLexer::LexToken(RootSignatureToken &Result) { + // Record where this token is in the text for usage in parser diagnostics + Result.TokLoc = SourceLoc; + + char C = Buffer.front(); + + // Punctuators + switch (C) { +#define PUNCTUATOR(X, Y) \ + case Y: { \ +Result.Kind = TokenKind::pu_##X; \ +AdvanceBuffer(); \ +return false; \ + } +#include "clang/Parse/HLSLRootSignatureTokenKinds.def" V-FEXrt wrote: if it must always be defined before inclusion you could do ``` #ifndef PUNCTUATOR #error some message #endif ``` https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,152 @@ +#include "clang/Parse/ParseHLSLRootSignature.h" + +namespace llvm { +namespace hlsl { +namespace root_signature { + +// Lexer Definitions + +static bool IsPreprocessorNumberChar(char C) { + // TODO: extend for float support with or without hexadecimal/exponent + return isdigit(C); // integer support +} + +bool RootSignatureLexer::LexNumber(RootSignatureToken &Result) { + // NumericLiteralParser does not handle the sign so we will manually apply it + Result.Signed = Buffer.front() == '-'; V-FEXrt wrote: I'm assuming no, but is unary `+` allowed here? https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,152 @@ +#include "clang/Parse/ParseHLSLRootSignature.h" + +namespace llvm { +namespace hlsl { +namespace root_signature { + +// Lexer Definitions + +static bool IsPreprocessorNumberChar(char C) { + // TODO: extend for float support with or without hexadecimal/exponent + return isdigit(C); // integer support +} + +bool RootSignatureLexer::LexNumber(RootSignatureToken &Result) { + // NumericLiteralParser does not handle the sign so we will manually apply it + Result.Signed = Buffer.front() == '-'; + if (Result.Signed) +AdvanceBuffer(); + + // Retrieve the possible number + StringRef NumSpelling = Buffer.take_while(IsPreprocessorNumberChar); + + // Parse the numeric value and so semantic checks on its specification + clang::NumericLiteralParser Literal(NumSpelling, SourceLoc, + PP.getSourceManager(), PP.getLangOpts(), + PP.getTargetInfo(), PP.getDiagnostics()); + if (Literal.hadError) +return true; // Error has already been reported so just return + + // Retrieve the number value to store into the token + if (Literal.isIntegerLiteral()) { +Result.Kind = TokenKind::int_literal; + +APSInt X = APSInt(32, Result.Signed); +if (Literal.GetIntegerValue(X)) + return true; // TODO: Report overflow error + +X = Result.Signed ? -X : X; +Result.IntLiteral = (uint32_t)X.getZExtValue(); + } else { +return true; // TODO: report unsupported number literal specification + } V-FEXrt wrote: nit: invert the condition and early exit ```suggestion if (!Literal.isIntegerLiteral()) { return true; // TODO: report unsupported number literal specification } Result.Kind = TokenKind::int_literal; APSInt X = APSInt(32, Result.Signed); if (Literal.GetIntegerValue(X)) return true; // TODO: Report overflow error X = Result.Signed ? -X : X; Result.IntLiteral = (uint32_t)X.getZExtValue(); ``` https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
https://github.com/V-FEXrt edited https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
https://github.com/V-FEXrt closed https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,152 @@ +#include "clang/Parse/ParseHLSLRootSignature.h" + +namespace llvm { +namespace hlsl { +namespace root_signature { + +// Lexer Definitions + +static bool IsPreprocessorNumberChar(char C) { + // TODO: extend for float support with or without hexadecimal/exponent + return isdigit(C); // integer support +} + +bool RootSignatureLexer::LexNumber(RootSignatureToken &Result) { + // NumericLiteralParser does not handle the sign so we will manually apply it + Result.Signed = Buffer.front() == '-'; + if (Result.Signed) +AdvanceBuffer(); + + // Retrieve the possible number + StringRef NumSpelling = Buffer.take_while(IsPreprocessorNumberChar); + + // Parse the numeric value and so semantic checks on its specification V-FEXrt wrote: typo? ```suggestion // Parse the numeric value and do semantic checks on its specification ``` https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
@@ -0,0 +1,130 @@ +//=== ParseHLSLRootSignatureTest.cpp - Parse Root Signature tests -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" + +#include "clang/Parse/ParseHLSLRootSignature.h" +#include "gtest/gtest.h" + +using namespace llvm::hlsl::root_signature; +using namespace clang; + +namespace { + +// The test fixture. +class ParseHLSLRootSignatureTest : public ::testing::Test { +protected: + ParseHLSLRootSignatureTest() + : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), +Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), +SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) { +TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; +Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); + } + + Preprocessor *CreatePP(StringRef Source, TrivialModuleLoader &ModLoader) { +std::unique_ptr Buf = +llvm::MemoryBuffer::getMemBuffer(Source); +SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); + +HeaderSearch HeaderInfo(std::make_shared(), SourceMgr, +Diags, LangOpts, Target.get()); +Preprocessor *PP = +new Preprocessor(std::make_shared(), Diags, V-FEXrt wrote: I think you can just derefence the `unique_ptr`. Something like `*ptr->get()` https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
https://github.com/V-FEXrt edited https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL][RootSignature] Implement Lexing of DescriptorTables (PR #122981)
https://github.com/V-FEXrt edited https://github.com/llvm/llvm-project/pull/122981 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3181,136 +3193,250 @@ Register SPIRVInstructionSelector::buildPointerToResource( return AcReg; } -bool SPIRVInstructionSelector::selectFirstBitHigh16(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; - // zero or sign extend +bool SPIRVInstructionSelector::selectFirstBitSet16( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +unsigned ExtendOpcode, unsigned BitSetOpcode) const { Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); - bool Result = - selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, Opcode); - return Result && selectFirstBitHigh32(ResVReg, ResType, I, ExtReg, IsSigned); + bool Result = selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, + ExtendOpcode); + + return Result && + selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode); } -bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -Register SrcReg, -bool IsSigned) const { - unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb; +bool SPIRVInstructionSelector::selectFirstBitSet32( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode) const { return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) .addDef(ResVReg) .addUse(GR.getSPIRVTypeID(ResType)) .addImm(static_cast(SPIRV::InstructionSet::GLSL_std_450)) - .addImm(Opcode) + .addImm(BitSetOpcode) .addUse(SrcReg) .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + + // SPIR-V only allow vecs of size 2,3,4. Calling with a larger vec requires + // creating a param reg and return reg with an invalid vec size. If that is + // resolved then this function is valid for vectors of any component size. + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops"); + + bool ZeroAsNull = STI.isOpenCLEnv(); MachineIRBuilder MIRBuilder(I); - SPIRVType *postCastT = - GR.getOrCreateSPIRVVectorType(baseType, 2 * count, MIRBuilder); - Register bitcastReg = MRI->createVirtualRegister(GR.getRegClass(postCastT)); - bool Result = - selectOpWithSrcs(bitcastReg, postCastT, I, {OpReg}, SPIRV::OpBitcast); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + SPIRVType *I64Type = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); + SPIRVType *I64x2Type = GR.getOrCreateSPIRVVectorType(I64Type, 2, MIRBuilder); + SPIRVType *Vec2ResType = + GR.getOrCreateSPIRVVectorType(BaseType, 2, MIRBuilder); + + std::vector PartialRegs; + + // Loops 0, 2, 4, ... but stops one loop early when ComponentCount is odd + unsigned CurrentComponent = 0; + for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) { +// This register holds the firstbitX result for each of the i64x2 vectors +// extracted from SrcReg +Register BitSetResult = +MRI->createVirtualRegister(GR.getRegClass(I64x2Type)); + +auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), + TII.get(SPIRV::OpVectorShuffle)) + .addDef(BitSetResult) + .addUse(GR.getSPIRVTypeID(I64x2Type)) + .addUse(SrcReg) + // Per the spec, repeat the vector if only one vec is needed + .addUse(SrcReg); + +MIB.addImm(CurrentComponent); +MIB.addImm(CurrentComponent + 1); V-FEXrt wrote: Is it not true? The generated op code does list the src vector reg twice ``` ; CHECK: [[high_bits:%.+]] = OpVectorShuffle [[u32x2_t]] [[lsb_bits]] [[lsb_bits]] 0 2 ; CHECK: [[low_bits:%.+]] = OpVecto
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3181,136 +3193,250 @@ Register SPIRVInstructionSelector::buildPointerToResource( return AcReg; } -bool SPIRVInstructionSelector::selectFirstBitHigh16(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; - // zero or sign extend +bool SPIRVInstructionSelector::selectFirstBitSet16( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +unsigned ExtendOpcode, unsigned BitSetOpcode) const { Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); - bool Result = - selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, Opcode); - return Result && selectFirstBitHigh32(ResVReg, ResType, I, ExtReg, IsSigned); + bool Result = selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, + ExtendOpcode); + + return Result && + selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode); } -bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -Register SrcReg, -bool IsSigned) const { - unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb; +bool SPIRVInstructionSelector::selectFirstBitSet32( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode) const { return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) .addDef(ResVReg) .addUse(GR.getSPIRVTypeID(ResType)) .addImm(static_cast(SPIRV::InstructionSet::GLSL_std_450)) - .addImm(Opcode) + .addImm(BitSetOpcode) .addUse(SrcReg) .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + + // SPIR-V only allow vecs of size 2,3,4. Calling with a larger vec requires + // creating a param reg and return reg with an invalid vec size. If that is + // resolved then this function is valid for vectors of any component size. + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops"); + + bool ZeroAsNull = STI.isOpenCLEnv(); MachineIRBuilder MIRBuilder(I); - SPIRVType *postCastT = - GR.getOrCreateSPIRVVectorType(baseType, 2 * count, MIRBuilder); - Register bitcastReg = MRI->createVirtualRegister(GR.getRegClass(postCastT)); - bool Result = - selectOpWithSrcs(bitcastReg, postCastT, I, {OpReg}, SPIRV::OpBitcast); + SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); + SPIRVType *I64Type = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); + SPIRVType *I64x2Type = GR.getOrCreateSPIRVVectorType(I64Type, 2, MIRBuilder); + SPIRVType *Vec2ResType = + GR.getOrCreateSPIRVVectorType(BaseType, 2, MIRBuilder); + + std::vector PartialRegs; + + // Loops 0, 2, 4, ... but stops one loop early when ComponentCount is odd + unsigned CurrentComponent = 0; + for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) { +// This register holds the firstbitX result for each of the i64x2 vectors +// extracted from SrcReg +Register BitSetResult = +MRI->createVirtualRegister(GR.getRegClass(I64x2Type)); + +auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), + TII.get(SPIRV::OpVectorShuffle)) + .addDef(BitSetResult) + .addUse(GR.getSPIRVTypeID(I64x2Type)) + .addUse(SrcReg) + // Per the spec, repeat the vector if only one vec is needed + .addUse(SrcReg); + +MIB.addImm(CurrentComponent); +MIB.addImm(CurrentComponent + 1); V-FEXrt wrote: Well, I suppose its not true that you _have_ to set the second vector to the first but you have to set _something_ and setting the same thing works because you always have the first. But that causes
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
https://github.com/V-FEXrt edited https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3181,136 +3193,250 @@ Register SPIRVInstructionSelector::buildPointerToResource( return AcReg; } -bool SPIRVInstructionSelector::selectFirstBitHigh16(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; - // zero or sign extend +bool SPIRVInstructionSelector::selectFirstBitSet16( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +unsigned ExtendOpcode, unsigned BitSetOpcode) const { Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); - bool Result = - selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, Opcode); - return Result && selectFirstBitHigh32(ResVReg, ResType, I, ExtReg, IsSigned); + bool Result = selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, + ExtendOpcode); + + return Result && + selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode); } -bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -Register SrcReg, -bool IsSigned) const { - unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb; +bool SPIRVInstructionSelector::selectFirstBitSet32( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode) const { return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) .addDef(ResVReg) .addUse(GR.getSPIRVTypeID(ResType)) .addImm(static_cast(SPIRV::InstructionSet::GLSL_std_450)) - .addImm(Opcode) + .addImm(BitSetOpcode) .addUse(SrcReg) .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + + // SPIR-V only allow vecs of size 2,3,4. Calling with a larger vec requires + // creating a param reg and return reg with an invalid vec size. If that is + // resolved then this function is valid for vectors of any component size. + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops"); + + bool ZeroAsNull = STI.isOpenCLEnv(); V-FEXrt wrote: > If this is only used in 1 place, we should move it closer to the use. Yeah sorry, it got moved during the loop refactor > why can't we use OpConstantNull in Vulkan looking into it https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
https://github.com/V-FEXrt edited https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
@@ -3181,136 +3193,250 @@ Register SPIRVInstructionSelector::buildPointerToResource( return AcReg; } -bool SPIRVInstructionSelector::selectFirstBitHigh16(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; - // zero or sign extend +bool SPIRVInstructionSelector::selectFirstBitSet16( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +unsigned ExtendOpcode, unsigned BitSetOpcode) const { Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); - bool Result = - selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, Opcode); - return Result && selectFirstBitHigh32(ResVReg, ResType, I, ExtReg, IsSigned); + bool Result = selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, + ExtendOpcode); + + return Result && + selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode); } -bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -Register SrcReg, -bool IsSigned) const { - unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb; +bool SPIRVInstructionSelector::selectFirstBitSet32( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode) const { return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) .addDef(ResVReg) .addUse(GR.getSPIRVTypeID(ResType)) .addImm(static_cast(SPIRV::InstructionSet::GLSL_std_450)) - .addImm(Opcode) + .addImm(BitSetOpcode) .addUse(SrcReg) .constrainAllUses(TII, TRI, RBI); } -bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg, -const SPIRVType *ResType, -MachineInstr &I, -bool IsSigned) const { - Register OpReg = I.getOperand(2).getReg(); - // 1. split our int64 into 2 pieces using a bitcast - unsigned count = GR.getScalarOrVectorComponentCount(ResType); - SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType); +bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( +Register ResVReg, const SPIRVType *ResType, MachineInstr &I, +Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { + + // SPIR-V only allow vecs of size 2,3,4. Calling with a larger vec requires + // creating a param reg and return reg with an invalid vec size. If that is + // resolved then this function is valid for vectors of any component size. + unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); + assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops"); + + bool ZeroAsNull = STI.isOpenCLEnv(); V-FEXrt wrote: Looks like it does bottom out in `OpConstantNull` https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp#L347 https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL] Implement HLSL Flat casting (excluding splat cases) (PR #118842)
@@ -6358,3 +6359,89 @@ RValue CodeGenFunction::EmitPseudoObjectRValue(const PseudoObjectExpr *E, LValue CodeGenFunction::EmitPseudoObjectLValue(const PseudoObjectExpr *E) { return emitPseudoObjectExpr(*this, E, true, AggValueSlot::ignored()).LV; } + +void CodeGenFunction::FlattenAccessAndType( +Address Addr, QualType AddrType, +SmallVectorImpl> &AccessList, +SmallVectorImpl &FlatTypes) { + // WorkList is list of type we are processing + the Index List to access + // the field of that type in Addr for use in a GEP + llvm::SmallVector>, +16> + WorkList; + llvm::IntegerType *IdxTy = llvm::IntegerType::get(getLLVMContext(), 32); + WorkList.push_back( + {AddrType, + {llvm::ConstantInt::get( + IdxTy, + 0)}}); // Addr should be a pointer so we need to 'dereference' it + + while (!WorkList.empty()) { +std::pair> P = +WorkList.pop_back_val(); +QualType T = P.first; +llvm::SmallVector IdxList = P.second; +T = T.getCanonicalType().getUnqualifiedType(); +assert(!isa(T) && "Matrix types not yet supported in HLSL"); +if (const auto *CAT = dyn_cast(T)) { + uint64_t Size = CAT->getZExtSize(); + for (int64_t i = Size - 1; i > -1; i--) { V-FEXrt wrote: nit: `i` should be `I` https://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly aside: At least for my setup, using a lower case, even in loops, raises a warning https://github.com/llvm/llvm-project/pull/118842 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL] Implement HLSL Flat casting (excluding splat cases) (PR #118842)
@@ -2412,6 +2412,102 @@ bool SemaHLSL::CheckCompatibleParameterABI(FunctionDecl *New, return HadError; } +// Generally follows PerformScalarCast, with cases reordered for +// clarity of what types are supported +bool SemaHLSL::CanPerformScalarCast(QualType SrcTy, QualType DestTy) { + + if (SemaRef.getASTContext().hasSameUnqualifiedType(SrcTy, DestTy)) +return true; + + switch (Type::ScalarTypeKind SrcKind = SrcTy->getScalarTypeKind()) { + case Type::STK_Bool: // casting from bool is like casting from an integer + case Type::STK_Integral: +switch (DestTy->getScalarTypeKind()) { +case Type::STK_Bool: +case Type::STK_Integral: +case Type::STK_Floating: + return true; +case Type::STK_CPointer: +case Type::STK_ObjCObjectPointer: +case Type::STK_BlockPointer: +case Type::STK_MemberPointer: + llvm_unreachable("HLSL doesn't support pointers."); +case Type::STK_IntegralComplex: +case Type::STK_FloatingComplex: + llvm_unreachable("HLSL doesn't support complex types."); +case Type::STK_FixedPoint: + llvm_unreachable("HLSL doesn't support fixed point types."); +} +llvm_unreachable("Should have returned before this"); + + case Type::STK_Floating: +switch (DestTy->getScalarTypeKind()) { +case Type::STK_Floating: +case Type::STK_Bool: +case Type::STK_Integral: + return true; +case Type::STK_FloatingComplex: +case Type::STK_IntegralComplex: + llvm_unreachable("HLSL doesn't support complex types."); +case Type::STK_FixedPoint: + llvm_unreachable("HLSL doesn't support fixed point types."); +case Type::STK_CPointer: +case Type::STK_ObjCObjectPointer: +case Type::STK_BlockPointer: +case Type::STK_MemberPointer: + llvm_unreachable("HLSL doesn't support pointers."); +} +llvm_unreachable("Should have returned before this"); + + case Type::STK_MemberPointer: + case Type::STK_CPointer: + case Type::STK_BlockPointer: + case Type::STK_ObjCObjectPointer: +llvm_unreachable("HLSL doesn't support pointers."); + + case Type::STK_FixedPoint: +llvm_unreachable("HLSL doesn't support fixed point types."); + + case Type::STK_FloatingComplex: + case Type::STK_IntegralComplex: +llvm_unreachable("HLSL doesn't support complex types."); + } + + llvm_unreachable("Unhandled scalar cast"); +} + +// Can we perform an HLSL Flattened cast? +// TODO: update this code when matrices are added V-FEXrt wrote: idk if this is something llvm has, but other projects I've worked on will tie "future todos" like this to an issue somewhere so they are easier to find later. If that's something llvm does then this todo would be good to associate with an issue https://github.com/llvm/llvm-project/pull/118842 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL] Make bool in hlsl i32 (PR #122977)
https://github.com/V-FEXrt approved this pull request. https://github.com/llvm/llvm-project/pull/122977 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL] Implement elementwise firstbitlow builtin (PR #116858)
V-FEXrt wrote: Yeah I figured they weren't broken by me but I had assumed I needed all green before merging so was waiting for the fix to make it into main but happy to merge as is if that's acceptable https://github.com/llvm/llvm-project/pull/116858 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL] Implement HLSL intialization list support (PR #123141)
https://github.com/V-FEXrt approved this pull request. https://github.com/llvm/llvm-project/pull/123141 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL] Implement HLSL intialization list support (PR #123141)
@@ -1730,6 +1731,16 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( } #endif + // HLSL initialization lists in the AST are an expansion which can contain + // side-effecting expressions wrapped in opaque value expressions. To properly + // emit these we need to emit the opaque values before we emit the argument + // expressions themselves. This is a little hacky, but it prevents us needing + // to do a bigger AST-level change for a language feature that we need + // deprecate in the near future. V-FEXrt wrote: Can you/should you reference an issue here to link this to the "future deprecation"? https://github.com/llvm/llvm-project/pull/123141 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL] Implement HLSL intialization list support (PR #123141)
@@ -3173,9 +3173,18 @@ bool SemaHLSL::TransformInitList(const InitializedEntity &Entity, BuildFlattenedTypeList(InitTy, DestTypes); llvm::SmallVector ArgExprs; - for (Expr *Arg : Init->inits()) -if (!BuildInitializerList(SemaRef, Ctx, Arg, ArgExprs, DestTypes)) + for (unsigned I = 0; I < Init->getNumInits(); ++I) { +Expr *E = Init->getInit(I); +if (E->HasSideEffects(Ctx)) { + QualType Ty = E->getType(); + if (auto *RTy = Ty->getAs()) +E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue()); V-FEXrt wrote: Unless there is some magic I'm missing, this is memory leak right? 3182 reassigns `E` without freeing? Does `OpaqueValueExpr` take ownership of the old `E`? https://github.com/llvm/llvm-project/pull/123141 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [HLSL] Implement HLSL splatting (PR #118992)
https://github.com/V-FEXrt approved this pull request. https://github.com/llvm/llvm-project/pull/118992 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits