# 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-4byte-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 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: PseudoSD_RV32_OPT [[COPY1]], [[COPY1]], [[COPY]], 0 :: (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 ... --- 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 ...