[PATCH] D100879: [Clang] Propagate guaranteed alignment for malloc and others

2021-11-22 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt added a comment.

(For background: I'm a jemalloc maintainer and wrote N2293).

In D100879#3145361 , @rjmccall wrote:

> Platforms are permitted to make stronger guarantees than the C standard 
> requires, and it is totally reasonable for compilers to assume that `malloc` 
> meets the target platform's documented guarantees.  Arguably, libraries 
> should not be replacing `malloc` if they fail to meet the platform's 
> documented guarantees.

I agree generally that assuming platform guarantees is reasonable for the 
compiler in targeting that platform, but I don't think I agree that the 
dlmalloc alignment is one of them. Supporting malloc replacement is a 
first-class feature for glibc malloc, and related projects avoid relying on 
alignment guarantees (e.g. libstdc++ at one point considered assuming that 
8-byte allocs were 16-byte aligned, and decided not to). At least one Linux 
distribution using clang (Alpine) uses musl, which is a weak-alignment 
implementation (contrary to what I claimed in N2293; I screwed up my background 
research).

> With that said, it's probably not unreasonable for Clang to provide an option 
> that controls its assumptions about `malloc`.  We should think somewhat 
> carefully about whether there are other behaviors we'd want to include in 
> that, though.

This makes sense to me; this is broadly how clang handles `operator new` 
alignment as well.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100879/new/

https://reviews.llvm.org/D100879

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2022-11-17 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt created this revision.
Herald added a project: All.
davidtgoldblatt updated this revision to Diff 476281.
davidtgoldblatt added a comment.
davidtgoldblatt updated this revision to Diff 476283.
davidtgoldblatt retitled this revision from "[builtins] add separate storage 
builtin support." to "[builtins] Add __builtin_assume_separate_storage.".
davidtgoldblatt edited the summary of this revision.
davidtgoldblatt published this revision for review.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Updating per review comments.


davidtgoldblatt added a comment.

Updating per review comments.


Just plumbing from the language level to the assume intrinsics with
separate_storage operand bundles.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D136515

Files:
  clang/include/clang/Basic/Builtins.def
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/test/CodeGen/builtin-assume-separate-storage.c
  clang/test/Sema/builtin-assume-separate-storage.c

Index: clang/test/Sema/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/Sema/builtin-assume-separate-storage.c
@@ -0,0 +1,13 @@
+// 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}}
+}
Index: clang/test/CodeGen/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/CodeGen/builtin-assume-separate-storage.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+void *nonconst(void);
+
+// 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.assume(i1 true) [ "separate_storage"(ptr [[A]], ptr [[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
+void test2(int *a, int *b) {
+  // CHECK: call ptr @nonconst()
+  // CHECK: call void @llvm.assume
+  __builtin_assume_separate_storage(a, nonconst());
+}
Index: clang/lib/Sema/SemaChecking.cpp
===
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -2169,6 +2169,10 @@
 if (SemaBuiltinAssumeAligned(TheCall))
   return ExprError();
 break;
+  case Builtin::BI__builtin_assume_separate_storage:
+if (SemaBuiltinAssumeSeparateStorage(TheCall))
+  return ExprError();
+break;
   case Builtin::BI__builtin_dynamic_object_size:
   case Builtin::BI__builtin_object_size:
 if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3))
@@ -7732,6 +7736,11 @@
   return false;
 }
 
+/// Handle __builtin_assume_separate_storage. For now this is a no-op, but
+/// eventually we expect an optional multi-arg variadic version (to handle an
+/// excluded range).
+bool Sema::SemaBuiltinAssumeSeparateStorage(CallExpr *TheCall) { return false; }
+
 bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) {
   unsigned BuiltinID =
   cast(TheCall->getCalleeDecl())->getBuiltinID();
Index: clang/lib/CodeGen/CGBuiltin.cpp
===
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2808,6 +2808,21 @@
 Builder.CreateCall(FnAssume, ArgValue);
 return RValue::get(nullptr);
   }
