Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -1495,6 +1495,9 @@ BUILTIN(__builtin_ms_va_end, "vc*&", "n") BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n") +// T __builtin_speculation_safe_value (T val) +BUILTIN(__builtin_speculation_safe_value, "vv", "t") + #undef BUILTIN #undef LIBBUILTIN #undef LANGBUILTIN Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -9324,4 +9324,8 @@ "member '%2' is missing|" "the type is not trivially copyable|" "the type does not have the expected form}1">; + +def err_specsafevalue_builtin_must_be_pointer_or_integral : Error< + "argument to speculation_safe_value builtin must be a pointer or integer " + "(%0 invalid)">; } // end of sema component. Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -10430,6 +10430,8 @@ AtomicExpr::AtomicOp Op); ExprResult SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, bool IsDelete); + ExprResult + SemaBuiltinSpeculationSafeValueOverloaded(ExprResult TheCallResult); bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -3632,6 +3632,17 @@ Value *ArgPtr = Builder.CreateLoad(SrcAddr, "ap.val"); return RValue::get(Builder.CreateStore(ArgPtr, DestAddr)); } + + case Builtin::BI__builtin_speculation_safe_value: { + Value *Val = EmitScalarExpr(E->getArg(0)); + + llvm::Type *T = ConvertType(E->getType()); + assert((isa(T) || isa(T)) && + "unsupported type"); + + return RValue::get(Builder.CreateCall( + CGM.getIntrinsic(Intrinsic::speculationsafevalue, T), {Val})); + } } // If this is an alias for a lib function (e.g. __builtin_sin), emit Index: lib/Frontend/InitPreprocessor.cpp =================================================================== --- lib/Frontend/InitPreprocessor.cpp +++ lib/Frontend/InitPreprocessor.cpp @@ -1095,6 +1095,8 @@ Builder.defineMacro("__GLIBCXX_BITSIZE_INT_N_0", "128"); } + Builder.defineMacro("__HAVE_SPECULATION_SAFE_VALUE"); + // Get other target #defines. TI.getTargetDefines(LangOpts, Builder); } Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1333,6 +1333,8 @@ if (SemaBuiltinOSLogFormat(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_speculation_safe_value: + return SemaBuiltinSpeculationSafeValueOverloaded(TheCallResult); } // Since the target specific builtins for each arch overlap, only check those @@ -4271,6 +4273,50 @@ return TheCallResult; } +ExprResult +Sema::SemaBuiltinSpeculationSafeValueOverloaded(ExprResult TheCallResult) { + CallExpr *TheCall = (CallExpr *)TheCallResult.get(); + DeclRefExpr *DRE = + cast(TheCall->getCallee()->IgnoreParenCasts()); + FunctionDecl *FDecl = cast(DRE->getDecl()); + unsigned BuiltinID = FDecl->getBuiltinID(); + assert(BuiltinID == Builtin::BI__builtin_speculation_safe_value && + "Unexpected speculation_safe_value builtin!"); + + // Too few args. + if (TheCall->getNumArgs() < 1) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << 1 /* min args */ << TheCall->getNumArgs(); + + // Too many args. + if (TheCall->getNumArgs() > 1) + return Diag(TheCall->getArg(1)->getLocStart(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << 1 << TheCall->getNumArgs() + << SourceRange(TheCall->getArg(1)->getLocStart(), + (*(TheCall->arg_end() - 1))->getLocEnd()); + + // Derive the return type from the pointer argument. + ExprResult FirstArg = + DefaultFunctionArrayLvalueConversion(TheCall->getArg(0)); + if (FirstArg.isInvalid()) + return true; + TheCall->setArg(0, FirstArg.get()); + QualType FirstArgType = FirstArg.get()->getType(); + + TheCall->setType(FirstArgType); + + // The first argument must be an integer or pointer type. + if (!(FirstArgType->isIntegerType() || FirstArgType->isAnyPointerType())) + return Diag(TheCall->getArg(0)->getLocStart(), + diag::err_specsafevalue_builtin_must_be_pointer_or_integral) + << TheCall->getArg(0)->getType() + << TheCall->getArg(0)->getSourceRange(); + + return TheCallResult; +} + /// CheckObjCString - Checks that the argument to the builtin /// CFString constructor is correct /// Note: It might also make sense to do the UTF-16 conversion here (would Index: test/CodeGen/builtin-speculation-safe-value.c =================================================================== --- /dev/null +++ test/CodeGen/builtin-speculation-safe-value.c @@ -0,0 +1,19 @@ +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-SUPPORTED %s + +void test(char c, int i, void *p) { + // CHECK-LABEL-SUPPORTED: define void @test + + char c_safe = __builtin_speculation_safe_value(c); + // CHECK-SUPPORTED: call i8 @llvm.speculationsafevalue.i8(i8 %{{[0-9a-z]+}}) + + int i_safe = __builtin_speculation_safe_value(i); + // CHECK-SUPPORTED: call i32 @llvm.speculationsafevalue.i32(i32 %{{[0-9a-z]+}}) + + void *p_safe = __builtin_speculation_safe_value(p); + // CHECK-SUPPORTED: call i8* @llvm.speculationsafevalue.p0i8(i8* %{{[0-9a-z]+}}) + + int arr[4]; + int *arr_safe = __builtin_speculation_safe_value(arr); + // CHECK-SUPPORTED: call i32* @llvm.speculationsafevalue.p0i32(i32* %{{[0-9a-z]+}}) +} Index: test/Preprocessor/init.c =================================================================== --- test/Preprocessor/init.c +++ test/Preprocessor/init.c @@ -9144,6 +9144,7 @@ // WEBASSEMBLY32-NEXT:#define __GNUC_STDC_INLINE__ 1 // WEBASSEMBLY32-NEXT:#define __GNUC__ {{.*}} // WEBASSEMBLY32-NEXT:#define __GXX_ABI_VERSION 1002 +// WEBASSEMBLY32-NEXT:#define __HAVE_SPECULATION_SAFE_VALUE 1 // WEBASSEMBLY32-NEXT:#define __ILP32__ 1 // WEBASSEMBLY32-NEXT:#define __INT16_C_SUFFIX__ // WEBASSEMBLY32-NEXT:#define __INT16_FMTd__ "hd" @@ -9476,6 +9477,7 @@ // WEBASSEMBLY64-NEXT:#define __GNUC_STDC_INLINE__ 1 // WEBASSEMBLY64-NEXT:#define __GNUC__ {{.}} // WEBASSEMBLY64-NEXT:#define __GXX_ABI_VERSION 1002 +// WEBASSEMBLY64-NEXT:#define __HAVE_SPECULATION_SAFE_VALUE 1 // WEBASSEMBLY64-NOT:#define __ILP32__ // WEBASSEMBLY64-NEXT:#define __INT16_C_SUFFIX__ // WEBASSEMBLY64-NEXT:#define __INT16_FMTd__ "hd" Index: test/Sema/builtin-speculation-safe-value.c =================================================================== --- /dev/null +++ test/Sema/builtin-speculation-safe-value.c @@ -0,0 +1,46 @@ +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64 -DENABLE_ERRORS -verify %s +// RUN: %clang_cc1 -triple aarch64 %s -emit-llvm -o - + +void test_type() { + char c; + c = __builtin_speculation_safe_value(c); + + short s; + s = __builtin_speculation_safe_value(s); + + int i; + i = __builtin_speculation_safe_value(i); + + long l; + l = __builtin_speculation_safe_value(l); + + long long ll; + ll = __builtin_speculation_safe_value(ll); + + int *ip; + ip = __builtin_speculation_safe_value(ip); + + int (*fp)(int, int); + fp = __builtin_speculation_safe_value(fp); + + enum {e1, e2} e; + e = __builtin_speculation_safe_value(e); + +#ifdef ENABLE_ERRORS + float f; + f = __builtin_speculation_safe_value(f); // expected-error {{argument to speculation_safe_value builtin must be a pointer or integer ('float' invalid)}} + + struct S { int a; } S; + S = __builtin_speculation_safe_value(S); // expected-error {{argument to speculation_safe_value builtin must be a pointer or integer ('struct S' invalid)}} + + union U { int a; } U; + U = __builtin_speculation_safe_value(U); // expected-error {{argument to speculation_safe_value builtin must be a pointer or integer ('union U' invalid)}} + + char __attribute__((vector_size(16))) v; + v = __builtin_speculation_safe_value(v); // expected-error {{argument to speculation_safe_value builtin must be a pointer or integer ('__attribute__((__vector_size__(16 * sizeof(char)))) char' (vector of 16 'char' values) invalid)}} + + c = __builtin_speculation_safe_value(); // expected-error {{too few arguments to function call, expected at least 1, have 0}} + c = __builtin_speculation_safe_value(c, s); // expected-error {{too many arguments to function call, expected at most 1, have 2}} +#endif +} Index: test/Sema/builtin-speculation-safe-value.cpp =================================================================== --- /dev/null +++ test/Sema/builtin-speculation-safe-value.cpp @@ -0,0 +1,58 @@ +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64 -x c++ -std=c++11 -DENABLE_ERRORS -verify %s +// RUN: %clang_cc1 -triple aarch64 -x c++ -std=c++11 %s -emit-llvm -o - + +void test_type() { + char c; + c = __builtin_speculation_safe_value(c); + + short s; + s = __builtin_speculation_safe_value(s); + + int i; + i = __builtin_speculation_safe_value(i); + + long l; + l = __builtin_speculation_safe_value(l); + + long long ll; + ll = __builtin_speculation_safe_value(ll); + + int *ip; + ip = __builtin_speculation_safe_value(ip); + + int (*fp)(int, int); + fp = __builtin_speculation_safe_value(fp); + + enum {e1, e2} e; + e = __builtin_speculation_safe_value(e); + +#ifdef enable_errors + float f; + f = __builtin_speculation_safe_value(f); // expected-error {{argument to speculation_safe_value builtin must be a pointer or integer ('float' invalid)}} + + struct s { int a; } s; + s = __builtin_speculation_safe_value(s); // expected-error {{argument to speculation_safe_value builtin must be a pointer or integer ('struct s' invalid)}} + + union u { int a; } u; + u = __builtin_speculation_safe_value(u); // expected-error {{argument to speculation_safe_value builtin must be a pointer or integer ('union u' invalid)}} + + char __attribute__((vector_size(16))) v; + v = __builtin_speculation_safe_value(v); // expected-error {{argument to speculation_safe_value builtin must be a pointer or integer ('__attribute__((__vector_size__(16 * sizeof(char)))) char' (vector of 16 'char' values) invalid)}} +#endif +} + +#ifdef ENABLE_ERRORS +template +T load(const T v) { + return __builtin_speculation_safe_value(v); // expected-error {{argument to speculation_safe_value builtin must be a pointer or integer ('float' invalid)}} +} + +void test_templates() { + int i; + load(i); + + float f; + load(f); // expected-note {{in instantiation of function template specialization 'load' requested here}} +} +#endif