EricWF created this revision.
Herald added a subscriber: Prazek.

This patch adds `__builtin_launder`, which is required to implement 
`std::launder`. Additionally GCC provides `__builtin_launder`, so thing brings 
Clang in-line with GCC.

I'm not exactly sure what magic `__builtin_launder` requires, but  based on 
previous discussions this patch applies a `@llvm.invariant.group.barrier`. As 
noted in previous discussions, this may not be enough to correctly handle 
vtables.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===================================================================
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,22 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+#define TEST_TYPE(Ptr, Type) \
+static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip, const float*& fp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  TEST_TYPE(p, char*);
+  TEST_TYPE(vp, void*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+#undef TEST_TYPE
Index: test/Sema/builtins.c
===================================================================
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,14 @@
 
     return buf;
 }
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+}
Index: test/Preprocessor/feature_tests.c
===================================================================
--- test/Preprocessor/feature_tests.c
+++ test/Preprocessor/feature_tests.c
@@ -14,6 +14,7 @@
      !__has_builtin(__builtin_convertvector) || \
      !__has_builtin(__builtin_trap) || \
      !__has_builtin(__c11_atomic_init) || \
+     !__has_builtin(__builtin_launder) || \
      !__has_feature(attribute_analyzer_noreturn) || \
      !__has_feature(attribute_overloadable)
 #error Clang should have these
Index: test/CodeGen/builtins.c
===================================================================
--- test/CodeGen/builtins.c
+++ test/CodeGen/builtins.c
@@ -132,6 +132,8 @@
   R(extract_return_addr, (&N));
   P(signbit, (1.0));
 
+  R(launder, (&N));
+
   return 0;
 }
 
@@ -396,6 +398,20 @@
   return __builtin_readcyclecounter();
 }
 
+// CHECK-LABEL: define void @test_builtin_launder
+void test_builtin_launder(int *p) {
+  // CHECK: entry
+  // CHECK-NEXT: %p.addr = alloca i32*
+  // CHECK-NEXT: %d = alloca i32*
+  // CHECK-NEXT: store i32* %p, i32** %p.addr, align 8
+  // CHECK-NEXT: [[TMP:%.*]] = load i32*, i32** %p.addr
+  // CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP]] to i8*
+  // CHECK-NEXT: [[TMP2:%.*]] = call i8* @llvm.invariant.group.barrier.p0i8(i8* [[TMP1]])
+  // CHECK-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32*
+  // CHECK-NEXT: store i32* [[TMP3]], i32** %d
+  int *d = __builtin_launder(p);
+}
+
 // Behavior of __builtin_os_log differs between platforms, so only test on X86
 #ifdef __x86_64__
 
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -850,6 +850,20 @@
   return false;
 }
 
+static bool SemaBuiltinLaunder(Sema& S, CallExpr *TheCall) {
+  if (checkArgCount(S, TheCall, 1)) return true;
+  Expr *Arg = TheCall->getArg(0);
+  QualType ArgT = Arg->getType();
+  if (!ArgT->isPointerType()) {
+    S.Diag(TheCall->getLocStart(), diag::err_builtin_launder_non_pointer_arg)
+        << TheCall->getSourceRange();
+    return true;
+  }
+  TheCall->setType(Arg->getType());
+  // FIXME: Add attributes to argument
+  return false; // OK
+}
+
 ExprResult
 Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
                                CallExpr *TheCall) {
@@ -967,6 +981,10 @@
     if (checkArgCount(*this, TheCall, 1)) return true;
     TheCall->setType(Context.IntTy);
     break;
+  case Builtin::BI__builtin_launder:
+    if (SemaBuiltinLaunder(*this, TheCall))
+      return ExprError();
+    break;
   case Builtin::BI__sync_fetch_and_add:
   case Builtin::BI__sync_fetch_and_add_1:
   case Builtin::BI__sync_fetch_and_add_2:
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -1669,6 +1669,11 @@
 
     return RValue::get(nullptr);
   }
+  case Builtin::BI__builtin_launder: {
+    Value *Ptr = EmitScalarExpr(E->getArg(0));
+    Ptr = Builder.CreateInvariantGroupBarrier(Ptr);
+    return RValue::get(Ptr);
+  }
   case Builtin::BI__sync_fetch_and_add:
   case Builtin::BI__sync_fetch_and_sub:
   case Builtin::BI__sync_fetch_and_or:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -9337,4 +9337,7 @@
   InGroup<ShadowField>, DefaultIgnore;
 def note_shadow_field : Note<"declared here">;
 
+def err_builtin_launder_non_pointer_arg :
+  Error<"non-pointer argument to '__builtin_launder'">;
+
 } // end of sema component.
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -477,6 +477,7 @@
 BUILTIN(__builtin_vsprintf, "ic*cC*a", "nFP:1:")
 BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:")
 BUILTIN(__builtin_thread_pointer, "v*", "nc")
+BUILTIN(__builtin_launder, "v*v*", "nt")
 
 // GCC exception builtins
 BUILTIN(__builtin_eh_return, "vzv*", "r") // FIXME: Takes intptr_t, not size_t!
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to