+  case Builtin::BI__builtin_assume_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);
+
+Value *Value0 = EmitScalarExpr(Arg0);
+Value *Value1 = EmitScalarExpr(Arg1);
+
+Value *Values[] = {Value0, Value1};
+OperandBundleDefT 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
 //

[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2022-11-28 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt updated this revision to Diff 478394.
davidtgoldblatt added a comment.

Fix out-of-date comment.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136515/new/

https://reviews.llvm.org/D136515

Files:
  clang/include/clang/Basic/Builtins.def
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/test/CodeGen/builtin-assume-separate-storage.c
  clang/test/Sema/builtin-assume-separate-storage.c

Index: clang/test/Sema/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/Sema/builtin-assume-separate-storage.c
@@ -0,0 +1,13 @@
+// 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}}
+}
Index: clang/test/CodeGen/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/CodeGen/builtin-assume-separate-storage.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+void *nonconst(void);
+
+// 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.assume(i1 true) [ "separate_storage"(ptr [[A]], ptr [[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
+void test2(int *a, int *b) {
+  // CHECK: call ptr @nonconst()
+  // CHECK: call void @llvm.assume
+  __builtin_assume_separate_storage(a, nonconst());
+}
Index: clang/lib/Sema/SemaChecking.cpp
===
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -2169,6 +2169,10 @@
 if (SemaBuiltinAssumeAligned(TheCall))
   return ExprError();
 break;
+  case Builtin::BI__builtin_assume_separate_storage:
+if (SemaBuiltinAssumeSeparateStorage(TheCall))
+  return ExprError();
+break;
   case Builtin::BI__builtin_dynamic_object_size:
   case Builtin::BI__builtin_object_size:
 if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3))
@@ -7732,6 +7736,11 @@
   return false;
 }
 
+/// Handle __builtin_assume_separate_storage. For now this is a no-op, but
+/// eventually we expect an optional multi-arg variadic version (to handle an
+/// excluded range).
+bool Sema::SemaBuiltinAssumeSeparateStorage(CallExpr *TheCall) { return false; }
+
 bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) {
   unsigned BuiltinID =
   cast(TheCall->getCalleeDecl())->getBuiltinID();
Index: clang/lib/CodeGen/CGBuiltin.cpp
===
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2808,6 +2808,19 @@
 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 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.
Index: clang/include/clang/Sema/Sema.h
===
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -13384,6 +13384,7 @@
   bool SemaBuiltinArithmeticFence(CallExpr *TheCall);
   bool SemaBuiltinAssume(CallExpr *TheCall);
   bool SemaBuiltinAssumeAligned(CallExpr *TheCall);
+  bool SemaBuiltinAssumeSeparateStorage(CallExpr *TheCall);
   bool SemaBuiltinLongjmp(CallExpr *TheCall);
   bool SemaBuiltinSetjmp(CallExpr *TheCall);
   ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult);
Index: clang/include/clang/Basic/Builtins.def
===

[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2023-03-15 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt added inline comments.



Comment at: clang/docs/LanguageExtensions.rst:2393
+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.).

bruno wrote:
> Not necessarily a blocker, but it seems like some of these things you mention 
> can actually be caught by diagnostics without too much effort? Any plans to 
> add them?
I hadn't planned to (at least in the short term). Practically I expect uses of 
this to be mostly backed out from looking at bad assembly (this is the way I've 
been using it so far in experimentation). You wouldn't generally expect people 
to want to try to express "these two struct fields don't alias" and so on 
because alias analysis can already handle those cases fairly well.

My inclination would be to wait on the diagnostics until we see if it's a real 
problem, but I'm not strongly opposed if you'd really like them in v1. 
(Although in that case I'll probably bug you for some help with where / how to 
put the diagnostics).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136515/new/

https://reviews.llvm.org/D136515

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2023-03-21 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt updated this revision to Diff 507133.
davidtgoldblatt added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136515/new/

https://reviews.llvm.org/D136515

