Test cases have been enhanced. We now use @llvm.invariant.
http://llvm-reviews.chandlerc.com/D149
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D149?vs=383&id=438#toc
Files:
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.c
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -402,6 +402,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")
@@ -917,5 +918,8 @@
// Annotation function
BUILTIN(__builtin_annotation, "v.", "tn")
+// Invariants
+BUILTIN(__builtin_assume, "vb", "n")
+
#undef BUILTIN
#undef LIBBUILTIN
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -7201,6 +7201,7 @@
private:
bool SemaBuiltinPrefetch(CallExpr *TheCall);
+ bool SemaBuiltinAssumeAligned(CallExpr *TheCall);
bool SemaBuiltinObjectSize(CallExpr *TheCall);
bool SemaBuiltinLongjmp(CallExpr *TheCall);
ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult);
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -4314,6 +4314,7 @@
}
case Builtin::BI__builtin_expect:
+ case Builtin::BI__builtin_assume_aligned:
return Visit(E->getArg(0));
case Builtin::BIstrlen:
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -354,6 +354,38 @@
"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__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
@@ -38,6 +38,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Value.h"
#include <limits>
using namespace clang;
using namespace sema;
@@ -159,6 +160,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 (SemaBuiltinObjectSize(TheCall))
return ExprError();
@@ -1582,6 +1587,52 @@
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,9 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @test1
+int test1(int *a) {
+// CHECK: call void @llvm.invariant(i1
+ __builtin_assume(a != 0);
+ return a[0];
+}
+
Index: test/Sema/builtin-assume-aligned.c
===================================================================
--- /dev/null
+++ test/Sema/builtin-assume-aligned.c
@@ -0,0 +1,37 @@
+// 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}}
+ return a[0];
+}
+
+int test5(int *a, unsigned *b) {
+ a = __builtin_assume_aligned(a, 32, b); // expected-error {{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];
+}
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits