198 lines
6.5 KiB
LLVM
198 lines
6.5 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc < %s -mtriple=i686-- -O3 -verify-machineinstrs | FileCheck %s
|
|
|
|
; Tests for using callbr as an asm-goto wrapper
|
|
|
|
; Test 1 - fallthrough label gets removed, but the fallthrough code that is
|
|
; unreachable due to asm ending on a jmp is still left in.
|
|
define i32 @test1(i32 %a) {
|
|
; CHECK-LABEL: test1:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax
|
|
; CHECK-NEXT: addl $4, %eax
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: xorl %eax, %eax
|
|
; CHECK-NEXT: jmp .LBB0_2
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: # %bb.1: # %normal
|
|
; CHECK-NEXT: xorl %eax, %eax
|
|
; CHECK-NEXT: retl
|
|
; CHECK-NEXT: .LBB0_2: # Block address taken
|
|
; CHECK-NEXT: # %fail
|
|
; CHECK-NEXT: # Label of block must be emitted
|
|
; CHECK-NEXT: movl $1, %eax
|
|
; CHECK-NEXT: retl
|
|
entry:
|
|
%0 = add i32 %a, 4
|
|
callbr void asm "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail]
|
|
|
|
normal:
|
|
ret i32 0
|
|
|
|
fail:
|
|
ret i32 1
|
|
}
|
|
|
|
; Test 1b - Like test 1 but using `asm inteldialect`.
|
|
define i32 @test1b(i32 %a) {
|
|
; CHECK-LABEL: test1b:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax
|
|
; CHECK-NEXT: addl $4, %eax
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-EMPTY:
|
|
; CHECK-NEXT: xorl %eax, %eax
|
|
; CHECK-NEXT: jmp .LBB1_2
|
|
; CHECK-EMPTY:
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: # %bb.1: # %normal
|
|
; CHECK-NEXT: xorl %eax, %eax
|
|
; CHECK-NEXT: retl
|
|
; CHECK-NEXT: .LBB1_2: # Block address taken
|
|
; CHECK-NEXT: # %fail
|
|
; CHECK-NEXT: # Label of block must be emitted
|
|
; CHECK-NEXT: movl $1, %eax
|
|
; CHECK-NEXT: retl
|
|
entry:
|
|
%0 = add i32 %a, 4
|
|
callbr void asm inteldialect "xor $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail]
|
|
|
|
normal:
|
|
ret i32 0
|
|
|
|
fail:
|
|
ret i32 1
|
|
}
|
|
|
|
; Test 2 - callbr terminates an unreachable block, function gets simplified
|
|
; to a trivial zero return.
|
|
define i32 @test2(i32 %a) {
|
|
; CHECK-LABEL: test2:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: xorl %eax, %eax
|
|
; CHECK-NEXT: retl
|
|
entry:
|
|
br label %normal
|
|
|
|
unreachableasm:
|
|
%0 = add i32 %a, 4
|
|
callbr void asm sideeffect "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail]
|
|
|
|
normal:
|
|
ret i32 0
|
|
|
|
fail:
|
|
ret i32 1
|
|
}
|
|
|
|
; Test 3 - asm-goto implements a loop. The loop gets recognized, but many loop
|
|
; transforms fail due to canonicalization having callbr exceptions. Trivial
|
|
; blocks at labels 1 and 3 also don't get simplified due to callbr.
|
|
define i32 @test3(i32 %a) {
|
|
; CHECK-LABEL: test3:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: .LBB3_1: # Block address taken
|
|
; CHECK-NEXT: # %label01
|
|
; CHECK-NEXT: # =>This Loop Header: Depth=1
|
|
; CHECK-NEXT: # Child Loop BB3_2 Depth 2
|
|
; CHECK-NEXT: # Child Loop BB3_3 Depth 3
|
|
; CHECK-NEXT: # Child Loop BB3_4 Depth 4
|
|
; CHECK-NEXT: # Label of block must be emitted
|
|
; CHECK-NEXT: .LBB3_2: # Block address taken
|
|
; CHECK-NEXT: # %label02
|
|
; CHECK-NEXT: # Parent Loop BB3_1 Depth=1
|
|
; CHECK-NEXT: # => This Loop Header: Depth=2
|
|
; CHECK-NEXT: # Child Loop BB3_3 Depth 3
|
|
; CHECK-NEXT: # Child Loop BB3_4 Depth 4
|
|
; CHECK-NEXT: # Label of block must be emitted
|
|
; CHECK-NEXT: addl $4, {{[0-9]+}}(%esp)
|
|
; CHECK-NEXT: .LBB3_3: # Block address taken
|
|
; CHECK-NEXT: # %label03
|
|
; CHECK-NEXT: # Parent Loop BB3_1 Depth=1
|
|
; CHECK-NEXT: # Parent Loop BB3_2 Depth=2
|
|
; CHECK-NEXT: # => This Loop Header: Depth=3
|
|
; CHECK-NEXT: # Child Loop BB3_4 Depth 4
|
|
; CHECK-NEXT: # Label of block must be emitted
|
|
; CHECK-NEXT: .LBB3_4: # Block address taken
|
|
; CHECK-NEXT: # %label04
|
|
; CHECK-NEXT: # Parent Loop BB3_1 Depth=1
|
|
; CHECK-NEXT: # Parent Loop BB3_2 Depth=2
|
|
; CHECK-NEXT: # Parent Loop BB3_3 Depth=3
|
|
; CHECK-NEXT: # => This Inner Loop Header: Depth=4
|
|
; CHECK-NEXT: # Label of block must be emitted
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: jmp .LBB3_1
|
|
; CHECK-NEXT: jmp .LBB3_2
|
|
; CHECK-NEXT: jmp .LBB3_3
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: # %bb.5: # %normal0
|
|
; CHECK-NEXT: # in Loop: Header=BB3_4 Depth=4
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: jmp .LBB3_1
|
|
; CHECK-NEXT: jmp .LBB3_2
|
|
; CHECK-NEXT: jmp .LBB3_3
|
|
; CHECK-NEXT: jmp .LBB3_4
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: # %bb.6: # %normal1
|
|
; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax
|
|
; CHECK-NEXT: retl
|
|
entry:
|
|
%a.addr = alloca i32, align 4
|
|
store i32 %a, ptr %a.addr, align 4
|
|
br label %label01
|
|
|
|
label01: ; preds = %normal0, %label04, %entry
|
|
br label %label02
|
|
|
|
label02: ; preds = %normal0, %label04, %label01
|
|
%0 = load i32, ptr %a.addr, align 4
|
|
%add = add nsw i32 %0, 4
|
|
store i32 %add, ptr %a.addr, align 4
|
|
br label %label03
|
|
|
|
label03: ; preds = %normal0, %label04, %label02
|
|
br label %label04
|
|
|
|
label04: ; preds = %normal0, %label03
|
|
callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}", "!i,!i,!i,~{dirflag},~{fpsr},~{flags}"()
|
|
to label %normal0 [label %label01, label %label02, label %label03]
|
|
|
|
normal0: ; preds = %label04
|
|
callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}; jmp ${3:l}", "!i,!i,!i,!i,~{dirflag},~{fpsr},~{flags}"()
|
|
to label %normal1 [label %label01, label %label02, label %label03, label %label04]
|
|
|
|
normal1: ; preds = %normal0
|
|
%1 = load i32, ptr %a.addr, align 4
|
|
ret i32 %1
|
|
}
|
|
|
|
; Test 4 - asm-goto referenced with the 'l' (ell) modifier and not.
|
|
define void @test4() {
|
|
; CHECK-LABEL: test4:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: ja .LBB4_3
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: # %bb.1: # %asm.fallthrough
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: ja .LBB4_3
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: .LBB4_3: # Block address taken
|
|
; CHECK-NEXT: # %quux
|
|
; CHECK-NEXT: # Label of block must be emitted
|
|
; CHECK-NEXT: retl
|
|
entry:
|
|
callbr void asm sideeffect "ja $0", "!i,~{dirflag},~{fpsr},~{flags}"()
|
|
to label %asm.fallthrough [label %quux]
|
|
|
|
asm.fallthrough: ; preds = %entry
|
|
callbr void asm sideeffect "ja ${0:l}", "!i,~{dirflag},~{fpsr},~{flags}"()
|
|
to label %cleanup [label %quux]
|
|
|
|
quux: ; preds = %asm.fallthrough, %entry
|
|
br label %cleanup
|
|
|
|
cleanup: ; preds = %asm.fallthrough, %quux
|
|
ret void
|
|
}
|