Files:
  clang/docs/LanguageExtensions.rst
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Builtins.def
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/test/CodeGen/builtin-assume-separate-storage.c
  clang/test/Sema/builtin-assume-separate-storage.c

Index: clang/test/Sema/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/Sema/builtin-assume-separate-storage.c
@@ -0,0 +1,13 @@
+// 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}}
+}
Index: clang/test/CodeGen/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/CodeGen/builtin-assume-separate-storage.c
@@ -0,0 +1,36 @@
+// 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());
+}
Index: clang/lib/CodeGen/CGBuiltin.cpp
===
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2856,6 +2856,18 @@
 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 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.
Index: clang/include/clang/Basic/Builtins.def
===
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -1591,6 +1591,7 @@
 
 // Invariants
 BUILTIN(__builtin_assume, "vb", "nE")
+BUILTIN(__builtin_assume_separate_storage, "vvCD*vCD*", "nE")
 
 // Multiprecision Arithmetic Builtins.
 BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n")
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -124,6 +124,8 @@
 - 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
+  

[PATCH] D147021: [Builtins] Add __builtin_implicit_object_fence.

2023-03-28 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt created this revision.
Herald added subscribers: jeroen.dobbelaere, kosarev.
Herald added a project: All.
davidtgoldblatt updated this revision to Diff 509069.
davidtgoldblatt added a comment.
davidtgoldblatt added a reviewer: rsmith.
davidtgoldblatt published this revision for review.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Update


davidtgoldblatt added a comment.

Adding @zygoloid as a p2590 author for review


This is a builtin that allows the easy implementation of C++23's
start_lifetime_as. It takes a pointer, and returns a pointer allowing
implicit object creation at the given region of storage that will keep
the same object representation.

For now this just means forwarding llvm.tbaa.fence, which I believe is the only
place that C++-level type information makes it into LLVM IR in a
semantics-affecting way.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D147021

Files:
  clang/include/clang/Basic/Builtins.def
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/test/CodeGen/builtin-implicit-object-fence.c


Index: clang/test/CodeGen/builtin-implicit-object-fence.c
===
--- /dev/null
+++ clang/test/CodeGen/builtin-implicit-object-fence.c
@@ -0,0 +1,19 @@
+// 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
+
+// CHECK-LABEL: @test1(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[B:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT:[[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT:[[TMP1:%.*]] = call ptr @llvm.tbaa.fence(ptr [[TMP0]])
+// CHECK-NEXT:store ptr [[TMP1]], ptr [[B]], align 8
+// CHECK-NEXT:[[TMP2:%.*]] = load ptr, ptr [[B]], align 8
+// CHECK-NEXT:[[TMP3:%.*]] = load float, ptr [[TMP2]], align 4
+// CHECK-NEXT:ret float [[TMP3]]
+//
+float test1(int *a) {
+  float *b = __builtin_implicit_object_fence(a);
+  return *b;
+}
Index: clang/lib/CodeGen/CGBuiltin.cpp
===
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2472,7 +2472,7 @@
   return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
Intrinsic::roundeven,

Intrinsic::experimental_constrained_roundeven));
-   
+
 case Builtin::BIsin:
 case Builtin::BIsinf:
 case Builtin::BIsinl:
@@ -3904,6 +3904,14 @@
 
 return RValue::get(Ptr);
   }
+  case Builtin::BI__builtin_implicit_object_fence: {
+const Expr *Arg = E->getArg(0);
+Value *Ptr = EmitScalarExpr(Arg);
+Function *F =
+Intrinsic::getDeclaration(&CGM.getModule(), Intrinsic::tbaa_fence);
+Value *Result = Builder.CreateCall(F, {Ptr});
+return RValue::get(Result);
+  }
   case Builtin::BI__sync_fetch_and_add:
   case Builtin::BI__sync_fetch_and_sub:
   case Builtin::BI__sync_fetch_and_or:
