Query for this feature with ``__has_builtin(__builtin_assume)``.
+.. _langext-__builtin_assume_separate_storage:
+
+``__builtin_assume_separate_storage``
+--------------------
+
+``__builtin_assume_separate_storage`` is used to provide the optimizer with the
+knowledge that its two arguments point to separately allocated objects.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ __builtin_assume_separate_storage(const volatile void *, const volatile void *)
+
+**Example of Use**:
+
+.. code-block:: c++
+
+ int foo(int *x, int *y) {
+ __builtin_assume_separate_storage(x, y);
+ *x = 0;
+ *y = 1;
+ // The optimizer may optimize this to return 0 without reloading from *x.
+ return *x;
+ }
+
+**Description**:
+
+The arguments to this function are assumed to point into separately allocated
+storage (either different variable definitions or different dynamic storage
+allocations). The optimizer may use this fact to aid in alias analysis. If the
+arguments point into the same storage, the behavior is undefined. Note that the
+definition of "storage" here refers to the outermost enclosing allocation of any
+particular object (so for example, it's never correct to call this function
+passing the addresses of fields in the same struct, elements of the same array,
+etc.).
+
+Query for this feature with ``__has_builtin(__builtin_assume_separate_storage)``.
+
+
``__builtin_offsetof``
----------------------
- Clang now supports ``__builtin_FILE_NAME()`` which returns the same
information as the ``__FILE_NAME__`` macro (the presumed file name
from the invocation point, with no path components included).
+- Clang now supports ``__builtin_assume_separate_storage`` that indicates that
+ its arguments point to objects in separate storage allocations.
New Compiler Flags
------------------
// Invariants
BUILTIN(__builtin_assume, "vb", "nE")
+BUILTIN(__builtin_assume_separate_storage, "vvCD*vCD*", "nE")
// Multiprecision Arithmetic Builtins.
BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n")
Builder.CreateCall(FnAssume, ArgValue);
return RValue::get(nullptr);
}
+ case Builtin::BI__builtin_assume_separate_storage: {
+ const Expr *Arg0 = E->getArg(0);
+ const Expr *Arg1 = E->getArg(1);
+
+ Value *Value0 = EmitScalarExpr(Arg0);
+ Value *Value1 = EmitScalarExpr(Arg1);
+
+ Value *Values[] = {Value0, Value1};
+ OperandBundleDefT<Value *> OBD("separate_storage", Values);
+ Builder.CreateAssumption(ConstantInt::getTrue(getLLVMContext()), {OBD});
+ return RValue::get(nullptr);
+ }
case Builtin::BI__arithmetic_fence: {
// Create the builtin call if FastMath is selected, and the target
// supports the builtin, otherwise just return the argument.
--- /dev/null
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+void *nonconst(void);
+
+// CHECK-LABEL: @test1(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT: store ptr [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[TMP0]], ptr [[TMP1]]) ]
+// CHECK-NEXT: ret void
+//
+void test1(int *a, int *b) {
+
+ __builtin_assume_separate_storage(a, b);
+}
+
+// Separate storage assumptions evaluate their arguments unconditionally, like
+// assume_aligned but *unlike* assume. Check that we actually do so.
+// CHECK-LABEL: @test2(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT: store ptr [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT: [[CALL:%.*]] = call ptr @nonconst()
+// CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[TMP0]], ptr [[CALL]]) ]
+// CHECK-NEXT: ret void
+//
+void test2(int *a, int *b) {
+ __builtin_assume_separate_storage(a, nonconst());
+}
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
+
+void *nonconst(void);
+
+void test1(int *a, int *b) {
+ __builtin_assume_separate_storage(a, b);
+ // Separate storage assumptions evaluate their arguments unconditionally, like
+ // assume_aligned but *unlike* assume. Check that we don't warn on it.
+ __builtin_assume_separate_storage(a, nonconst());
+ __builtin_assume_separate_storage(nonconst(), a);
+ __builtin_assume_separate_storage(a, 3); // expected-error {{incompatible integer to pointer conversion}}
+ __builtin_assume_separate_storage(3, a); // expected-error {{incompatible integer to pointer conversion}}
+}