Skip to content

Implement the select HLSL Function #75377

New issue

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

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

Already on GitHub? # 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

# for free to join this conversation on GitHub. Already have an account? # 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