Use +llvm::Value::MaximumAlignment in Sema to force evaluation and prevent 
errors like this (in Debug builds):
  libclang.so: undefined reference to `llvm::Value::MaximumAlignment'
(which is the same thing that is done in lib/Transforms/Utils/Local.cpp)

http://reviews.llvm.org/D149

Files:
  docs/LanguageExtensions.rst
  include/clang/Basic/Builtins.def
  include/clang/Sema/Sema.h
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtin-assume-aligned.c
  test/CodeGen/builtin-assume.c
  test/Sema/builtin-assume-aligned-tmpl.cpp
  test/Sema/builtin-assume-aligned.c
Index: docs/LanguageExtensions.rst
===================================================================
--- docs/LanguageExtensions.rst
+++ docs/LanguageExtensions.rst
@@ -1224,8 +1224,9 @@
 Clang supports a number of builtin library functions with the same syntax as
 GCC, including things like ``__builtin_nan``, ``__builtin_constant_p``,
 ``__builtin_choose_expr``, ``__builtin_types_compatible_p``,
-``__sync_fetch_and_add``, etc.  In addition to the GCC builtins, Clang supports
-a number of builtins that GCC does not, which are listed here.
+``__builtin_assume_aligned``, ``__sync_fetch_and_add``, etc.  In addition to
+the GCC builtins, Clang supports a number of builtins that GCC does not, which
+are listed here.
 
 Please note that Clang does not and will not support all of the GCC builtins
 for vector operations.  Instead of using builtins, you should use the functions
@@ -1235,6 +1236,41 @@
 <langext-vectors>` instead of builtins, in order to reduce the number of
 builtins that we need to implement.
 
+``__builtin_assume``
+------------------------------
+
+``__builtin_assume`` is used to provide the optimizer with a boolean
+invariant that is defined to be true.
+
+**Syntax**:
+
+.. code-block:: c++
+
+  __builtin_assume(bool)
+
+**Example of Use**:
+
+.. code-block:: c++
+
+  int foo(int x) {
+    __builtin_assume(x != 0);
+
+    // The optimizer may short-circuit this check using the invariant.
+    if (x == 0)
+      return do_something();
+
+    return do_something_else();
+  }
+
+**Description**:
+
+The boolean argument to this function is defined to be true. The optimizer may
+analyze the expression used to compute the argument and deduce from that
+information used to optimize the program. If the condition is violated during
+execution, the behavior is undefined.
+
+Query for this feature with ``__has_builtin(__builtin_assume)``.
+
 ``__builtin_readcyclecounter``
 ------------------------------
 
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -412,6 +412,7 @@
 BUILTIN(__builtin_va_end, "vA", "n")
 BUILTIN(__builtin_va_copy, "vAA", "n")
 BUILTIN(__builtin_stdarg_start, "vA.", "n")
+BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc")
 BUILTIN(__builtin_bcmp, "iv*v*z", "n")
 BUILTIN(__builtin_bcopy, "vv*v*z", "n")
 BUILTIN(__builtin_bzero, "vv*z", "nF")
@@ -1173,6 +1174,9 @@
 // Annotation function
 BUILTIN(__builtin_annotation, "v.", "tn")
 
+// Invariants
+BUILTIN(__builtin_assume, "vb", "n")
+
 // Multiprecision Arithmetic Builtins.
 BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n")
 BUILTIN(__builtin_addcs, "UsUsCUsCUsCUs*", "n")
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -8244,6 +8244,7 @@
 
 private:
   bool SemaBuiltinPrefetch(CallExpr *TheCall);
+  bool SemaBuiltinAssumeAligned(CallExpr *TheCall);
   bool SemaBuiltinLongjmp(CallExpr *TheCall);
   ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult);
   ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult,
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -6086,6 +6086,7 @@
     return Success(Operand, E);
   }
 
+  case Builtin::BI__builtin_assume_aligned:
   case Builtin::BI__builtin_expect:
     return Visit(E->getArg(0));
 
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -388,6 +388,39 @@
                                         "expval");
     return RValue::get(Result);
   }
