Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 244 additions & 24 deletions llvm/test/Transforms/IndVarSimplify/X86/overflow-intrinsics.ll
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -passes=indvars < %s | FileCheck %s

target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

define void @f_sadd(ptr %a) {
; CHECK-LABEL: @f_sadd(
; CHECK-LABEL: define void @f_sadd(
; CHECK-SAME: ptr [[A:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_COND_CLEANUP:.*]]:
; CHECK-NEXT: ret void
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; CHECK-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0:![0-9]+]]
; CHECK: [[TRAP]]:
; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
; CHECK-NEXT: unreachable, !nosanitize [[META0]]
; CHECK: [[CONT]]:
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], 16
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
;
entry:
br label %for.body

Expand All @@ -18,9 +37,6 @@ for.body: ; preds = %entry, %cont
store i8 0, ptr %arrayidx, align 1
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %i.04, i32 1)
%1 = extractvalue { i32, i1 } %0, 1
; CHECK: for.body:
; CHECK-NOT: @llvm.sadd.with.overflow
; CHECK: br i1 false, label %trap, label %cont, !nosanitize !0
br i1 %1, label %trap, label %cont, !nosanitize !{}

trap: ; preds = %for.body
Expand All @@ -33,8 +49,71 @@ cont: ; preds = %for.body
br i1 %cmp, label %for.body, label %for.cond.cleanup
}

define void @f_sadd_overflow(ptr %a) {
; CHECK-LABEL: define void @f_sadd_overflow(
; CHECK-SAME: ptr [[A:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_COND_CLEANUP:.*]]:
; CHECK-NEXT: ret void
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 2147483645, %[[ENTRY]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV]], 2147483647
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
; CHECK: [[TRAP]]:
; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
; CHECK-NEXT: unreachable, !nosanitize [[META0]]
; CHECK: [[CONT]]:
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; CHECK-NEXT: br i1 true, label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
;
entry:
br label %for.body

for.cond.cleanup: ; preds = %cont
ret void

for.body: ; preds = %entry, %cont
%i.04 = phi i32 [ 2147483645, %entry ], [ %2, %cont ]
%idxprom = sext i32 %i.04 to i64
%arrayidx = getelementptr inbounds i8, ptr %a, i64 %idxprom
store i8 0, ptr %arrayidx, align 1
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %i.04, i32 1)
%1 = extractvalue { i32, i1 } %0, 1
br i1 %1, label %trap, label %cont, !nosanitize !{}

trap: ; preds = %for.body
tail call void @llvm.trap() #2, !nosanitize !{}
unreachable, !nosanitize !{}

cont: ; preds = %for.body
%2 = extractvalue { i32, i1 } %0, 0
%cmp = icmp sle i32 %2, 2147483647
br i1 %cmp, label %for.body, label %for.cond.cleanup
}

define void @f_uadd(ptr %a) {
; CHECK-LABEL: @f_uadd(
; CHECK-LABEL: define void @f_uadd(
; CHECK-SAME: ptr [[A:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_COND_CLEANUP:.*]]:
; CHECK-NEXT: ret void
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; CHECK-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
; CHECK: [[TRAP]]:
; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
; CHECK-NEXT: unreachable, !nosanitize [[META0]]
; CHECK: [[CONT]]:
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], 16
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
;
entry:
br label %for.body

Expand All @@ -48,9 +127,6 @@ for.body: ; preds = %entry, %cont
store i8 0, ptr %arrayidx, align 1
%0 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %i.04, i32 1)
%1 = extractvalue { i32, i1 } %0, 1
; CHECK: for.body:
; CHECK-NOT: @llvm.uadd.with.overflow
; CHECK: br i1 false, label %trap, label %cont, !nosanitize !0
br i1 %1, label %trap, label %cont, !nosanitize !{}

trap: ; preds = %for.body
Expand All @@ -63,8 +139,71 @@ cont: ; preds = %for.body
br i1 %cmp, label %for.body, label %for.cond.cleanup
}

define void @f_uadd_overflow(ptr %a) {
; CHECK-LABEL: define void @f_uadd_overflow(
; CHECK-SAME: ptr [[A:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_COND_CLEANUP:.*]]:
; CHECK-NEXT: ret void
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ -6, %[[ENTRY]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV]], -1
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
; CHECK: [[TRAP]]:
; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
; CHECK-NEXT: unreachable, !nosanitize [[META0]]
; CHECK: [[CONT]]:
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], 1
; CHECK-NEXT: br i1 true, label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
;
entry:
br label %for.body

for.cond.cleanup: ; preds = %cont
ret void

for.body: ; preds = %entry, %cont
%i.04 = phi i32 [ 4294967290, %entry ], [ %2, %cont ]
%idxprom = sext i32 %i.04 to i64
%arrayidx = getelementptr inbounds i8, ptr %a, i64 %idxprom
store i8 0, ptr %arrayidx, align 1
%0 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %i.04, i32 1)
%1 = extractvalue { i32, i1 } %0, 1
br i1 %1, label %trap, label %cont, !nosanitize !{}

trap: ; preds = %for.body
tail call void @llvm.trap(), !nosanitize !{}
unreachable, !nosanitize !{}

cont: ; preds = %for.body
%2 = extractvalue { i32, i1 } %0, 0
%cmp = icmp ule i32 %2, 4294967295
br i1 %cmp, label %for.body, label %for.cond.cleanup
}

