From 0db7244295b15181991a793e99fe9a1a0b54a56d Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Wed, 18 Mar 2020 11:33:38 +0000 Subject: [PATCH] [SCCP] Precommit some additional tests for integer ranges. --- .../SCCP/binaryops-range-special-cases.ll | 103 +++++++++ .../Transforms/SCCP/ipsccp-range-crashes.ll | 195 ++++++++++++++++++ llvm/test/Transforms/SCCP/range-and.ll | 39 +++- 3 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll create mode 100644 llvm/test/Transforms/SCCP/ipsccp-range-crashes.ll diff --git a/llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll b/llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll new file mode 100644 index 000000000000..a354ae0d4d5d --- /dev/null +++ b/llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll @@ -0,0 +1,103 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -ipsccp -S | FileCheck %s + +declare void @use(i1) +define void @sdiv1_cmp_constants(i32 %x) { +; CHECK-LABEL: @sdiv1_cmp_constants( +; CHECK-NEXT: [[D:%.*]] = sdiv i32 1, [[X:%.*]] +; CHECK-NEXT: [[C_0:%.*]] = icmp slt i32 0, [[D]] +; CHECK-NEXT: call void @use(i1 [[C_0]]) +; CHECK-NEXT: [[C_1:%.*]] = icmp slt i32 1, [[D]] +; CHECK-NEXT: call void @use(i1 [[C_1]]) +; CHECK-NEXT: [[C_2:%.*]] = icmp slt i32 2, [[D]] +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: [[C_3:%.*]] = icmp eq i32 1, [[D]] +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: [[C_4:%.*]] = icmp eq i32 0, [[D]] +; CHECK-NEXT: call void @use(i1 [[C_4]]) +; CHECK-NEXT: [[C_5:%.*]] = icmp eq i32 2, [[D]] +; CHECK-NEXT: call void @use(i1 [[C_5]]) +; CHECK-NEXT: ret void +; + %d = sdiv i32 1, %x + %c.0 = icmp slt i32 0, %d + call void @use(i1 %c.0) + %c.1 = icmp slt i32 1, %d + call void @use(i1 %c.1) + %c.2 = icmp slt i32 2, %d + call void @use(i1 %c.2) + + %c.3 = icmp eq i32 1, %d + call void @use(i1 %c.3) + %c.4 = icmp eq i32 0, %d + call void @use(i1 %c.4) + %c.5 = icmp eq i32 2, %d + call void @use(i1 %c.5) + + ret void +} + +define void @sdiv1_cmp_range_1(i32 %x, i1 %c) { +; CHECK-LABEL: @sdiv1_cmp_range_1( +; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ 1, [[BB1]] ], [ 2, [[BB2]] ] +; CHECK-NEXT: [[D:%.*]] = sdiv i32 1, [[X:%.*]] +; CHECK-NEXT: [[C_0:%.*]] = icmp slt i32 [[P]], [[D]] +; CHECK-NEXT: call void @use(i1 [[C_0]]) +; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[P]], [[D]] +; CHECK-NEXT: call void @use(i1 [[C_1]]) +; CHECK-NEXT: ret void +; + br i1 %c, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + br label %bb3 + +bb3: + %p = phi i32 [1, %bb1], [2, %bb2] + %d = sdiv i32 1, %x + %c.0 = icmp slt i32 %p, %d + call void @use(i1 %c.0) + %c.1 = icmp eq i32 %p, %d + call void @use(i1 %c.1) + ret void +} + + +define void @sdiv1_cmp_range_2(i32 %x, i1 %c) { +; CHECK-LABEL: @sdiv1_cmp_range_2( +; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ 3, [[BB1]] ], [ 2, [[BB2]] ] +; CHECK-NEXT: [[D:%.*]] = sdiv i32 1, [[X:%.*]] +; CHECK-NEXT: [[C_0:%.*]] = icmp slt i32 [[P]], [[D]] +; CHECK-NEXT: call void @use(i1 [[C_0]]) +; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[P]], [[D]] +; CHECK-NEXT: call void @use(i1 [[C_1]]) +; CHECK-NEXT: ret void +; + br i1 %c, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + br label %bb3 + +bb3: + %p = phi i32 [3, %bb1], [2, %bb2] + %d = sdiv i32 1, %x + %c.0 = icmp slt i32 %p, %d + call void @use(i1 %c.0) + %c.1 = icmp eq i32 %p, %d + call void @use(i1 %c.1) + ret void +} diff --git a/llvm/test/Transforms/SCCP/ipsccp-range-crashes.ll b/llvm/test/Transforms/SCCP/ipsccp-range-crashes.ll new file mode 100644 index 000000000000..117eed78064e --- /dev/null +++ b/llvm/test/Transforms/SCCP/ipsccp-range-crashes.ll @@ -0,0 +1,195 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -ipsccp -S %s | FileCheck %s + +; A few test cases exposing crashes with the initial range implementation. + +@global.2 = external dso_local unnamed_addr constant [25 x i8], align 1 +@global = internal local_unnamed_addr global i32 0, align 4 +@global.3 = internal local_unnamed_addr global i32 0, align 4 + +define void @main(i8** %arg) { +; CHECK-LABEL: @main( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP:%.*]] = getelementptr inbounds i8*, i8** [[ARG:%.*]], i64 undef +; CHECK-NEXT: [[TMP1:%.*]] = load i8*, i8** [[TMP]], align 8 +; CHECK-NEXT: [[TMP2:%.*]] = load i8, i8* [[TMP1]], align 1 +; CHECK-NEXT: [[TMP3:%.*]] = sext i8 [[TMP2]] to i32 +; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 45 +; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP4]], i32 2, i32 4 +; CHECK-NEXT: ret void +; +bb: + %tmp = getelementptr inbounds i8*, i8** %arg, i64 undef + %tmp1 = load i8*, i8** %tmp, align 8 + %tmp2 = load i8, i8* %tmp1, align 1 + %tmp3 = sext i8 %tmp2 to i32 + %tmp4 = icmp ne i32 %tmp3, 45 + %tmp5 = select i1 %tmp4, i32 2, i32 4 + ret void +} + +define void @ham() local_unnamed_addr { +; CHECK-LABEL: @ham( +; CHECK-NEXT: bb: +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[TMP:%.*]] = icmp slt i32 undef, 40 +; CHECK-NEXT: br i1 [[TMP]], label [[BB2:%.*]], label [[BB4:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB7:%.*]] +; CHECK: bb3: +; CHECK-NEXT: br label [[BB4]] +; CHECK: bb4: +; CHECK-NEXT: [[TMP5:%.*]] = phi i64 [ 0, [[BB1]] ], [ 15, [[BB3:%.*]] ] +; CHECK-NEXT: [[TMP6:%.*]] = add i64 [[TMP5]], add (i64 xor (i64 ptrtoint ([25 x i8]* @global.2 to i64), i64 -1), i64 1) +; CHECK-NEXT: unreachable +; CHECK: bb7: +; CHECK-NEXT: br label [[BB3]] +; +bb: + br label %bb1 + +bb1: ; preds = %bb + %tmp = icmp slt i32 undef, 40 + br i1 %tmp, label %bb2, label %bb4 + +bb2: ; preds = %bb1 + br label %bb7 + +bb3: ; preds = %bb7 + br label %bb4 + +bb4: ; preds = %bb3, %bb1 + %tmp5 = phi i64 [ 0, %bb1 ], [ %tmp10, %bb3 ] + %tmp6 = add i64 %tmp5, add (i64 xor (i64 ptrtoint ([25 x i8]* @global.2 to i64), i64 -1), i64 1) + unreachable + +bb7: ; preds = %bb2 + %tmp8 = add i64 0, 15 + %tmp9 = add i64 %tmp8, 0 + %tmp10 = add i64 %tmp9, 0 + br label %bb3 +} + +declare i32 @barney.4() + +define void @wobble() { +; CHECK-LABEL: @wobble( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* @global, align 4 +; CHECK-NEXT: store i32 [[TMP]], i32* @global.3, align 4 +; CHECK-NEXT: ret void +; +bb: + %tmp = load i32, i32* @global, align 4 + store i32 %tmp, i32* @global.3, align 4 + ret void +} + +define i32 @wobble.5(i32 %arg) { +bb: + %tmp = load i32, i32* @global.3, align 4 + %tmp1 = sdiv i32 0, %tmp + ret i32 %tmp1 +} + +define void @eggs() { +; CHECK-LABEL: @eggs( +; CHECK-NEXT: bb: +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[TMP:%.*]] = phi i32 [ 0, [[BB:%.*]] ], [ [[TMP2:%.*]], [[BB1]] ] +; CHECK-NEXT: [[TMP2]] = add nsw i32 [[TMP]], 1 +; CHECK-NEXT: [[TMP3:%.*]] = call i32 @barney.4() +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 1 +; CHECK-NEXT: br i1 [[TMP4]], label [[BB1]], label [[BB5:%.*]] +; CHECK: bb5: +; CHECK-NEXT: store i32 [[TMP2]], i32* @global, align 4 +; CHECK-NEXT: ret void +; +bb: + br label %bb1 + +bb1: ; preds = %bb1, %bb + %tmp = phi i32 [ 0, %bb ], [ %tmp2, %bb1 ] + %tmp2 = add nsw i32 %tmp, 1 + %tmp3 = call i32 @barney.4() + %tmp4 = icmp eq i32 %tmp3, 1 + br i1 %tmp4, label %bb1, label %bb5 + +bb5: ; preds = %bb1 + store i32 %tmp2, i32* @global, align 4 + ret void +} + +declare i32* @bar(i32) local_unnamed_addr #3 + +; Function Attrs: nounwind ssp uwtable +define { i8, i32* } @struct_crash(i32 %BitWidth) local_unnamed_addr #0 align 2 { +; CHECK-LABEL: @struct_crash( +; CHECK-NEXT: entry: +; CHECK-NEXT: switch i32 [[BITWIDTH:%.*]], label [[IF_END:%.*]] [ +; CHECK-NEXT: i32 1, label [[CLEANUP:%.*]] +; CHECK-NEXT: i32 8, label [[SW_BB1_I:%.*]] +; CHECK-NEXT: ] +; CHECK: sw.bb1.i: +; CHECK-NEXT: br label [[CLEANUP]] +; CHECK: if.end: +; CHECK-NEXT: [[CALL_I:%.*]] = tail call i32* @bar(i32 [[BITWIDTH]]) +; CHECK-NEXT: br label [[CLEANUP]] +; CHECK: cleanup: +; CHECK-NEXT: [[V1:%.*]] = phi i32* [ [[CALL_I]], [[IF_END]] ], [ null, [[SW_BB1_I]] ], [ null, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[V2:%.*]] = phi i8 [ 0, [[IF_END]] ], [ 3, [[SW_BB1_I]] ], [ 2, [[ENTRY]] ] +; CHECK-NEXT: [[DOTFCA_0_INSERT:%.*]] = insertvalue { i8, i32* } undef, i8 [[V2]], 0 +; CHECK-NEXT: [[DOTFCA_1_INSERT:%.*]] = insertvalue { i8, i32* } [[DOTFCA_0_INSERT]], i32* [[V1]], 1 +; CHECK-NEXT: ret { i8, i32* } [[DOTFCA_1_INSERT]] +; +entry: + switch i32 %BitWidth, label %if.end [ + i32 1, label %cleanup + i32 8, label %sw.bb1.i + ] + +sw.bb1.i: ; preds = %entry + br label %cleanup + +if.end: ; preds = %entry + %call.i = tail call i32* @bar(i32 %BitWidth) + br label %cleanup + +cleanup: ; preds = %entry, %sw.bb1.i, %sw.bb2.i, %sw.bb3.i, %sw.bb4.i, %sw.bb5.i, %if.end + %v1 = phi i32* [ %call.i, %if.end ], [ null, %sw.bb1.i ], [ null, %entry ] + %v2 = phi i8 [ 0, %if.end ], [ 3, %sw.bb1.i ], [ 2, %entry ] + %.fca.0.insert = insertvalue { i8, i32* } undef, i8 %v2, 0 + %.fca.1.insert = insertvalue { i8, i32* } %.fca.0.insert, i32* %v1, 1 + ret { i8, i32* } %.fca.1.insert +} + +define i64 @crash_ctpop(i1 %cond, i32* %addr) { +; CHECK-LABEL: @crash_ctpop( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: ret i64 0 +; CHECK: if.else: +; CHECK-NEXT: [[LV:%.*]] = load i32, i32* [[ADDR:%.*]], align 8 +; CHECK-NEXT: [[ANDV:%.*]] = and i32 [[LV]], 16777215 +; CHECK-NEXT: [[TRUNCV:%.*]] = zext i32 [[ANDV]] to i64 +; CHECK-NEXT: [[RES:%.*]] = tail call i64 @llvm.ctpop.i64(i64 [[TRUNCV]]) +; CHECK-NEXT: ret i64 [[RES]] +; +entry: + br i1 %cond, label %if.then, label %if.else + +if.then: ; preds = %entry + ret i64 0 + +if.else: ; preds = %entry + %lv = load i32, i32* %addr, align 8 + %andv = and i32 %lv, 16777215 + %truncv = zext i32 %andv to i64 + %res = tail call i64 @llvm.ctpop.i64(i64 %truncv) + ret i64 %res +} + +declare i64 @llvm.ctpop.i64(i64) diff --git a/llvm/test/Transforms/SCCP/range-and.ll b/llvm/test/Transforms/SCCP/range-and.ll index 1ca089f4aa8c..e948274dd8f1 100644 --- a/llvm/test/Transforms/SCCP/range-and.ll +++ b/llvm/test/Transforms/SCCP/range-and.ll @@ -1,7 +1,42 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --verbose ; RUN: opt -S -sccp %s | FileCheck %s -; Test case for PR44949. +declare void @use(i1) + +define void @and_range_limit(i64 %a) { +; CHECK-LABEL: @and_range_limit( +; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 +; CHECK-NEXT: [[C_0:%.*]] = icmp slt i64 [[R]], 15 +; CHECK-NEXT: call void @use(i1 [[C_0]]) +; CHECK-NEXT: [[C_1:%.*]] = icmp slt i64 [[R]], 256 +; CHECK-NEXT: call void @use(i1 [[C_1]]) +; CHECK-NEXT: [[C_2:%.*]] = icmp eq i64 [[R]], 100 +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: [[C_3:%.*]] = icmp eq i64 [[R]], 300 +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: [[C_4:%.*]] = icmp ne i64 [[R]], 100 +; CHECK-NEXT: call void @use(i1 [[C_4]]) +; CHECK-NEXT: [[C_5:%.*]] = icmp ne i64 [[R]], 300 +; CHECK-NEXT: call void @use(i1 [[C_5]]) +; CHECK-NEXT: ret void +; + %r = and i64 %a, 255 + %c.0 = icmp slt i64 %r, 15 + call void @use(i1 %c.0) + %c.1 = icmp slt i64 %r, 256 + call void @use(i1 %c.1) + %c.2 = icmp eq i64 %r, 100 + call void @use(i1 %c.2) + %c.3 = icmp eq i64 %r, 300 + call void @use(i1 %c.3) + %c.4 = icmp ne i64 %r, 100 + call void @use(i1 %c.4) + %c.5 = icmp ne i64 %r, 300 + call void @use(i1 %c.5) + ret void +} + +; Below are test cases for PR44949. ; We can remove `%res = and i64 %p, 255`, because %r = 0 and we can eliminate ; %p as well.