From d5f1adcf6651a1c10400ad7b1517272ea8e81c53 Mon Sep 17 00:00:00 2001 From: Max Kazantsev Date: Fri, 28 Apr 2023 17:52:54 +0700 Subject: [PATCH] [TEST][LICM] Add test cases on widenable condition hoisting opportunity Patch by Aleksandr Popov! Differential Revision: https://reviews.llvm.org/D149373 --- llvm/test/Transforms/LICM/explicit_guards.ll | 108 +++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/llvm/test/Transforms/LICM/explicit_guards.ll b/llvm/test/Transforms/LICM/explicit_guards.ll index 469acf1..84e5517 100644 --- a/llvm/test/Transforms/LICM/explicit_guards.ll +++ b/llvm/test/Transforms/LICM/explicit_guards.ll @@ -3,6 +3,8 @@ declare void @llvm.experimental.guard(i1,...) declare void @maythrow() +declare void @llvm.experimental.deoptimize.isVoid(...) +declare i1 @llvm.experimental.widenable.condition() ; Make sure that we do not hoist widenable_cond out of loop. ; Widenable conditions don't actually alias anything or throw, however @@ -125,3 +127,109 @@ loop: exit: ret void } + +; TODO: Hoist widenable condition out of loop since it's the only +; non-invariant operand of its user. If we hoist wc here, we can hoist +; `and` as well, otherwise it prevents us from doing that. +define void @hoist_widenable_cond_1(ptr %p, i32 %x) { +; CHECK-LABEL: @hoist_widenable_cond_1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[LOAD:%.*]] = load atomic i32, ptr [[P:%.*]] unordered, align 8 +; CHECK-NEXT: [[ICMP7:%.*]] = icmp ult i32 0, [[LOAD]] +; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] +; CHECK: loop.header: +; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[ICMP:%.*]] = icmp ult i32 [[IV]], [[X:%.*]] +; CHECK-NEXT: br i1 [[ICMP]], label [[LOOP_BODY:%.*]], label [[EXIT:%.*]] +; CHECK: loop.body: +; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() +; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[ICMP7]], [[WIDENABLE_COND]] +; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]] +; CHECK: deopt: +; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid(i32 13) [ "deopt"() ] +; CHECK-NEXT: ret void +; CHECK: guarded: +; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 +; CHECK-NEXT: br label [[LOOP_HEADER]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %load = load atomic i32, ptr %p unordered, align 8 + br label %loop.header + +loop.header: + %iv = phi i32 [ %iv.next, %guarded ], [ 0, %entry ] + %icmp = icmp ult i32 %iv, %x + br i1 %icmp, label %loop.body, label %exit + +loop.body: + %icmp7 = icmp ult i32 0, %load + %widenable_cond = call i1 @llvm.experimental.widenable.condition() + %exiplicit_guard_cond = and i1 %icmp7, %widenable_cond + br i1 %exiplicit_guard_cond, label %guarded, label %deopt + +deopt: + call void (...) @llvm.experimental.deoptimize.isVoid(i32 13) [ "deopt"() ] + ret void + +guarded: + %iv.next = add nuw nsw i32 %iv, 1 + br label %loop.header + +exit: + ret void +} + +; Same as hoist_widenable_cond_1 test, but widenable condition goes before +; icmp - the second operand of wc's user. +; TODO: Hoist widenable condition out of loop. +define void @hoist_widenable_cond_2(ptr %p, i32 %x) { +; CHECK-LABEL: @hoist_widenable_cond_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[LOAD:%.*]] = load atomic i32, ptr [[P:%.*]] unordered, align 8 +; CHECK-NEXT: [[ICMP7:%.*]] = icmp ult i32 0, [[LOAD]] +; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] +; CHECK: loop.header: +; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[ICMP:%.*]] = icmp ult i32 [[IV]], [[X:%.*]] +; CHECK-NEXT: br i1 [[ICMP]], label [[LOOP_BODY:%.*]], label [[EXIT:%.*]] +; CHECK: loop.body: +; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() +; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[ICMP7]], [[WIDENABLE_COND]] +; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]] +; CHECK: deopt: +; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid(i32 13) [ "deopt"() ] +; CHECK-NEXT: ret void +; CHECK: guarded: +; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 +; CHECK-NEXT: br label [[LOOP_HEADER]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %load = load atomic i32, ptr %p unordered, align 8 + br label %loop.header + +loop.header: + %iv = phi i32 [ %iv.next, %guarded ], [ 0, %entry ] + %icmp = icmp ult i32 %iv, %x + br i1 %icmp, label %loop.body, label %exit + +loop.body: + %widenable_cond = call i1 @llvm.experimental.widenable.condition() + %icmp7 = icmp ult i32 0, %load + %exiplicit_guard_cond = and i1 %icmp7, %widenable_cond + br i1 %exiplicit_guard_cond, label %guarded, label %deopt + +deopt: + call void (...) @llvm.experimental.deoptimize.isVoid(i32 13) [ "deopt"() ] + ret void + +guarded: + %iv.next = add nuw nsw i32 %iv, 1 + br label %loop.header + +exit: + ret void +} -- 2.7.4