blob: 09c0f5d00f786f0aa121c47ae5025c21f947cf15 [file] [edit]
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
# RUN: llc -mtriple=riscv32 -mattr=+zilsd -run-pass riscv-prera-zilsd-opt %s -o - | FileCheck %s
# RUN: llc -mtriple=riscv32 -mattr=+zilsd,+zilsd-word-align -run-pass riscv-prera-zilsd-opt %s -o - | FileCheck %s --check-prefix=CHECK-4BYTE
--- |
declare void @external_func()
define i32 @basic_load_combine(ptr %0) {
%2 = load i32, ptr %0, align 4
%3 = getelementptr inbounds i32, ptr %0, i32 1
%4 = load i32, ptr %3, align 4
%5 = add i32 %2, %4
ret i32 %5
}
define void @basic_store_combine(ptr %0, i32 %1, i32 %2) {
store i32 %1, ptr %0, align 4
%4 = getelementptr inbounds i32, ptr %0, i32 1
store i32 %2, ptr %4, align 4
ret void
}
define void @basic_store_zero_combine(ptr %0, i32 %1, i32 %2) {
store i32 0, ptr %0, align 4
%4 = getelementptr inbounds i32, ptr %0, i32 1
store i32 0, ptr %4, align 4
ret void
}
define void @basic_store_zero_no_combine(ptr %0, i32 %1, i32 %2) {
store i32 0, ptr %0, align 4
%4 = getelementptr inbounds i32, ptr %0, i32 1
store i32 0, ptr %4, align 4
ret void
}
define i32 @basic_load_combine_8_byte_aligned(ptr %0) {
%2 = load i32, ptr %0, align 8
%3 = getelementptr inbounds i32, ptr %0, i32 1
%4 = load i32, ptr %3, align 4
%5 = add i32 %2, %4
ret i32 %5
}
define void @basic_store_combine_8_byte_aligned(ptr %0, i32 %1, i32 %2) {
store i32 %1, ptr %0, align 8
%4 = getelementptr inbounds i32, ptr %0, i32 1
store i32 %2, ptr %4, align 4
ret void
}
define i32 @non_consecutive_offsets(ptr %0) {
%2 = load i32, ptr %0, align 4
%3 = getelementptr inbounds i32, ptr %0, i32 2
%4 = load i32, ptr %3, align 4
%5 = add i32 %2, %4
ret i32 %5
}
define i32 @different_base_regs(ptr %0, ptr %1) {
%3 = load i32, ptr %0, align 4
%4 = getelementptr inbounds i32, ptr %1, i32 1
%5 = load i32, ptr %4, align 4
%6 = add i32 %3, %5
ret i32 %6
}
define i32 @call_blocks_optimization(ptr %0) {
%2 = load i32, ptr %0, align 4
call void @external_func()
%3 = getelementptr inbounds i32, ptr %0, i32 1
%4 = load i32, ptr %3, align 4
%5 = add i32 %2, %4
ret i32 %5
}
define i32 @terminator_blocks_optimization(ptr %0, i32 %1) {
%3 = load i32, ptr %0, align 4
%4 = icmp eq i32 %1, %3
br i1 %4, label %5, label %5
5:
%6 = getelementptr inbounds i32, ptr %0, i32 1
%7 = load i32, ptr %6, align 4
%8 = add i32 %3, %7
ret i32 %8
}
define i32 @memory_aliasing(ptr %0, i32 %1) {
%3 = load i32, ptr %0, align 4
%4 = getelementptr inbounds i32, ptr %0, i32 2
store i32 %1, ptr %4, align 4
%5 = getelementptr inbounds i32, ptr %0, i32 1
%6 = load i32, ptr %5, align 4
%7 = add i32 %3, %6
ret i32 %7
}
define i32 @multiple_pairs(ptr %0, ptr %1) {
%3 = load i32, ptr %0, align 4
%4 = getelementptr inbounds i32, ptr %0, i32 1
%5 = load i32, ptr %4, align 4
%6 = add i32 %3, %5
%7 = getelementptr inbounds i32, ptr %1, i32 2
%8 = load i32, ptr %7, align 4
%9 = getelementptr inbounds i32, ptr %1, i32 3
%10 = load i32, ptr %9, align 4
%11 = add i32 %8, %10
%12 = add i32 %6, %11
ret i32 %12
}
define i32 @many_loads(ptr %0) {
%2 = getelementptr inbounds i32, ptr %0, i32 4
%3 = load i32, ptr %2, align 4
%4 = getelementptr inbounds i32, ptr %0, i32 5
%5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds i32, ptr %0, i32 6
%7 = load i32, ptr %6, align 4
%8 = getelementptr inbounds i32, ptr %0, i32 7
%9 = load i32, ptr %8, align 4
%10 = getelementptr inbounds i32, ptr %0, i32 8
%11 = load i32, ptr %10, align 4
%12 = getelementptr inbounds i32, ptr %0, i32 9
%13 = load i32, ptr %12, align 4
%14 = getelementptr inbounds i32, ptr %0, i32 10
%15 = load i32, ptr %14, align 4
%16 = getelementptr inbounds i32, ptr %0, i32 11
%17 = load i32, ptr %16, align 4
%18 = getelementptr inbounds i32, ptr %0, i32 12
%19 = load i32, ptr %18, align 4
%20 = getelementptr inbounds i32, ptr %0, i32 13
%21 = load i32, ptr %20, align 4
%22 = getelementptr inbounds i32, ptr %0, i32 14
%23 = load i32, ptr %22, align 4
%24 = getelementptr inbounds i32, ptr %0, i32 15
%25 = load i32, ptr %24, align 4
%26 = load i32, ptr %0, align 4
%27 = getelementptr inbounds i32, ptr %0, i32 1
%28 = load i32, ptr %27, align 4
%29 = add i32 %3, %5
%30 = add i32 %7, %9
%31 = add i32 %11, %13
%32 = add i32 %15, %17
%33 = add i32 %19, %21
%34 = add i32 %23, %25
%35 = add i32 %26, %28
%36 = add i32 %29, %30
%37 = add i32 %31, %32
%38 = add i32 %33, %34
%39 = add i32 %35, %36
%40 = add i32 %37, %38
%41 = add i32 %39, %40
ret i32 %41
}
define i32 @reverse_order_loads(ptr %0) {
%2 = getelementptr inbounds i32, ptr %0, i32 1
%3 = load i32, ptr %2, align 4
%4 = load i32, ptr %0, align 4
%5 = add i32 %3, %4
ret i32 %5
}
define i32 @offset_calculation(ptr %0) {
%2 = getelementptr inbounds i8, ptr %0, i32 100
%3 = load i32, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 104
%5 = load i32, ptr %4, align 4
%6 = add i32 %3, %5
ret i32 %6
}
define i32 @large_offsets(ptr %0) {
%2 = getelementptr inbounds i8, ptr %0, i32 2040
%3 = load i32, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 2044
%5 = load i32, ptr %4, align 4
%6 = add i32 %3, %5
ret i32 %6
}
define i32 @negative_offsets(ptr %0) {
%2 = getelementptr inbounds i8, ptr %0, i32 -8
%3 = load i32, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 -4
%5 = load i32, ptr %4, align 4
%6 = add i32 %3, %5
ret i32 %6
}
define i32 @volatile_loads(ptr %0) {
%2 = load volatile i32, ptr %0, align 4
%3 = getelementptr inbounds i32, ptr %0, i32 1
%4 = load volatile i32, ptr %3, align 4
%5 = add i32 %2, %4
ret i32 %5
}
define i32 @store_dependency(ptr %0, i32 %1) {
%3 = load i32, ptr %0, align 4
%4 = getelementptr inbounds i32, ptr %0, i32 1
store i32 %1, ptr %4, align 4
%5 = load i32, ptr %4, align 4
%6 = add i32 %3, %5
ret i32 %6
}
define i32 @three_loads(ptr %0) {
%2 = load i32, ptr %0, align 4
%3 = getelementptr inbounds i32, ptr %0, i32 1
%4 = load i32, ptr %3, align 4
%5 = getelementptr inbounds i32, ptr %0, i32 2
%6 = load i32, ptr %5, align 4
%7 = add i32 %2, %4
%8 = add i32 %7, %6
ret i32 %8
}
define i32 @distance_exceeds_max(ptr %0, i32 %1) {
%3 = load i32, ptr %0, align 4
%4 = add i32 %3, %1
%5 = add i32 %4, %1
%6 = add i32 %5, %1
%7 = add i32 %6, %1
%8 = add i32 %7, %1
%9 = add i32 %8, %1
%10 = add i32 %9, %1
%11 = add i32 %10, %1
%12 = add i32 %11, %1
%13 = add i32 %12, %1
%14 = add i32 %13, %1
%15 = getelementptr inbounds i32, ptr %0, i32 1
%16 = load i32, ptr %15, align 4
%17 = add i32 %14, %16
ret i32 %17
}
@global_var = external global [100 x i32]
define i32 @symbolic_operands_global() {
ret i32 0
}
define i32 @symbolic_operands_different_globals() {
ret i32 0
}
define i32 @symbolic_operands_constantpool() {
ret i32 0
}
define i32 @symbolic_operands_interleave() {
ret i32 0
}
declare void @external(ptr)
define i32 @frame_index() {
%arr = alloca [2 x i32], align 4
%arrayidx1 = getelementptr inbounds nuw i8, ptr %arr, i32 4
ret i32 0
}
define i32 @frame_index_operands_interleave() {
%arr = alloca [2 x i32], align 4
%arrayidx1 = getelementptr inbounds nuw i8, ptr %arr, i32 4
ret i32 0
}
---
# Basic case: two consecutive 32-bit loads that can be combined into LD
name: basic_load_combine
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: basic_load_combine
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: basic_load_combine
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = LW %0, 0 :: (load (s32))
%2:gpr = LW %0, 4 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Basic case: two consecutive 32-bit stores that can be combined into SD
name: basic_store_combine
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
- { reg: '$x12', virtual-reg: '%2' }
body: |
bb.0:
liveins: $x10, $x11, $x12
; CHECK-LABEL: name: basic_store_combine
; CHECK: liveins: $x10, $x11, $x12
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
; CHECK-NEXT: SW [[COPY1]], [[COPY]], 0 :: (store (s32))
; CHECK-NEXT: SW [[COPY2]], [[COPY]], 4 :: (store (s32))
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: basic_store_combine
; CHECK-4BYTE: liveins: $x10, $x11, $x12
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
; CHECK-4BYTE-NEXT: PseudoSD_RV32_OPT [[COPY1]], [[COPY2]], [[COPY]], 0 :: (store (s32))
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
%2:gpr = COPY $x12
SW %1, %0, 0 :: (store (s32))
SW %2, %0, 4 :: (store (s32))
PseudoRET
...
---
# Basic case: two consecutive 32-bit store 0 that can be combined into SD
name: basic_store_zero_combine
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: basic_store_zero_combine
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x0
; CHECK-NEXT: SW [[COPY1]], [[COPY]], 0 :: (store (s32))
; CHECK-NEXT: SW [[COPY1]], [[COPY]], 4 :: (store (s32))
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: basic_store_zero_combine
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x0
; CHECK-4BYTE-NEXT: SW [[COPY1]], [[COPY]], 0 :: (store (s32))
; CHECK-4BYTE-NEXT: SW [[COPY1]], [[COPY]], 4 :: (store (s32))
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x0
SW %1, %0, 0 :: (store (s32))
SW %1, %0, 4 :: (store (s32))
PseudoRET
...
---
# Basic case: two consecutive 32-bit store 0 that cannot be combined into SD
name: basic_store_zero_no_combine
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: basic_store_zero_no_combine
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gprnox0 = COPY $x0
; CHECK-NEXT: SW [[COPY1]], [[COPY]], 0 :: (store (s32))
; CHECK-NEXT: SW [[COPY1]], [[COPY]], 4 :: (store (s32))
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: basic_store_zero_no_combine
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gprnox0 = COPY $x0
; CHECK-4BYTE-NEXT: SW [[COPY1]], [[COPY]], 0 :: (store (s32))
; CHECK-4BYTE-NEXT: SW [[COPY1]], [[COPY]], 4 :: (store (s32))
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gprnox0 = COPY $x0
SW %1, %0, 0 :: (store (s32))
SW %1, %0, 4 :: (store (s32))
PseudoRET
...
---
name: basic_load_combine_8_byte_aligned
alignment: 8
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: basic_load_combine_8_byte_aligned
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32), align 8), (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: basic_load_combine_8_byte_aligned
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32), align 8), (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = LW %0, 0 :: (load (s32), align 8)
%2:gpr = LW %0, 4 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Basic case: two consecutive 32-bit stores that can be combined into SD
name: basic_store_combine_8_byte_aligned
alignment: 8
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
- { reg: '$x12', virtual-reg: '%2' }
body: |
bb.0:
liveins: $x10, $x11, $x12
; CHECK-LABEL: name: basic_store_combine_8_byte_aligned
; CHECK: liveins: $x10, $x11, $x12
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
; CHECK-NEXT: PseudoSD_RV32_OPT [[COPY1]], [[COPY2]], [[COPY]], 0 :: (store (s32), align 8), (store (s32))
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: basic_store_combine_8_byte_aligned
; CHECK-4BYTE: liveins: $x10, $x11, $x12
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
; CHECK-4BYTE-NEXT: PseudoSD_RV32_OPT [[COPY1]], [[COPY2]], [[COPY]], 0 :: (store (s32), align 8), (store (s32))
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
%2:gpr = COPY $x12
SW %1, %0, 0 :: (store (s32), align 8)
SW %2, %0, 4 :: (store (s32))
PseudoRET
...
---
# Non-consecutive offsets - should not combine
name: non_consecutive_offsets
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: non_consecutive_offsets
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 8 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: non_consecutive_offsets
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 8 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Should not combine - offset gap is 8, not 4
%1:gpr = LW %0, 0 :: (load (s32))
%2:gpr = LW %0, 8 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Different base registers - should not combine
name: different_base_regs
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
body: |
bb.0:
liveins: $x10, $x11
; CHECK-LABEL: name: different_base_regs
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY1]], 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: different_base_regs
; CHECK-4BYTE: liveins: $x10, $x11
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY1]], 4 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
; Should not combine - different base registers
%2:gpr = LW %0, 0 :: (load (s32))
%3:gpr = LW %1, 4 :: (load (s32))
%4:gpr = ADD %2, %3
PseudoRET
...
---
# Call instruction blocks optimization
name: call_blocks_optimization
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: call_blocks_optimization
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: PseudoCALL target-flags(riscv-call) @external_func, csr_ilp32_lp64, implicit-def $x1
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: call_blocks_optimization
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: PseudoCALL target-flags(riscv-call) @external_func, csr_ilp32_lp64, implicit-def $x1
; CHECK-4BYTE-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = LW %0, 0 :: (load (s32))
; Call instruction should block combining across it
PseudoCALL target-flags(riscv-call) @external_func, csr_ilp32_lp64, implicit-def $x1
%2:gpr = LW %0, 4 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Terminator instruction blocks optimization
name: terminator_blocks_optimization
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
body: |
; CHECK-LABEL: name: terminator_blocks_optimization
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x80000000)
; CHECK-NEXT: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: BEQ [[COPY1]], [[LW]], %bb.1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: terminator_blocks_optimization
; CHECK-4BYTE: bb.0:
; CHECK-4BYTE-NEXT: successors: %bb.1(0x80000000)
; CHECK-4BYTE-NEXT: liveins: $x10, $x11
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: BEQ [[COPY1]], [[LW]], %bb.1
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: bb.1:
; CHECK-4BYTE-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-4BYTE-NEXT: PseudoRET
bb.0:
liveins: $x10, $x11
%0:gpr = COPY $x10
%1:gpr = COPY $x11
%2:gpr = LW %0, 0 :: (load (s32))
BEQ %1, %2, %bb.1
bb.1:
; Should not combine across basic block boundary
%3:gpr = LW %0, 4 :: (load (s32))
%4:gpr = ADD %2, %3
PseudoRET
...
---
# Memory aliasing - store between loads with unknown base should prevent combining
name: memory_aliasing
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
- { reg: '$x12', virtual-reg: '%2' }
body: |
bb.0:
liveins: $x10, $x11, $x12
; CHECK-LABEL: name: memory_aliasing
; CHECK: liveins: $x10, $x11, $x12
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: SW [[COPY1]], [[COPY2]], 8 :: (store (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: memory_aliasing
; CHECK-4BYTE: liveins: $x10, $x11, $x12
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: SW [[COPY1]], [[COPY2]], 8 :: (store (s32))
; CHECK-4BYTE-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
%2:gpr = COPY $x12
%3:gpr = LW %0, 0 :: (load (s32))
SW %1, %2, 8 :: (store (s32))
%4:gpr = LW %0, 4 :: (load (s32))
%5:gpr = ADD %3, %4
PseudoRET
...
---
# Multiple pairs in same function
name: multiple_pairs
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
body: |
bb.0:
liveins: $x10, $x11
; CHECK-LABEL: name: multiple_pairs
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: [[LW2:%[0-9]+]]:gpr = LW [[COPY1]], 8 :: (load (s32))
; CHECK-NEXT: [[LW3:%[0-9]+]]:gpr = LW [[COPY1]], 12 :: (load (s32))
; CHECK-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[LW2]], [[LW3]]
; CHECK-NEXT: [[ADD2:%[0-9]+]]:gpr = ADD [[ADD]], [[ADD1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: multiple_pairs
; CHECK-4BYTE: liveins: $x10, $x11
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT2:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT3:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY1]], 8 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT2]], [[PseudoLD_RV32_OPT3]]
; CHECK-4BYTE-NEXT: [[ADD2:%[0-9]+]]:gpr = ADD [[ADD]], [[ADD1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
; First pair should combine
%2:gpr = LW %0, 0 :: (load (s32))
%3:gpr = LW %0, 4 :: (load (s32))
%4:gpr = ADD %2, %3
; Second pair should also combine
%5:gpr = LW %1, 8 :: (load (s32))
%6:gpr = LW %1, 12 :: (load (s32))
%7:gpr = ADD %5, %6
%8:gpr = ADD %4, %7
PseudoRET
...
---
# Many loads test
name: many_loads
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: many_loads
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 16 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 20 :: (load (s32))
; CHECK-NEXT: [[LW2:%[0-9]+]]:gpr = LW [[COPY]], 24 :: (load (s32))
; CHECK-NEXT: [[LW3:%[0-9]+]]:gpr = LW [[COPY]], 28 :: (load (s32))
; CHECK-NEXT: [[LW4:%[0-9]+]]:gpr = LW [[COPY]], 32 :: (load (s32))
; CHECK-NEXT: [[LW5:%[0-9]+]]:gpr = LW [[COPY]], 36 :: (load (s32))
; CHECK-NEXT: [[LW6:%[0-9]+]]:gpr = LW [[COPY]], 40 :: (load (s32))
; CHECK-NEXT: [[LW7:%[0-9]+]]:gpr = LW [[COPY]], 44 :: (load (s32))
; CHECK-NEXT: [[LW8:%[0-9]+]]:gpr = LW [[COPY]], 48 :: (load (s32))
; CHECK-NEXT: [[LW9:%[0-9]+]]:gpr = LW [[COPY]], 52 :: (load (s32))
; CHECK-NEXT: [[LW10:%[0-9]+]]:gpr = LW [[COPY]], 56 :: (load (s32))
; CHECK-NEXT: [[LW11:%[0-9]+]]:gpr = LW [[COPY]], 60 :: (load (s32))
; CHECK-NEXT: [[LW12:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[LW13:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[LW2]], [[LW3]]
; CHECK-NEXT: [[ADD2:%[0-9]+]]:gpr = ADD [[LW4]], [[LW5]]
; CHECK-NEXT: [[ADD3:%[0-9]+]]:gpr = ADD [[LW6]], [[LW7]]
; CHECK-NEXT: [[ADD4:%[0-9]+]]:gpr = ADD [[LW8]], [[LW9]]
; CHECK-NEXT: [[ADD5:%[0-9]+]]:gpr = ADD [[LW10]], [[LW11]]
; CHECK-NEXT: [[ADD6:%[0-9]+]]:gpr = ADD [[LW12]], [[LW13]]
; CHECK-NEXT: [[ADD7:%[0-9]+]]:gpr = ADD [[ADD]], [[ADD1]]
; CHECK-NEXT: [[ADD8:%[0-9]+]]:gpr = ADD [[ADD2]], [[ADD3]]
; CHECK-NEXT: [[ADD9:%[0-9]+]]:gpr = ADD [[ADD4]], [[ADD5]]
; CHECK-NEXT: [[ADD10:%[0-9]+]]:gpr = ADD [[ADD6]], [[ADD7]]
; CHECK-NEXT: [[ADD11:%[0-9]+]]:gpr = ADD [[ADD8]], [[ADD9]]
; CHECK-NEXT: [[ADD12:%[0-9]+]]:gpr = ADD [[ADD10]], [[ADD11]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: many_loads
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 16 :: (load (s32))
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT2:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT3:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 24 :: (load (s32))
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT4:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT5:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 32 :: (load (s32))
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT6:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT7:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 40 :: (load (s32))
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT8:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT9:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 48 :: (load (s32))
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT10:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT11:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 56 :: (load (s32))
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT12:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT13:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT2]], [[PseudoLD_RV32_OPT3]]
; CHECK-4BYTE-NEXT: [[ADD2:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT4]], [[PseudoLD_RV32_OPT5]]
; CHECK-4BYTE-NEXT: [[ADD3:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT6]], [[PseudoLD_RV32_OPT7]]
; CHECK-4BYTE-NEXT: [[ADD4:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT8]], [[PseudoLD_RV32_OPT9]]
; CHECK-4BYTE-NEXT: [[ADD5:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT10]], [[PseudoLD_RV32_OPT11]]
; CHECK-4BYTE-NEXT: [[ADD6:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT12]], [[PseudoLD_RV32_OPT13]]
; CHECK-4BYTE-NEXT: [[ADD7:%[0-9]+]]:gpr = ADD [[ADD]], [[ADD1]]
; CHECK-4BYTE-NEXT: [[ADD8:%[0-9]+]]:gpr = ADD [[ADD2]], [[ADD3]]
; CHECK-4BYTE-NEXT: [[ADD9:%[0-9]+]]:gpr = ADD [[ADD4]], [[ADD5]]
; CHECK-4BYTE-NEXT: [[ADD10:%[0-9]+]]:gpr = ADD [[ADD6]], [[ADD7]]
; CHECK-4BYTE-NEXT: [[ADD11:%[0-9]+]]:gpr = ADD [[ADD8]], [[ADD9]]
; CHECK-4BYTE-NEXT: [[ADD12:%[0-9]+]]:gpr = ADD [[ADD10]], [[ADD11]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Create high register pressure with many live values
%1:gpr = LW %0, 16 :: (load (s32))
%2:gpr = LW %0, 20 :: (load (s32))
%3:gpr = LW %0, 24 :: (load (s32))
%4:gpr = LW %0, 28 :: (load (s32))
%5:gpr = LW %0, 32 :: (load (s32))
%6:gpr = LW %0, 36 :: (load (s32))
%7:gpr = LW %0, 40 :: (load (s32))
%8:gpr = LW %0, 44 :: (load (s32))
%9:gpr = LW %0, 48 :: (load (s32))
%10:gpr = LW %0, 52 :: (load (s32))
%11:gpr = LW %0, 56 :: (load (s32))
%12:gpr = LW %0, 60 :: (load (s32))
; With high register pressure, these loads might not be combined
; depending on the profitability analysis
%13:gpr = LW %0, 0 :: (load (s32))
%14:gpr = LW %0, 4 :: (load (s32))
; Use all the loaded values to keep them live
%15:gpr = ADD %1, %2
%16:gpr = ADD %3, %4
%17:gpr = ADD %5, %6
%18:gpr = ADD %7, %8
%19:gpr = ADD %9, %10
%20:gpr = ADD %11, %12
%21:gpr = ADD %13, %14
%22:gpr = ADD %15, %16
%23:gpr = ADD %17, %18
%24:gpr = ADD %19, %20
%25:gpr = ADD %21, %22
%26:gpr = ADD %23, %24
%27:gpr = ADD %25, %26
PseudoRET
...
---
# Test reverse order - second load has lower offset than first
name: reverse_order_loads
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: reverse_order_loads
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: reverse_order_loads
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT1]], [[PseudoLD_RV32_OPT]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Load at higher offset first, then lower offset
; Should still be combined as LD with lower offset
%1:gpr = LW %0, 4 :: (load (s32))
%2:gpr = LW %0, 0 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Test with immediate offset calculation
name: offset_calculation
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: offset_calculation
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 100 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 104 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: offset_calculation
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 100 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Test with different immediate values that are consecutive
%1:gpr = LW %0, 100 :: (load (s32))
%2:gpr = LW %0, 104 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Test large offset values
name: large_offsets
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: large_offsets
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 2040 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 2044 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: large_offsets
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 2040 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Test with large offset values
%1:gpr = LW %0, 2040 :: (load (s32))
%2:gpr = LW %0, 2044 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Test with negative offsets
name: negative_offsets
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: negative_offsets
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], -8 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], -4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: negative_offsets
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], -8 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Test with negative consecutive offsets
%1:gpr = LW %0, -8 :: (load (s32))
%2:gpr = LW %0, -4 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Test with volatile loads - should not combine
name: volatile_loads
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: volatile_loads
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (volatile load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (volatile load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: volatile_loads
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (volatile load (s32))
; CHECK-4BYTE-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (volatile load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Volatile loads should not be combined
%1:gpr = LW %0, 0 :: (volatile load (s32))
%2:gpr = LW %0, 4 :: (volatile load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Test store dependency - store modifies same location as load
name: store_dependency
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
body: |
bb.0:
liveins: $x10, $x11
; CHECK-LABEL: name: store_dependency
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: SW [[COPY1]], [[COPY]], 4 :: (store (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: store_dependency
; CHECK-4BYTE: liveins: $x10, $x11
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: SW [[COPY1]], [[COPY]], 4 :: (store (s32))
; CHECK-4BYTE-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
%2:gpr = LW %0, 0 :: (load (s32))
; Store to same location as second load - should prevent combination
SW %1, %0, 4 :: (store (s32))
%3:gpr = LW %0, 4 :: (load (s32))
%4:gpr = ADD %2, %3
PseudoRET
...
---
# Test three loads:
# align 8: last two should combine
# align 4: first two should combine
name: three_loads
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: three_loads
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[LW2:%[0-9]+]]:gpr = LW [[COPY]], 8 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[ADD]], [[LW2]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: three_loads
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 8 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[ADD]], [[LW]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; First two loads should combine, third should remain separate
%1:gpr = LW %0, 0 :: (load (s32))
%2:gpr = LW %0, 4 :: (load (s32))
%3:gpr = LW %0, 8 :: (load (s32))
%4:gpr = ADD %1, %2
%5:gpr = ADD %4, %3
PseudoRET
...
---
# Test where distance between loads exceeds MaxRescheduleDistance
name: distance_exceeds_max
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
body: |
bb.0:
liveins: $x10, $x11
; CHECK-LABEL: name: distance_exceeds_max
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[COPY1]]
; CHECK-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[ADD]], [[COPY1]]
; CHECK-NEXT: [[ADD2:%[0-9]+]]:gpr = ADD [[ADD1]], [[COPY1]]
; CHECK-NEXT: [[ADD3:%[0-9]+]]:gpr = ADD [[ADD2]], [[COPY1]]
; CHECK-NEXT: [[ADD4:%[0-9]+]]:gpr = ADD [[ADD3]], [[COPY1]]
; CHECK-NEXT: [[ADD5:%[0-9]+]]:gpr = ADD [[ADD4]], [[COPY1]]
; CHECK-NEXT: [[ADD6:%[0-9]+]]:gpr = ADD [[ADD5]], [[COPY1]]
; CHECK-NEXT: [[ADD7:%[0-9]+]]:gpr = ADD [[ADD6]], [[COPY1]]
; CHECK-NEXT: [[ADD8:%[0-9]+]]:gpr = ADD [[ADD7]], [[COPY1]]
; CHECK-NEXT: [[ADD9:%[0-9]+]]:gpr = ADD [[ADD8]], [[COPY1]]
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: distance_exceeds_max
; CHECK-4BYTE: liveins: $x10, $x11
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[ADD]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[ADD2:%[0-9]+]]:gpr = ADD [[ADD1]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[ADD3:%[0-9]+]]:gpr = ADD [[ADD2]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[ADD4:%[0-9]+]]:gpr = ADD [[ADD3]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[ADD5:%[0-9]+]]:gpr = ADD [[ADD4]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[ADD6:%[0-9]+]]:gpr = ADD [[ADD5]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[ADD7:%[0-9]+]]:gpr = ADD [[ADD6]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[ADD8:%[0-9]+]]:gpr = ADD [[ADD7]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[ADD9:%[0-9]+]]:gpr = ADD [[ADD8]], [[COPY1]]
; CHECK-4BYTE-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
%2:gpr = LW %0, 0 :: (load (s32))
; Insert 11 instructions between the two loads
; This makes the distance greater than the configured MaxRescheduleDistance
%3:gpr = ADD %2, %1
%4:gpr = ADD %3, %1
%5:gpr = ADD %4, %1
%6:gpr = ADD %5, %1
%7:gpr = ADD %6, %1
%8:gpr = ADD %7, %1
%9:gpr = ADD %8, %1
%10:gpr = ADD %9, %1
%11:gpr = ADD %10, %1
%12:gpr = ADD %11, %1
; Second load at offset 4 - too far from first load
%14:gpr = LW %0, 4 :: (load (s32))
PseudoRET
...
---
# Test combining loads with symbolic operands (global address)
name: symbolic_operands_global
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: symbolic_operands_global
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], target-flags(riscv-lo) @global_var :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], target-flags(riscv-lo) @global_var + 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: symbolic_operands_global
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], target-flags(riscv-lo) @global_var :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Two consecutive loads with symbolic global address operands
%1:gpr = LW %0, target-flags(riscv-lo) @global_var :: (load (s32))
%2:gpr = LW %0, target-flags(riscv-lo) @global_var + 4 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Test that loads with different global symbols are not combined
name: symbolic_operands_different_globals
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
stack:
- { id: 0, offset: -4, size: 4 }
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: symbolic_operands_different_globals
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], target-flags(riscv-lo) @global_var :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], %stack.0 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: symbolic_operands_different_globals
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], target-flags(riscv-lo) @global_var :: (load (s32))
; CHECK-4BYTE-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], %stack.0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Should not combine - different symbol types
%1:gpr = LW %0, target-flags(riscv-lo) @global_var :: (load (s32))
%2:gpr = LW %0, %stack.0 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
# Test combining loads with constant pool operands
name: symbolic_operands_constantpool
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
constants:
- id: 0
value: 'double 3.140000e+00'
alignment: 8
body: |
bb.0:
liveins: $x10
; CHECK-LABEL: name: symbolic_operands_constantpool
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], target-flags(riscv-lo) %const.0 :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], target-flags(riscv-lo) %const.0 + 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW1]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: symbolic_operands_constantpool
; CHECK-4BYTE: liveins: $x10
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], target-flags(riscv-lo) %const.0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
; Two consecutive loads with constant pool operands
%1:gpr = LW %0, target-flags(riscv-lo) %const.0 :: (load (s32))
%2:gpr = LW %0, target-flags(riscv-lo) %const.0 + 4 :: (load (s32))
%3:gpr = ADD %1, %2
PseudoRET
...
---
name: symbolic_operands_interleave
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
body: |
bb.0:
liveins: $x10, $x11
; CHECK-LABEL: name: symbolic_operands_interleave
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW [[COPY]], target-flags(riscv-lo) @global_var :: (load (s32))
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[LW2:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[LW3:%[0-9]+]]:gpr = LW [[COPY]], target-flags(riscv-lo) @global_var + 4 :: (load (s32))
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW2]]
; CHECK-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[LW1]], [[LW3]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: symbolic_operands_interleave
; CHECK-4BYTE: liveins: $x10, $x11
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], target-flags(riscv-lo) @global_var :: (load (s32))
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT2:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT3:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT2]]
; CHECK-4BYTE-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT3]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
%2:gpr = LW %0, target-flags(riscv-lo) @global_var :: (load (s32))
%3:gpr = LW %0, 4 :: (load (s32))
%4:gpr = LW %0, 0 :: (load (s32))
%5:gpr = LW %0, target-flags(riscv-lo) @global_var + 4 :: (load (s32))
%6:gpr = ADD %2, %4
%7:gpr = ADD %3, %5
PseudoRET
...
---
name: frame_index
alignment: 4
tracksRegLiveness: true
stack:
- { id: 0, offset: 0, size: 8, alignment: 4 }
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
body: |
bb.0:
liveins: $x10, $x11
; CHECK-LABEL: name: frame_index
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: SW [[COPY]], %stack.0, 0 :: (store (s32) into %ir.arr)
; CHECK-NEXT: SW [[COPY1]], %stack.0, 4 :: (store (s32) into %ir.arrayidx1)
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: frame_index
; CHECK-4BYTE: liveins: $x10, $x11
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: PseudoSD_RV32_OPT [[COPY]], [[COPY1]], %stack.0, 0 :: (store (s32) into %ir.arr), (store (s32) into %ir.arrayidx1)
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
SW %0:gpr, %stack.0, 0 :: (store (s32) into %ir.arr)
SW %1:gpr, %stack.0, 4 :: (store (s32) into %ir.arrayidx1)
PseudoRET
...
---
name: frame_index_operands_interleave
alignment: 4
tracksRegLiveness: true
stack:
- { id: 0, offset: 0, size: 8, alignment: 4 }
liveins:
- { reg: '$x10', virtual-reg: '%0' }
- { reg: '$x11', virtual-reg: '%1' }
body: |
bb.0:
liveins: $x10, $x11
; CHECK-LABEL: name: frame_index_operands_interleave
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[LW:%[0-9]+]]:gpr = LW %stack.0, 0 :: (load (s32) from %ir.arr)
; CHECK-NEXT: [[LW1:%[0-9]+]]:gpr = LW [[COPY]], 4 :: (load (s32))
; CHECK-NEXT: [[LW2:%[0-9]+]]:gpr = LW [[COPY]], 0 :: (load (s32))
; CHECK-NEXT: [[LW3:%[0-9]+]]:gpr = LW %stack.0, 4 :: (load (s32) from %ir.arrayidx1)
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[LW]], [[LW2]]
; CHECK-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[LW1]], [[LW3]]
; CHECK-NEXT: PseudoRET
;
; CHECK-4BYTE-LABEL: name: frame_index_operands_interleave
; CHECK-4BYTE: liveins: $x10, $x11
; CHECK-4BYTE-NEXT: {{ $}}
; CHECK-4BYTE-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-4BYTE-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT1:%[0-9]+]]:gpr = PseudoLD_RV32_OPT %stack.0, 0 :: (load (s32) from %ir.arr), (load (s32) from %ir.arrayidx1)
; CHECK-4BYTE-NEXT: [[PseudoLD_RV32_OPT2:%[0-9]+]]:gpr, [[PseudoLD_RV32_OPT3:%[0-9]+]]:gpr = PseudoLD_RV32_OPT [[COPY]], 0 :: (load (s32))
; CHECK-4BYTE-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT]], [[PseudoLD_RV32_OPT2]]
; CHECK-4BYTE-NEXT: [[ADD1:%[0-9]+]]:gpr = ADD [[PseudoLD_RV32_OPT3]], [[PseudoLD_RV32_OPT1]]
; CHECK-4BYTE-NEXT: PseudoRET
%0:gpr = COPY $x10
%1:gpr = COPY $x11
%2:gpr = LW %stack.0, 0 :: (load (s32) from %ir.arr)
%3:gpr = LW %0, 4 :: (load (s32))
%4:gpr = LW %0, 0 :: (load (s32))
%5:gpr = LW %stack.0, 4 :: (load (s32) from %ir.arrayidx1)
%6:gpr = ADD %2, %4
%7:gpr = ADD %3, %5
PseudoRET
...