+  case Builtin::BI__builtin_assume_aligned: {
+    Value *PtrValue = EmitScalarExpr(E->getArg(0));
+    Value *PtrIntValue =
+      Builder.CreatePtrToInt(PtrValue, IntPtrTy, "ptrint");
+
+    Value *AlignmentValue = EmitScalarExpr(E->getArg(1));
+    ConstantInt *AlignmentCI = cast<ConstantInt>(AlignmentValue);
+    unsigned Alignment = (unsigned) AlignmentCI->getZExtValue();
+
+    Value *Mask = llvm::ConstantInt::get(IntPtrTy,
+      Alignment > 0 ? Alignment - 1 : 0);
+    if (E->getNumArgs() > 2) {
+      Value *OffsetValue = EmitScalarExpr(E->getArg(2));
+      if (OffsetValue->getType() != IntPtrTy)
+        OffsetValue = Builder.CreateIntCast(OffsetValue, IntPtrTy,
+                        /*isSigned*/true, "offsetcast");
+      PtrIntValue = Builder.CreateSub(PtrIntValue, OffsetValue, "offsetptr");
+    }
+
+    Value *Zero = llvm::ConstantInt::get(IntPtrTy, 0);
+    Value *MaskedPtr = Builder.CreateAnd(PtrIntValue, Mask, "maskedptr");
+    Value *InvCond = Builder.CreateICmpEQ(MaskedPtr, Zero, "maskcond");
+
+    Value *FnInvariant = CGM.getIntrinsic(Intrinsic::invariant);
+    Builder.CreateCall(FnInvariant, InvCond);
+    return RValue::get(PtrValue);
+  }
+  case Builtin::BI__assume:
+  case Builtin::BI__builtin_assume: {
+    Value *ArgValue = EmitScalarExpr(E->getArg(0));
+    Value *FnInvariant = CGM.getIntrinsic(Intrinsic::invariant);
+    return RValue::get(Builder.CreateCall(FnInvariant, ArgValue));
+  }
   case Builtin::BI__builtin_bswap16:
   case Builtin::BI__builtin_bswap32:
   case Builtin::BI__builtin_bswap64: {
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -35,6 +35,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/IR/Value.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/raw_ostream.h"
 #include <limits>
@@ -175,6 +176,10 @@
     if (SemaBuiltinPrefetch(TheCall))
       return ExprError();
     break;
+  case Builtin::BI__builtin_assume_aligned:
+    if (SemaBuiltinAssumeAligned(TheCall))
+      return ExprError();
+    break;
   case Builtin::BI__builtin_object_size:
     if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3))
       return ExprError();
@@ -1942,6 +1947,51 @@
   return false;
 }
 
+/// Handle __builtin_assume_aligned. This is declared
+/// as (const void*, size_t, ...) and can take one optional constant int arg.
+bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) {
+  unsigned NumArgs = TheCall->getNumArgs();
+
+  if (NumArgs > 3)
+    return Diag(TheCall->getLocEnd(),
+             diag::err_typecheck_call_too_many_args_at_most)
+             << 0 /*function call*/ << 3 << NumArgs
+             << TheCall->getSourceRange();
+
+  // Argument 0 is checked for us; the alignment must be a constant integer.
+  Expr *Arg = TheCall->getArg(1);
+
+  // We can't check the value of a dependent argument.
+  if (!Arg->isTypeDependent() && !Arg->isValueDependent()) {
+    llvm::APSInt Result;
+    if (SemaBuiltinConstantArg(TheCall, 1, Result))
+      return true;
+
+    if (Result.getLimitedValue() > +llvm::Value::MaximumAlignment ||
+        !Result.isUnsigned())
+      return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
+           << "0" << +llvm::Value::MaximumAlignment << Arg->getSourceRange();
+    if (!Result.isPowerOf2())
+      return Diag(TheCall->getLocStart(),
+                  diag::err_attribute_aligned_not_power_of_two)
+           << Arg->getSourceRange();
+  }
+
+  if (NumArgs > 2) {
+    Arg = TheCall->getArg(2);
+    QualType T = Arg->getType();
+
+    // Note: gcc specifies the prototype as taking a size_t, but LLVM can
+    // handle only 32-bit alignment values.
+    if (!T->isIntegralType(Context))
+      return Diag(TheCall->getLocStart(),
+               diag::err_typecheck_converted_constant_expression)
+          << T << "an integral type" << Arg->getSourceRange();
+  }
+
+  return false;
+}
+
 /// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr
 /// TheCall is a constant expression.
 bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
