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 @@ -1569,6 +1569,9 @@ // Invariants BUILTIN(__builtin_assume, "vb", "nE") +// facebook begin T130678741 +BUILTIN(__builtin_experimental_separate_storage, "vvCD*vCD*", "nE") +// facebook end T130678741 // Multiprecision Arithmetic Builtins. BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n") 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 @@ -13318,6 +13318,9 @@ bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall); bool SemaBuiltinArithmeticFence(CallExpr *TheCall); bool SemaBuiltinAssume(CallExpr *TheCall); + // facebook begin T130678741 + bool SemaBuiltinExperimentalSeparateStorage(CallExpr *TheCall); + // facebook end T130678741 bool SemaBuiltinAssumeAligned(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); bool SemaBuiltinSetjmp(CallExpr *TheCall); 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 @@ -2806,6 +2806,22 @@ Function *FnAssume = CGM.getIntrinsic(Intrinsic::assume); return RValue::get(Builder.CreateCall(FnAssume, ArgValue)); } + // facebook begin T130678741 + case Builtin::BI__builtin_experimental_separate_storage: { + // We copy __builtin_assume's semantics and don't let side-effecting + // expressions do anything. Maybe this is the wrong thing? + const Expr *Arg0 = E->getArg(0); + const Expr *Arg1 = E->getArg(1); + if (Arg0->HasSideEffects(getContext()) || + Arg1->HasSideEffects(getContext())) + return RValue::get(nullptr); + + Value *Arg0Value = EmitScalarExpr(Arg0); + Value *Arg1Value = EmitScalarExpr(Arg1); + Function *Fn = CGM.getIntrinsic(Intrinsic::experimental_separate_storage); + return RValue::get(Builder.CreateCall(Fn, {Arg0Value, Arg1Value})); + } + // facebook end T130678741 case Builtin::BI__arithmetic_fence: { // Create the builtin call if FastMath is selected, and the target // supports the builtin, otherwise just return the argument. 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 @@ -2162,6 +2162,12 @@ if (SemaBuiltinAssume(TheCall)) return ExprError(); break; + // facebook begin T130678741 + case Builtin::BI__builtin_experimental_separate_storage: + if (SemaBuiltinExperimentalSeparateStorage(TheCall)) + return ExprError(); + break; + // facebook end T130678741 case Builtin::BI__builtin_assume_aligned: if (SemaBuiltinAssumeAligned(TheCall)) return ExprError(); @@ -7623,6 +7629,28 @@ return false; } +// facebook begin T130678741 +bool Sema::SemaBuiltinExperimentalSeparateStorage(CallExpr *TheCall) { + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + + // We don't actually have semantics for what happens when there are + // side-effecting operations inside the separate storage hint. + + if (!Arg0->isInstantiationDependent() && Arg0->HasSideEffects(Context)) + Diag(Arg0->getBeginLoc(), diag::warn_assume_side_effects) + << Arg0->getSourceRange() + << cast(TheCall->getCalleeDecl())->getIdentifier(); + + if (!Arg1->isInstantiationDependent() && Arg1->HasSideEffects(Context)) + Diag(Arg1->getBeginLoc(), diag::warn_assume_side_effects) + << Arg1->getSourceRange() + << cast(TheCall->getCalleeDecl())->getIdentifier(); + + return false; +} +// facebook end T130678741 + /// Handle __builtin_alloca_with_align. This is declared /// as (size_t, size_t) where the second size_t must be a power of 2 greater /// than 8. diff --git a/clang/test/CodeGen/builtin-experimental-separate-storage.c b/clang/test/CodeGen/builtin-experimental-separate-storage.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtin-experimental-separate-storage.c @@ -0,0 +1,39 @@ +// facebook begin T130678741 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s +void *nonconst(void); +void *isconst(void) __attribute__((const)); +void *ispure(void) __attribute__((pure)); + +// CHECK-LABEL: @test1 +void test1(int *a, int *b) { + // CHECK: store ptr %a, ptr [[A_ADDR:%.+]], align + // CHECK: store ptr %b, ptr [[B_ADDR:%.+]], align + // CHECK: [[A:%.+]] = load ptr, ptr [[A_ADDR]] + // CHECK: [[B:%.+]] = load ptr, ptr [[B_ADDR]] + + // CHECK: call void @llvm.experimental.separate.storage(ptr [[A]], ptr [[B]]) + __builtin_experimental_separate_storage(a, b); +} + +// CHECK-LABEL: @test2 +void test2(int *a, int *b) { + // CHECK-NOT: call void @llvm.experimental.separate.storage + // CHECK-NOT: call i32 @nonconst() + __builtin_experimental_separate_storage(a, nonconst()); + __builtin_experimental_separate_storage(a++, b++); +} + +// CHECK_LABEL @test3 +void test3(int *a) { + // CHECK: call ptr @isconst() + // CHECK: call void @llvm.experimental.separate.storage + __builtin_experimental_separate_storage(a, isconst()); +} + +// CHECK_LABEL @test4 +void test4(int *a) { + // CHECK: call ptr @ispure() + // CHECK: call void @llvm.experimental.separate.storage + __builtin_experimental_separate_storage(a, ispure()); +} +// facebook end T130678741 diff --git a/clang/test/Sema/builtin-experimental-separate-storage.c b/clang/test/Sema/builtin-experimental-separate-storage.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/builtin-experimental-separate-storage.c @@ -0,0 +1,14 @@ +// facebook begin T130678741 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s + +void *nonconst(void); + +void test1(int *a, int *b) { + __builtin_experimental_separate_storage(a, b); + __builtin_experimental_separate_storage(a++, b); // expected-warning {{the argument to '__builtin_experimental_separate_storage' has side effects that will be discarded}} + __builtin_experimental_separate_storage(nonconst(), a); // expected-warning {{the argument to '__builtin_experimental_separate_storage' has side effects that will be discarded}} + __builtin_experimental_separate_storage(a, nonconst()); // expected-warning {{the argument to '__builtin_experimental_separate_storage' has side effects that will be discarded}} + __builtin_experimental_separate_storage(a, 3); // expected-error {{incompatible integer to pointer conversion}} + __builtin_experimental_separate_storage(3, a); // expected-error {{incompatible integer to pointer conversion}} +} +// facebook end T130678741