[cfe-commits] [PATCH RFC] Emit nsw/nuw flags for shl
Xi Wang
xi.wang at gmail.com
Sun Dec 30 16:30:55 PST 2012
The attached patch adds nsw/nuw flags to signed left shift. This is
useful for LLVM-based tools to distinguish between signed and unsigned
left shift operations.
The patch is also available at:
https://github.com/xiw/clang/compare/shl
BTW, I am confused by some comments in ScalarExprEmitter::EmitShl().
In C99, we are not permitted to shift a 1 bit into the sign bit.
Under C++11's rules, shifting a 1 bit into the sign bit is
OK, but shifting a 1 bit out of it is not. (C89 and C++03 don't
define signed left shifts, so we use the C99 and C++11 rules there).
It looks to me that both C99 (6.5.7p4) and C++11 (5.8p2) have the same
rules for signed left shift.
If E1 has a signed type and non-negative value, and E1 * 2^E2 is
representable in the result type, then that is the resulting value;
otherwise, the behavior is undefined.
- xi
-------------- next part --------------
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 61126e1..92551e1 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -2388,6 +2388,17 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
+ bool HasNSW = false;
+ bool HasNUW = false;
+ // C99 6.5.7p4, C++11 5.8p2:
+ // If E1 has a signed type and non-negative value, and E1 * 2^E2 is
+ // representable in the result type, then that is the resulting value;
+ // otherwise, the behavior is undefined.
+ if (Ops.Ty->isSignedIntegerType()) {
+ HasNSW = true;
+ HasNUW = true;
+ }
+
if (CGF.getLangOpts().SanitizeShift &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
@@ -2418,7 +2429,7 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
}
}
- return Builder.CreateShl(Ops.LHS, RHS, "shl");
+ return Builder.CreateShl(Ops.LHS, RHS, "shl", HasNUW, HasNSW);
}
Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index d0b6d19..aa3f270 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -91,7 +91,7 @@ int lsh_overflow(int a, int b) {
// CHECK-NEXT: %[[ARG2:.*]] = zext
// CHECK-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_300_B]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
- // CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
+ // CHECK: %[[RET:.*]] = shl nuw nsw i32 %[[LHS]], %[[RHS]]
// CHECK-NEXT: ret i32 %[[RET]]
#line 300
return a << b;
diff --git a/test/CodeGen/compound-type.c b/test/CodeGen/compound-type.c
index 63ba694..d6a2f5a 100644
--- a/test/CodeGen/compound-type.c
+++ b/test/CodeGen/compound-type.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 < %s -emit-llvm -triple i686-pc-linux-gnu > %t
// RUN: grep "div i32" %t
-// RUN: grep "shl i32" %t
+// RUN: grep "shl nuw nsw i32" %t
unsigned char a,b;
void c(void) {a <<= b;}
diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp
index 3a3536b..d9b4408 100644
--- a/test/CodeGenCXX/catch-undef-behavior.cpp
+++ b/test/CodeGenCXX/catch-undef-behavior.cpp
@@ -130,7 +130,7 @@ int lsh_overflow(int a, int b) {
// CHECK-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT_NOT_SIGN]], 0
// CHECK-NEXT: br i1 %[[NO_OVERFLOW]]
- // CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
+ // CHECK: %[[RET:.*]] = shl nuw nsw i32 %[[LHS]], %[[RHS]]
// CHECK-NEXT: ret i32 %[[RET]]
return a << b;
}
More information about the cfe-commits
mailing list