Index: test/CodeGen/builtin-assume-aligned.c
===================================================================
--- /dev/null
+++ test/CodeGen/builtin-assume-aligned.c
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @test1
+int test1(int *a) {
+// CHECK: %ptrint = ptrtoint
+// CHECK: %offsetptr = sub i64 %ptrint, 0
+// CHECK: %maskedptr = and i64 %offsetptr, 31
+// CHECK: %maskcond = icmp eq i64 %maskedptr, 0
+// CHECK: call void @llvm.invariant(i1 %maskcond)
+  a = __builtin_assume_aligned(a, 32, 0ull);
+  return a[0];
+}
+
+// CHECK: @test2
+int test2(int *a) {
+// CHECK: %ptrint = ptrtoint
+// CHECK: %offsetptr = sub i64 %ptrint, 0
+// CHECK: %maskedptr = and i64 %offsetptr, 31
+// CHECK: %maskcond = icmp eq i64 %maskedptr, 0
+// CHECK: call void @llvm.invariant(i1 %maskcond)
+  a = __builtin_assume_aligned(a, 32, 0);
+  return a[0];
+}
+
+// CHECK: @test3
+int test3(int *a) {
+// CHECK: %ptrint = ptrtoint
+// CHECK: %maskedptr = and i64 %ptrint, 31
+// CHECK: %maskcond = icmp eq i64 %maskedptr, 0
+// CHECK: call void @llvm.invariant(i1 %maskcond)
+  a = __builtin_assume_aligned(a, 32);
+  return a[0];
+}
+
+// CHECK: @test4
+int test4(int *a, int b) {
+// CHECK: %ptrint = ptrtoint
+// CHECK: %offsetcast = sext i32
+// CHECK: %offsetptr = sub i64 %ptrint, %offsetcast
+// CHECK: %maskedptr = and i64 %offsetptr, 31
+// CHECK: %maskcond = icmp eq i64 %maskedptr, 0
+// CHECK: call void @llvm.invariant(i1 %maskcond)
+  a = __builtin_assume_aligned(a, 32, b);
+  return a[0];
+}
+
Index: test/CodeGen/builtin-assume.c
===================================================================
--- /dev/null
+++ test/CodeGen/builtin-assume.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @test1
+int test1(int *a) {
+// CHECK: %0 = load i32** %a.addr
+// CHECK: %cmp = icmp ne i32* %0, null
+// CHECK: call void @llvm.invariant(i1 %cmp)
+#ifdef _MSC_VER
+  __assume(a != 0)
+#else
+  __builtin_assume(a != 0);
+#endif
+  return a[0];
+}
+
Index: test/Sema/builtin-assume-aligned-tmpl.cpp
===================================================================
--- /dev/null
+++ test/Sema/builtin-assume-aligned-tmpl.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<int z>
+int test9(int *a) {
+  a = (int *) __builtin_assume_aligned(a, z + 1); // expected-error {{requested alignment is not a power of 2}}
+  return a[0];
+}
+
+void test9i(int *a) {
+  test9<42>(a); // expected-note {{in instantiation of function template specialization 'test9<42>' requested here}}
+}
+
+template<typename T>
+int test10(int *a, T z) {
+  a = (int *) __builtin_assume_aligned(a, z + 1); // expected-error {{must be a constant integer}}
+  return a[0];
+}
+
+int test10i(int *a) {
+  return test10(a, 42); // expected-note {{in instantiation of function template specialization 'test10<int>' requested here}}
+}
+
Index: test/Sema/builtin-assume-aligned.c
===================================================================
--- /dev/null
+++ test/Sema/builtin-assume-aligned.c
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int test1(int *a) {
+  a = __builtin_assume_aligned(a, 32, 0ull);
+  return a[0];
+}
+
+int test2(int *a) {
+  a = __builtin_assume_aligned(a, 32, 0);
+  return a[0];
+}
+
+int test3(int *a) {
+  a = __builtin_assume_aligned(a, 32);
+  return a[0];
+}
+
+int test4(int *a) {
+  a = __builtin_assume_aligned(a, -32); // expected-error {{argument should be a value from 0 to 536870912}}
+  a = __builtin_assume_aligned(a, 1ULL << 63); // expected-error {{argument should be a value from 0 to 536870912}}
+  return a[0];
+}
+
+int test5(int *a, unsigned *b) {
+  a = __builtin_assume_aligned(a, 32, b); // expected-error {{value of type 'unsigned int *' is not implicitly convertible to an integral type}}
+  return a[0];
+}
+
+int test6(int *a) {
+  a = __builtin_assume_aligned(a, 32, 0, 0); // expected-error {{too many arguments to function call, expected at most 3, have 4}}
+  return a[0];
+}
+
+int test7(int *a) {
+  a = __builtin_assume_aligned(a, 31); // expected-error {{requested alignment is not a power of 2}}
+  return a[0];
+}
+
+int test8(int *a, int j) {
+  a = __builtin_assume_aligned(a, j); // expected-error {{must be a constant integer}}
+  return a[0];
+}
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to