[llvm-branch-commits] [llvm] [LLVM][MIPS] Add comprehensive tests for ct.select (PR #166705)
https://github.com/wizardengineer created
https://github.com/llvm/llvm-project/pull/166705
None
>From 22e92921b5a3b7720e53ba32777e2bccf024896a Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 11:01:26 -0500
Subject: [PATCH] [LLVM][MIPS] Add comprehensive tests for ct.select
---
.../Mips/ctselect-fallback-edge-cases.ll | 244 +
.../Mips/ctselect-fallback-patterns.ll| 426 +
.../CodeGen/Mips/ctselect-fallback-vector.ll | 830 ++
llvm/test/CodeGen/Mips/ctselect-fallback.ll | 371
.../CodeGen/Mips/ctselect-side-effects.ll | 183
5 files changed, 2054 insertions(+)
create mode 100644 llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
create mode 100644 llvm/test/CodeGen/Mips/ctselect-fallback-patterns.ll
create mode 100644 llvm/test/CodeGen/Mips/ctselect-fallback-vector.ll
create mode 100644 llvm/test/CodeGen/Mips/ctselect-fallback.ll
create mode 100644 llvm/test/CodeGen/Mips/ctselect-side-effects.ll
diff --git a/llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
b/llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0..f1831a625d4a4
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,244 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=mipsel-unknown-linux-gnu -O3 | FileCheck %s
--check-prefix=M32
+; RUN: llc < %s -mtriple=mips64el-unknown-linux-gnu -O3 | FileCheck %s
--check-prefix=M64
+
+; Portable edge case tests
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; M32-LABEL: test_ctselect_i1:
+; M32: # %bb.0:
+; M32-NEXT:xori $2, $4, 1
+; M32-NEXT:and $1, $4, $5
+; M32-NEXT:and $2, $2, $6
+; M32-NEXT:jr $ra
+; M32-NEXT:or $2, $1, $2
+;
+; M64-LABEL: test_ctselect_i1:
+; M64: # %bb.0:
+; M64-NEXT:sll $2, $4, 0
+; M64-NEXT:sll $1, $6, 0
+; M64-NEXT:xori $2, $2, 1
+; M64-NEXT:and $1, $2, $1
+; M64-NEXT:and $2, $4, $5
+; M64-NEXT:sll $2, $2, 0
+; M64-NEXT:jr $ra
+; M64-NEXT:or $2, $2, $1
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; M32-LABEL: test_ctselect_extremal_values:
+; M32: # %bb.0:
+; M32-NEXT:lui $3, 32767
+; M32-NEXT:andi $1, $4, 1
+; M32-NEXT:negu $2, $1
+; M32-NEXT:ori $3, $3, 65535
+; M32-NEXT:addiu $1, $1, -1
+; M32-NEXT:and $2, $2, $3
+; M32-NEXT:lui $3, 32768
+; M32-NEXT:and $1, $1, $3
+; M32-NEXT:jr $ra
+; M32-NEXT:or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_extremal_values:
+; M64: # %bb.0:
+; M64-NEXT:sll $1, $4, 0
+; M64-NEXT:lui $3, 32767
+; M64-NEXT:andi $1, $1, 1
+; M64-NEXT:ori $3, $3, 65535
+; M64-NEXT:negu $2, $1
+; M64-NEXT:addiu $1, $1, -1
+; M64-NEXT:and $2, $2, $3
+; M64-NEXT:lui $3, 32768
+; M64-NEXT:and $1, $1, $3
+; M64-NEXT:jr $ra
+; M64-NEXT:or $2, $2, $1
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32
-2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; M32-LABEL: test_ctselect_null_ptr:
+; M32: # %bb.0:
+; M32-NEXT:andi $1, $4, 1
+; M32-NEXT:negu $1, $1
+; M32-NEXT:jr $ra
+; M32-NEXT:and $2, $1, $5
+;
+; M64-LABEL: test_ctselect_null_ptr:
+; M64: # %bb.0:
+; M64-NEXT:andi $1, $4, 1
+; M64-NEXT:dnegu $1, $1
+; M64-NEXT:jr $ra
+; M64-NEXT:and $2, $1, $5
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+; M32-LABEL: test_ctselect_function_ptr:
+; M32: # %bb.0:
+; M32-NEXT:andi $1, $4, 1
+; M32-NEXT:negu $2, $1
+; M32-NEXT:addiu $1, $1, -1
+; M32-NEXT:and $2, $2, $5
+; M32-NEXT:and $1, $1, $6
+; M32-NEXT:jr $ra
+; M32-NEXT:or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_function_ptr:
+; M64: # %bb.0:
+; M64-NEXT:andi $1, $4, 1
+; M64-NEXT:dnegu $2, $1
+; M64-NEXT:daddiu $1, $1, -1
+; M64-NEXT:and $2, $2, $5
+; M64-NEXT:and $1, $1, $6
+; M64-NEXT:jr $ra
+; M64-NEXT:or $2, $2, $1
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %func1, ptr %func2)
+ ret ptr %result
+}
+
+; Test with condition from icmp on pointers
+define ptr @test_ctselect_ptr_cmp(ptr %p1, ptr %p2, ptr %a, ptr %b) {
+; M32-LABEL: test_ctselect_ptr_cmp:
+; M32: # %bb.0:
+; M32-NEXT:xor $1, $4, $5
+; M32-NEXT:sltu $1, $zero, $1
+; M32-NEXT:addiu $1, $1, -1
+; M32-NEXT:and $2, $1, $6
+; M32-NEXT:not $1, $1
+; M32-NEXT:and $1, $1, $7
+; M32-NEXT:jr $ra
+; M32-NEXT:or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_ptr_cmp:
+; M64: # %bb.0:
[llvm-branch-commits] [llvm] [LLVM][AArch64] Add native ct.select support for ARM64 (PR #166706)
https://github.com/wizardengineer created
https://github.com/llvm/llvm-project/pull/166706
This patch implements architecture-specific lowering for ct.select on AArch64
using CSEL (conditional select) instructions for constant-time selection.
Implementation details:
- Uses CSEL family of instructions for scalar integer types
- Uses FCSEL for floating-point types (F16, BF16, F32, F64)
- Post-RA MC lowering to convert pseudo-instructions to real CSEL/FCSEL
- Handles vector types appropriately
- Comprehensive test coverage for AArch64
The implementation includes:
- ISelLowering: Custom lowering to CTSELECT pseudo-instructions
- InstrInfo: Pseudo-instruction definitions and patterns
- MCInstLower: Post-RA lowering of pseudo-instructions to actual CSEL/FCSEL
- Proper handling of condition codes for constant-time guarantees
>From 071428b7a6eed7a800364cc4b9a7e25e1d8e310e Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 17:09:45 -0500
Subject: [PATCH] [LLVM][AArch64] Add native ct.select support for ARM64
This patch implements architecture-specific lowering for ct.select on AArch64
using CSEL (conditional select) instructions for constant-time selection.
Implementation details:
- Uses CSEL family of instructions for scalar integer types
- Uses FCSEL for floating-point types (F16, BF16, F32, F64)
- Post-RA MC lowering to convert pseudo-instructions to real CSEL/FCSEL
- Handles vector types appropriately
- Comprehensive test coverage for AArch64
The implementation includes:
- ISelLowering: Custom lowering to CTSELECT pseudo-instructions
- InstrInfo: Pseudo-instruction definitions and patterns
- MCInstLower: Post-RA lowering of pseudo-instructions to actual CSEL/FCSEL
- Proper handling of condition codes for constant-time guarantees
---
.../Target/AArch64/AArch64ISelLowering.cpp| 53 +
llvm/lib/Target/AArch64/AArch64ISelLowering.h | 12 ++
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 200 --
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 45
.../lib/Target/AArch64/AArch64MCInstLower.cpp | 18 ++
llvm/test/CodeGen/AArch64/ctselect.ll | 153 ++
6 files changed, 371 insertions(+), 110 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/ctselect.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 60aa61e993b26..a86aac88b94a8 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -511,12 +511,35 @@ AArch64TargetLowering::AArch64TargetLowering(const
TargetMachine &TM,
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
setOperationAction(ISD::SELECT, MVT::i32, Custom);
setOperationAction(ISD::SELECT, MVT::i64, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::i8, Promote);
+ setOperationAction(ISD::CTSELECT, MVT::i16, Promote);
+ setOperationAction(ISD::CTSELECT, MVT::i32, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::i64, Custom);
if (Subtarget->hasFPARMv8()) {
setOperationAction(ISD::SELECT, MVT::f16, Custom);
setOperationAction(ISD::SELECT, MVT::bf16, Custom);
}
+ if (Subtarget->hasFullFP16()) {
+setOperationAction(ISD::CTSELECT, MVT::f16, Custom);
+setOperationAction(ISD::CTSELECT, MVT::bf16, Custom);
+ } else {
+setOperationAction(ISD::CTSELECT, MVT::f16, Promote);
+setOperationAction(ISD::CTSELECT, MVT::bf16, Promote);
+ }
setOperationAction(ISD::SELECT, MVT::f32, Custom);
setOperationAction(ISD::SELECT, MVT::f64, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::f32, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::f64, Custom);
+ for (MVT VT : MVT::vector_valuetypes()) {
+MVT elemType = VT.getVectorElementType();
+if (elemType == MVT::i8 || elemType == MVT::i16) {
+ setOperationAction(ISD::CTSELECT, VT, Promote);
+} else if ((elemType == MVT::f16 || elemType == MVT::bf16) &&
!Subtarget->hasFullFP16()) {
+ setOperationAction(ISD::CTSELECT, VT, Promote);
+} else {
+ setOperationAction(ISD::CTSELECT, VT, Expand);
+}
+ }
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f16, Custom);
@@ -3328,6 +3351,18 @@ void AArch64TargetLowering::fixupPtrauthDiscriminator(
IntDiscOp.setImm(IntDisc);
}
+MachineBasicBlock *AArch64TargetLowering::EmitCTSELECT(MachineInstr &MI,
MachineBasicBlock *MBB, unsigned Opcode) const {
+ const TargetInstrInfo *TII = Subtarget->getInstrInfo();
+ DebugLoc DL = MI.getDebugLoc();
+ MachineInstrBuilder Builder = BuildMI(*MBB, MI, DL, TII->get(Opcode));
+ for (unsigned Idx = 0; Idx < MI.getNumOperands(); ++Idx) {
+Builder.add(MI.getOperand(Idx));
+ }
+ Builder->setFlag(MachineInstr::NoMerge);
+ MBB->remove_instr(&MI);
+ return MBB;
+}
+
MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
MachineInstr &MI, MachineBasicBlock *BB) const
[llvm-branch-commits] [llvm] [ConstantTime][RISCV] Add comprehensive tests for ct.select (PR #166708)
https://github.com/wizardengineer created
https://github.com/llvm/llvm-project/pull/166708
Add comprehensive test suite for RISC-V fallback implementation:
- Edge cases (zero conditions, large integers, sign extension)
- Pattern matching (nested selects, chains)
- Vector support with RVV extensions
- Side effects and memory operations
The basic fallback test is in the core infrastructure PR.
>From 05465f4247bd1e05138118a697625b0ad9378e81 Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 11:01:00 -0500
Subject: [PATCH] [ConstantTime][RISCV] Add comprehensive tests for ct.select
Add comprehensive test suite for RISC-V fallback implementation:
- Edge cases (zero conditions, large integers, sign extension)
- Pattern matching (nested selects, chains)
- Vector support with RVV extensions
- Side effects and memory operations
The basic fallback test is in the core infrastructure PR.
---
.../RISCV/ctselect-fallback-edge-cases.ll | 214 +
.../RISCV/ctselect-fallback-patterns.ll | 383 +
.../RISCV/ctselect-fallback-vector-rvv.ll | 804 ++
llvm/test/CodeGen/RISCV/ctselect-fallback.ll | 330 ---
.../CodeGen/RISCV/ctselect-side-effects.ll| 176
5 files changed, 1577 insertions(+), 330 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-patterns.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-vector-rvv.ll
delete mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-side-effects.ll
diff --git a/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
b/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0..af1be0c8f3ddc
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,214 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=riscv64 -O3 | FileCheck %s --check-prefix=RV64
+; RUN: llc < %s -mtriple=riscv32 -O3 | FileCheck %s --check-prefix=RV32
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; RV64-LABEL: test_ctselect_i1:
+; RV64: # %bb.0:
+; RV64-NEXT:and a1, a0, a1
+; RV64-NEXT:xori a0, a0, 1
+; RV64-NEXT:and a0, a0, a2
+; RV64-NEXT:or a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_i1:
+; RV32: # %bb.0:
+; RV32-NEXT:and a1, a0, a1
+; RV32-NEXT:xori a0, a0, 1
+; RV32-NEXT:and a0, a0, a2
+; RV32-NEXT:or a0, a1, a0
+; RV32-NEXT:ret
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; RV64-LABEL: test_ctselect_extremal_values:
+; RV64: # %bb.0:
+; RV64-NEXT:andi a0, a0, 1
+; RV64-NEXT:lui a1, 524288
+; RV64-NEXT:subw a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_extremal_values:
+; RV32: # %bb.0:
+; RV32-NEXT:andi a0, a0, 1
+; RV32-NEXT:lui a1, 524288
+; RV32-NEXT:addi a2, a0, -1
+; RV32-NEXT:neg a0, a0
+; RV32-NEXT:and a1, a2, a1
+; RV32-NEXT:slli a0, a0, 1
+; RV32-NEXT:srli a0, a0, 1
+; RV32-NEXT:or a0, a0, a1
+; RV32-NEXT:ret
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32
-2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; RV64-LABEL: test_ctselect_null_ptr:
+; RV64: # %bb.0:
+; RV64-NEXT:slli a0, a0, 63
+; RV64-NEXT:srai a0, a0, 63
+; RV64-NEXT:and a0, a0, a1
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_null_ptr:
+; RV32: # %bb.0:
+; RV32-NEXT:slli a0, a0, 31
+; RV32-NEXT:srai a0, a0, 31
+; RV32-NEXT:and a0, a0, a1
+; RV32-NEXT:ret
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+; RV64-LABEL: test_ctselect_function_ptr:
+; RV64: # %bb.0:
+; RV64-NEXT:andi a0, a0, 1
+; RV64-NEXT:neg a3, a0
+; RV64-NEXT:addi a0, a0, -1
+; RV64-NEXT:and a1, a3, a1
+; RV64-NEXT:and a0, a0, a2
+; RV64-NEXT:or a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_function_ptr:
+; RV32: # %bb.0:
+; RV32-NEXT:andi a0, a0, 1
+; RV32-NEXT:neg a3, a0
+; RV32-NEXT:addi a0, a0, -1
+; RV32-NEXT:and a1, a3, a1
+; RV32-NEXT:and a0, a0, a2
+; RV32-NEXT:or a0, a1, a0
+; RV32-NEXT:ret
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %func1, ptr %func2)
+ ret ptr %result
+}
+
+; Test with condition from icmp on pointers
+define ptr @test_ctselect_ptr_cmp(ptr %p1, ptr %p2, ptr %a, ptr %b) {
+; RV64-LABEL: test_ctselect_ptr_cmp:
+; RV64: # %bb.0:
+; RV64-NEXT:xor a
[llvm-branch-commits] [llvm] [ConstantTime][WebAssembly] Add comprehensive tests for ct.select (PR #166709)
https://github.com/wizardengineer created
https://github.com/llvm/llvm-project/pull/166709
None
>From d55c2d69a0d48538f7376d9f06b8cbf0e2215e93 Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 11:03:23 -0500
Subject: [PATCH] [ConstantTime][WebAssembly] Add comprehensive tests for
ct.select
---
.../ctselect-fallback-edge-cases.ll | 376 +
.../WebAssembly/ctselect-fallback-patterns.ll | 641
.../WebAssembly/ctselect-fallback-vector.ll | 714 ++
.../CodeGen/WebAssembly/ctselect-fallback.ll | 552 ++
.../WebAssembly/ctselect-side-effects.ll | 226 ++
5 files changed, 2509 insertions(+)
create mode 100644
llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-fallback-patterns.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-fallback-vector.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-fallback.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-side-effects.ll
diff --git a/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0..b0f7f2807debd
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,376 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=wasm32-unknown-unknown -O3 -filetype=asm | FileCheck
%s --check-prefix=W32
+; RUN: llc < %s -mtriple=wasm64-unknown-unknown -O3 -filetype=asm | FileCheck
%s --check-prefix=W64
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; W32-LABEL: test_ctselect_i1:
+; W32: .functype test_ctselect_i1 (i32, i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT:local.get 0
+; W32-NEXT:local.get 1
+; W32-NEXT:i32.and
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const 1
+; W32-NEXT:i32.xor
+; W32-NEXT:local.get 2
+; W32-NEXT:i32.and
+; W32-NEXT:i32.or
+; W32-NEXT:# fallthrough-return
+;
+; W64-LABEL: test_ctselect_i1:
+; W64: .functype test_ctselect_i1 (i32, i32, i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT:local.get 0
+; W64-NEXT:local.get 1
+; W64-NEXT:i32.and
+; W64-NEXT:local.get 0
+; W64-NEXT:i32.const 1
+; W64-NEXT:i32.xor
+; W64-NEXT:local.get 2
+; W64-NEXT:i32.and
+; W64-NEXT:i32.or
+; W64-NEXT:# fallthrough-return
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; W32-LABEL: test_ctselect_extremal_values:
+; W32: .functype test_ctselect_extremal_values (i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT:i32.const 0
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const 1
+; W32-NEXT:i32.and
+; W32-NEXT:local.tee 0
+; W32-NEXT:i32.sub
+; W32-NEXT:i32.const 2147483647
+; W32-NEXT:i32.and
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const -1
+; W32-NEXT:i32.add
+; W32-NEXT:i32.const -2147483648
+; W32-NEXT:i32.and
+; W32-NEXT:i32.or
+; W32-NEXT:# fallthrough-return
+;
+; W64-LABEL: test_ctselect_extremal_values:
+; W64: .functype test_ctselect_extremal_values (i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT:i32.const 0
+; W64-NEXT:local.get 0
+; W64-NEXT:i32.const 1
+; W64-NEXT:i32.and
+; W64-NEXT:local.tee 0
+; W64-NEXT:i32.sub
+; W64-NEXT:i32.const 2147483647
+; W64-NEXT:i32.and
+; W64-NEXT:local.get 0
+; W64-NEXT:i32.const -1
+; W64-NEXT:i32.add
+; W64-NEXT:i32.const -2147483648
+; W64-NEXT:i32.and
+; W64-NEXT:i32.or
+; W64-NEXT:# fallthrough-return
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32
-2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; W32-LABEL: test_ctselect_null_ptr:
+; W32: .functype test_ctselect_null_ptr (i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT:i32.const 0
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const 1
+; W32-NEXT:i32.and
+; W32-NEXT:i32.sub
+; W32-NEXT:local.get 1
+; W32-NEXT:i32.and
+; W32-NEXT:# fallthrough-return
+;
+; W64-LABEL: test_ctselect_null_ptr:
+; W64: .functype test_ctselect_null_ptr (i32, i64) -> (i64)
+; W64-NEXT: # %bb.0:
+; W64-NEXT:i64.const 0
+; W64-NEXT:local.get 0
+; W64-NEXT:i64.extend_i32_u
+; W64-NEXT:i64.const 1
+; W64-NEXT:i64.and
+; W64-NEXT:i64.sub
+; W64-NEXT:local.get 1
+; W64-NEXT:i64.and
+; W64-NEXT:# fallthrough-return
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+
[llvm-branch-commits] [clang] [ConstantTime][Clang] Add __builtin_ct_select for constant-time selection (PR #166703)
wizardengineer wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.com/github/pr/llvm/llvm-project/166703?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#166703** https://app.graphite.com/github/pr/llvm/llvm-project/166703?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>: 6 dependent PRs ([#166704](https://github.com/llvm/llvm-project/pull/166704) https://app.graphite.com/github/pr/llvm/llvm-project/166704?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166705](https://github.com/llvm/llvm-project/pull/166705) https://app.graphite.com/github/pr/llvm/llvm-project/166705?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166706](https://github.com/llvm/llvm-project/pull/166706) https://app.graphite.com/github/pr/llvm/llvm-project/166706?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> and 3 others) 👈 https://app.graphite.com/github/pr/llvm/llvm-project/166703?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#166702** https://app.graphite.com/github/pr/llvm/llvm-project/166702?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * `main` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/166703 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [ConstantTime][Clang] Add __builtin_ct_select for constant-time selection (PR #166703)
https://github.com/wizardengineer created
https://github.com/llvm/llvm-project/pull/166703
None
>From cbb549061c8ec8023ca44b664e0f9d9b4727afde Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 10:56:34 -0500
Subject: [PATCH] [ConstantTime][Clang] Add __builtin_ct_select for
constant-time selection
---
clang/include/clang/Basic/Builtins.td | 8 +
clang/lib/CodeGen/CGBuiltin.cpp | 35 +
clang/lib/Sema/SemaChecking.cpp | 87 +++
.../test/Sema/builtin-ct-select-edge-cases.c | 384 ++
clang/test/Sema/builtin-ct-select.c | 683 ++
5 files changed, 1197 insertions(+)
create mode 100644 clang/test/Sema/builtin-ct-select-edge-cases.c
create mode 100644 clang/test/Sema/builtin-ct-select.c
diff --git a/clang/include/clang/Basic/Builtins.td
b/clang/include/clang/Basic/Builtins.td
index 2b400b012d6ed..13e2a9849bfca 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5278,3 +5278,11 @@ def CountedByRef : Builtin {
let Attributes = [NoThrow, CustomTypeChecking];
let Prototype = "int(...)";
}
+
+// Constant-time select builtin
+def CtSelect : Builtin {
+ let Spellings = ["__builtin_ct_select"];
+ let Attributes = [NoThrow, Const, UnevaluatedArguments,
+ConstIgnoringExceptions, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index b81e0d02da2c9..6c0a9eb1e7d86 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -28,6 +28,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Intrinsics.h"
@@ -6450,6 +6451,40 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl
GD, unsigned BuiltinID,
auto Str = CGM.GetAddrOfConstantCString(Name, "");
return RValue::get(Str.getPointer());
}
+ case Builtin::BI__builtin_ct_select: {
+if (E->getNumArgs() != 3) {
+ CGM.getDiags().Report(E->getBeginLoc(),
+E->getNumArgs() > 3
+? diag::err_typecheck_call_too_many_args
+: diag::err_typecheck_call_too_few_args);
+ return GetUndefRValue(E->getType());
+}
+
+auto *Cond = EmitScalarExpr(E->getArg(0));
+auto *A = EmitScalarExpr(E->getArg(1));
+auto *B = EmitScalarExpr(E->getArg(2));
+
+// Verify types match
+if (A->getType() != B->getType()) {
+ CGM.getDiags().Report(E->getBeginLoc(),
+diag::err_typecheck_convert_incompatible);
+ return GetUndefRValue(E->getType());
+}
+
+// Verify condition is integer type
+if (!Cond->getType()->isIntegerTy()) {
+ CGM.getDiags().Report(E->getBeginLoc(), diag::err_typecheck_expect_int);
+ return GetUndefRValue(E->getType());
+}
+
+if (Cond->getType()->getIntegerBitWidth() != 1)
+ Cond = Builder.CreateICmpNE(
+ Cond, llvm::ConstantInt::get(Cond->getType(), 0), "cond.bool");
+
+llvm::Function *Fn =
+CGM.getIntrinsic(llvm::Intrinsic::ct_select, {A->getType()});
+return RValue::get(Builder.CreateCall(Fn, {Cond, A, B}));
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ad2c2e4a97bb9..bce47cc4586c6 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3494,6 +3494,93 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl,
unsigned BuiltinID,
if (BuiltinCountedByRef(TheCall))
return ExprError();
break;
+
+ case Builtin::BI__builtin_ct_select: {
+if (TheCall->getNumArgs() != 3) {
+ // Simple argument count check without complex diagnostics
+ if (TheCall->getNumArgs() < 3) {
+return Diag(TheCall->getEndLoc(),
diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 3 << TheCall->getNumArgs() << 0
+ << TheCall->getCallee()->getSourceRange();
+ } else {
+return Diag(TheCall->getEndLoc(),
diag::err_typecheck_call_too_many_args)
+ << 0 << 3 << TheCall->getNumArgs() << 0
+ << TheCall->getCallee()->getSourceRange();
+ }
+}
+auto *Cond = TheCall->getArg(0);
+auto *A = TheCall->getArg(1);
+auto *B = TheCall->getArg(2);
+
+QualType CondTy = Cond->getType();
+if (!CondTy->isIntegerType()) {
+ return Diag(Cond->getBeginLoc(), diag::err_typecheck_cond_expect_scalar)
+ << CondTy << Cond->getSourceRange();
+}
+
+QualType ATy = A->getType();
+QualType BTy = B->getType();
+
+// check for scalar or vector scalar type
+if ((!ATy->isScalarType() && !ATy->isVectorType()) ||
+(!BTy
[llvm-branch-commits] [llvm] [LLVM][X86] Add native ct.select support for X86 and i386 (PR #166704)
wizardengineer wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.com/github/pr/llvm/llvm-project/166704?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#166704** https://app.graphite.com/github/pr/llvm/llvm-project/166704?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> 👈 https://app.graphite.com/github/pr/llvm/llvm-project/166704?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#166703** https://app.graphite.com/github/pr/llvm/llvm-project/166703?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>: 5 other dependent PRs ([#166705](https://github.com/llvm/llvm-project/pull/166705) https://app.graphite.com/github/pr/llvm/llvm-project/166705?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166706](https://github.com/llvm/llvm-project/pull/166706) https://app.graphite.com/github/pr/llvm/llvm-project/166706?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166707](https://github.com/llvm/llvm-project/pull/166707) https://app.graphite.com/github/pr/llvm/llvm-project/166707?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> and 2 others) * **#166702** https://app.graphite.com/github/pr/llvm/llvm-project/166702?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * `main` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/166704 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [ConstantTime][WebAssembly] Add comprehensive tests for ct.select (PR #166709)
wizardengineer wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.com/github/pr/llvm/llvm-project/166709?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#166709** https://app.graphite.com/github/pr/llvm/llvm-project/166709?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> 👈 https://app.graphite.com/github/pr/llvm/llvm-project/166709?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#166703** https://app.graphite.com/github/pr/llvm/llvm-project/166703?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>: 5 other dependent PRs ([#166704](https://github.com/llvm/llvm-project/pull/166704) https://app.graphite.com/github/pr/llvm/llvm-project/166704?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166705](https://github.com/llvm/llvm-project/pull/166705) https://app.graphite.com/github/pr/llvm/llvm-project/166705?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166706](https://github.com/llvm/llvm-project/pull/166706) https://app.graphite.com/github/pr/llvm/llvm-project/166706?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> and 2 others) * **#166702** https://app.graphite.com/github/pr/llvm/llvm-project/166702?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * `main` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/166709 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [LLVM][ARM] Add native ct.select support for ARM32 and Thumb (PR #166707)
wizardengineer wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.com/github/pr/llvm/llvm-project/166707?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#166707** https://app.graphite.com/github/pr/llvm/llvm-project/166707?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> 👈 https://app.graphite.com/github/pr/llvm/llvm-project/166707?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#166703** https://app.graphite.com/github/pr/llvm/llvm-project/166703?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>: 5 other dependent PRs ([#166704](https://github.com/llvm/llvm-project/pull/166704) https://app.graphite.com/github/pr/llvm/llvm-project/166704?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166705](https://github.com/llvm/llvm-project/pull/166705) https://app.graphite.com/github/pr/llvm/llvm-project/166705?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166706](https://github.com/llvm/llvm-project/pull/166706) https://app.graphite.com/github/pr/llvm/llvm-project/166706?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> and 2 others) * **#166702** https://app.graphite.com/github/pr/llvm/llvm-project/166702?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * `main` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/166707 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [ConstantTime][RISCV] Add comprehensive tests for ct.select (PR #166708)
wizardengineer wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.com/github/pr/llvm/llvm-project/166708?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#166708** https://app.graphite.com/github/pr/llvm/llvm-project/166708?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> 👈 https://app.graphite.com/github/pr/llvm/llvm-project/166708?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#166703** https://app.graphite.com/github/pr/llvm/llvm-project/166703?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>: 5 other dependent PRs ([#166704](https://github.com/llvm/llvm-project/pull/166704) https://app.graphite.com/github/pr/llvm/llvm-project/166704?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166705](https://github.com/llvm/llvm-project/pull/166705) https://app.graphite.com/github/pr/llvm/llvm-project/166705?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166706](https://github.com/llvm/llvm-project/pull/166706) https://app.graphite.com/github/pr/llvm/llvm-project/166706?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> and 2 others) * **#166702** https://app.graphite.com/github/pr/llvm/llvm-project/166702?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * `main` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/166708 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [LLVM][AArch64] Add native ct.select support for ARM64 (PR #166706)
wizardengineer wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.com/github/pr/llvm/llvm-project/166706?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#166706** https://app.graphite.com/github/pr/llvm/llvm-project/166706?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> 👈 https://app.graphite.com/github/pr/llvm/llvm-project/166706?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#166703** https://app.graphite.com/github/pr/llvm/llvm-project/166703?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>: 5 other dependent PRs ([#166704](https://github.com/llvm/llvm-project/pull/166704) https://app.graphite.com/github/pr/llvm/llvm-project/166704?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166705](https://github.com/llvm/llvm-project/pull/166705) https://app.graphite.com/github/pr/llvm/llvm-project/166705?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166707](https://github.com/llvm/llvm-project/pull/166707) https://app.graphite.com/github/pr/llvm/llvm-project/166707?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> and 2 others) * **#166702** https://app.graphite.com/github/pr/llvm/llvm-project/166702?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * `main` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/166706 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [LLVM][MIPS] Add comprehensive tests for ct.select (PR #166705)
wizardengineer wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.com/github/pr/llvm/llvm-project/166705?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#166705** https://app.graphite.com/github/pr/llvm/llvm-project/166705?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> 👈 https://app.graphite.com/github/pr/llvm/llvm-project/166705?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#166703** https://app.graphite.com/github/pr/llvm/llvm-project/166703?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>: 5 other dependent PRs ([#166704](https://github.com/llvm/llvm-project/pull/166704) https://app.graphite.com/github/pr/llvm/llvm-project/166704?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166706](https://github.com/llvm/llvm-project/pull/166706) https://app.graphite.com/github/pr/llvm/llvm-project/166706?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>, [#166707](https://github.com/llvm/llvm-project/pull/166707) https://app.graphite.com/github/pr/llvm/llvm-project/166707?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> and 2 others) * **#166702** https://app.graphite.com/github/pr/llvm/llvm-project/166702?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * `main` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/166705 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [ConstantTime][RISCV] Add comprehensive tests for ct.select (PR #166708)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166708
>From 7aec58aa6f8029c514857a755b5a381e6a6b22af Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 11:01:00 -0500
Subject: [PATCH] [ConstantTime][RISCV] Add comprehensive tests for ct.select
Add comprehensive test suite for RISC-V fallback implementation:
- Edge cases (zero conditions, large integers, sign extension)
- Pattern matching (nested selects, chains)
- Vector support with RVV extensions
- Side effects and memory operations
The basic fallback test is in the core infrastructure PR.
---
.../RISCV/ctselect-fallback-edge-cases.ll | 214 +
.../RISCV/ctselect-fallback-patterns.ll | 383 +
.../RISCV/ctselect-fallback-vector-rvv.ll | 804 ++
.../CodeGen/RISCV/ctselect-side-effects.ll| 176
4 files changed, 1577 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-patterns.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-vector-rvv.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-side-effects.ll
diff --git a/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
b/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0..af1be0c8f3ddc
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,214 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=riscv64 -O3 | FileCheck %s --check-prefix=RV64
+; RUN: llc < %s -mtriple=riscv32 -O3 | FileCheck %s --check-prefix=RV32
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; RV64-LABEL: test_ctselect_i1:
+; RV64: # %bb.0:
+; RV64-NEXT:and a1, a0, a1
+; RV64-NEXT:xori a0, a0, 1
+; RV64-NEXT:and a0, a0, a2
+; RV64-NEXT:or a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_i1:
+; RV32: # %bb.0:
+; RV32-NEXT:and a1, a0, a1
+; RV32-NEXT:xori a0, a0, 1
+; RV32-NEXT:and a0, a0, a2
+; RV32-NEXT:or a0, a1, a0
+; RV32-NEXT:ret
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; RV64-LABEL: test_ctselect_extremal_values:
+; RV64: # %bb.0:
+; RV64-NEXT:andi a0, a0, 1
+; RV64-NEXT:lui a1, 524288
+; RV64-NEXT:subw a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_extremal_values:
+; RV32: # %bb.0:
+; RV32-NEXT:andi a0, a0, 1
+; RV32-NEXT:lui a1, 524288
+; RV32-NEXT:addi a2, a0, -1
+; RV32-NEXT:neg a0, a0
+; RV32-NEXT:and a1, a2, a1
+; RV32-NEXT:slli a0, a0, 1
+; RV32-NEXT:srli a0, a0, 1
+; RV32-NEXT:or a0, a0, a1
+; RV32-NEXT:ret
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32
-2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; RV64-LABEL: test_ctselect_null_ptr:
+; RV64: # %bb.0:
+; RV64-NEXT:slli a0, a0, 63
+; RV64-NEXT:srai a0, a0, 63
+; RV64-NEXT:and a0, a0, a1
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_null_ptr:
+; RV32: # %bb.0:
+; RV32-NEXT:slli a0, a0, 31
+; RV32-NEXT:srai a0, a0, 31
+; RV32-NEXT:and a0, a0, a1
+; RV32-NEXT:ret
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+; RV64-LABEL: test_ctselect_function_ptr:
+; RV64: # %bb.0:
+; RV64-NEXT:andi a0, a0, 1
+; RV64-NEXT:neg a3, a0
+; RV64-NEXT:addi a0, a0, -1
+; RV64-NEXT:and a1, a3, a1
+; RV64-NEXT:and a0, a0, a2
+; RV64-NEXT:or a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_function_ptr:
+; RV32: # %bb.0:
+; RV32-NEXT:andi a0, a0, 1
+; RV32-NEXT:neg a3, a0
+; RV32-NEXT:addi a0, a0, -1
+; RV32-NEXT:and a1, a3, a1
+; RV32-NEXT:and a0, a0, a2
+; RV32-NEXT:or a0, a1, a0
+; RV32-NEXT:ret
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %func1, ptr %func2)
+ ret ptr %result
+}
+
+; Test with condition from icmp on pointers
+define ptr @test_ctselect_ptr_cmp(ptr %p1, ptr %p2, ptr %a, ptr %b) {
+; RV64-LABEL: test_ctselect_ptr_cmp:
+; RV64: # %bb.0:
+; RV64-NEXT:xor a0, a0, a1
+; RV64-NEXT:snez a0, a0
+; RV64-NEXT:addi a0, a0, -1
+; RV64-NEXT:and a2, a0, a2
+; RV64-NEXT:not a0, a0
+; RV64-NEXT:and a0, a0, a3
+; RV64-NEXT:or a0, a2, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_ptr_cmp:
+; RV32: # %bb.0:
+; RV32-NEXT:xor a0, a0, a1
+; RV32-NEXT:snez a0, a0
+; RV32-NEXT:addi a0, a0, -1
+; RV32-NEXT:and a2, a0, a2
+; RV32-NEXT:not a0, a0
+; RV32-NEXT:
[llvm-branch-commits] [llvm] [ConstantTime][RISCV] Add comprehensive tests for ct.select (PR #166708)
https://github.com/wizardengineer ready_for_review https://github.com/llvm/llvm-project/pull/166708 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [ConstantTime][WebAssembly] Add comprehensive tests for ct.select (PR #166709)
https://github.com/wizardengineer ready_for_review https://github.com/llvm/llvm-project/pull/166709 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [ConstantTime][Clang] Add __builtin_ct_select for constant-time selection (PR #166703)
https://github.com/wizardengineer ready_for_review https://github.com/llvm/llvm-project/pull/166703 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [ConstantTime] Native ct.select support for ARM32 and Thumb (PR #166707)
https://github.com/wizardengineer ready_for_review https://github.com/llvm/llvm-project/pull/166707 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [ConstantTime] Native ct.select support for X86 and i386 (PR #166704)
https://github.com/wizardengineer ready_for_review https://github.com/llvm/llvm-project/pull/166704 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [ConstantTime][MIPS] Add comprehensive tests for ct.select (PR #166705)
https://github.com/wizardengineer ready_for_review https://github.com/llvm/llvm-project/pull/166705 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [ConstantTime] Native ct.select support for ARM64 (PR #166706)
https://github.com/wizardengineer ready_for_review https://github.com/llvm/llvm-project/pull/166706 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [ConstantTime][MIPS] Add comprehensive tests for ct.select (PR #166705)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166705
>From 9dac6cad69ae839442c551be1e0a03617f8579d8 Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 11:01:26 -0500
Subject: [PATCH] [LLVM][MIPS] Add comprehensive tests for ct.select
---
.../Mips/ctselect-fallback-edge-cases.ll | 244 +
.../Mips/ctselect-fallback-patterns.ll| 426 +
.../CodeGen/Mips/ctselect-fallback-vector.ll | 830 ++
llvm/test/CodeGen/Mips/ctselect-fallback.ll | 371
.../CodeGen/Mips/ctselect-side-effects.ll | 183
5 files changed, 2054 insertions(+)
create mode 100644 llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
create mode 100644 llvm/test/CodeGen/Mips/ctselect-fallback-patterns.ll
create mode 100644 llvm/test/CodeGen/Mips/ctselect-fallback-vector.ll
create mode 100644 llvm/test/CodeGen/Mips/ctselect-fallback.ll
create mode 100644 llvm/test/CodeGen/Mips/ctselect-side-effects.ll
diff --git a/llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
b/llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0..f1831a625d4a4
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,244 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=mipsel-unknown-linux-gnu -O3 | FileCheck %s
--check-prefix=M32
+; RUN: llc < %s -mtriple=mips64el-unknown-linux-gnu -O3 | FileCheck %s
--check-prefix=M64
+
+; Portable edge case tests
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; M32-LABEL: test_ctselect_i1:
+; M32: # %bb.0:
+; M32-NEXT:xori $2, $4, 1
+; M32-NEXT:and $1, $4, $5
+; M32-NEXT:and $2, $2, $6
+; M32-NEXT:jr $ra
+; M32-NEXT:or $2, $1, $2
+;
+; M64-LABEL: test_ctselect_i1:
+; M64: # %bb.0:
+; M64-NEXT:sll $2, $4, 0
+; M64-NEXT:sll $1, $6, 0
+; M64-NEXT:xori $2, $2, 1
+; M64-NEXT:and $1, $2, $1
+; M64-NEXT:and $2, $4, $5
+; M64-NEXT:sll $2, $2, 0
+; M64-NEXT:jr $ra
+; M64-NEXT:or $2, $2, $1
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; M32-LABEL: test_ctselect_extremal_values:
+; M32: # %bb.0:
+; M32-NEXT:lui $3, 32767
+; M32-NEXT:andi $1, $4, 1
+; M32-NEXT:negu $2, $1
+; M32-NEXT:ori $3, $3, 65535
+; M32-NEXT:addiu $1, $1, -1
+; M32-NEXT:and $2, $2, $3
+; M32-NEXT:lui $3, 32768
+; M32-NEXT:and $1, $1, $3
+; M32-NEXT:jr $ra
+; M32-NEXT:or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_extremal_values:
+; M64: # %bb.0:
+; M64-NEXT:sll $1, $4, 0
+; M64-NEXT:lui $3, 32767
+; M64-NEXT:andi $1, $1, 1
+; M64-NEXT:ori $3, $3, 65535
+; M64-NEXT:negu $2, $1
+; M64-NEXT:addiu $1, $1, -1
+; M64-NEXT:and $2, $2, $3
+; M64-NEXT:lui $3, 32768
+; M64-NEXT:and $1, $1, $3
+; M64-NEXT:jr $ra
+; M64-NEXT:or $2, $2, $1
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32
-2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; M32-LABEL: test_ctselect_null_ptr:
+; M32: # %bb.0:
+; M32-NEXT:andi $1, $4, 1
+; M32-NEXT:negu $1, $1
+; M32-NEXT:jr $ra
+; M32-NEXT:and $2, $1, $5
+;
+; M64-LABEL: test_ctselect_null_ptr:
+; M64: # %bb.0:
+; M64-NEXT:andi $1, $4, 1
+; M64-NEXT:dnegu $1, $1
+; M64-NEXT:jr $ra
+; M64-NEXT:and $2, $1, $5
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+; M32-LABEL: test_ctselect_function_ptr:
+; M32: # %bb.0:
+; M32-NEXT:andi $1, $4, 1
+; M32-NEXT:negu $2, $1
+; M32-NEXT:addiu $1, $1, -1
+; M32-NEXT:and $2, $2, $5
+; M32-NEXT:and $1, $1, $6
+; M32-NEXT:jr $ra
+; M32-NEXT:or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_function_ptr:
+; M64: # %bb.0:
+; M64-NEXT:andi $1, $4, 1
+; M64-NEXT:dnegu $2, $1
+; M64-NEXT:daddiu $1, $1, -1
+; M64-NEXT:and $2, $2, $5
+; M64-NEXT:and $1, $1, $6
+; M64-NEXT:jr $ra
+; M64-NEXT:or $2, $2, $1
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %func1, ptr %func2)
+ ret ptr %result
+}
+
+; Test with condition from icmp on pointers
+define ptr @test_ctselect_ptr_cmp(ptr %p1, ptr %p2, ptr %a, ptr %b) {
+; M32-LABEL: test_ctselect_ptr_cmp:
+; M32: # %bb.0:
+; M32-NEXT:xor $1, $4, $5
+; M32-NEXT:sltu $1, $zero, $1
+; M32-NEXT:addiu $1, $1, -1
+; M32-NEXT:and $2, $1, $6
+; M32-NEXT:not $1, $1
+; M32-NEXT:and $1, $1, $7
+; M32-NEXT:jr $ra
+; M32-NEXT:or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_ptr_cmp:
+; M64: # %bb.0:
+; M6
[llvm-branch-commits] [llvm] [ConstantTime] Native ct.select support for ARM64 (PR #166706)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166706
>From 7de2b8134fa87b1f113834b5ab0b218cbde5a821 Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 17:09:45 -0500
Subject: [PATCH] [LLVM][AArch64] Add native ct.select support for ARM64
This patch implements architecture-specific lowering for ct.select on AArch64
using CSEL (conditional select) instructions for constant-time selection.
Implementation details:
- Uses CSEL family of instructions for scalar integer types
- Uses FCSEL for floating-point types (F16, BF16, F32, F64)
- Post-RA MC lowering to convert pseudo-instructions to real CSEL/FCSEL
- Handles vector types appropriately
- Comprehensive test coverage for AArch64
The implementation includes:
- ISelLowering: Custom lowering to CTSELECT pseudo-instructions
- InstrInfo: Pseudo-instruction definitions and patterns
- MCInstLower: Post-RA lowering of pseudo-instructions to actual CSEL/FCSEL
- Proper handling of condition codes for constant-time guarantees
---
.../Target/AArch64/AArch64ISelLowering.cpp| 56 +
llvm/lib/Target/AArch64/AArch64ISelLowering.h | 11 +
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 200 --
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 40
.../lib/Target/AArch64/AArch64MCInstLower.cpp | 18 ++
llvm/test/CodeGen/AArch64/ctselect.ll | 153 ++
6 files changed, 368 insertions(+), 110 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/ctselect.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 60aa61e993b26..54d0ea168d0b6 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -511,12 +511,36 @@ AArch64TargetLowering::AArch64TargetLowering(const
TargetMachine &TM,
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
setOperationAction(ISD::SELECT, MVT::i32, Custom);
setOperationAction(ISD::SELECT, MVT::i64, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::i8, Promote);
+ setOperationAction(ISD::CTSELECT, MVT::i16, Promote);
+ setOperationAction(ISD::CTSELECT, MVT::i32, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::i64, Custom);
if (Subtarget->hasFPARMv8()) {
setOperationAction(ISD::SELECT, MVT::f16, Custom);
setOperationAction(ISD::SELECT, MVT::bf16, Custom);
}
+ if (Subtarget->hasFullFP16()) {
+setOperationAction(ISD::CTSELECT, MVT::f16, Custom);
+setOperationAction(ISD::CTSELECT, MVT::bf16, Custom);
+ } else {
+setOperationAction(ISD::CTSELECT, MVT::f16, Promote);
+setOperationAction(ISD::CTSELECT, MVT::bf16, Promote);
+ }
setOperationAction(ISD::SELECT, MVT::f32, Custom);
setOperationAction(ISD::SELECT, MVT::f64, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::f32, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::f64, Custom);
+ for (MVT VT : MVT::vector_valuetypes()) {
+MVT elemType = VT.getVectorElementType();
+if (elemType == MVT::i8 || elemType == MVT::i16) {
+ setOperationAction(ISD::CTSELECT, VT, Promote);
+} else if ((elemType == MVT::f16 || elemType == MVT::bf16) &&
+ !Subtarget->hasFullFP16()) {
+ setOperationAction(ISD::CTSELECT, VT, Promote);
+} else {
+ setOperationAction(ISD::CTSELECT, VT, Expand);
+}
+ }
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f16, Custom);
@@ -3328,6 +3352,20 @@ void AArch64TargetLowering::fixupPtrauthDiscriminator(
IntDiscOp.setImm(IntDisc);
}
+MachineBasicBlock *AArch64TargetLowering::EmitCTSELECT(MachineInstr &MI,
+ MachineBasicBlock *MBB,
+ unsigned Opcode) const {
+ const TargetInstrInfo *TII = Subtarget->getInstrInfo();
+ DebugLoc DL = MI.getDebugLoc();
+ MachineInstrBuilder Builder = BuildMI(*MBB, MI, DL, TII->get(Opcode));
+ for (unsigned Idx = 0; Idx < MI.getNumOperands(); ++Idx) {
+Builder.add(MI.getOperand(Idx));
+ }
+ Builder->setFlag(MachineInstr::NoMerge);
+ MBB->remove_instr(&MI);
+ return MBB;
+}
+
MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
MachineInstr &MI, MachineBasicBlock *BB) const {
@@ -7590,6 +7628,8 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
return LowerSELECT(Op, DAG);
case ISD::SELECT_CC:
return LowerSELECT_CC(Op, DAG);
+ case ISD::CTSELECT:
+return LowerCTSELECT(Op, DAG);
case ISD::JumpTable:
return LowerJumpTable(Op, DAG);
case ISD::BR_JT:
@@ -12149,6 +12189,22 @@ SDValue AArch64TargetLowering::LowerSELECT(SDValue Op,
return Res;
}
+SDValue AArch64TargetLowering::LowerCTSELECT(SDValue Op,
+ SelectionDAG &DAG) const {
+ SDValue CCVal = Op->getOperand(0);
+ SDValue TVal = Op->getOper
[llvm-branch-commits] [llvm] [ConstantTime][WebAssembly] Add comprehensive tests for ct.select (PR #166709)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166709
>From 046e875568de9a6a794725bc69572151be8b8b9f Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 11:03:23 -0500
Subject: [PATCH] [ConstantTime][WebAssembly] Add comprehensive tests for
ct.select
---
.../ctselect-fallback-edge-cases.ll | 376 +
.../WebAssembly/ctselect-fallback-patterns.ll | 641
.../WebAssembly/ctselect-fallback-vector.ll | 714 ++
.../CodeGen/WebAssembly/ctselect-fallback.ll | 552 ++
.../WebAssembly/ctselect-side-effects.ll | 226 ++
5 files changed, 2509 insertions(+)
create mode 100644
llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-fallback-patterns.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-fallback-vector.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-fallback.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-side-effects.ll
diff --git a/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0..b0f7f2807debd
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,376 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=wasm32-unknown-unknown -O3 -filetype=asm | FileCheck
%s --check-prefix=W32
+; RUN: llc < %s -mtriple=wasm64-unknown-unknown -O3 -filetype=asm | FileCheck
%s --check-prefix=W64
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; W32-LABEL: test_ctselect_i1:
+; W32: .functype test_ctselect_i1 (i32, i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT:local.get 0
+; W32-NEXT:local.get 1
+; W32-NEXT:i32.and
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const 1
+; W32-NEXT:i32.xor
+; W32-NEXT:local.get 2
+; W32-NEXT:i32.and
+; W32-NEXT:i32.or
+; W32-NEXT:# fallthrough-return
+;
+; W64-LABEL: test_ctselect_i1:
+; W64: .functype test_ctselect_i1 (i32, i32, i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT:local.get 0
+; W64-NEXT:local.get 1
+; W64-NEXT:i32.and
+; W64-NEXT:local.get 0
+; W64-NEXT:i32.const 1
+; W64-NEXT:i32.xor
+; W64-NEXT:local.get 2
+; W64-NEXT:i32.and
+; W64-NEXT:i32.or
+; W64-NEXT:# fallthrough-return
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; W32-LABEL: test_ctselect_extremal_values:
+; W32: .functype test_ctselect_extremal_values (i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT:i32.const 0
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const 1
+; W32-NEXT:i32.and
+; W32-NEXT:local.tee 0
+; W32-NEXT:i32.sub
+; W32-NEXT:i32.const 2147483647
+; W32-NEXT:i32.and
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const -1
+; W32-NEXT:i32.add
+; W32-NEXT:i32.const -2147483648
+; W32-NEXT:i32.and
+; W32-NEXT:i32.or
+; W32-NEXT:# fallthrough-return
+;
+; W64-LABEL: test_ctselect_extremal_values:
+; W64: .functype test_ctselect_extremal_values (i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT:i32.const 0
+; W64-NEXT:local.get 0
+; W64-NEXT:i32.const 1
+; W64-NEXT:i32.and
+; W64-NEXT:local.tee 0
+; W64-NEXT:i32.sub
+; W64-NEXT:i32.const 2147483647
+; W64-NEXT:i32.and
+; W64-NEXT:local.get 0
+; W64-NEXT:i32.const -1
+; W64-NEXT:i32.add
+; W64-NEXT:i32.const -2147483648
+; W64-NEXT:i32.and
+; W64-NEXT:i32.or
+; W64-NEXT:# fallthrough-return
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32
-2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; W32-LABEL: test_ctselect_null_ptr:
+; W32: .functype test_ctselect_null_ptr (i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT:i32.const 0
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const 1
+; W32-NEXT:i32.and
+; W32-NEXT:i32.sub
+; W32-NEXT:local.get 1
+; W32-NEXT:i32.and
+; W32-NEXT:# fallthrough-return
+;
+; W64-LABEL: test_ctselect_null_ptr:
+; W64: .functype test_ctselect_null_ptr (i32, i64) -> (i64)
+; W64-NEXT: # %bb.0:
+; W64-NEXT:i64.const 0
+; W64-NEXT:local.get 0
+; W64-NEXT:i64.extend_i32_u
+; W64-NEXT:i64.const 1
+; W64-NEXT:i64.and
+; W64-NEXT:i64.sub
+; W64-NEXT:local.get 1
+; W64-NEXT:i64.and
+; W64-NEXT:# fallthrough-return
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+; W32-
[llvm-branch-commits] [llvm] [ConstantTime][RISCV] Add comprehensive tests for ct.select (PR #166708)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166708
>From 9ed3c7d206aa6d9dcba0fdbc3afe773b431bf597 Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 11:01:00 -0500
Subject: [PATCH] [ConstantTime][RISCV] Add comprehensive tests for ct.select
Add comprehensive test suite for RISC-V fallback implementation:
- Edge cases (zero conditions, large integers, sign extension)
- Pattern matching (nested selects, chains)
- Vector support with RVV extensions
- Side effects and memory operations
The basic fallback test is in the core infrastructure PR.
---
.../RISCV/ctselect-fallback-edge-cases.ll | 214 +
.../RISCV/ctselect-fallback-patterns.ll | 383 +
.../RISCV/ctselect-fallback-vector-rvv.ll | 804 ++
llvm/test/CodeGen/RISCV/ctselect-fallback.ll | 330 ---
.../CodeGen/RISCV/ctselect-side-effects.ll| 176
5 files changed, 1577 insertions(+), 330 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-patterns.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-vector-rvv.ll
delete mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-side-effects.ll
diff --git a/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
b/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0..af1be0c8f3ddc
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,214 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=riscv64 -O3 | FileCheck %s --check-prefix=RV64
+; RUN: llc < %s -mtriple=riscv32 -O3 | FileCheck %s --check-prefix=RV32
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; RV64-LABEL: test_ctselect_i1:
+; RV64: # %bb.0:
+; RV64-NEXT:and a1, a0, a1
+; RV64-NEXT:xori a0, a0, 1
+; RV64-NEXT:and a0, a0, a2
+; RV64-NEXT:or a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_i1:
+; RV32: # %bb.0:
+; RV32-NEXT:and a1, a0, a1
+; RV32-NEXT:xori a0, a0, 1
+; RV32-NEXT:and a0, a0, a2
+; RV32-NEXT:or a0, a1, a0
+; RV32-NEXT:ret
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; RV64-LABEL: test_ctselect_extremal_values:
+; RV64: # %bb.0:
+; RV64-NEXT:andi a0, a0, 1
+; RV64-NEXT:lui a1, 524288
+; RV64-NEXT:subw a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_extremal_values:
+; RV32: # %bb.0:
+; RV32-NEXT:andi a0, a0, 1
+; RV32-NEXT:lui a1, 524288
+; RV32-NEXT:addi a2, a0, -1
+; RV32-NEXT:neg a0, a0
+; RV32-NEXT:and a1, a2, a1
+; RV32-NEXT:slli a0, a0, 1
+; RV32-NEXT:srli a0, a0, 1
+; RV32-NEXT:or a0, a0, a1
+; RV32-NEXT:ret
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32
-2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; RV64-LABEL: test_ctselect_null_ptr:
+; RV64: # %bb.0:
+; RV64-NEXT:slli a0, a0, 63
+; RV64-NEXT:srai a0, a0, 63
+; RV64-NEXT:and a0, a0, a1
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_null_ptr:
+; RV32: # %bb.0:
+; RV32-NEXT:slli a0, a0, 31
+; RV32-NEXT:srai a0, a0, 31
+; RV32-NEXT:and a0, a0, a1
+; RV32-NEXT:ret
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+; RV64-LABEL: test_ctselect_function_ptr:
+; RV64: # %bb.0:
+; RV64-NEXT:andi a0, a0, 1
+; RV64-NEXT:neg a3, a0
+; RV64-NEXT:addi a0, a0, -1
+; RV64-NEXT:and a1, a3, a1
+; RV64-NEXT:and a0, a0, a2
+; RV64-NEXT:or a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_function_ptr:
+; RV32: # %bb.0:
+; RV32-NEXT:andi a0, a0, 1
+; RV32-NEXT:neg a3, a0
+; RV32-NEXT:addi a0, a0, -1
+; RV32-NEXT:and a1, a3, a1
+; RV32-NEXT:and a0, a0, a2
+; RV32-NEXT:or a0, a1, a0
+; RV32-NEXT:ret
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %func1, ptr %func2)
+ ret ptr %result
+}
+
+; Test with condition from icmp on pointers
+define ptr @test_ctselect_ptr_cmp(ptr %p1, ptr %p2, ptr %a, ptr %b) {
+; RV64-LABEL: test_ctselect_ptr_cmp:
+; RV64: # %bb.0:
+; RV64-NEXT:xor a0, a0, a1
+; RV64-NEXT:snez a0, a0
+; RV64-NEXT:addi a0, a0, -1
+; RV64-NEXT:and a2, a0, a2
+; RV64-NEXT:not a0, a0
+; RV64-NEXT:and a0, a0, a3
+; RV64-NEXT:or a0, a2, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_ptr_cmp:
+; RV32: # %bb.0:
+; RV32-NEXT:xor a0,
[llvm-branch-commits] [llvm] [ConstantTime][RISCV] Add comprehensive tests for ct.select (PR #166708)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166708
>From 9ed3c7d206aa6d9dcba0fdbc3afe773b431bf597 Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 11:01:00 -0500
Subject: [PATCH] [ConstantTime][RISCV] Add comprehensive tests for ct.select
Add comprehensive test suite for RISC-V fallback implementation:
- Edge cases (zero conditions, large integers, sign extension)
- Pattern matching (nested selects, chains)
- Vector support with RVV extensions
- Side effects and memory operations
The basic fallback test is in the core infrastructure PR.
---
.../RISCV/ctselect-fallback-edge-cases.ll | 214 +
.../RISCV/ctselect-fallback-patterns.ll | 383 +
.../RISCV/ctselect-fallback-vector-rvv.ll | 804 ++
llvm/test/CodeGen/RISCV/ctselect-fallback.ll | 330 ---
.../CodeGen/RISCV/ctselect-side-effects.ll| 176
5 files changed, 1577 insertions(+), 330 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-patterns.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback-vector-rvv.ll
delete mode 100644 llvm/test/CodeGen/RISCV/ctselect-fallback.ll
create mode 100644 llvm/test/CodeGen/RISCV/ctselect-side-effects.ll
diff --git a/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
b/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0..af1be0c8f3ddc
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,214 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=riscv64 -O3 | FileCheck %s --check-prefix=RV64
+; RUN: llc < %s -mtriple=riscv32 -O3 | FileCheck %s --check-prefix=RV32
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; RV64-LABEL: test_ctselect_i1:
+; RV64: # %bb.0:
+; RV64-NEXT:and a1, a0, a1
+; RV64-NEXT:xori a0, a0, 1
+; RV64-NEXT:and a0, a0, a2
+; RV64-NEXT:or a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_i1:
+; RV32: # %bb.0:
+; RV32-NEXT:and a1, a0, a1
+; RV32-NEXT:xori a0, a0, 1
+; RV32-NEXT:and a0, a0, a2
+; RV32-NEXT:or a0, a1, a0
+; RV32-NEXT:ret
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; RV64-LABEL: test_ctselect_extremal_values:
+; RV64: # %bb.0:
+; RV64-NEXT:andi a0, a0, 1
+; RV64-NEXT:lui a1, 524288
+; RV64-NEXT:subw a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_extremal_values:
+; RV32: # %bb.0:
+; RV32-NEXT:andi a0, a0, 1
+; RV32-NEXT:lui a1, 524288
+; RV32-NEXT:addi a2, a0, -1
+; RV32-NEXT:neg a0, a0
+; RV32-NEXT:and a1, a2, a1
+; RV32-NEXT:slli a0, a0, 1
+; RV32-NEXT:srli a0, a0, 1
+; RV32-NEXT:or a0, a0, a1
+; RV32-NEXT:ret
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32
-2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; RV64-LABEL: test_ctselect_null_ptr:
+; RV64: # %bb.0:
+; RV64-NEXT:slli a0, a0, 63
+; RV64-NEXT:srai a0, a0, 63
+; RV64-NEXT:and a0, a0, a1
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_null_ptr:
+; RV32: # %bb.0:
+; RV32-NEXT:slli a0, a0, 31
+; RV32-NEXT:srai a0, a0, 31
+; RV32-NEXT:and a0, a0, a1
+; RV32-NEXT:ret
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+; RV64-LABEL: test_ctselect_function_ptr:
+; RV64: # %bb.0:
+; RV64-NEXT:andi a0, a0, 1
+; RV64-NEXT:neg a3, a0
+; RV64-NEXT:addi a0, a0, -1
+; RV64-NEXT:and a1, a3, a1
+; RV64-NEXT:and a0, a0, a2
+; RV64-NEXT:or a0, a1, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_function_ptr:
+; RV32: # %bb.0:
+; RV32-NEXT:andi a0, a0, 1
+; RV32-NEXT:neg a3, a0
+; RV32-NEXT:addi a0, a0, -1
+; RV32-NEXT:and a1, a3, a1
+; RV32-NEXT:and a0, a0, a2
+; RV32-NEXT:or a0, a1, a0
+; RV32-NEXT:ret
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %func1, ptr %func2)
+ ret ptr %result
+}
+
+; Test with condition from icmp on pointers
+define ptr @test_ctselect_ptr_cmp(ptr %p1, ptr %p2, ptr %a, ptr %b) {
+; RV64-LABEL: test_ctselect_ptr_cmp:
+; RV64: # %bb.0:
+; RV64-NEXT:xor a0, a0, a1
+; RV64-NEXT:snez a0, a0
+; RV64-NEXT:addi a0, a0, -1
+; RV64-NEXT:and a2, a0, a2
+; RV64-NEXT:not a0, a0
+; RV64-NEXT:and a0, a0, a3
+; RV64-NEXT:or a0, a2, a0
+; RV64-NEXT:ret
+;
+; RV32-LABEL: test_ctselect_ptr_cmp:
+; RV32: # %bb.0:
+; RV32-NEXT:xor a0,
[llvm-branch-commits] [llvm] [ConstantTime] Native ct.select support for ARM64 (PR #166706)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166706
>From 7de2b8134fa87b1f113834b5ab0b218cbde5a821 Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 17:09:45 -0500
Subject: [PATCH] [LLVM][AArch64] Add native ct.select support for ARM64
This patch implements architecture-specific lowering for ct.select on AArch64
using CSEL (conditional select) instructions for constant-time selection.
Implementation details:
- Uses CSEL family of instructions for scalar integer types
- Uses FCSEL for floating-point types (F16, BF16, F32, F64)
- Post-RA MC lowering to convert pseudo-instructions to real CSEL/FCSEL
- Handles vector types appropriately
- Comprehensive test coverage for AArch64
The implementation includes:
- ISelLowering: Custom lowering to CTSELECT pseudo-instructions
- InstrInfo: Pseudo-instruction definitions and patterns
- MCInstLower: Post-RA lowering of pseudo-instructions to actual CSEL/FCSEL
- Proper handling of condition codes for constant-time guarantees
---
.../Target/AArch64/AArch64ISelLowering.cpp| 56 +
llvm/lib/Target/AArch64/AArch64ISelLowering.h | 11 +
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 200 --
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 40
.../lib/Target/AArch64/AArch64MCInstLower.cpp | 18 ++
llvm/test/CodeGen/AArch64/ctselect.ll | 153 ++
6 files changed, 368 insertions(+), 110 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/ctselect.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 60aa61e993b26..54d0ea168d0b6 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -511,12 +511,36 @@ AArch64TargetLowering::AArch64TargetLowering(const
TargetMachine &TM,
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
setOperationAction(ISD::SELECT, MVT::i32, Custom);
setOperationAction(ISD::SELECT, MVT::i64, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::i8, Promote);
+ setOperationAction(ISD::CTSELECT, MVT::i16, Promote);
+ setOperationAction(ISD::CTSELECT, MVT::i32, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::i64, Custom);
if (Subtarget->hasFPARMv8()) {
setOperationAction(ISD::SELECT, MVT::f16, Custom);
setOperationAction(ISD::SELECT, MVT::bf16, Custom);
}
+ if (Subtarget->hasFullFP16()) {
+setOperationAction(ISD::CTSELECT, MVT::f16, Custom);
+setOperationAction(ISD::CTSELECT, MVT::bf16, Custom);
+ } else {
+setOperationAction(ISD::CTSELECT, MVT::f16, Promote);
+setOperationAction(ISD::CTSELECT, MVT::bf16, Promote);
+ }
setOperationAction(ISD::SELECT, MVT::f32, Custom);
setOperationAction(ISD::SELECT, MVT::f64, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::f32, Custom);
+ setOperationAction(ISD::CTSELECT, MVT::f64, Custom);
+ for (MVT VT : MVT::vector_valuetypes()) {
+MVT elemType = VT.getVectorElementType();
+if (elemType == MVT::i8 || elemType == MVT::i16) {
+ setOperationAction(ISD::CTSELECT, VT, Promote);
+} else if ((elemType == MVT::f16 || elemType == MVT::bf16) &&
+ !Subtarget->hasFullFP16()) {
+ setOperationAction(ISD::CTSELECT, VT, Promote);
+} else {
+ setOperationAction(ISD::CTSELECT, VT, Expand);
+}
+ }
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f16, Custom);
@@ -3328,6 +3352,20 @@ void AArch64TargetLowering::fixupPtrauthDiscriminator(
IntDiscOp.setImm(IntDisc);
}
+MachineBasicBlock *AArch64TargetLowering::EmitCTSELECT(MachineInstr &MI,
+ MachineBasicBlock *MBB,
+ unsigned Opcode) const {
+ const TargetInstrInfo *TII = Subtarget->getInstrInfo();
+ DebugLoc DL = MI.getDebugLoc();
+ MachineInstrBuilder Builder = BuildMI(*MBB, MI, DL, TII->get(Opcode));
+ for (unsigned Idx = 0; Idx < MI.getNumOperands(); ++Idx) {
+Builder.add(MI.getOperand(Idx));
+ }
+ Builder->setFlag(MachineInstr::NoMerge);
+ MBB->remove_instr(&MI);
+ return MBB;
+}
+
MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
MachineInstr &MI, MachineBasicBlock *BB) const {
@@ -7590,6 +7628,8 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
return LowerSELECT(Op, DAG);
case ISD::SELECT_CC:
return LowerSELECT_CC(Op, DAG);
+ case ISD::CTSELECT:
+return LowerCTSELECT(Op, DAG);
case ISD::JumpTable:
return LowerJumpTable(Op, DAG);
case ISD::BR_JT:
@@ -12149,6 +12189,22 @@ SDValue AArch64TargetLowering::LowerSELECT(SDValue Op,
return Res;
}
+SDValue AArch64TargetLowering::LowerCTSELECT(SDValue Op,
+ SelectionDAG &DAG) const {
+ SDValue CCVal = Op->getOperand(0);
+ SDValue TVal = Op->getOper
[llvm-branch-commits] [llvm] [ConstantTime][WebAssembly] Add comprehensive tests for ct.select (PR #166709)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166709
>From 046e875568de9a6a794725bc69572151be8b8b9f Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 11:03:23 -0500
Subject: [PATCH] [ConstantTime][WebAssembly] Add comprehensive tests for
ct.select
---
.../ctselect-fallback-edge-cases.ll | 376 +
.../WebAssembly/ctselect-fallback-patterns.ll | 641
.../WebAssembly/ctselect-fallback-vector.ll | 714 ++
.../CodeGen/WebAssembly/ctselect-fallback.ll | 552 ++
.../WebAssembly/ctselect-side-effects.ll | 226 ++
5 files changed, 2509 insertions(+)
create mode 100644
llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-fallback-patterns.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-fallback-vector.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-fallback.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/ctselect-side-effects.ll
diff --git a/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0..b0f7f2807debd
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,376 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=wasm32-unknown-unknown -O3 -filetype=asm | FileCheck
%s --check-prefix=W32
+; RUN: llc < %s -mtriple=wasm64-unknown-unknown -O3 -filetype=asm | FileCheck
%s --check-prefix=W64
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; W32-LABEL: test_ctselect_i1:
+; W32: .functype test_ctselect_i1 (i32, i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT:local.get 0
+; W32-NEXT:local.get 1
+; W32-NEXT:i32.and
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const 1
+; W32-NEXT:i32.xor
+; W32-NEXT:local.get 2
+; W32-NEXT:i32.and
+; W32-NEXT:i32.or
+; W32-NEXT:# fallthrough-return
+;
+; W64-LABEL: test_ctselect_i1:
+; W64: .functype test_ctselect_i1 (i32, i32, i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT:local.get 0
+; W64-NEXT:local.get 1
+; W64-NEXT:i32.and
+; W64-NEXT:local.get 0
+; W64-NEXT:i32.const 1
+; W64-NEXT:i32.xor
+; W64-NEXT:local.get 2
+; W64-NEXT:i32.and
+; W64-NEXT:i32.or
+; W64-NEXT:# fallthrough-return
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; W32-LABEL: test_ctselect_extremal_values:
+; W32: .functype test_ctselect_extremal_values (i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT:i32.const 0
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const 1
+; W32-NEXT:i32.and
+; W32-NEXT:local.tee 0
+; W32-NEXT:i32.sub
+; W32-NEXT:i32.const 2147483647
+; W32-NEXT:i32.and
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const -1
+; W32-NEXT:i32.add
+; W32-NEXT:i32.const -2147483648
+; W32-NEXT:i32.and
+; W32-NEXT:i32.or
+; W32-NEXT:# fallthrough-return
+;
+; W64-LABEL: test_ctselect_extremal_values:
+; W64: .functype test_ctselect_extremal_values (i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT:i32.const 0
+; W64-NEXT:local.get 0
+; W64-NEXT:i32.const 1
+; W64-NEXT:i32.and
+; W64-NEXT:local.tee 0
+; W64-NEXT:i32.sub
+; W64-NEXT:i32.const 2147483647
+; W64-NEXT:i32.and
+; W64-NEXT:local.get 0
+; W64-NEXT:i32.const -1
+; W64-NEXT:i32.add
+; W64-NEXT:i32.const -2147483648
+; W64-NEXT:i32.and
+; W64-NEXT:i32.or
+; W64-NEXT:# fallthrough-return
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32
-2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; W32-LABEL: test_ctselect_null_ptr:
+; W32: .functype test_ctselect_null_ptr (i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT:i32.const 0
+; W32-NEXT:local.get 0
+; W32-NEXT:i32.const 1
+; W32-NEXT:i32.and
+; W32-NEXT:i32.sub
+; W32-NEXT:local.get 1
+; W32-NEXT:i32.and
+; W32-NEXT:# fallthrough-return
+;
+; W64-LABEL: test_ctselect_null_ptr:
+; W64: .functype test_ctselect_null_ptr (i32, i64) -> (i64)
+; W64-NEXT: # %bb.0:
+; W64-NEXT:i64.const 0
+; W64-NEXT:local.get 0
+; W64-NEXT:i64.extend_i32_u
+; W64-NEXT:i64.const 1
+; W64-NEXT:i64.and
+; W64-NEXT:i64.sub
+; W64-NEXT:local.get 1
+; W64-NEXT:i64.and
+; W64-NEXT:# fallthrough-return
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+; W32-
[llvm-branch-commits] [clang] [ConstantTime][Clang] Add __builtin_ct_select for constant-time selection (PR #166703)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166703
>From 6ac8221eef92f3e8c615c2218b8db2e3d26cf692 Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 10:56:34 -0500
Subject: [PATCH] [ConstantTime][Clang] Add __builtin_ct_select for
constant-time selection
---
clang/include/clang/Basic/Builtins.td | 8 +
clang/lib/CodeGen/CGBuiltin.cpp | 37 +-
clang/lib/Sema/SemaChecking.cpp | 89 +++
.../test/Sema/builtin-ct-select-edge-cases.c | 384 ++
clang/test/Sema/builtin-ct-select.c | 683 ++
5 files changed, 1200 insertions(+), 1 deletion(-)
create mode 100644 clang/test/Sema/builtin-ct-select-edge-cases.c
create mode 100644 clang/test/Sema/builtin-ct-select.c
diff --git a/clang/include/clang/Basic/Builtins.td
b/clang/include/clang/Basic/Builtins.td
index 2b400b012d6ed..13e2a9849bfca 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5278,3 +5278,11 @@ def CountedByRef : Builtin {
let Attributes = [NoThrow, CustomTypeChecking];
let Prototype = "int(...)";
}
+
+// Constant-time select builtin
+def CtSelect : Builtin {
+ let Spellings = ["__builtin_ct_select"];
+ let Attributes = [NoThrow, Const, UnevaluatedArguments,
+ConstIgnoringExceptions, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index b81e0d02da2c9..3703c9a4ffa79 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -26,8 +26,9 @@
#include "TargetInfo.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Intrinsics.h"
@@ -6450,6 +6451,40 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl
GD, unsigned BuiltinID,
auto Str = CGM.GetAddrOfConstantCString(Name, "");
return RValue::get(Str.getPointer());
}
+ case Builtin::BI__builtin_ct_select: {
+if (E->getNumArgs() != 3) {
+ CGM.getDiags().Report(E->getBeginLoc(),
+E->getNumArgs() > 3
+? diag::err_typecheck_call_too_many_args
+: diag::err_typecheck_call_too_few_args);
+ return GetUndefRValue(E->getType());
+}
+
+auto *Cond = EmitScalarExpr(E->getArg(0));
+auto *A = EmitScalarExpr(E->getArg(1));
+auto *B = EmitScalarExpr(E->getArg(2));
+
+// Verify types match
+if (A->getType() != B->getType()) {
+ CGM.getDiags().Report(E->getBeginLoc(),
+diag::err_typecheck_convert_incompatible);
+ return GetUndefRValue(E->getType());
+}
+
+// Verify condition is integer type
+if (!Cond->getType()->isIntegerTy()) {
+ CGM.getDiags().Report(E->getBeginLoc(), diag::err_typecheck_expect_int);
+ return GetUndefRValue(E->getType());
+}
+
+if (Cond->getType()->getIntegerBitWidth() != 1)
+ Cond = Builder.CreateICmpNE(
+ Cond, llvm::ConstantInt::get(Cond->getType(), 0), "cond.bool");
+
+llvm::Function *Fn =
+CGM.getIntrinsic(llvm::Intrinsic::ct_select, {A->getType()});
+return RValue::get(Builder.CreateCall(Fn, {Cond, A, B}));
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ad2c2e4a97bb9..026912c859c73 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3494,6 +3494,95 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl,
unsigned BuiltinID,
if (BuiltinCountedByRef(TheCall))
return ExprError();
break;
+
+ case Builtin::BI__builtin_ct_select: {
+if (TheCall->getNumArgs() != 3) {
+ // Simple argument count check without complex diagnostics
+ if (TheCall->getNumArgs() < 3) {
+return Diag(TheCall->getEndLoc(),
+diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 3 << TheCall->getNumArgs() << 0
+ << TheCall->getCallee()->getSourceRange();
+ } else {
+return Diag(TheCall->getEndLoc(),
+diag::err_typecheck_call_too_many_args)
+ << 0 << 3 << TheCall->getNumArgs() << 0
+ << TheCall->getCallee()->getSourceRange();
+ }
+}
+auto *Cond = TheCall->getArg(0);
+auto *A = TheCall->getArg(1);
+auto *B = TheCall->getArg(2);
+
+QualType CondTy = Cond->getType();
+if (!CondTy->isIntegerType()) {
+ return Diag(Cond->getBeginLoc(), diag::err_typecheck_cond_expect_scalar)
+ << CondTy << Cond->getSourceRange();
+}
+
+QualType ATy = A->getType();
+Qu
[llvm-branch-commits] [clang] [ConstantTime][Clang] Add __builtin_ct_select for constant-time selection (PR #166703)
https://github.com/wizardengineer updated
https://github.com/llvm/llvm-project/pull/166703
>From 6ac8221eef92f3e8c615c2218b8db2e3d26cf692 Mon Sep 17 00:00:00 2001
From: wizardengineer
Date: Wed, 5 Nov 2025 10:56:34 -0500
Subject: [PATCH] [ConstantTime][Clang] Add __builtin_ct_select for
constant-time selection
---
clang/include/clang/Basic/Builtins.td | 8 +
clang/lib/CodeGen/CGBuiltin.cpp | 37 +-
clang/lib/Sema/SemaChecking.cpp | 89 +++
.../test/Sema/builtin-ct-select-edge-cases.c | 384 ++
clang/test/Sema/builtin-ct-select.c | 683 ++
5 files changed, 1200 insertions(+), 1 deletion(-)
create mode 100644 clang/test/Sema/builtin-ct-select-edge-cases.c
create mode 100644 clang/test/Sema/builtin-ct-select.c
diff --git a/clang/include/clang/Basic/Builtins.td
b/clang/include/clang/Basic/Builtins.td
index 2b400b012d6ed..13e2a9849bfca 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5278,3 +5278,11 @@ def CountedByRef : Builtin {
let Attributes = [NoThrow, CustomTypeChecking];
let Prototype = "int(...)";
}
+
+// Constant-time select builtin
+def CtSelect : Builtin {
+ let Spellings = ["__builtin_ct_select"];
+ let Attributes = [NoThrow, Const, UnevaluatedArguments,
+ConstIgnoringExceptions, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index b81e0d02da2c9..3703c9a4ffa79 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -26,8 +26,9 @@
#include "TargetInfo.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Intrinsics.h"
@@ -6450,6 +6451,40 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl
GD, unsigned BuiltinID,
auto Str = CGM.GetAddrOfConstantCString(Name, "");
return RValue::get(Str.getPointer());
}
+ case Builtin::BI__builtin_ct_select: {
+if (E->getNumArgs() != 3) {
+ CGM.getDiags().Report(E->getBeginLoc(),
+E->getNumArgs() > 3
+? diag::err_typecheck_call_too_many_args
+: diag::err_typecheck_call_too_few_args);
+ return GetUndefRValue(E->getType());
+}
+
+auto *Cond = EmitScalarExpr(E->getArg(0));
+auto *A = EmitScalarExpr(E->getArg(1));
+auto *B = EmitScalarExpr(E->getArg(2));
+
+// Verify types match
+if (A->getType() != B->getType()) {
+ CGM.getDiags().Report(E->getBeginLoc(),
+diag::err_typecheck_convert_incompatible);
+ return GetUndefRValue(E->getType());
+}
+
+// Verify condition is integer type
+if (!Cond->getType()->isIntegerTy()) {
+ CGM.getDiags().Report(E->getBeginLoc(), diag::err_typecheck_expect_int);
+ return GetUndefRValue(E->getType());
+}
+
+if (Cond->getType()->getIntegerBitWidth() != 1)
+ Cond = Builder.CreateICmpNE(
+ Cond, llvm::ConstantInt::get(Cond->getType(), 0), "cond.bool");
+
+llvm::Function *Fn =
+CGM.getIntrinsic(llvm::Intrinsic::ct_select, {A->getType()});
+return RValue::get(Builder.CreateCall(Fn, {Cond, A, B}));
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ad2c2e4a97bb9..026912c859c73 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3494,6 +3494,95 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl,
unsigned BuiltinID,
if (BuiltinCountedByRef(TheCall))
return ExprError();
break;
+
+ case Builtin::BI__builtin_ct_select: {
+if (TheCall->getNumArgs() != 3) {
+ // Simple argument count check without complex diagnostics
+ if (TheCall->getNumArgs() < 3) {
+return Diag(TheCall->getEndLoc(),
+diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 3 << TheCall->getNumArgs() << 0
+ << TheCall->getCallee()->getSourceRange();
+ } else {
+return Diag(TheCall->getEndLoc(),
+diag::err_typecheck_call_too_many_args)
+ << 0 << 3 << TheCall->getNumArgs() << 0
+ << TheCall->getCallee()->getSourceRange();
+ }
+}
+auto *Cond = TheCall->getArg(0);
+auto *A = TheCall->getArg(1);
+auto *B = TheCall->getArg(2);
+
+QualType CondTy = Cond->getType();
+if (!CondTy->isIntegerType()) {
+ return Diag(Cond->getBeginLoc(), diag::err_typecheck_cond_expect_scalar)
+ << CondTy << Cond->getSourceRange();
+}
+
+QualType ATy = A->getType();
+Qu