define void @f_ssub(ptr nocapture %a) {
; CHECK-LABEL: @f_ssub(
; CHECK-LABEL: define void @f_ssub(
; CHECK-SAME: ptr captures(none) [[A:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_COND_CLEANUP:.*]]:
; CHECK-NEXT: ret void
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 15, %[[ENTRY]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
; CHECK-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
; CHECK: [[TRAP]]:
; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
; CHECK-NEXT: unreachable, !nosanitize [[META0]]
; CHECK: [[CONT]]:
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[INDVARS_IV_NEXT]], -1
; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
;
entry:
br label %for.body

Expand All @@ -78,9 +217,6 @@ for.body: ; preds = %entry, %cont
store i8 0, ptr %arrayidx, align 1
%0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %i.04, i32 1)
%1 = extractvalue { i32, i1 } %0, 1
; CHECK: for.body:
; CHECK-NOT: @llvm.ssub.with.overflow.i32
; CHECK: br i1 false, label %trap, label %cont, !nosanitize !0
br i1 %1, label %trap, label %cont, !nosanitize !{}

trap: ; preds = %for.body
Expand All @@ -93,8 +229,76 @@ cont: ; preds = %for.body
br i1 %cmp, label %for.body, label %for.cond.cleanup
}

; It is theoretically possible to replace the `ssub.with.overflow` with a
; condition on the IV, but SCEV cannot represent non-unsigned-wrapping
; subtraction operations.
define void @f_ssub_overflow(ptr nocapture %a) {
; CHECK-LABEL: define void @f_ssub_overflow(
; CHECK-SAME: ptr captures(none) [[A:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_COND_CLEANUP:.*]]:
; CHECK-NEXT: ret void
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ -2147483642, %[[ENTRY]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT: [[TMP0:%.*]] = trunc nsw i64 [[INDVARS_IV]] to i32
; CHECK-NEXT: [[TMP1:%.*]] = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP0]], i32 1)
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP2]], label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
; CHECK: [[TRAP]]:
; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
; CHECK-NEXT: unreachable, !nosanitize [[META0]]
; CHECK: [[CONT]]:
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
; CHECK-NEXT: br i1 true, label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
;
entry:
br label %for.body

for.cond.cleanup: ; preds = %cont
ret void

for.body: ; preds = %entry, %cont
%i.04 = phi i32 [ -2147483642, %entry ], [ %2, %cont ]
%idxprom = sext i32 %i.04 to i64
%arrayidx = getelementptr inbounds i8, ptr %a, i64 %idxprom
store i8 0, ptr %arrayidx, align 1
%0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %i.04, i32 1)
%1 = extractvalue { i32, i1 } %0, 1
br i1 %1, label %trap, label %cont, !nosanitize !{}

trap: ; preds = %for.body
tail call void @llvm.trap(), !nosanitize !{}
unreachable, !nosanitize !{}

cont: ; preds = %for.body
%2 = extractvalue { i32, i1 } %0, 0
%cmp = icmp sge i32 %2, -2147483648
br i1 %cmp, label %for.body, label %for.cond.cleanup
}

define void @f_usub(ptr nocapture %a) {
; CHECK-LABEL: @f_usub(
; CHECK-LABEL: define void @f_usub(
; CHECK-SAME: ptr captures(none) [[A:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_COND_CLEANUP:.*]]:
; CHECK-NEXT: ret void
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 15, %[[ENTRY]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
; CHECK-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
; CHECK: [[TRAP]]:
; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
; CHECK-NEXT: unreachable, !nosanitize [[META0]]
; CHECK: [[CONT]]:
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i64 [[INDVARS_IV_NEXT]], 0
; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
;
entry:
br label %for.body

Expand All @@ -109,9 +313,6 @@ for.body: ; preds = %entry, %cont
%0 = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %i.04, i32 1)
%1 = extractvalue { i32, i1 } %0, 1

; CHECK: for.body:
; CHECK-NOT: @llvm.usub.with.overflow.i32
; CHECK: br i1 false, label %trap, label %cont, !nosanitize !0
br i1 %1, label %trap, label %cont, !nosanitize !{}

trap: ; preds = %for.body
Expand All @@ -124,8 +325,31 @@ cont: ; preds = %for.body
br i1 %cmp, label %for.body, label %for.cond.cleanup
}

; It is theoretically possible to replace the `usub.with.overflow` with a
; condition on the IV, but SCEV cannot represent non-unsigned-wrapping
; subtraction operations.
define void @f_usub_overflow(ptr nocapture %a) {
; CHECK-LABEL: @f_usub_overflow(
; CHECK-LABEL: define void @f_usub_overflow(
; CHECK-SAME: ptr captures(none) [[A:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_COND_CLEANUP:.*]]:
; CHECK-NEXT: ret void
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 15, %[[ENTRY]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT: [[TMP0:%.*]] = trunc nuw nsw i64 [[INDVARS_IV]] to i32
; CHECK-NEXT: [[TMP1:%.*]] = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP0]], i32 1)
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP2]], label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
; CHECK: [[TRAP]]:
; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
; CHECK-NEXT: unreachable, !nosanitize [[META0]]
; CHECK: [[CONT]]:
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
; CHECK-NEXT: br i1 true, label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
;
entry:
br label %for.body

Expand All @@ -139,13 +363,6 @@ for.body: ; preds = %entry, %cont
store i8 0, ptr %arrayidx, align 1
%0 = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %i.04, i32 1)
%1 = extractvalue { i32, i1 } %0, 1

; It is theoretically possible to prove this, but SCEV cannot
; represent non-unsigned-wrapping subtraction operations.

; CHECK: for.body:
; CHECK: [[COND:%[^ ]+]] = extractvalue { i32, i1 } %1, 1
; CHECK-NEXT: br i1 [[COND]], label %trap, label %cont, !nosanitize !0
br i1 %1, label %trap, label %cont, !nosanitize !{}

trap: ; preds = %for.body
Expand All @@ -166,3 +383,6 @@ declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) nounwind readnone
declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) nounwind readnone

declare void @llvm.trap() #2
;.
; CHECK: [[META0]] = !{}
;.