Skip to content

Implement the select HLSL Function #75377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
9 tasks
Tracked by #99235 ...
llvm-beanz opened this issue Dec 13, 2023 · 3 comments
Closed
9 tasks
Tracked by #99235 ...

Implement the select HLSL Function #75377

llvm-beanz opened this issue Dec 13, 2023 · 3 comments
Assignees
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" HLSL HLSL Language Support

Comments

@llvm-beanz
Copy link
Collaborator

llvm-beanz commented Dec 13, 2023

HLSL 2021 introduced the select intrinsic as a replacement for the ternary operator on vector types.

The select intrinsic has the following approximate forms:

template<typename T, int Sz>
void select(vector<bool, Sz> Conds, vector<T, Sz> TrueVals, vector<T, Sz> FalseVals) {
  vector<T, Sz> Result;
  for (int I = 0; I < Sz; ++I) {
    if (Conds[I])
      Result[I] = TrueVals[I];
    else
      Result[I] = FalseVals[I];
  }
  return Result;
}

template<typename T>
void select(bool Cond, T TrueVal, T FalseVal) {
  if (T)
    return TrueVal;
  return FalseVal;
}

The vector case can lower to a shufflevector mask:

template<typename T, int Sz>
void select(vector<bool, Sz> Conds, vector<T, Sz> TrueVals, vector<T, Sz> FalseVals) {
  vector<int, Sz> Mask;
  for (int I = 0; I < Sz; ++I) {
    Mask[I] = I;
    if (!Conds[I])
      Mask[I] += Sz;
  }
  return __builtin_shufflevector(TrueVals, FalseVals, Mask);
}

Acceptance Criteria
Implementation of the select intrinsic in the HLSL builtin headers and corresponding lowering to LLVM IR with appropriate test coverage.

  • Implement select clang builtin,
  • Link select clang builtin with hlsl_intrinsics.h
  • Add sema checks for select to CheckHLSLBuiltinFunctionCall in SemaChecking.cpp
  • Add codegen for select to EmitHLSLBuiltinExpr in CGBuiltin.cpp
  • Add codegen tests to clang/test/CodeGenHLSL/builtins/select.hlsl
  • Add sema tests to clang/test/SemaHLSL/BuiltIns/select-errors.hlsl
  • Create the int_spv_select intrinsic in IntrinsicsSPIRV.td
  • In SPIRVInstructionSelector.cpp create the select lowering and map it to int_spv_select in SPIRVInstructionSelector::selectIntrinsic.
  • Create SPIR-V backend test case in llvm/test/CodeGen/SPIRV/hlsl-intrinsics/select.ll

DirectX

There were no DXIL opcodes found for select.

SPIR-V

OpSelect:

Description:

Select between two objects. Before version 1.4, results are only
computed per component.

Before version 1.4, Result Type must be a pointer, scalar, or
vector. Starting with version 1.4, Result Type can additionally be
a composite type other than a vector.

The types of Object 1 and Object 2 must be the same as Result
Type
.

Condition must be a scalar or vector of Boolean type.

If Condition is a scalar and true, the result is Object 1. If
Condition is a scalar and false, the result is Object 2.

If Condition is a vector, Result Type must be a vector with the same
number of components as Condition and the result is a mix of Object
1
and Object 2: If a component of Condition is true, the
corresponding component in the result is taken from Object 1,
otherwise it is taken from Object 2.

Word Count Opcode Results Operands

6

169

<id>
Result Type

Result <id>

<id>
Condition

<id>
Object 1

<id>
Object 2

Test Case(s)

Example 1

//dxc select_test.hlsl -T lib_6_8 -E fn -enable-16bit-types -spirv -fspv-target-env=universal1.5 -fcgl -O0

export float4 fn(bool4 p1, float4 p2, float4 p3) {
    return select(p1, p2, p3);
}

Example 2

//dxc select_1_test.hlsl -T lib_6_8 -E fn -enable-16bit-types -spirv -fspv-target-env=universal1.5 -fcgl -O0

export float4 fn(bool p1, float4 p2, float4 p3) {
    return select(p1, p2, p3);
}

HLSL:

Syntax

any<> select(bool<> cond, any<> t, any<> f);
any_sampler select(bool cond, any_sampler t, any_sampler f);

Type Description

Name Template Type Component Type Size
ret scalar, vector, or matrix bool, float, or int any
cond scalar, vector, or matrix bool any
t scalar, vector, or matrix bool, float, or int any
f scalar, vector, or matrix bool, float, or int any

Type Description

Name Template Type Component Type Size
ret scalar float, int, or uint 1
cond scalar bool 1
t scalar float, int, or uint 1
f scalar float, int, or uint 1

Minimum Shader Model

This function is supported in the following shader models.

Shader Model Supported
HLSL 2021 and higher shader models yes

Shader Stages

Remarks

In HLSL 2021 int3 Z = select(X, 1, 0); is a replacement for

int3 X = {1, 1, 1};
int3 Z = X ? 1 : 0;

See also

@llvm-beanz llvm-beanz converted this from a draft issue Dec 13, 2023
@llvm-beanz llvm-beanz added the HLSL HLSL Language Support label Dec 13, 2023
@farzonl farzonl changed the title [HLSL] Implement select intrinsic Implement the select HLSL Function Jul 16, 2024
@spall
Copy link
Contributor

spall commented Aug 22, 2024

looking at this

bogner pushed a commit that referenced this issue Sep 9, 2024
Implement support for HLSL intrinsic select.
This would close issue #75377
@damyanp damyanp closed this as completed Sep 9, 2024
@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. labels Sep 9, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 9, 2024

@llvm/issue-subscribers-clang-codegen

Author: Chris B (llvm-beanz)

HLSL 2021 introduced the `select` intrinsic as a replacement for the ternary operator on vector types.

The select intrinsic has the following approximate forms:

template&lt;typename T, int Sz&gt;
void select(vector&lt;bool, Sz&gt; Conds, vector&lt;T, Sz&gt; TrueVals, vector&lt;T, Sz&gt; FalseVals) {
  vector&lt;T, Sz&gt; Result;
  for (int I = 0; I &lt; Sz; ++I) {
    if (Conds[I])
      Result[I] = TrueVals[I];
    else
      Result[I] = FalseVals[I];
  }
  return Result;
}

template&lt;typename T&gt;
void select(bool Cond, T TrueVal, T FalseVal) {
  if (T)
    return TrueVal;
  return FalseVal;
}

The vector case can lower to a shufflevector mask:

template&lt;typename T, int Sz&gt;
void select(vector&lt;bool, Sz&gt; Conds, vector&lt;T, Sz&gt; TrueVals, vector&lt;T, Sz&gt; FalseVals) {
  vector&lt;int, Sz&gt; Mask;
  for (int I = 0; I &lt; Sz; ++I) {
    Mask[I] = I;
    if (!Conds[I])
      Mask[I] += Sz;
  }
  return __builtin_shufflevector(TrueVals, FalseVals, Mask);
}

Acceptance Criteria
Implementation of the select intrinsic in the HLSL builtin headers and corresponding lowering to LLVM IR with appropriate test coverage.

  • Implement select clang builtin,
  • Link select clang builtin with hlsl_intrinsics.h
  • Add sema checks for select to CheckHLSLBuiltinFunctionCall in SemaChecking.cpp
  • Add codegen for select to EmitHLSLBuiltinExpr in CGBuiltin.cpp
  • Add codegen tests to clang/test/CodeGenHLSL/builtins/select.hlsl
  • Add sema tests to clang/test/SemaHLSL/BuiltIns/select-errors.hlsl
  • Create the int_spv_select intrinsic in IntrinsicsSPIRV.td
  • In SPIRVInstructionSelector.cpp create the select lowering and map it to int_spv_select in SPIRVInstructionSelector::selectIntrinsic.
  • Create SPIR-V backend test case in llvm/test/CodeGen/SPIRV/hlsl-intrinsics/select.ll

DirectX

There were no DXIL opcodes found for select.

SPIR-V

OpSelect:

Description:

Select between two objects. Before version 1.4, results are only
computed per component.

Before version 1.4, Result Type must be a pointer, scalar, or
vector. Starting with version 1.4, Result Type can additionally be
a composite type other than a vector.

The types of Object 1 and Object 2 must be the same as Result
Type
.

Condition must be a scalar or vector of Boolean type.

If Condition is a scalar and true, the result is Object 1. If
Condition is a scalar and false, the result is Object 2.

If Condition is a vector, Result Type must be a vector with the same
number of components as Condition and the result is a mix of Object
1
and Object 2: If a component of Condition is true, the
corresponding component in the result is taken from Object 1,
otherwise it is taken from Object 2.

<table style="width:100%;">
<colgroup>
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
</colgroup>
<thead>
<tr>
<th>Word Count</th>
<th>Opcode</th>
<th>Results</th>
<th>Operands</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p>6</p></td>
<td class="tableblock halign-left valign-top"><p>169</p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Result Type</em></p></td>
<td class="tableblock halign-left valign-top"><p><a
href="#ResultId"><em>Result &lt;id&gt;</em></a></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Condition</em></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Object 1</em></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Object 2</em></p></td>
</tr>
</tbody>
</table>

Test Case(s)

Example 1

//dxc select_test.hlsl -T lib_6_8 -E fn -enable-16bit-types -spirv -fspv-target-env=universal1.5 -fcgl -O0

export float4 fn(bool4 p1, float4 p2, float4 p3) {
    return select(p1, p2, p3);
}

Example 2

//dxc select_1_test.hlsl -T lib_6_8 -E fn -enable-16bit-types -spirv -fspv-target-env=universal1.5 -fcgl -O0

export float4 fn(bool p1, float4 p2, float4 p3) {
    return select(p1, p2, p3);
}

HLSL:

Syntax

any&lt;&gt; select(bool&lt;&gt; cond, any&lt;&gt; t, any&lt;&gt; f);
any_sampler select(bool cond, any_sampler t, any_sampler f);

Type Description

Name Template Type Component Type Size
ret scalar, vector, or matrix bool, float, or int any
cond scalar, vector, or matrix bool any
t scalar, vector, or matrix bool, float, or int any
f scalar, vector, or matrix bool, float, or int any

Type Description

Name Template Type Component Type Size
ret scalar float, int, or uint 1
cond scalar bool 1
t scalar float, int, or uint 1
f scalar float, int, or uint 1

Minimum Shader Model

This function is supported in the following shader models.

Shader Model Supported
HLSL 2021 and higher shader models yes

Shader Stages

Remarks

In HLSL 2021 int3 Z = select(X, 1, 0); is a replacement for

int3 X = {1, 1, 1};
int3 Z = X ? 1 : 0;

See also

@llvmbot
Copy link
Member

llvmbot commented Sep 9, 2024

@llvm/issue-subscribers-clang-frontend

Author: Chris B (llvm-beanz)

HLSL 2021 introduced the `select` intrinsic as a replacement for the ternary operator on vector types.

The select intrinsic has the following approximate forms:

template&lt;typename T, int Sz&gt;
void select(vector&lt;bool, Sz&gt; Conds, vector&lt;T, Sz&gt; TrueVals, vector&lt;T, Sz&gt; FalseVals) {
  vector&lt;T, Sz&gt; Result;
  for (int I = 0; I &lt; Sz; ++I) {
    if (Conds[I])
      Result[I] = TrueVals[I];
    else
      Result[I] = FalseVals[I];
  }
  return Result;
}

template&lt;typename T&gt;
void select(bool Cond, T TrueVal, T FalseVal) {
  if (T)
    return TrueVal;
  return FalseVal;
}

The vector case can lower to a shufflevector mask:

template&lt;typename T, int Sz&gt;
void select(vector&lt;bool, Sz&gt; Conds, vector&lt;T, Sz&gt; TrueVals, vector&lt;T, Sz&gt; FalseVals) {
  vector&lt;int, Sz&gt; Mask;
  for (int I = 0; I &lt; Sz; ++I) {
    Mask[I] = I;
    if (!Conds[I])
      Mask[I] += Sz;
  }
  return __builtin_shufflevector(TrueVals, FalseVals, Mask);
}

