135 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=instcombine -S | FileCheck %s3; RUN: opt < %s -passes=instcombine -S -debugify-each | FileCheck %s4 5declare void @llvm.experimental.guard(i1, ...)6 7define void @test_guard_adjacent_same_cond(i1 %A) {8; CHECK-LABEL: @test_guard_adjacent_same_cond(9; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[A:%.*]]) [ "deopt"() ]10; CHECK-NEXT: ret void11;12 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]13 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]14 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]15 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]16 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]17 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]18 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]19 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]20 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]21 call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ]22 ret void23}24 25define void @test_guard_adjacent_diff_cond(i1 %A, i1 %B, i1 %C) {26; CHECK-LABEL: @test_guard_adjacent_diff_cond(27; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[A:%.*]], [[B:%.*]]28; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[C:%.*]]29; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 123) [ "deopt"() ]30; CHECK-NEXT: ret void31;32 call void(i1, ...) @llvm.experimental.guard( i1 %A, i32 123 )[ "deopt"() ]33 call void(i1, ...) @llvm.experimental.guard( i1 %B, i32 456 )[ "deopt"() ]34 call void(i1, ...) @llvm.experimental.guard( i1 %C, i32 789 )[ "deopt"() ]35 ret void36}37 38; This version tests for the common form where the conditions are39; between the guards40define void @test_guard_adjacent_diff_cond2(i32 %V1, i32 %V2) {41; CHECK-LABEL: @test_guard_adjacent_diff_cond2(42; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[V1:%.*]], [[V2:%.*]]43; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 044; CHECK-NEXT: [[AND:%.*]] = and i32 [[V1]], 25545; CHECK-NEXT: [[C:%.*]] = icmp samesign ult i32 [[AND]], 12946; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[C]]47; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 123) [ "deopt"() ]48; CHECK-NEXT: ret void49;50 %A = icmp slt i32 %V1, 051 call void(i1, ...) @llvm.experimental.guard( i1 %A, i32 123 )[ "deopt"() ]52 %B = icmp slt i32 %V2, 053 call void(i1, ...) @llvm.experimental.guard( i1 %B, i32 456 )[ "deopt"() ]54 %and = and i32 %V1, 25555 %C = icmp sle i32 %and, 12856 call void(i1, ...) @llvm.experimental.guard( i1 %C, i32 789 )[ "deopt"() ]57 ret void58}59 60; Might not be legal to hoist the load above the first guard since the61; guard might control dereferenceability62define void @negative_load(i32 %V1, ptr %P) {63; CHECK-LABEL: @negative_load(64; CHECK-NEXT: [[A:%.*]] = icmp slt i32 [[V1:%.*]], 065; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[A]], i32 123) [ "deopt"() ]66; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P:%.*]], align 467; CHECK-NEXT: [[B:%.*]] = icmp slt i32 [[V2]], 068; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[B]], i32 456) [ "deopt"() ]69; CHECK-NEXT: ret void70;71 %A = icmp slt i32 %V1, 072 call void(i1, ...) @llvm.experimental.guard( i1 %A, i32 123 )[ "deopt"() ]73 %V2 = load i32, ptr %P74 %B = icmp slt i32 %V2, 075 call void(i1, ...) @llvm.experimental.guard( i1 %B, i32 456 )[ "deopt"() ]76 ret void77}78 79define void @deref_load(i32 %V1, ptr dereferenceable(4) align 4 %P) nofree nosync {80; CHECK-LABEL: @deref_load(81; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P:%.*]], align 482; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[V1:%.*]], [[V2]]83; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 084; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 123) [ "deopt"() ]85; CHECK-NEXT: ret void86;87 %A = icmp slt i32 %V1, 088 call void(i1, ...) @llvm.experimental.guard( i1 %A, i32 123 )[ "deopt"() ]89 %V2 = load i32, ptr %P90 %B = icmp slt i32 %V2, 091 call void(i1, ...) @llvm.experimental.guard( i1 %B, i32 456 )[ "deopt"() ]92 ret void93}94 95; The divide might fault above the guard96define void @negative_div(i32 %V1, i32 %D) {97; CHECK-LABEL: @negative_div(98; CHECK-NEXT: [[A:%.*]] = icmp slt i32 [[V1:%.*]], 099; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[A]], i32 123) [ "deopt"() ]100; CHECK-NEXT: [[V2:%.*]] = udiv i32 [[V1]], [[D:%.*]]101; CHECK-NEXT: [[B:%.*]] = icmp slt i32 [[V2]], 0102; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[B]], i32 456) [ "deopt"() ]103; CHECK-NEXT: ret void104;105 %A = icmp slt i32 %V1, 0106 call void(i1, ...) @llvm.experimental.guard( i1 %A, i32 123 )[ "deopt"() ]107 %V2 = udiv i32 %V1, %D108 %B = icmp slt i32 %V2, 0109 call void(i1, ...) @llvm.experimental.guard( i1 %B, i32 456 )[ "deopt"() ]110 ret void111}112 113; Highlight the limit of the window in a case which would otherwise be mergable114define void @negative_window(i32 %V1, i32 %a, i32 %b, i32 %c, i32 %d) {115; CHECK-LABEL: @negative_window(116; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[V1:%.*]], 0117; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[CMP1]], i32 123) [ "deopt"() ]118; CHECK-NEXT: [[V2:%.*]] = add i32 [[A:%.*]], [[B:%.*]]119; CHECK-NEXT: [[V3:%.*]] = add i32 [[V2]], [[C:%.*]]120; CHECK-NEXT: [[V4:%.*]] = add i32 [[V3]], [[D:%.*]]121; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V4]], 0122; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[CMP2]], i32 456) [ "deopt"() ]123; CHECK-NEXT: ret void124;125 %cmp1 = icmp slt i32 %V1, 0126 call void(i1, ...) @llvm.experimental.guard( i1 %cmp1, i32 123 )[ "deopt"() ]127 %V2 = add i32 %a, %b128 %V3 = add i32 %V2, %c129 %V4 = add i32 %V3, %d130 %cmp2 = icmp slt i32 %V4, 0131 call void(i1, ...) @llvm.experimental.guard( i1 %cmp2, i32 456 )[ "deopt"() ]132 ret void133}134 135