Index: clang/include/clang/Basic/Builtins.def
===
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -662,6 +662,7 @@
 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_implicit_object_fence, "v*v*", "n")
 
 BUILTIN(__builtin_elementwise_abs, "v.", "nct")
 BUILTIN(__builtin_elementwise_max, "v.", "nct")


Index: clang/test/CodeGen/builtin-implicit-object-fence.c
===
--- /dev/null
+++ clang/test/CodeGen/builtin-implicit-object-fence.c
@@ -0,0 +1,19 @@
+// 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
+
+// CHECK-LABEL: @test1(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[B:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT:[[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT:[[TMP1:%.*]] = call ptr @llvm.tbaa.fence(ptr [[TMP0]])
+// CHECK-NEXT:store ptr [[TMP1]], ptr [[B]], align 8
+// CHECK-NEXT:[[TMP2:%.*]] = load ptr, ptr [[B]], align 8
+// CHECK-NEXT:[[TMP3:%.*]] = load float, ptr [[TMP2]], align 4
+// CHECK-NEXT:ret float [[TMP3]]
+//
+float test1(int *a) {
+  float *b = __builtin_implicit_object_fence(a);
+  return *b;
+}
Index: clang/lib/CodeGen/CGBuiltin.cpp
===
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2472,7 +2472,7 @@
  

[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2023-02-28 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt updated this revision to Diff 501297.
davidtgoldblatt added a comment.

Per comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136515/new/

https://reviews.llvm.org/D136515

Files:
  clang/docs/LanguageExtensions.rst
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Builtins.def
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/test/CodeGen/builtin-assume-separate-storage.c
  clang/test/Sema/builtin-assume-separate-storage.c

Index: clang/test/Sema/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/Sema/builtin-assume-separate-storage.c
@@ -0,0 +1,13 @@
+// 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}}
+}
Index: clang/test/CodeGen/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/CodeGen/builtin-assume-separate-storage.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+void *nonconst(void);
+
+// 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.assume(i1 true) [ "separate_storage"(ptr [[A]], ptr [[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
+void test2(int *a, int *b) {
+  // CHECK: call ptr @nonconst()
+  // CHECK: call void @llvm.assume
+  __builtin_assume_separate_storage(a, nonconst());
+}
Index: clang/lib/CodeGen/CGBuiltin.cpp
===
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2827,6 +2827,18 @@
 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 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.
Index: clang/include/clang/Basic/Builtins.def
===
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -1579,6 +1579,7 @@
 
 // Invariants
 BUILTIN(__builtin_assume, "vb", "nE")
+BUILTIN(__builtin_assume_separate_storage, "vvCD*vCD*", "nE")
 
 // Multiprecision Arithmetic Builtins.
 BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n")
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -108,6 +108,8 @@
   optimizations.
 - Clang now supports ``__builtin_nondeterministic_value`` that returns a
   nondeterministic value of the same type as the provided argument.
+- Clang now supports ``__builtin_assume_separate_storage`` that indicates that
+  its arguments point to objects in separate storage allocations.
 
 New Compiler Flags
 --
Index: clang/docs/LanguageExtensions.rst
===
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -2356,6 +2356,46 @@
 
 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**:
+
+.. cod

[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2023-02-28 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt added a comment.

In addition to the release notes addition, I also added an entry in 
LanguageExtensions.rst.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136515/new/

https://reviews.llvm.org/D136515

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2023-02-28 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt updated this revision to Diff 501315.
davidtgoldblatt added a comment.

Use utils/update_cc_test_checks.py for the codegen test.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136515/new/

https://reviews.llvm.org/D136515

Files:
  clang/docs/LanguageExtensions.rst
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Builtins.def
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/test/CodeGen/builtin-assume-separate-storage.c
  clang/test/Sema/builtin-assume-separate-storage.c

Index: clang/test/Sema/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/Sema/builtin-assume-separate-storage.c
@@ -0,0 +1,13 @@
+// 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}}
+}
Index: clang/test/CodeGen/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/CodeGen/builtin-assume-separate-storage.c
@@ -0,0 +1,36 @@
+// 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());
+}
Index: clang/lib/CodeGen/CGBuiltin.cpp
===
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2827,6 +2827,18 @@
 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 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.