Acceptance Criteria
Implementation of the select intrinsic in the HLSL builtin headers and corresponding lowering to LLVM IR with appropriate test coverage.

  • Implement select clang builtin,
  • Link select clang builtin with hlsl_intrinsics.h
  • Add sema checks for select to CheckHLSLBuiltinFunctionCall in SemaChecking.cpp
  • Add codegen for select to EmitHLSLBuiltinExpr in CGBuiltin.cpp
  • Add codegen tests to clang/test/CodeGenHLSL/builtins/select.hlsl
  • Add sema tests to clang/test/SemaHLSL/BuiltIns/select-errors.hlsl
  • Create the int_spv_select intrinsic in IntrinsicsSPIRV.td
  • In SPIRVInstructionSelector.cpp create the select lowering and map it to int_spv_select in SPIRVInstructionSelector::selectIntrinsic.
  • Create SPIR-V backend test case in llvm/test/CodeGen/SPIRV/hlsl-intrinsics/select.ll

DirectX

There were no DXIL opcodes found for select.

SPIR-V

OpSelect:

Description:

Select between two objects. Before version 1.4, results are only
computed per component.

Before version 1.4, Result Type must be a pointer, scalar, or
vector. Starting with version 1.4, Result Type can additionally be
a composite type other than a vector.

The types of Object 1 and Object 2 must be the same as Result
Type
.

Condition must be a scalar or vector of Boolean type.

If Condition is a scalar and true, the result is Object 1. If
Condition is a scalar and false, the result is Object 2.

If Condition is a vector, Result Type must be a vector with the same
number of components as Condition and the result is a mix of Object
1
and Object 2: If a component of Condition is true, the
corresponding component in the result is taken from Object 1,
otherwise it is taken from Object 2.

<table style="width:100%;">
<colgroup>
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
</colgroup>
<thead>
<tr>
<th>Word Count</th>
<th>Opcode</th>
<th>Results</th>
<th>Operands</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p>6</p></td>
<td class="tableblock halign-left valign-top"><p>169</p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Result Type</em></p></td>
<td class="tableblock halign-left valign-top"><p><a
href="#ResultId"><em>Result &lt;id&gt;</em></a></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Condition</em></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Object 1</em></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Object 2</em></p></td>
</tr>
</tbody>
</table>

Test Case(s)

Example 1

//dxc select_test.hlsl -T lib_6_8 -E fn -enable-16bit-types -spirv -fspv-target-env=universal1.5 -fcgl -O0

export float4 fn(bool4 p1, float4 p2, float4 p3) {
    return select(p1, p2, p3);
}

Example 2

//dxc select_1_test.hlsl -T lib_6_8 -E fn -enable-16bit-types -spirv -fspv-target-env=universal1.5 -fcgl -O0

export float4 fn(bool p1, float4 p2, float4 p3) {
    return select(p1, p2, p3);
}

HLSL:

Syntax

any&lt;&gt; select(bool&lt;&gt; cond, any&lt;&gt; t, any&lt;&gt; f);
any_sampler select(bool cond, any_sampler t, any_sampler f);

Type Description

Name Template Type Component Type Size
ret scalar, vector, or matrix bool, float, or int any
cond scalar, vector, or matrix bool any
t scalar, vector, or matrix bool, float, or int any
f scalar, vector, or matrix bool, float, or int any

Type Description

Name Template Type Component Type Size
ret scalar float, int, or uint 1
cond scalar bool 1
t scalar float, int, or uint 1
f scalar float, int, or uint 1

Minimum Shader Model

This function is supported in the following shader models.

Shader Model Supported
HLSL 2021 and higher shader models yes

Shader Stages

Remarks

In HLSL 2021 int3 Z = select(X, 1, 0); is a replacement for

int3 X = {1, 1, 1};
int3 Z = X ? 1 : 0;

See also

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" HLSL HLSL Language Support
Projects
Status: Closed
Development

No branches or pull requests

5 participants