-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[ConstantTime][Clang] Add __builtin_ct_select for constant-time selection #166703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: users/wizardengineer/ct-select-core
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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(); | ||
| QualType BTy = B->getType(); | ||
|
|
||
| // check for scalar or vector scalar type | ||
| if ((!ATy->isScalarType() && !ATy->isVectorType()) || | ||
| (!BTy->isScalarType() && !BTy->isVectorType())) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You probably want to do array/function promotion before this check? |
||
| 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 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The type computation for conditional expressions is complicated; I'd prefer not to extend it to contexts where we don't need it. |
||
| 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; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unnecessary break. |
||
| } | ||
|
|
||
| if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall)) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be generating diagnostics here; Sema should have already generated the relevant diagnostics, and if Sema generates a diagnostic, we don't reach codegen.