Index: clang/include/clang/Basic/Builtins.def
===
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -1579,6 +1579,7 @@
 
 // Invariants
 BUILTIN(__builtin_assume, "vb", "nE")
+BUILTIN(__builtin_assume_separate_storage, "vvCD*vCD*", "nE")
 
 // Multiprecision Arithmetic Builtins.
 BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n")
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -108,6 +108,8 @@
   optimizations.
 - Clang now supports ``__builtin_nondeterministic_value`` that returns a
   nondeterministic value of the same type as the provided argument.
+- Clang now supports ``__builtin_assume_separate_storage`` that indicates tha

[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2023-02-21 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt added a comment.

Summarizing a brief offline discussion: I think it's probably fine to just get 
rid of the SemaChecking changes entirely; type-checking here is done by the 
generalized builtin-handling code. I'll do the change if there's no objection.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136515/new/

https://reviews.llvm.org/D136515

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D146178: [Clang][Sema] Fix comparison of constraint expressions

2023-05-04 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt added a comment.

This version of the commit also introduces some breakages; as before I'm not 
sure if it's the code or the diff that's incorrect.

Repro:

  enum class Enum { E1 };
  
  template 
  inline constexpr bool some_concept = true;
  
  template 
  struct S {
template 
requires some_concept
void func(const T2 &);
  };
  
  template 
  struct S {
template 
requires some_concept
void func(const T2 &);
  };
  
  template 
  template 
  requires some_concept
  inline void S::func(const T2 &) {}

Error:

  repro.cpp:23:30: error: out-of-line definition of 'func' does not match any 
declaration in 'S'
  inline void S::func(const T2 &) {}


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146178/new/

https://reviews.llvm.org/D146178

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D146178: [Clang][Sema] Fix comparison of constraint expressions

2023-05-02 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt added a comment.

This breaks ~the world in the versions of libstdc++ I can easily check -- see 
e.g. https://gcc.godbolt.org/z/ETeGzc3ve (crashes at this commit, changes to an 
error at ce861ec782ae3f41807b61e855512aaccf3c2149 
).

I'm not deep enough into this nook of the language to tell if the bug is here 
or libstdc++, though.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146178/new/

https://reviews.llvm.org/D146178

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2022-12-08 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt updated this revision to Diff 481481.
davidtgoldblatt added a comment.

Per review comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136515/new/

https://reviews.llvm.org/D136515

Files:
  clang/include/clang/Basic/Builtins.def
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/test/CodeGen/builtin-assume-separate-storage.c
  clang/test/Sema/builtin-assume-separate-storage.c

Index: clang/test/Sema/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/Sema/builtin-assume-separate-storage.c
@@ -0,0 +1,13 @@
+// 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}}
+}
Index: clang/test/CodeGen/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/CodeGen/builtin-assume-separate-storage.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+void *nonconst(void);
+
+// 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.assume(i1 true) [ "separate_storage"(ptr [[A]], ptr [[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
+void test2(int *a, int *b) {
+  // CHECK: call ptr @nonconst()
+  // CHECK: call void @llvm.assume
+  __builtin_assume_separate_storage(a, nonconst());
+}
Index: clang/lib/Sema/SemaChecking.cpp
===
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -2169,6 +2169,10 @@
 if (SemaBuiltinAssumeAligned(TheCall))
   return ExprError();
 break;
+  case Builtin::BI__builtin_assume_separate_storage:
+if (SemaBuiltinAssumeSeparateStorage(TheCall))
+  return ExprError();
+break;
   case Builtin::BI__builtin_dynamic_object_size:
   case Builtin::BI__builtin_object_size:
 if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3))
@@ -7767,6 +7771,11 @@
   return false;
 }
 
