| # 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 |
| |
| ... |