llvm-project/llvm/test/CodeGen/AArch64/fast-isel-branch-cond-split.ll
Juneyoung Lee 5cdf6ed744 [CodeGen] recognize select form of and/ors when splitting branch conditions
Recently a few patches are made to move towards using select i1 instead of and/or i1 to represent "a && b"/"a || b" in C/C++.
"a && b" in C/C++ does not evaluate b if a is false whereas 'and a, b' in IR evaluates b and uses its result regardless of the result of a.
This is problematic because it can cause miscompilation if b was an erroneous operation (https://llvm.org/pr48353).
In C/C++, the result is simply false because b is not evaluated, but in IR the result is poison.
The discussion at D93065 has more context about this.

This patch makes two branch-splitting optimizations (one in SelectionDAGBuilder, one in CodeGenPrepare) recognize
select form of and/or as well using m_LogicalAnd/Or.
Since it is CodeGen, I think this is semantically ok (at least as safe as what codegen already did).

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D93853
2021-01-01 04:46:10 +09:00

127 lines
2.6 KiB
LLVM

; RUN: llc -mtriple=aarch64-apple-darwin -fast-isel -fast-isel-abort=1 -verify-machineinstrs < %s | FileCheck %s
; CHECK-LABEL: test_or
; CHECK: cbnz w0, {{LBB[0-9]+_2}}
; CHECK: cbz w1, {{LBB[0-9]+_1}}
define i64 @test_or(i32 %a, i32 %b) {
bb1:
%0 = icmp eq i32 %a, 0
%1 = icmp eq i32 %b, 0
%or.cond = or i1 %0, %1
br i1 %or.cond, label %bb3, label %bb4, !prof !0
bb3:
ret i64 0
bb4:
%2 = call i64 @bar()
ret i64 %2
}
; CHECK-LABEL: test_or_select
; CHECK: cbnz w0, {{LBB[0-9]+_2}}
; CHECK: cbz w1, {{LBB[0-9]+_1}}
define i64 @test_or_select(i32 %a, i32 %b) {
bb1:
%0 = icmp eq i32 %a, 0
%1 = icmp eq i32 %b, 0
%or.cond = select i1 %0, i1 true, i1 %1
br i1 %or.cond, label %bb3, label %bb4, !prof !0
bb3:
ret i64 0
bb4:
%2 = call i64 @bar()
ret i64 %2
}
; CHECK-LABEL: test_and
; CHECK: cbnz w0, {{LBB[0-9]+_2}}
; CHECK: cbz w1, {{LBB[0-9]+_1}}
define i64 @test_and(i32 %a, i32 %b) {
bb1:
%0 = icmp ne i32 %a, 0
%1 = icmp ne i32 %b, 0
%or.cond = and i1 %0, %1
br i1 %or.cond, label %bb4, label %bb3, !prof !1
bb3:
ret i64 0
bb4:
%2 = call i64 @bar()
ret i64 %2
}
; CHECK-LABEL: test_and_select
; CHECK: cbnz w0, {{LBB[0-9]+_2}}
; CHECK: cbz w1, {{LBB[0-9]+_1}}
define i64 @test_and_select(i32 %a, i32 %b) {
bb1:
%0 = icmp ne i32 %a, 0
%1 = icmp ne i32 %b, 0
%or.cond = select i1 %0, i1 %1, i1 false
br i1 %or.cond, label %bb4, label %bb3, !prof !1
bb3:
ret i64 0
bb4:
%2 = call i64 @bar()
ret i64 %2
}
; If the branch is unpredictable, don't add another branch.
; CHECK-LABEL: test_or_unpredictable
; CHECK: cmp w0, #0
; CHECK-NEXT: cset w8, eq
; CHECK-NEXT: cmp w1, #0
; CHECK-NEXT: cset w9, eq
; CHECK-NEXT: orr w8, w8, w9
; CHECK-NEXT: tbnz w8, #0,
define i64 @test_or_unpredictable(i32 %a, i32 %b) {
bb1:
%0 = icmp eq i32 %a, 0
%1 = icmp eq i32 %b, 0
%or.cond = or i1 %0, %1
br i1 %or.cond, label %bb3, label %bb4, !unpredictable !2
bb3:
ret i64 0
bb4:
%2 = call i64 @bar()
ret i64 %2
}
; CHECK-LABEL: test_and_unpredictable
; CHECK: cmp w0, #0
; CHECK-NEXT: cset w8, ne
; CHECK-NEXT: cmp w1, #0
; CHECK-NEXT: cset w9, ne
; CHECK-NEXT: and w8, w8, w9
; CHECK-NEXT: tbz w8, #0,
define i64 @test_and_unpredictable(i32 %a, i32 %b) {
bb1:
%0 = icmp ne i32 %a, 0
%1 = icmp ne i32 %b, 0
%or.cond = and i1 %0, %1
br i1 %or.cond, label %bb4, label %bb3, !unpredictable !2
bb3:
ret i64 0
bb4:
%2 = call i64 @bar()
ret i64 %2
}
declare i64 @bar()
!0 = !{!"branch_weights", i32 5128, i32 32}
!1 = !{!"branch_weights", i32 1024, i32 4136}
!2 = !{}