+/// Handle __builtin_assume_separate_storage. For now this is a no-op, but
+/// eventually we expect an optional multi-arg variadic version (to handle an
+/// excluded range).
+bool Sema::SemaBuiltinAssumeSeparateStorage(CallExpr *TheCall) { return false; }
+
 bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) {
   unsigned BuiltinID =
   cast(TheCall->getCalleeDecl())->getBuiltinID();
Index: clang/lib/CodeGen/CGBuiltin.cpp
===
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2823,6 +2823,19 @@
 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 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.
Index: clang/include/clang/Sema/Sema.h
===
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -13410,6 +13410,7 @@
   bool SemaBuiltinArithmeticFence(CallExpr *TheCall);
   bool SemaBuiltinAssume(CallExpr *TheCall);
   bool SemaBuiltinAssumeAligned(CallExpr *TheCall);
+  bool SemaBuiltinAssumeSeparateStorage(CallExpr *TheCall);
   bool SemaBuiltinLongjmp(CallExpr *TheCall);
   bool SemaBuiltinSetjmp(CallExpr *TheCall);
   ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult);
Index: clang/include/clang/Basic/Builtins.def
===

[PATCH] D136515: [builtins] Add __builtin_assume_separate_storage.

2022-12-09 Thread David Goldblatt via Phabricator via cfe-commits
davidtgoldblatt updated this revision to Diff 481770.
davidtgoldblatt added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136515/new/

https://reviews.llvm.org/D136515

Files:
  clang/include/clang/Basic/Builtins.def
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/test/CodeGen/builtin-assume-separate-storage.c
  clang/test/Sema/builtin-assume-separate-storage.c

Index: clang/test/Sema/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/Sema/builtin-assume-separate-storage.c
@@ -0,0 +1,13 @@
+// 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}}
+}
Index: clang/test/CodeGen/builtin-assume-separate-storage.c
===
--- /dev/null
+++ clang/test/CodeGen/builtin-assume-separate-storage.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+void *nonconst(void);
+
+// 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.assume(i1 true) [ "separate_storage"(ptr [[A]], ptr [[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
+void test2(int *a, int *b) {
+  // CHECK: call ptr @nonconst()
+  // CHECK: call void @llvm.assume
+  __builtin_assume_separate_storage(a, nonconst());
+}
Index: clang/lib/Sema/SemaChecking.cpp
===
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -2169,6 +2169,10 @@
 if (SemaBuiltinAssumeAligned(TheCall))
   return ExprError();
 break;
+  case Builtin::BI__builtin_assume_separate_storage:
+if (SemaBuiltinAssumeSeparateStorage(TheCall))
+  return ExprError();
+break;
   case Builtin::BI__builtin_dynamic_object_size:
   case Builtin::BI__builtin_object_size:
 if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3))
@@ -7800,6 +7804,11 @@
   return false;
 }
 
+/// Handle __builtin_assume_separate_storage. For now this is a no-op, but
+/// eventually we expect an optional multi-arg variadic version (to handle an
+/// excluded range).
+bool Sema::SemaBuiltinAssumeSeparateStorage(CallExpr *TheCall) { return false; }
+
 bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) {
   unsigned BuiltinID =
   cast(TheCall->getCalleeDecl())->getBuiltinID();
Index: clang/lib/CodeGen/CGBuiltin.cpp
===
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2823,6 +2823,19 @@
 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 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.
Index: clang/include/clang/Sema/Sema.h
===
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -13411,6 +13411,7 @@
   bool SemaBuiltinArithmeticFence(CallExpr *TheCall);
   bool SemaBuiltinAssume(CallExpr *TheCall);
   bool SemaBuiltinAssumeAligned(CallExpr *TheCall);
+  bool SemaBuiltinAssumeSeparateStorage(CallExpr *TheCall);
   bool SemaBuiltinLongjmp(CallExpr *TheCall);
   bool SemaBuiltinSetjmp(CallExpr *TheCall);
   ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult);
Index: clang/include/clang/Basic/Builtins.def
=