diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -3080,6 +3080,32 @@ Query for this feature with ``__has_builtin(__builtin_trap)``. +``__builtin_nondeterministic_value`` +------------------------------------ + +``__builtin_nondeterministic_value`` returns a valid nondeterministic value of the same type as the provided argument. + +**Syntax**: + +.. code-block:: c++ + + type __builtin_nondeterministic_value(type x) + +**Examples**: + +.. code-block:: c++ + + int x = __builtin_nondeterministic_value(x); + float y = __builtin_nondeterministic_value(y); + __m256i a = __builtin_nondeterministic_value(a); + +**Description** + +Each call to ``__builtin_nondeterministic_value`` returns a valid value of the type given by the argument. + +The types currently supported are: integer types, floating-point types, vector types. + +Query for this feature with ``__has_builtin(__builtin_nondeterministic_value)``. ``__builtin_sycl_unique_stable_name`` ------------------------------------- diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -72,6 +72,8 @@ - Clang now saves the address of ABI-indirect function parameters on the stack, improving the debug information available in programs compiled without optimizations. +- Clang now supports ``__builtin_nondeterministic_value`` that returns a + nondeterministic value of the same type as the provided argument. New Compiler Flags ------------------ diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -655,6 +655,7 @@ BUILTIN(__builtin_alloca_with_align, "v*zIz", "Fn") BUILTIN(__builtin_alloca_with_align_uninitialized, "v*zIz", "Fn") BUILTIN(__builtin_call_with_static_chain, "v.", "nt") +BUILTIN(__builtin_nondeterministic_value, "v.", "nt") BUILTIN(__builtin_elementwise_abs, "v.", "nct") BUILTIN(__builtin_elementwise_max, "v.", "nct") diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -13571,6 +13571,8 @@ bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall); bool PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall); + bool SemaBuiltinNonDeterministicValue(CallExpr *TheCall); + // Matrix builtin handling. ExprResult SemaBuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3060,6 +3060,15 @@ return RValue::get(V); } + case Builtin::BI__builtin_nondeterministic_value: { + llvm::Type *Ty = ConvertType(E->getArg(0)->getType()); + + Value *Result = PoisonValue::get(Ty); + Result = Builder.CreateFreeze(Result); + + return RValue::get(Result); + } + case Builtin::BI__builtin_elementwise_abs: { Value *Result; QualType QT = E->getArg(0)->getType(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2584,6 +2584,12 @@ break; } + case Builtin::BI__builtin_nondeterministic_value: { + if (SemaBuiltinNonDeterministicValue(TheCall)) + return ExprError(); + break; + } + // __builtin_elementwise_abs restricts the element type to signed integers or // floating point types only. case Builtin::BI__builtin_elementwise_abs: { @@ -17857,6 +17863,21 @@ return false; } +bool Sema::SemaBuiltinNonDeterministicValue(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 1)) + return true; + + ExprResult Arg = TheCall->getArg(0); + QualType TyArg = Arg.get()->getType(); + + if (!TyArg->isBuiltinType() && !TyArg->isVectorType()) + return Diag(TheCall->getArg(0)->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 1 << /*vector, integer or floating point ty*/ 0 << TyArg; + + TheCall->setType(TyArg); + return false; +} + ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult) { if (checkArgCount(*this, TheCall, 1)) diff --git a/clang/test/CodeGen/builtins-nondeterministic-value.c b/clang/test/CodeGen/builtins-nondeterministic-value.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtins-nondeterministic-value.c @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +typedef float float4 __attribute__((ext_vector_type(4))); +typedef _Bool bool4 __attribute__((ext_vector_type(4))); + +int clang_nondet_i( int x ) { +// CHECK-LABEL: entry +// CHECK: [[A:%.*]] = alloca i32, align 4 +// CHECK: store i32 [[X:%.*]], ptr [[A]], align 4 +// CHECK: [[R:%.*]] = freeze i32 poison +// CHECK: ret i32 [[R]] + return __builtin_nondeterministic_value(x); +} + +float clang_nondet_f( float x ) { +// CHECK-LABEL: entry +// CHECK: [[A:%.*]] = alloca float, align 4 +// CHECK: store float [[X:%.*]], ptr [[A]], align 4 +// CHECK: [[R:%.*]] = freeze float poison +// CHECK: ret float [[R]] + return __builtin_nondeterministic_value(x); +} + +double clang_nondet_d( double x ) { +// CHECK-LABEL: entry +// CHECK: [[A:%.*]] = alloca double, align 8 +// CHECK: store double [[X:%.*]], ptr [[A]], align 8 +// CHECK: [[R:%.*]] = freeze double poison +// CHECK: ret double [[R]] + return __builtin_nondeterministic_value(x); +} + +_Bool clang_nondet_b( _Bool x) { +// CHECK-LABEL: entry +// CHECK: [[A:%.*]] = alloca i8, align 1 +// CHECK: [[B:%.*]] = zext i1 %x to i8 +// CHECK: store i8 [[B]], ptr [[A]], align 1 +// CHECK: [[R:%.*]] = freeze i1 poison +// CHECK: ret i1 [[R]] + return __builtin_nondeterministic_value(x); +} + +void clang_nondet_fv( ) { +// CHECK-LABEL: entry +// CHECK: [[A:%.*]] = alloca <4 x float>, align 16 +// CHECK: [[R:%.*]] = freeze <4 x float> poison +// CHECK: store <4 x float> [[R]], ptr [[A]], align 16 +// CHECK: ret void + float4 x = __builtin_nondeterministic_value(x); +} + +void clang_nondet_bv( ) { +// CHECK: [[A:%.*]] = alloca i8, align 1 +// CHECK: [[V:%.*]] = freeze <4 x i1> poison +// CHECK: [[SV:%.*]] = shufflevector <4 x i1> [[V]], <4 x i1> poison, <8 x i32> +// CHECK: [[BC:%.*]] = bitcast <8 x i1> [[SV]] to i8 +// CHECK: store i8 [[BC]], ptr [[A]], align 1 +// CHECK: ret void + bool4 x = __builtin_nondeterministic_value(x); +} \ No newline at end of file