llvm-project/llvm/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1330 lines
34 KiB
Plaintext
Raw Normal View History

# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -O0 -mtriple arm-- -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
--- |
define void @test_trunc_and_zext_s1_to_s32() { ret void }
define void @test_trunc_and_sext_s1_to_s32() { ret void }
define void @test_trunc_and_sext_s8_to_s32() { ret void }
define void @test_trunc_and_zext_s16_to_s32() { ret void }
define void @test_trunc_and_anyext_s8_to_s32() { ret void }
define void @test_trunc_and_anyext_s16_to_s32() { ret void }
define void @test_trunc_and_zext_s1_to_s16() { ret void }
define void @test_trunc_and_sext_s1_to_s16() { ret void }
define void @test_trunc_and_anyext_s1_to_s16() { ret void }
define void @test_trunc_and_zext_s8_to_s16() { ret void }
define void @test_trunc_and_sext_s8_to_s16() { ret void }
define void @test_trunc_and_anyext_s8_to_s16() { ret void }
define void @test_trunc_and_zext_s1_to_s8() { ret void }
define void @test_trunc_and_sext_s1_to_s8() { ret void }
define void @test_trunc_and_anyext_s1_to_s8() { ret void }
define void @test_add_s32() { ret void }
define void @test_add_fold_imm_s32() { ret void }
define void @test_add_no_fold_imm_s32() #2 { ret void }
define void @test_sub_s32() { ret void }
define void @test_sub_imm_s32() { ret void }
define void @test_sub_rev_imm_s32() { ret void }
define void @test_mul_s32() #0 { ret void }
define void @test_mulv5_s32() { ret void }
define void @test_sdiv_s32() #1 { ret void }
define void @test_udiv_s32() #1 { ret void }
define void @test_lshr_s32() { ret void }
define void @test_ashr_s32() { ret void }
define void @test_shl_s32() { ret void }
define void @test_load_from_stack() { ret void }
define void @test_stores() { ret void }
define void @test_gep() { ret void }
define void @test_MOVi32imm() #2 { ret void }
define void @test_constant_imm() { ret void }
define void @test_constant_cimm() { ret void }
define void @test_pointer_constant_unconstrained() { ret void }
define void @test_pointer_constant_constrained() { ret void }
define void @test_inttoptr_s32() { ret void }
define void @test_ptrtoint_s32() { ret void }
define void @test_select_s32() { ret void }
define void @test_select_ptr() { ret void }
define void @test_br() { ret void }
define void @test_phi_s32() { ret void }
attributes #0 = { "target-features"="+v6" }
attributes #1 = { "target-features"="+hwdiv-arm" }
attributes #2 = { "target-features"="+v6t2" }
...
---
name: test_trunc_and_zext_s1_to_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_trunc_and_zext_s1_to_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[ANDri:%[0-9]+]]:gpr = ANDri [[COPY]], 1, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[ANDri]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s1) = G_TRUNC %0(s32)
%2(s32) = G_ZEXT %1(s1)
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_trunc_and_sext_s1_to_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_trunc_and_sext_s1_to_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[ANDri:%[0-9]+]]:gpr = ANDri [[COPY]], 1, 14 /* CC::al */, $noreg, $noreg
; CHECK: [[RSBri:%[0-9]+]]:gpr = RSBri [[ANDri]], 0, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[RSBri]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s1) = G_TRUNC %0(s32)
%2(s32) = G_SEXT %1(s1)
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_trunc_and_sext_s8_to_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_trunc_and_sext_s8_to_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gprnopc = COPY [[COPY]]
; CHECK: [[SXTB:%[0-9]+]]:gprnopc = SXTB [[COPY1]], 0, 14 /* CC::al */, $noreg
; CHECK: $r0 = COPY [[SXTB]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s8) = G_TRUNC %0(s32)
%2(s32) = G_SEXT %1(s8)
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_trunc_and_zext_s16_to_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_trunc_and_zext_s16_to_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gprnopc = COPY [[COPY]]
; CHECK: [[UXTH:%[0-9]+]]:gprnopc = UXTH [[COPY1]], 0, 14 /* CC::al */, $noreg
; CHECK: $r0 = COPY [[UXTH]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s16) = G_TRUNC %0(s32)
%2(s32) = G_ZEXT %1(s16)
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_trunc_and_anyext_s8_to_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_trunc_and_anyext_s8_to_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: $r0 = COPY [[COPY]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s8) = G_TRUNC %0(s32)
%2(s32) = G_ANYEXT %1(s8)
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_trunc_and_anyext_s16_to_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_trunc_and_anyext_s16_to_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: $r0 = COPY [[COPY]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s16) = G_TRUNC %0(s32)
%2(s32) = G_ANYEXT %1(s16)
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_trunc_and_zext_s1_to_s16
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_trunc_and_zext_s1_to_s16
; CHECK: liveins: $r0, $r1
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[ANDri:%[0-9]+]]:gpr = ANDri [[COPY1]], 1, 14 /* CC::al */, $noreg, $noreg
; CHECK: STRH [[ANDri]], [[COPY]], $noreg, 0, 14 /* CC::al */, $noreg :: (store (s16))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(s1) = G_TRUNC %1(s32)
%3(s16) = G_ZEXT %2(s1)
G_STORE %3(s16), %0(p0) :: (store (s16))
BX_RET 14, $noreg
...
---
name: test_trunc_and_sext_s1_to_s16
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_trunc_and_sext_s1_to_s16
; CHECK: liveins: $r0, $r1
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[ANDri:%[0-9]+]]:gpr = ANDri [[COPY1]], 1, 14 /* CC::al */, $noreg, $noreg
; CHECK: [[RSBri:%[0-9]+]]:gpr = RSBri [[ANDri]], 0, 14 /* CC::al */, $noreg, $noreg
; CHECK: STRH [[RSBri]], [[COPY]], $noreg, 0, 14 /* CC::al */, $noreg :: (store (s16))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(s1) = G_TRUNC %1(s32)
%3(s16) = G_SEXT %2(s1)
G_STORE %3(s16), %0(p0) :: (store (s16))
BX_RET 14, $noreg
...
---
name: test_trunc_and_anyext_s1_to_s16
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_trunc_and_anyext_s1_to_s16
; CHECK: liveins: $r0, $r1
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: STRH [[COPY1]], [[COPY]], $noreg, 0, 14 /* CC::al */, $noreg :: (store (s16))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(s1) = G_TRUNC %1(s32)
%3(s16) = G_ANYEXT %2(s1)
G_STORE %3(s16), %0(p0) :: (store (s16))
BX_RET 14, $noreg
...
---
name: test_trunc_and_zext_s8_to_s16
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_trunc_and_zext_s8_to_s16
; CHECK: liveins: $r0, $r1
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[COPY2:%[0-9]+]]:gprnopc = COPY [[COPY1]]
; CHECK: [[UXTB:%[0-9]+]]:gprnopc = UXTB [[COPY2]], 0, 14 /* CC::al */, $noreg
; CHECK: STRH [[UXTB]], [[COPY]], $noreg, 0, 14 /* CC::al */, $noreg :: (store (s16))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(s8) = G_TRUNC %1(s32)
%3(s16) = G_ZEXT %2(s8)
G_STORE %3(s16), %0(p0) :: (store (s16))
BX_RET 14, $noreg
...
---
name: test_trunc_and_sext_s8_to_s16
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_trunc_and_sext_s8_to_s16
; CHECK: liveins: $r0, $r1
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[COPY2:%[0-9]+]]:gprnopc = COPY [[COPY1]]
; CHECK: [[SXTB:%[0-9]+]]:gprnopc = SXTB [[COPY2]], 0, 14 /* CC::al */, $noreg
; CHECK: STRH [[SXTB]], [[COPY]], $noreg, 0, 14 /* CC::al */, $noreg :: (store (s16))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(s8) = G_TRUNC %1(s32)
%3(s16) = G_SEXT %2(s8)
G_STORE %3(s16), %0(p0) :: (store (s16))
BX_RET 14, $noreg
...
---
name: test_trunc_and_anyext_s8_to_s16
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_trunc_and_anyext_s8_to_s16
; CHECK: liveins: $r0, $r1
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: STRH [[COPY1]], [[COPY]], $noreg, 0, 14 /* CC::al */, $noreg :: (store (s16))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(s8) = G_TRUNC %1(s32)
%3(s16) = G_ANYEXT %2(s8)
G_STORE %3(s16), %0(p0) :: (store (s16))
BX_RET 14, $noreg
...
---
name: test_trunc_and_zext_s1_to_s8
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_trunc_and_zext_s1_to_s8
; CHECK: liveins: $r0, $r1
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[ANDri:%[0-9]+]]:gprnopc = ANDri [[COPY1]], 1, 14 /* CC::al */, $noreg, $noreg
; CHECK: STRBi12 [[ANDri]], [[COPY]], 0, 14 /* CC::al */, $noreg :: (store (s8))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(s1) = G_TRUNC %1(s32)
%3(s8) = G_ZEXT %2(s1)
G_STORE %3(s8), %0(p0) :: (store (s8))
BX_RET 14, $noreg
...
---
name: test_trunc_and_sext_s1_to_s8
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_trunc_and_sext_s1_to_s8
; CHECK: liveins: $r0, $r1
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[ANDri:%[0-9]+]]:gpr = ANDri [[COPY1]], 1, 14 /* CC::al */, $noreg, $noreg
; CHECK: [[RSBri:%[0-9]+]]:gprnopc = RSBri [[ANDri]], 0, 14 /* CC::al */, $noreg, $noreg
; CHECK: STRBi12 [[RSBri]], [[COPY]], 0, 14 /* CC::al */, $noreg :: (store (s8))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(s1) = G_TRUNC %1(s32)
%3(s8) = G_SEXT %2(s1)
G_STORE %3(s8), %0(p0) :: (store (s8))
BX_RET 14, $noreg
...
---
name: test_trunc_and_anyext_s1_to_s8
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_trunc_and_anyext_s1_to_s8
; CHECK: liveins: $r0, $r1
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[COPY2:%[0-9]+]]:gprnopc = COPY [[COPY1]]
; CHECK: STRBi12 [[COPY2]], [[COPY]], 0, 14 /* CC::al */, $noreg :: (store (s8))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(s1) = G_TRUNC %1(s32)
%3(s8) = G_ANYEXT %2(s1)
G_STORE %3(s8), %0(p0) :: (store (s8))
BX_RET 14, $noreg
...
---
name: test_add_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_add_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[ADDrr:%[0-9]+]]:gpr = ADDrr [[COPY]], [[COPY1]], 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[ADDrr]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s32) = G_ADD %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_add_fold_imm_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_add_fold_imm_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[ADDri:%[0-9]+]]:gpr = ADDri [[COPY]], 255, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[ADDri]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = G_CONSTANT i32 255
%2(s32) = G_ADD %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_add_no_fold_imm_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_add_no_fold_imm_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[MOVi16_:%[0-9]+]]:gpr = MOVi16 65535, 14 /* CC::al */, $noreg
; CHECK: [[ADDrr:%[0-9]+]]:gpr = ADDrr [[COPY]], [[MOVi16_]], 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[ADDrr]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = G_CONSTANT i32 65535
%2(s32) = G_ADD %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_sub_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_sub_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[SUBrr:%[0-9]+]]:gpr = SUBrr [[COPY]], [[COPY1]], 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[SUBrr]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s32) = G_SUB %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_sub_imm_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_sub_imm_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[SUBri:%[0-9]+]]:gpr = SUBri [[COPY]], 17, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[SUBri]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = G_CONSTANT i32 17
%2(s32) = G_SUB %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_sub_rev_imm_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_sub_rev_imm_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[RSBri:%[0-9]+]]:gpr = RSBri [[COPY]], 17, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[RSBri]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = G_CONSTANT i32 17
%2(s32) = G_SUB %1, %0
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_mul_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_mul_s32
; CHECK: [[COPY:%[0-9]+]]:gprnopc = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gprnopc = COPY $r1
; CHECK: [[MUL:%[0-9]+]]:gprnopc = MUL [[COPY]], [[COPY1]], 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[MUL]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s32) = G_MUL %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_mulv5_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_mulv5_s32
; CHECK: [[COPY:%[0-9]+]]:gprnopc = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gprnopc = COPY $r1
; CHECK: early-clobber %2:gprnopc = MULv5 [[COPY]], [[COPY1]], 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY %2
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s32) = G_MUL %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_sdiv_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_sdiv_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[SDIV:%[0-9]+]]:gpr = SDIV [[COPY]], [[COPY1]], 14 /* CC::al */, $noreg
; CHECK: $r0 = COPY [[SDIV]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s32) = G_SDIV %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_udiv_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_udiv_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[UDIV:%[0-9]+]]:gpr = UDIV [[COPY]], [[COPY1]], 14 /* CC::al */, $noreg
; CHECK: $r0 = COPY [[UDIV]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s32) = G_UDIV %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_lshr_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_lshr_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[MOVsr:%[0-9]+]]:gprnopc = MOVsr [[COPY]], [[COPY1]], 3, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[MOVsr]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s32) = G_LSHR %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_ashr_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_ashr_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[MOVsr:%[0-9]+]]:gprnopc = MOVsr [[COPY]], [[COPY1]], 1, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[MOVsr]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s32) = G_ASHR %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_shl_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_shl_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[MOVsr:%[0-9]+]]:gprnopc = MOVsr [[COPY]], [[COPY1]], 2, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[MOVsr]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s32) = G_SHL %0, %1
$r0 = COPY %2(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_load_from_stack
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
- { id: 4, class: gprb }
fixedStack:
- { id: 0, offset: 0, size: 1, alignment: 4, isImmutable: true, isAliased: false }
- { id: 1, offset: 4, size: 4, alignment: 4, isImmutable: true, isAliased: false }
- { id: 2, offset: 8, size: 4, alignment: 4, isImmutable: true, isAliased: false }
body: |
bb.0:
liveins: $r0, $r1, $r2, $r3
; CHECK-LABEL: name: test_load_from_stack
; CHECK: [[ADDri:%[0-9]+]]:gpr = ADDri %fixed-stack.0, 0, 14 /* CC::al */, $noreg, $noreg
; CHECK: [[LDRi12_:%[0-9]+]]:gpr = LDRi12 [[ADDri]], 0, 14 /* CC::al */, $noreg :: (load (s32))
; CHECK: $r0 = COPY [[LDRi12_]]
; CHECK: [[ADDri1:%[0-9]+]]:gpr = ADDri %fixed-stack.2, 0, 14 /* CC::al */, $noreg, $noreg
; CHECK: [[LDRBi12_:%[0-9]+]]:gprnopc = LDRBi12 [[ADDri1]], 0, 14 /* CC::al */, $noreg :: (load (s8))
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY [[LDRBi12_]]
; CHECK: $r0 = COPY [[COPY]]
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = G_FRAME_INDEX %fixed-stack.2
%1(s32) = G_LOAD %0(p0) :: (load (s32))
$r0 = COPY %1
%2(p0) = G_FRAME_INDEX %fixed-stack.0
%3(s8) = G_LOAD %2(p0) :: (load (s8))
%4(s32) = G_ANYEXT %3(s8)
$r0 = COPY %4
BX_RET 14, $noreg
...
---
name: test_stores
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
- { id: 4, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_stores
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[COPY2:%[0-9]+]]:gprnopc = COPY [[COPY1]]
; CHECK: STRBi12 [[COPY2]], [[COPY]], 0, 14 /* CC::al */, $noreg :: (store (s8))
; CHECK: STRH [[COPY1]], [[COPY]], $noreg, 0, 14 /* CC::al */, $noreg :: (store (s16))
; CHECK: STRi12 [[COPY1]], [[COPY]], 0, 14 /* CC::al */, $noreg :: (store (s32))
; CHECK: BX_RET 14 /* CC::al */, $noreg
%0(p0) = COPY $r0
%3(s32) = COPY $r1
%1(s8) = G_TRUNC %3(s32)
%2(s16) = G_TRUNC %3(s32)
G_STORE %1(s8), %0(p0) :: (store (s8))
G_STORE %2(s16), %0(p0) :: (store (s16))
G_STORE %3(s32), %0(p0) :: (store (s32))
BX_RET 14, $noreg
...
---
name: test_gep
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_gep
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[ADDrr:%[0-9]+]]:gpr = ADDrr [[COPY]], [[COPY1]], 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[ADDrr]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(p0) = COPY $r0
%1(s32) = COPY $r1
%2(p0) = G_PTR_ADD %0, %1(s32)
$r0 = COPY %2(p0)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_MOVi32imm
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
body: |
bb.0:
; CHECK-LABEL: name: test_MOVi32imm
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr = MOVi32imm 65537
; CHECK: $r0 = COPY [[MOVi32imm]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = G_CONSTANT i32 65537
$r0 = COPY %0(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_constant_imm
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
body: |
bb.0:
; CHECK-LABEL: name: test_constant_imm
; CHECK: [[MOVi:%[0-9]+]]:gpr = MOVi 42, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[MOVi]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = G_CONSTANT i32 42
$r0 = COPY %0(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_constant_cimm
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
body: |
bb.0:
; Adding a type on G_CONSTANT changes its operand from an Imm into a CImm.
; We still want to see the same thing in the output though.
; CHECK-LABEL: name: test_constant_cimm
; CHECK: [[MOVi:%[0-9]+]]:gpr = MOVi 42, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[MOVi]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = G_CONSTANT i32 42
$r0 = COPY %0(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_pointer_constant_unconstrained
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
body: |
bb.0:
; CHECK-LABEL: name: test_pointer_constant_unconstrained
; CHECK: [[MOVi:%[0-9]+]]:gpr = MOVi 0, 14 /* CC::al */, $noreg, $noreg
; CHECK: $r0 = COPY [[MOVi]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(p0) = G_CONSTANT i32 0
; This leaves %0 unconstrained before the G_CONSTANT is selected.
$r0 = COPY %0(p0)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_pointer_constant_constrained
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
body: |
bb.0:
; CHECK-LABEL: name: test_pointer_constant_constrained
; CHECK: [[MOVi:%[0-9]+]]:gpr = MOVi 0, 14 /* CC::al */, $noreg, $noreg
; CHECK: STRi12 [[MOVi]], [[MOVi]], 0, 14 /* CC::al */, $noreg :: (store (p0))
%0(p0) = G_CONSTANT i32 0
; This constrains %0 before the G_CONSTANT is selected.
G_STORE %0(p0), %0(p0) :: (store (p0))
...
---
name: test_inttoptr_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_inttoptr_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: $r0 = COPY [[COPY]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(p0) = G_INTTOPTR %0(s32)
$r0 = COPY %1(p0)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_ptrtoint_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
body: |
bb.0:
liveins: $r0
; CHECK-LABEL: name: test_ptrtoint_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: $r0 = COPY [[COPY]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(p0) = COPY $r0
%1(s32) = G_PTRTOINT %0(p0)
$r0 = COPY %1(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_select_s32
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
body: |
bb.0:
liveins: $r0, $r1
; CHECK-LABEL: name: test_select_s32
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: TSTri [[COPY1]], 1, 14 /* CC::al */, $noreg, implicit-def $cpsr
; CHECK: [[MOVCCr:%[0-9]+]]:gpr = MOVCCr [[COPY]], [[COPY1]], 0 /* CC::eq */, $cpsr
; CHECK: $r0 = COPY [[MOVCCr]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(s32) = COPY $r0
%1(s32) = COPY $r1
%2(s1) = G_TRUNC %1(s32)
%3(s32) = G_SELECT %2(s1), %0, %1
$r0 = COPY %3(s32)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_select_ptr
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
[GlobalISel] Enable legalizing non-power-of-2 sized types. This changes the interface of how targets describe how to legalize, see the below description. 1. Interface for targets to describe how to legalize. In GlobalISel, the API in the LegalizerInfo class is the main interface for targets to specify which types are legal for which operations, and what to do to turn illegal type/operation combinations into legal ones. For each operation the type sizes that can be legalized without having to change the size of the type are specified with a call to setAction. This isn't different to how GlobalISel worked before. For example, for a target that supports 32 and 64 bit adds natively: for (auto Ty : {s32, s64}) setAction({G_ADD, 0, s32}, Legal); or for a target that needs a library call for a 32 bit division: setAction({G_SDIV, s32}, Libcall); The main conceptual change to the LegalizerInfo API, is in specifying how to legalize the type sizes for which a change of size is needed. For example, in the above example, how to specify how all types from i1 to i8388607 (apart from s32 and s64 which are legal) need to be legalized and expressed in terms of operations on the available legal sizes (again, i32 and i64 in this case). Before, the implementation only allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0, s128}, NarrowScalar). A worse limitation was that if you'd wanted to specify how to legalize all the sized types as allowed by the LLVM-IR LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times and probably would need a lot of memory to store all of these specifications. Instead, the legalization actions that need to change the size of the type are specified now using a "SizeChangeStrategy". For example: setLegalizeScalarToDifferentSizeStrategy( G_ADD, 0, widenToLargerAndNarrowToLargest); This example indicates that for type sizes for which there is a larger size that can be legalized towards, do it by Widening the size. For example, G_ADD on s17 will be legalized by first doing WidenScalar to make it s32, after which it's legal. The "NarrowToLargest" indicates what to do if there is no larger size that can be legalized towards. E.g. G_ADD on s92 will be legalized by doing NarrowScalar to s64. Another example, taken from the ARM backend is: for (unsigned Op : {G_SDIV, G_UDIV}) { setLegalizeScalarToDifferentSizeStrategy(Op, 0, widenToLargerTypesUnsupportedOtherwise); if (ST.hasDivideInARMMode()) setAction({Op, s32}, Legal); else setAction({Op, s32}, Libcall); } For this example, G_SDIV on s8, on a target without a divide instruction, would be legalized by first doing action (WidenScalar, s32), followed by (Libcall, s32). The same principle is also followed for when the number of vector lanes on vector data types need to be changed, e.g.: setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal); setLegalizeVectorElementToDifferentSizeStrategy( G_ADD, 0, widenToLargerTypesUnsupportedOtherwise); As currently implemented here, vector types are legalized by first making the vector element size legal, followed by then making the number of lanes legal. The strategy to follow in the first step is set by a call to setLegalizeVectorElementToDifferentSizeStrategy, see example above. The strategy followed in the second step "moreToWiderTypesAndLessToWidest" (see code for its definition), indicating that vectors are widened to more elements so they map to natively supported vector widths, or when there isn't a legal wider vector, split the vector to map it to the widest vector supported. Therefore, for the above specification, some example legalizations are: * getAction({G_ADD, LLT::vector(3, 3)}) returns {WidenScalar, LLT::vector(3, 8)} * getAction({G_ADD, LLT::vector(3, 8)}) then returns {MoreElements, LLT::vector(8, 8)} * getAction({G_ADD, LLT::vector(20, 8)}) returns {FewerElements, LLT::vector(16, 8)} 2. Key implementation aspects. How to legalize a specific (operation, type index, size) tuple is represented by mapping intervals of integers representing a range of size types to an action to take, e.g.: setScalarAction({G_ADD, LLT:scalar(1)}, {{1, WidenScalar}, // bit sizes [ 1, 31[ {32, Legal}, // bit sizes [32, 33[ {33, WidenScalar}, // bit sizes [33, 64[ {64, Legal}, // bit sizes [64, 65[ {65, NarrowScalar} // bit sizes [65, +inf[ }); Please note that most of the code to do the actual lowering of non-power-of-2 sized types is currently missing, this is just trying to make it possible for targets to specify what is legal, and how non-legal types should be legalized. Probably quite a bit of further work is needed in the actual legalizing and the other passes in GlobalISel to support non-power-of-2 sized types. I hope the documentation in LegalizerInfo.h and the examples provided in the various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well enough how this is meant to be used. This drops the need for LLT::{half,double}...Size(). Differential Revision: https://reviews.llvm.org/D30529 llvm-svn: 317560
2017-11-07 18:34:34 +08:00
- { id: 4, class: gprb }
body: |
bb.0:
liveins: $r0, $r1, $r2
; CHECK-LABEL: name: test_select_ptr
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[COPY2:%[0-9]+]]:gpr = COPY $r2
; CHECK: TSTri [[COPY2]], 1, 14 /* CC::al */, $noreg, implicit-def $cpsr
; CHECK: [[MOVCCr:%[0-9]+]]:gpr = MOVCCr [[COPY]], [[COPY1]], 0 /* CC::eq */, $cpsr
; CHECK: $r0 = COPY [[MOVCCr]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
%0(p0) = COPY $r0
%1(p0) = COPY $r1
%2(s32) = COPY $r2
[GlobalISel] Enable legalizing non-power-of-2 sized types. This changes the interface of how targets describe how to legalize, see the below description. 1. Interface for targets to describe how to legalize. In GlobalISel, the API in the LegalizerInfo class is the main interface for targets to specify which types are legal for which operations, and what to do to turn illegal type/operation combinations into legal ones. For each operation the type sizes that can be legalized without having to change the size of the type are specified with a call to setAction. This isn't different to how GlobalISel worked before. For example, for a target that supports 32 and 64 bit adds natively: for (auto Ty : {s32, s64}) setAction({G_ADD, 0, s32}, Legal); or for a target that needs a library call for a 32 bit division: setAction({G_SDIV, s32}, Libcall); The main conceptual change to the LegalizerInfo API, is in specifying how to legalize the type sizes for which a change of size is needed. For example, in the above example, how to specify how all types from i1 to i8388607 (apart from s32 and s64 which are legal) need to be legalized and expressed in terms of operations on the available legal sizes (again, i32 and i64 in this case). Before, the implementation only allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0, s128}, NarrowScalar). A worse limitation was that if you'd wanted to specify how to legalize all the sized types as allowed by the LLVM-IR LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times and probably would need a lot of memory to store all of these specifications. Instead, the legalization actions that need to change the size of the type are specified now using a "SizeChangeStrategy". For example: setLegalizeScalarToDifferentSizeStrategy( G_ADD, 0, widenToLargerAndNarrowToLargest); This example indicates that for type sizes for which there is a larger size that can be legalized towards, do it by Widening the size. For example, G_ADD on s17 will be legalized by first doing WidenScalar to make it s32, after which it's legal. The "NarrowToLargest" indicates what to do if there is no larger size that can be legalized towards. E.g. G_ADD on s92 will be legalized by doing NarrowScalar to s64. Another example, taken from the ARM backend is: for (unsigned Op : {G_SDIV, G_UDIV}) { setLegalizeScalarToDifferentSizeStrategy(Op, 0, widenToLargerTypesUnsupportedOtherwise); if (ST.hasDivideInARMMode()) setAction({Op, s32}, Legal); else setAction({Op, s32}, Libcall); } For this example, G_SDIV on s8, on a target without a divide instruction, would be legalized by first doing action (WidenScalar, s32), followed by (Libcall, s32). The same principle is also followed for when the number of vector lanes on vector data types need to be changed, e.g.: setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal); setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal); setLegalizeVectorElementToDifferentSizeStrategy( G_ADD, 0, widenToLargerTypesUnsupportedOtherwise); As currently implemented here, vector types are legalized by first making the vector element size legal, followed by then making the number of lanes legal. The strategy to follow in the first step is set by a call to setLegalizeVectorElementToDifferentSizeStrategy, see example above. The strategy followed in the second step "moreToWiderTypesAndLessToWidest" (see code for its definition), indicating that vectors are widened to more elements so they map to natively supported vector widths, or when there isn't a legal wider vector, split the vector to map it to the widest vector supported. Therefore, for the above specification, some example legalizations are: * getAction({G_ADD, LLT::vector(3, 3)}) returns {WidenScalar, LLT::vector(3, 8)} * getAction({G_ADD, LLT::vector(3, 8)}) then returns {MoreElements, LLT::vector(8, 8)} * getAction({G_ADD, LLT::vector(20, 8)}) returns {FewerElements, LLT::vector(16, 8)} 2. Key implementation aspects. How to legalize a specific (operation, type index, size) tuple is represented by mapping intervals of integers representing a range of size types to an action to take, e.g.: setScalarAction({G_ADD, LLT:scalar(1)}, {{1, WidenScalar}, // bit sizes [ 1, 31[ {32, Legal}, // bit sizes [32, 33[ {33, WidenScalar}, // bit sizes [33, 64[ {64, Legal}, // bit sizes [64, 65[ {65, NarrowScalar} // bit sizes [65, +inf[ }); Please note that most of the code to do the actual lowering of non-power-of-2 sized types is currently missing, this is just trying to make it possible for targets to specify what is legal, and how non-legal types should be legalized. Probably quite a bit of further work is needed in the actual legalizing and the other passes in GlobalISel to support non-power-of-2 sized types. I hope the documentation in LegalizerInfo.h and the examples provided in the various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well enough how this is meant to be used. This drops the need for LLT::{half,double}...Size(). Differential Revision: https://reviews.llvm.org/D30529 llvm-svn: 317560
2017-11-07 18:34:34 +08:00
%3(s1) = G_TRUNC %2(s32)
%4(p0) = G_SELECT %3(s1), %0, %1
$r0 = COPY %4(p0)
BX_RET 14, $noreg, implicit $r0
...
---
name: test_br
legalized: true
regBankSelected: true
selected: false
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
body: |
; CHECK-LABEL: name: test_br
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: TSTri [[COPY]], 1, 14 /* CC::al */, $noreg, implicit-def $cpsr
; CHECK: Bcc %bb.1, 1 /* CC::ne */, $cpsr
; CHECK: B %bb.2
; CHECK: bb.1:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: B %bb.2
; CHECK: bb.2:
; CHECK: BX_RET 14 /* CC::al */, $noreg
bb.0:
successors: %bb.1(0x40000000), %bb.2(0x40000000)
liveins: $r0
%0(s32) = COPY $r0
%1(s1) = G_TRUNC %0(s32)
G_BRCOND %1(s1), %bb.1
G_BR %bb.2
bb.1:
successors: %bb.2(0x80000000)
G_BR %bb.2
bb.2:
BX_RET 14, $noreg
...
---
name: test_phi_s32
legalized: true
regBankSelected: true
selected: false
tracksRegLiveness: true
registers:
- { id: 0, class: gprb }
- { id: 1, class: gprb }
- { id: 2, class: gprb }
- { id: 3, class: gprb }
- { id: 4, class: gprb }
body: |
; CHECK-LABEL: name: test_phi_s32
; CHECK: bb.0:
; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK: liveins: $r0, $r1, $r2
; CHECK: [[COPY:%[0-9]+]]:gpr = COPY $r0
; CHECK: [[COPY1:%[0-9]+]]:gpr = COPY $r1
; CHECK: [[COPY2:%[0-9]+]]:gpr = COPY $r2
; CHECK: TSTri [[COPY]], 1, 14 /* CC::al */, $noreg, implicit-def $cpsr
; CHECK: Bcc %bb.1, 1 /* CC::ne */, $cpsr
; CHECK: B %bb.2
; CHECK: bb.1:
; CHECK: successors: %bb.2(0x80000000)
; CHECK: B %bb.2
; CHECK: bb.2:
; CHECK: [[PHI:%[0-9]+]]:gpr = PHI [[COPY1]], %bb.0, [[COPY2]], %bb.1
; CHECK: $r0 = COPY [[PHI]]
; CHECK: BX_RET 14 /* CC::al */, $noreg, implicit $r0
bb.0:
successors: %bb.1(0x40000000), %bb.2(0x40000000)
liveins: $r0, $r1, $r2
%0(s32) = COPY $r0
%1(s1) = G_TRUNC %0(s32)
%2(s32) = COPY $r1
%3(s32) = COPY $r2
G_BRCOND %1(s1), %bb.1
G_BR %bb.2
bb.1:
successors: %bb.2(0x80000000)
G_BR %bb.2
bb.2:
%4(s32) = G_PHI %2(s32), %bb.0, %3(s32), %bb.1
$r0 = COPY %4(s32)
BX_RET 14, $noreg, implicit $r0
...