Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
f8d58bf
[CT]implementation of ct.select intrinsics and clang frontend changes…
kumarak Jul 22, 2025
f578008
[CT] Expand vector CTSELECT (#26)
frabert Jul 29, 2025
7607d42
[CT] Fix promotion of (CT)SELECT nodes (#24)
frabert Jul 29, 2025
648cfce
[CT] Expand float and integer CTSELECTs (#27)
frabert Aug 5, 2025
18323ae
Enchance CT Checks for all supported Archs
wizardengineer Aug 7, 2025
e4ff2e4
Initial implement for fallback method
wizardengineer Aug 10, 2025
ceaf0e3
Added test for RISCVs, MIPs and WebAsm
wizardengineer Aug 10, 2025
f5d45aa
Used a more generic and simpler approach for managing NoMerge flag
wizardengineer Aug 14, 2025
17d1d9c
[CT] Implement CTSELECT pseudo instruction for AArch64
frabert Aug 15, 2025
c16db7b
Move pseudo instruction expansion to post RA target specific expansio…
kumarak Aug 18, 2025
3912a7d
Added guards for non-integral pointers
wizardengineer Aug 15, 2025
7418898
Added support for Float/Double data types
wizardengineer Aug 17, 2025
5cde83a
Added support for Vector types
wizardengineer Aug 17, 2025
2afa2a2
[CT] Used sext for normalizing the predicate
wizardengineer Aug 19, 2025
71b4955
Added specific test; cmovznz4
wizardengineer Aug 18, 2025
14b2768
[CT] These changes reflect the current fallback changes. Which is was…
wizardengineer Aug 19, 2025
28bf374
[CT] Lower CTSELECT in post-RA pass for AArch64
frabert Aug 19, 2025
211f567
[CT] Added support for Scalable Vector types
wizardengineer Aug 19, 2025
b248476
Changes to for DAG Chaining
wizardengineer Aug 25, 2025
9af537e
[CT] Added diffs for webasm tests
wizardengineer Aug 25, 2025
f0c36cb
[CT] Removed NoMerge flag and added chain dependency between both ANDs
wizardengineer Aug 26, 2025
ab6692c
[CT] Added both createProtect function for chaining and for NoMerge Flag
wizardengineer Aug 27, 2025
3353218
[CT] Fix for x86 floating point vector types
wizardengineer Aug 28, 2025
ea30b33
[CT] check for xmm0 register as live and handle accordingly
kumarak Aug 29, 2025
9702887
[CT] save and restore XMM0 for using as mask register
kumarak Aug 29, 2025
28ca4d5
[CT] Move floating point logic to right place
wizardengineer Sep 2, 2025
2f6082b
[CT] update handling of mask and remove avx512 pseudo and usage pattern
kumarak Sep 2, 2025
82c59e7
[CT] report error on vector types with avx512 and improve lower ctselect
kumarak Sep 2, 2025
4d00929
[CT] add back support for v8f16 vector types that was removed
kumarak Sep 3, 2025
b62fd47
[CT] disable bundling for vector types
kumarak Sep 4, 2025
00355a2
[CT] legalize vector types and remove error reporting for 512 bits ve…
kumarak Sep 5, 2025
6945ccc
[CT]implementation of ct.select intrinsics and clang frontend changes…
kumarak May 30, 2025
1815b06
[CT] WIP: Implement CTSELECT for ARM
frabert Jul 15, 2025
62e58e5
WIP: integrate the ctselect intrinsic so it can be recognised and low…
kaoudis Jul 17, 2025
82e3c4c
[CT] Expand float and integer CTSELECTs (#27)
frabert Aug 5, 2025
3863def
[CT] initial ARM lowering to pseudo and expansion to bitwise
kaoudis Aug 7, 2025
384b8fe
[CT] code quality improvements to ARM implementation (#43)
kaoudis Sep 10, 2025
9ea628e
[CT][NFC] Added Mips code-gen tests that's affected by DAG Chaining
wizardengineer Sep 16, 2025
034f1e8
[CT] implements thumb1 and thumb2 lowering for ARM back end
kaoudis Sep 16, 2025
1fdd126
[CT] removes constant folding from our intrinisic
kaoudis Sep 17, 2025
5732f37
[CT] do not allow duplication and do not touch memory
kaoudis Sep 17, 2025
4440482
[CT] fix codegen for thumb1 instructions
kumarak Sep 21, 2025
c4b5a5b
[CT] Fix legalization of vectors with small lanes on AArch64
frabert Sep 22, 2025
97c0044
[CT] create instruction bundle during post RA expansion
kumarak Sep 24, 2025
e61e4be
[CT] record last intstruction during bundling for x86
kumarak Sep 25, 2025
a9b12f0
[CT] Integer constant-time selection without CMOV on i386
hbrodin Sep 29, 2025
4492258
[CT] Make cmov predicates more stringent
hbrodin Oct 2, 2025
a20a64c
[CT] Implement constant-time CTSELECT for i386 targets without CMOV
hbrodin Aug 26, 2025
2102d14
[CT] VR64 support
hbrodin Aug 29, 2025
ab15655
[CT] Fix bundle unpacking
hbrodin Sep 1, 2025
c03aa50
[CT] Properly expand BUNDLEs on x86
hbrodin Sep 24, 2025
b321ad9
[CT] Fix bundled sequence for ints
hbrodin Sep 24, 2025
4d69736
[CT] FP32 via integer ct-select
hbrodin Sep 24, 2025
7a9c27a
[CT] FP64 via two 32-bit integer ctselect
hbrodin Sep 24, 2025
878d53d
[CT] FP80 support via 32-bit integer ctselect
hbrodin Sep 24, 2025
e4fcc0f
[CT] Optimize for when operands on stack already - skip FP
hbrodin Sep 24, 2025
c80ffd7
[CT] Update handling of floating type and emit pseudo code in custom …
kumarak Oct 8, 2025
a5702d4
[CT] update unit tests for fp types
kumarak Oct 9, 2025
dc9b327
[CT] fix mismatch of register type for CTSELECT_I386_GR16 pseudo inst…
kumarak Oct 9, 2025
def8b7b
[CT] switch to using class for CTSELECT_I386* and fix formatting
kumarak Oct 9, 2025
6dcb509
[CT] Generate more efficient code when fp is from memory
hbrodin Oct 14, 2025
110dcc9
[CT] Clean up, for rebase
wizardengineer Oct 18, 2025
2ae33e9
[CT] X86 Change tests to work with LLVM 21
wizardengineer Oct 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -5253,3 +5253,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, UnevaluatedArguments,
ConstIgnoringExceptions, CustomTypeChecking];
let Prototype = "void(...)";
}
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,7 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
.Case("ssve-fp8fma", HasSSVE_FP8FMA)
.Case("sme-f8f32", HasSME_F8F32)
.Case("sme-f8f16", HasSME_F8F16)
.Case("ctselect", true)
.Default(false);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ bool ARMTargetInfo::hasFeature(StringRef Feature) const {
.Case("hwdiv", HWDiv & HWDivThumb)
.Case("hwdiv-arm", HWDiv & HWDivARM)
.Case("mve", hasMVE())
.Case("ctselect", true)
.Default(false);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("cf", HasCF)
.Case("zu", HasZU)
.Case("branch-hint", HasBranchHint)
.Case("ctselect", true)
.Default(false);
}

Expand Down
38 changes: 38 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#include "TargetInfo.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/Type.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/IR/InlineAsm.h"
Expand Down Expand Up @@ -6441,6 +6445,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
Expand Down
87 changes: 87 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3472,6 +3472,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->isScalarType() && !BTy->isVectorType())) {
return Diag(A->getBeginLoc(),
diag::err_typecheck_cond_incompatible_operands)
<< ATy << BTy << A->getSourceRange() << B->getSourceRange();
}

// Check if both operands have the same type or can be implicitly converted
QualType ResultTy;
if (Context.hasSameType(ATy, BTy)) {
ResultTy = ATy;
} else {
// Try to find a common type using the same logic as conditional
// expressions
ExprResult ARes = ExprResult(A);
ExprResult BRes = ExprResult(B);

// For arithmetic types, allow promotions within the same category only
if (ATy->isArithmeticType() && BTy->isArithmeticType()) {
// Check if both are integer types or both are floating types
bool AIsInteger = ATy->isIntegerType();
bool BIsInteger = BTy->isIntegerType();
bool AIsFloating = ATy->isFloatingType();
bool BIsFloating = BTy->isFloatingType();

if ((AIsInteger && BIsInteger) || (AIsFloating && BIsFloating)) {
// Both are in the same category, allow usual arithmetic conversions
ResultTy = UsualArithmeticConversions(
ARes, BRes, TheCall->getBeginLoc(), ArithConvKind::Conditional);
if (ARes.isInvalid() || BRes.isInvalid() || ResultTy.isNull()) {
return Diag(A->getBeginLoc(),
diag::err_typecheck_cond_incompatible_operands)
<< ATy << BTy << A->getSourceRange() << B->getSourceRange();
}
// Update the arguments with any necessary implicit casts
TheCall->setArg(1, ARes.get());
TheCall->setArg(2, BRes.get());
} else {
// Different categories (int vs float), not allowed
return Diag(A->getBeginLoc(),
diag::err_typecheck_cond_incompatible_operands)
<< ATy << BTy << A->getSourceRange() << B->getSourceRange();
}
} else {
// For non-arithmetic types, they must be exactly the same
return Diag(A->getBeginLoc(),
diag::err_typecheck_cond_incompatible_operands)
<< ATy << BTy << A->getSourceRange() << B->getSourceRange();
}
}

ExprResult CondRes = PerformContextuallyConvertToBool(Cond);
if (CondRes.isInvalid())
return ExprError();

TheCall->setArg(0, CondRes.get());
TheCall->setType(ResultTy);
return TheCall;
} break;
}

if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall))
Expand Down
Loading
Loading