aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/ExprConstant.cpp22
-rw-r--r--lib/CodeGen/CGExprScalar.cpp31
-rw-r--r--lib/Sema/SemaExpr.cpp5
-rw-r--r--test/CodeGen/catch-undef-behavior.c2
-rw-r--r--test/CodeGenOpenCL/shifts.cl28
-rw-r--r--test/Sema/shiftOpenCL.cl14
6 files changed, 84 insertions, 18 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index a472951ab6..338cd74b32 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -4708,9 +4708,14 @@ bool DataRecursiveIntBinOpEvaluator::
return Success(E->getOpcode() == BO_Rem ? LHS % RHS : LHS / RHS, E,
Result);
case BO_Shl: {
- // During constant-folding, a negative shift is an opposite shift. Such
- // a shift is not a constant expression.
- if (RHS.isSigned() && RHS.isNegative()) {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(LHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such
+ // a shift is not a constant expression.
CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_right;
@@ -4735,9 +4740,14 @@ bool DataRecursiveIntBinOpEvaluator::
return Success(LHS << SA, E, Result);
}
case BO_Shr: {
- // During constant-folding, a negative shift is an opposite shift. Such a
- // shift is not a constant expression.
- if (RHS.isSigned() && RHS.isNegative()) {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(LHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_left;
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index eb62343bc6..7ec4bc2297 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -429,6 +429,8 @@ public:
// Check for undefined division and modulus behaviors.
void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops,
llvm::Value *Zero,bool isDiv);
+ // Common helper for getting how wide LHS of shift is.
+ static Value *GetWidthMinusOneValue(Value* LHS,Value* RHS);
Value *EmitDiv(const BinOpInfo &Ops);
Value *EmitRem(const BinOpInfo &Ops);
Value *EmitAdd(const BinOpInfo &Ops);
@@ -2365,6 +2367,11 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
return Builder.CreateExactSDiv(diffInChars, divisor, "sub.ptr.div");
}
+Value *ScalarExprEmitter::GetWidthMinusOneValue(Value* LHS,Value* RHS) {
+ unsigned Width = cast<llvm::IntegerType>(LHS->getType())->getBitWidth();
+ return llvm::ConstantInt::get(RHS->getType(), Width - 1);
+}
+
Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
// LLVM requires the LHS and RHS to be the same type: promote or truncate the
// RHS to the same size as the LHS.
@@ -2372,11 +2379,9 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.getLangOpts().SanitizeShift &&
- isa<llvm::IntegerType>(Ops.LHS->getType())) {
- unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::Value *WidthMinusOne =
- llvm::ConstantInt::get(RHS->getType(), Width - 1);
+ if (CGF.getLangOpts().SanitizeShift && !CGF.getLangOpts().OpenCL
+ && isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS);
// FIXME: Emit the branching explicitly rather than emitting the check
// twice.
EmitBinOpCheck(Builder.CreateICmpULE(RHS, WidthMinusOne), Ops);
@@ -2401,6 +2406,9 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
EmitBinOpCheck(Builder.CreateICmpEQ(BitsShiftedOff, Zero), Ops);
}
}
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ if (CGF.getLangOpts().OpenCL)
+ RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shl.mask");
return Builder.CreateShl(Ops.LHS, RHS, "shl");
}
@@ -2412,12 +2420,13 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.getLangOpts().SanitizeShift &&
- isa<llvm::IntegerType>(Ops.LHS->getType())) {
- unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::Value *WidthVal = llvm::ConstantInt::get(RHS->getType(), Width);
- EmitBinOpCheck(Builder.CreateICmpULT(RHS, WidthVal), Ops);
- }
+ if (CGF.getLangOpts().SanitizeShift && !CGF.getLangOpts().OpenCL
+ && isa<llvm::IntegerType>(Ops.LHS->getType()))
+ EmitBinOpCheck(Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS)), Ops);
+
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ if (CGF.getLangOpts().OpenCL)
+ RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shr.mask");
if (Ops.Ty->hasUnsignedIntegerRepresentation())
return Builder.CreateLShr(Ops.LHS, RHS, "shr");
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index b71491008b..bac897748f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -6578,6 +6578,11 @@ static bool isScopedEnumerationType(QualType T) {
static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, unsigned Opc,
QualType LHSType) {
+ // OpenCL 6.3j: shift values are effectively % word size of LHS (more defined),
+ // so skip remaining warnings as we don't want to modify values within Sema.
+ if (S.getLangOpts().OpenCL)
+ return;
+
llvm::APSInt Right;
// Check right/shifter operand
if (RHS.get()->isValueDependent() ||
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index d0b6d1969b..9170666d31 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -99,7 +99,7 @@ int lsh_overflow(int a, int b) {
// CHECK: @rsh_inbounds
int rsh_inbounds(int a, int b) {
- // CHECK: %[[INBOUNDS:.*]] = icmp ult i32 %[[RHS:.*]], 32
+ // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
// CHECK: br i1 %[[INBOUNDS]]
// CHECK: %[[ARG1:.*]] = zext
diff --git a/test/CodeGenOpenCL/shifts.cl b/test/CodeGenOpenCL/shifts.cl
new file mode 100644
index 0000000000..b84ec1eeef
--- /dev/null
+++ b/test/CodeGenOpenCL/shifts.cl
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -x cl -O1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// OpenCL essentially reduces all shift amounts to the last word-size bits before evaluating.
+// Test this both for variables and constants evaluated in the front-end.
+
+
+//CHECK: @positiveShift32
+int positiveShift32(int a,int b) {
+ //CHECK: %shl.mask = and i32 %b, 31
+ //CHECK-NEXT: %shl = shl i32 %a, %shl.mask
+ int c = a<<b;
+ int d = ((int)1)<<33;
+ //CHECK-NEXT: %add = add nsw i32 %shl, 2
+ int e = c + d;
+ //CHECK-NEXT: ret i32 %add
+ return e;
+}
+
+//CHECK: @positiveShift64
+long positiveShift64(long a,long b) {
+ //CHECK: %shr.mask = and i64 %b, 63
+ //CHECK-NEXT: %shr = ashr i64 %a, %shr.mask
+ long c = a>>b;
+ long d = ((long)8)>>65;
+ //CHECK-NEXT: %add = add nsw i64 %shr, 4
+ long e = c + d;
+ //CHECK-NEXT: ret i64 %add
+ return e;
+}
diff --git a/test/Sema/shiftOpenCL.cl b/test/Sema/shiftOpenCL.cl
new file mode 100644
index 0000000000..3bf9718768
--- /dev/null
+++ b/test/Sema/shiftOpenCL.cl
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -x cl -O1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// OpenCL essentially reduces all shift amounts to the last word-size bits before evaluating.
+// Test this both for variables and constants evaluated in the front-end.
+
+//CHECK: @array0 = common global [256 x i8]
+char array0[((int)1)<<40];
+//CHECK: @array1 = common global [256 x i8]
+char array1[((int)1)<<(-24)];
+
+//CHECK: @negativeShift32
+int negativeShift32(int a,int b) {
+ //CHECK: ret i32 65536
+ return ((int)1)<<(-16);
+}