diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index e85f3db1121af..dfdf06587f0e2 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -333,7 +333,7 @@ size_t test3_bdos(struct annotated *p) { // SANITIZE-WITH-ATTR-NEXT: [[COUNT50:%.*]] = sext i32 [[DOTCOUNTED_BY_LOAD44]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[TMP10:%.*]] = sub nsw i64 [[COUNT50]], [[IDXPROM42]] // SANITIZE-WITH-ATTR-NEXT: [[TMP11:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP10]], i64 0) -// SANITIZE-WITH-ATTR-NEXT: [[DOTTR:%.*]] = trunc nuw i64 [[TMP11]] to i32 +// SANITIZE-WITH-ATTR-NEXT: [[DOTTR:%.*]] = trunc nuw nsw i64 [[TMP11]] to i32 // SANITIZE-WITH-ATTR-NEXT: [[CONV54:%.*]] = shl i32 [[DOTTR]], 2 // SANITIZE-WITH-ATTR-NEXT: [[CONV55:%.*]] = and i32 [[CONV54]], 252 // SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV55]], ptr [[ARRAYIDX65]], align 4, !tbaa [[TBAA4]] diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 8e74b8645fad9..314a5d15f0f88 100644 --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -1212,6 +1212,34 @@ static bool processAnd(BinaryOperator *BinOp, LazyValueInfo *LVI) { return true; } +static bool processTrunc(TruncInst *TI, LazyValueInfo *LVI) { + if (TI->hasNoSignedWrap() && TI->hasNoUnsignedWrap()) + return false; + + ConstantRange Range = + LVI->getConstantRangeAtUse(TI->getOperandUse(0), /*UndefAllowed=*/false); + uint64_t DestWidth = TI->getDestTy()->getScalarSizeInBits(); + bool Changed = false; + + if (!TI->hasNoUnsignedWrap()) { + if (Range.getActiveBits() <= DestWidth) { + TI->setHasNoUnsignedWrap(true); + ++NumNUW; + Changed = true; + } + } + + if (!TI->hasNoSignedWrap()) { + if (Range.getMinSignedBits() <= DestWidth) { + TI->setHasNoSignedWrap(true); + ++NumNSW; + Changed = true; + } + } + + return Changed; +} + static bool runImpl(Function &F, LazyValueInfo *LVI, DominatorTree *DT, const SimplifyQuery &SQ) { bool FnChanged = false; @@ -1275,6 +1303,9 @@ static bool runImpl(Function &F, LazyValueInfo *LVI, DominatorTree *DT, case Instruction::And: BBChanged |= processAnd(cast<BinaryOperator>(&II), LVI); break; + case Instruction::Trunc: + BBChanged |= processTrunc(cast<TruncInst>(&II), LVI); + break; } } diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll index 5fa8f4e1b9f29..7fb1e0718795d 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll @@ -339,7 +339,7 @@ define i1 @test12(i32 %x) { ; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[X:%.*]] to i64 ; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[ZEXT]], 7 ; CHECK-NEXT: [[SHR:%.*]] = lshr i64 [[MUL]], 32 -; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[SHR]] to i32 +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw nsw i64 [[SHR]] to i32 ; CHECK-NEXT: ret i1 true ; %zext = zext i32 %x to i64 diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll index 03d71fa9b5277..caf1156d79229 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll @@ -937,7 +937,7 @@ entry: define i1 @ctlz_with_range_metadata(i16 %x) { ; CHECK-LABEL: @ctlz_with_range_metadata( ; CHECK-NEXT: [[CTLZ:%.*]] = call i16 @llvm.ctlz.i16(i16 [[X:%.*]], i1 false), !range [[RNG5:![0-9]+]] -; CHECK-NEXT: [[TRUNC:%.*]] = trunc i16 [[CTLZ]] to i8 +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw nsw i16 [[CTLZ]] to i8 ; CHECK-NEXT: ret i1 true ; %ctlz = call i16 @llvm.ctlz.i16(i16 %x, i1 false), !range !{i16 0, i16 8} @@ -949,7 +949,7 @@ define i1 @ctlz_with_range_metadata(i16 %x) { define i1 @abs_with_range_metadata(i16 %x) { ; CHECK-LABEL: @abs_with_range_metadata( ; CHECK-NEXT: [[ABS:%.*]] = call i16 @llvm.abs.i16(i16 [[X:%.*]], i1 false), !range [[RNG5]] -; CHECK-NEXT: [[TRUNC:%.*]] = trunc i16 [[ABS]] to i8 +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw nsw i16 [[ABS]] to i8 ; CHECK-NEXT: ret i1 true ; %abs = call i16 @llvm.abs.i16(i16 %x, i1 false), !range !{i16 0, i16 8} diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/sext.ll b/llvm/test/Transforms/CorrelatedValuePropagation/sext.ll index 0db520bfc68a2..648ef0864bf17 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/sext.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/sext.ll @@ -20,7 +20,7 @@ define void @test1(i32 %n) { ; CHECK: for.body: ; CHECK-NEXT: [[EXT_WIDE1:%.*]] = zext nneg i32 [[A]] to i64 ; CHECK-NEXT: call void @use64(i64 [[EXT_WIDE1]]) -; CHECK-NEXT: [[EXT]] = trunc i64 [[EXT_WIDE1]] to i32 +; CHECK-NEXT: [[EXT]] = trunc nuw nsw i64 [[EXT_WIDE1]] to i32 ; CHECK-NEXT: br label [[FOR_COND]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -55,7 +55,7 @@ define void @test2(i32 %n) { ; CHECK: for.body: ; CHECK-NEXT: [[EXT_WIDE:%.*]] = sext i32 [[A]] to i64 ; CHECK-NEXT: call void @use64(i64 [[EXT_WIDE]]) -; CHECK-NEXT: [[EXT]] = trunc i64 [[EXT_WIDE]] to i32 +; CHECK-NEXT: [[EXT]] = trunc nsw i64 [[EXT_WIDE]] to i32 ; CHECK-NEXT: br label [[FOR_COND]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -87,7 +87,7 @@ define void @test3(i32 %n) { ; CHECK: bb: ; CHECK-NEXT: [[EXT_WIDE1:%.*]] = zext nneg i32 [[N]] to i64 ; CHECK-NEXT: call void @use64(i64 [[EXT_WIDE1]]) -; CHECK-NEXT: [[EXT:%.*]] = trunc i64 [[EXT_WIDE1]] to i32 +; CHECK-NEXT: [[EXT:%.*]] = trunc nuw nsw i64 [[EXT_WIDE1]] to i32 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -115,7 +115,7 @@ define void @test4(i32 %n) { ; CHECK: bb: ; CHECK-NEXT: [[EXT_WIDE:%.*]] = sext i32 [[N]] to i64 ; CHECK-NEXT: call void @use64(i64 [[EXT_WIDE]]) -; CHECK-NEXT: [[EXT:%.*]] = trunc i64 [[EXT_WIDE]] to i32 +; CHECK-NEXT: [[EXT:%.*]] = trunc nsw i64 [[EXT_WIDE]] to i32 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/trunc.ll b/llvm/test/Transforms/CorrelatedValuePropagation/trunc.ll new file mode 100644 index 0000000000000..9b6604298840d --- /dev/null +++ b/llvm/test/Transforms/CorrelatedValuePropagation/trunc.ll @@ -0,0 +1,108 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s + + +define i1 @infer_nuw(i8 range(i8 0, 2) %A, i8 range(i8 0, 2) %B) { +; CHECK-LABEL: define i1 @infer_nuw( +; CHECK-SAME: i8 range(i8 0, 2) [[A:%.*]], i8 range(i8 0, 2) [[B:%.*]]) { +; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[B]], [[A]] +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[XOR]] to i1 +; CHECK-NEXT: ret i1 [[TRUNC]] +; + %xor = xor i8 %B, %A + %trunc = trunc i8 %xor to i1 + ret i1 %trunc +} + + +define i4 @infer_nsw(i8 %A) { +; CHECK-LABEL: define range(i4 -4, 4) i4 @infer_nsw( +; CHECK-SAME: i8 [[A:%.*]]) { +; CHECK-NEXT: [[ASHR:%.*]] = ashr i8 [[A]], 5 +; CHECK-NEXT: [[B:%.*]] = trunc nsw i8 [[ASHR]] to i4 +; CHECK-NEXT: ret i4 [[B]] +; + %ashr = ashr i8 %A, 5 + %result = trunc i8 %ashr to i4 + ret i4 %result +} + + +define i8 @infer_nuw_nsw(i16 range(i16 -5, -3) %A, i16 range(i16 -5, -3) %B) { +; CHECK-LABEL: define range(i8 0, 8) i8 @infer_nuw_nsw( +; CHECK-SAME: i16 range(i16 -5, -3) [[A:%.*]], i16 range(i16 -5, -3) [[B:%.*]]) { +; CHECK-NEXT: [[XOR:%.*]] = xor i16 [[B]], [[A]] +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw nsw i16 [[XOR]] to i8 +; CHECK-NEXT: ret i8 [[TRUNC]] +; + %xor = xor i16 %B, %A + %trunc = trunc i16 %xor to i8 + ret i8 %trunc +} + + +define i8 @infer_nsw_from_assume(i16 %x) { +; CHECK-LABEL: define i8 @infer_nsw_from_assume( +; CHECK-SAME: i16 [[X:%.*]]) { +; CHECK-NEXT: [[ADD:%.*]] = add i16 [[X]], 128 +; CHECK-NEXT: [[OR_COND_I:%.*]] = icmp ult i16 [[ADD]], 256 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[OR_COND_I]]) +; CHECK-NEXT: [[CONV1:%.*]] = trunc nsw i16 [[X]] to i8 +; CHECK-NEXT: ret i8 [[CONV1]] +; + %add = add i16 %x, 128 + %or.cond.i = icmp ult i16 %add, 256 + tail call void @llvm.assume(i1 %or.cond.i) + %conv1 = trunc i16 %x to i8 + ret i8 %conv1 +} + + +define i1 @rust_issue_122734(i8 range(i8 0, 3) %A, i8 range(i8 0, 3) %B) { +; CHECK-LABEL: define i1 @rust_issue_122734( +; CHECK-SAME: i8 range(i8 0, 3) [[A:%.*]], i8 range(i8 0, 3) [[B:%.*]]) { +; CHECK-NEXT: [[START:.*]]: +; CHECK-NEXT: [[LHS:%.*]] = icmp eq i8 [[A]], 2 +; CHECK-NEXT: [[RHS:%.*]] = icmp eq i8 [[B]], 2 +; CHECK-NEXT: [[OR:%.*]] = or i1 [[LHS]], [[RHS]] +; CHECK-NEXT: [[AND:%.*]] = and i1 [[LHS]], [[RHS]] +; CHECK-NEXT: br i1 [[OR]], label %[[IFTRUE:.*]], label %[[IFFALSE:.*]] +; CHECK: [[IFTRUE]]: +; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ [[XOR2:%.*]], %[[IFFALSE]] ], [ [[AND]], %[[START]] ] +; CHECK-NEXT: ret i1 [[PHI]] +; CHECK: [[IFFALSE]]: +; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[A]], [[B]] +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[XOR]] to i1 +; CHECK-NEXT: [[XOR2]] = xor i1 [[TRUNC]], true +; CHECK-NEXT: br label %[[IFTRUE]] +; +start: + %lhs = icmp eq i8 %A, 2 + %rhs = icmp eq i8 %B, 2 + %or = or i1 %lhs, %rhs + %and = and i1 %lhs, %rhs + br i1 %or, label %iftrue, label %iffalse + +iftrue: + %phi = phi i1 [ %xor2, %iffalse], [ %and, %start ] + ret i1 %phi + +iffalse: + %xor = xor i8 %A, %B + %trunc = trunc i8 %xor to i1 + %xor2 = xor i1 %trunc, true + br label %iftrue +} + + +define i1 @overdefined_range_negative(i8 %A, i8 %B) { +; CHECK-LABEL: define i1 @overdefined_range_negative( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) { +; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[A]], [[B]] +; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[XOR]] to i1 +; CHECK-NEXT: ret i1 [[TRUNC]] +; + %xor = xor i8 %A, %B + %trunc = trunc i8 %xor to i1 + ret i1 %trunc +} diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/zext.ll b/llvm/test/Transforms/CorrelatedValuePropagation/zext.ll index 44434c696fe37..8e43244a8eb62 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/zext.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/zext.ll @@ -14,7 +14,7 @@ define void @test1(i32 %n) { ; CHECK: for.body: ; CHECK-NEXT: [[EXT_WIDE:%.*]] = zext nneg i32 [[A]] to i64 ; CHECK-NEXT: call void @use64(i64 [[EXT_WIDE]]) -; CHECK-NEXT: [[EXT]] = trunc i64 [[EXT_WIDE]] to i32 +; CHECK-NEXT: [[EXT]] = trunc nuw nsw i64 [[EXT_WIDE]] to i32 ; CHECK-NEXT: br label [[FOR_COND]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -49,7 +49,7 @@ define void @test2(i32 %n) { ; CHECK: for.body: ; CHECK-NEXT: [[EXT_WIDE:%.*]] = zext i32 [[A]] to i64 ; CHECK-NEXT: call void @use64(i64 [[EXT_WIDE]]) -; CHECK-NEXT: [[EXT]] = trunc i64 [[EXT_WIDE]] to i32 +; CHECK-NEXT: [[EXT]] = trunc nuw i64 [[EXT_WIDE]] to i32 ; CHECK-NEXT: br label [[FOR_COND]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -81,7 +81,7 @@ define void @test3(i32 %n) { ; CHECK: bb: ; CHECK-NEXT: [[EXT_WIDE:%.*]] = zext nneg i32 [[N]] to i64 ; CHECK-NEXT: call void @use64(i64 [[EXT_WIDE]]) -; CHECK-NEXT: [[EXT:%.*]] = trunc i64 [[EXT_WIDE]] to i32 +; CHECK-NEXT: [[EXT:%.*]] = trunc nuw nsw i64 [[EXT_WIDE]] to i32 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -109,7 +109,7 @@ define void @test4(i32 %n) { ; CHECK: bb: ; CHECK-NEXT: [[EXT_WIDE:%.*]] = zext i32 [[N]] to i64 ; CHECK-NEXT: call void @use64(i64 [[EXT_WIDE]]) -; CHECK-NEXT: [[EXT:%.*]] = trunc i64 [[EXT_WIDE]] to i32 +; CHECK-NEXT: [[EXT:%.*]] = trunc nuw i64 [[EXT_WIDE]] to i32 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void