; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=riscv32 < %s | FileCheck %s --check-prefixes=RV32 ; RUN: llc -mtriple=riscv32 -mattr=+xqcili,+xqcilia < %s | FileCheck %s --check-prefixes=RV32XQCI ; RUN: llc -mtriple=riscv64 < %s | FileCheck %s --check-prefixes=RV64 ; RUN: llc -mtriple=riscv32 -mattr=+zba < %s | FileCheck %s --check-prefixes=RV32 ; RUN: llc -mtriple=riscv32 -mattr=+zba,+xqcili,+xqcilia < %s | FileCheck %s --check-prefixes=RV32XQCI ; RUN: llc -mtriple=riscv64 -mattr=+zba < %s | FileCheck %s --check-prefixes=RV64 %struct.S = type { [40 x i32], i32, i32, i32, [4100 x i32], i32, i32, i32 } @s = common dso_local global %struct.S zeroinitializer, align 4 @foo = global [6 x i16] [i16 1, i16 2, i16 3, i16 4, i16 5, i16 0], align 2 @g = global [1048576 x i8] zeroinitializer, align 1 @bar = external global [0 x i8], align 1 define dso_local void @multiple_stores() local_unnamed_addr nounwind { ; RV32-LABEL: multiple_stores: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(s) ; RV32-NEXT: addi a0, a0, %lo(s) ; RV32-NEXT: li a1, 10 ; RV32-NEXT: li a2, 20 ; RV32-NEXT: sw a1, 160(a0) ; RV32-NEXT: sw a2, 164(a0) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: multiple_stores: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, s ; RV32XQCI-NEXT: li a1, 10 ; RV32XQCI-NEXT: li a2, 20 ; RV32XQCI-NEXT: sw a1, 160(a0) ; RV32XQCI-NEXT: sw a2, 164(a0) ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: multiple_stores: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(s) ; RV64-NEXT: addi a0, a0, %lo(s) ; RV64-NEXT: li a1, 10 ; RV64-NEXT: li a2, 20 ; RV64-NEXT: sw a1, 160(a0) ; RV64-NEXT: sw a2, 164(a0) ; RV64-NEXT: ret entry: store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4 store i32 20, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4 ret void } define dso_local void @control_flow_with_mem_access() local_unnamed_addr nounwind { ; RV32-LABEL: control_flow_with_mem_access: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(s) ; RV32-NEXT: addi a0, a0, %lo(s) ; RV32-NEXT: lw a1, 164(a0) ; RV32-NEXT: blez a1, .LBB1_2 ; RV32-NEXT: # %bb.1: # %if.then ; RV32-NEXT: li a1, 10 ; RV32-NEXT: sw a1, 160(a0) ; RV32-NEXT: .LBB1_2: # %if.end ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: control_flow_with_mem_access: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, s ; RV32XQCI-NEXT: lw a1, 164(a0) ; RV32XQCI-NEXT: blez a1, .LBB1_2 ; RV32XQCI-NEXT: # %bb.1: # %if.then ; RV32XQCI-NEXT: li a1, 10 ; RV32XQCI-NEXT: sw a1, 160(a0) ; RV32XQCI-NEXT: .LBB1_2: # %if.end ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: control_flow_with_mem_access: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(s) ; RV64-NEXT: addi a0, a0, %lo(s) ; RV64-NEXT: lw a1, 164(a0) ; RV64-NEXT: blez a1, .LBB1_2 ; RV64-NEXT: # %bb.1: # %if.then ; RV64-NEXT: li a1, 10 ; RV64-NEXT: sw a1, 160(a0) ; RV64-NEXT: .LBB1_2: # %if.end ; RV64-NEXT: ret entry: %0 = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4 %cmp = icmp sgt i32 %0, 0 br i1 %cmp, label %if.then, label %if.end if.then: ; preds = %entry store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4 br label %if.end if.end: ; preds = %if.then, %entry ret void } ; This test checks that the offset is reconstructed correctly when ; "addi" of the big offset has a negative immediate. ; without peephole this generates: ; lui a1, %hi(g) ; addi a1, a0, %lo(g) ; lui a0, 18 ---> offset ; addi a0, a0, -160 ; add a0, a0, a1 ---> base + offset. define ptr @big_offset_neg_addi() nounwind { ; RV32-LABEL: big_offset_neg_addi: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(g+73568) ; RV32-NEXT: addi a0, a0, %lo(g+73568) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: big_offset_neg_addi: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, g+73568 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: big_offset_neg_addi: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(g+73568) ; RV64-NEXT: addi a0, a0, %lo(g+73568) ; RV64-NEXT: ret ret ptr getelementptr inbounds ([1048576 x i8], ptr @g, i32 0, i32 73568) } ; This test checks for the case where the offset is only an LUI. ; without peephole this generates: ; lui a0, %hi(g) ; addi a0, a0, %lo(g) ; lui a1, 128 ---> offset ; add a0, a0, a1 ---> base + offset. define ptr @big_offset_lui_tail() nounwind { ; RV32-LABEL: big_offset_lui_tail: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(g+524288) ; RV32-NEXT: addi a0, a0, %lo(g+524288) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: big_offset_lui_tail: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, g+524288 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: big_offset_lui_tail: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(g+524288) ; RV64-NEXT: addi a0, a0, %lo(g+524288) ; RV64-NEXT: ret ret ptr getelementptr inbounds ([1048576 x i8], ptr @g, i32 0, i32 524288) } define ptr @big_offset_neg_lui_tail() { ; RV32-LABEL: big_offset_neg_lui_tail: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar-8192) ; RV32-NEXT: addi a0, a0, %lo(bar-8192) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: big_offset_neg_lui_tail: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar-8192 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: big_offset_neg_lui_tail: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar-8192) ; RV64-NEXT: addi a0, a0, %lo(bar-8192) ; RV64-NEXT: ret ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i32 -8192) } define dso_local ptr @big_offset_one_use() local_unnamed_addr nounwind { ; RV32-LABEL: big_offset_one_use: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(s+16572) ; RV32-NEXT: addi a0, a0, %lo(s+16572) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: big_offset_one_use: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, s+16572 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: big_offset_one_use: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(s+16572) ; RV64-NEXT: addi a0, a0, %lo(s+16572) ; RV64-NEXT: ret entry: ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 5) } define dso_local ptr @small_offset_one_use() local_unnamed_addr nounwind { ; RV32-LABEL: small_offset_one_use: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(s+160) ; RV32-NEXT: addi a0, a0, %lo(s+160) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: small_offset_one_use: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, s+160 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: small_offset_one_use: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(s+160) ; RV64-NEXT: addi a0, a0, %lo(s+160) ; RV64-NEXT: ret entry: ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1) } define dso_local ptr @control_flow_no_mem(i32 %n) local_unnamed_addr nounwind { ; RV32-LABEL: control_flow_no_mem: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(s) ; RV32-NEXT: addi a0, a0, %lo(s) ; RV32-NEXT: lw a1, 164(a0) ; RV32-NEXT: beqz a1, .LBB7_2 ; RV32-NEXT: # %bb.1: # %if.end ; RV32-NEXT: addi a0, a0, 168 ; RV32-NEXT: ret ; RV32-NEXT: .LBB7_2: # %if.then ; RV32-NEXT: addi a0, a0, 160 ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: control_flow_no_mem: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, s ; RV32XQCI-NEXT: lw a1, 164(a0) ; RV32XQCI-NEXT: beqz a1, .LBB7_2 ; RV32XQCI-NEXT: # %bb.1: # %if.end ; RV32XQCI-NEXT: addi a0, a0, 168 ; RV32XQCI-NEXT: ret ; RV32XQCI-NEXT: .LBB7_2: # %if.then ; RV32XQCI-NEXT: addi a0, a0, 160 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: control_flow_no_mem: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(s) ; RV64-NEXT: addi a0, a0, %lo(s) ; RV64-NEXT: lw a1, 164(a0) ; RV64-NEXT: beqz a1, .LBB7_2 ; RV64-NEXT: # %bb.1: # %if.end ; RV64-NEXT: addi a0, a0, 168 ; RV64-NEXT: ret ; RV64-NEXT: .LBB7_2: # %if.then ; RV64-NEXT: addi a0, a0, 160 ; RV64-NEXT: ret entry: %0 = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4 %cmp = icmp eq i32 %0, 0 br i1 %cmp, label %if.then, label %if.end if.then: ; preds = %entry ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1) if.end: ; preds = %if.then, %entry ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 3) } define dso_local i32 @load_half() nounwind { ; RV32-LABEL: load_half: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(foo+8) ; RV32-NEXT: lhu a0, %lo(foo+8)(a0) ; RV32-NEXT: li a1, 140 ; RV32-NEXT: bne a0, a1, .LBB8_2 ; RV32-NEXT: # %bb.1: # %if.end ; RV32-NEXT: li a0, 0 ; RV32-NEXT: ret ; RV32-NEXT: .LBB8_2: # %if.then ; RV32-NEXT: addi sp, sp, -16 ; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill ; RV32-NEXT: call abort ; ; RV32XQCI-LABEL: load_half: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, foo+8 ; RV32XQCI-NEXT: lhu a0, 0(a0) ; RV32XQCI-NEXT: li a1, 140 ; RV32XQCI-NEXT: bne a0, a1, .LBB8_2 ; RV32XQCI-NEXT: # %bb.1: # %if.end ; RV32XQCI-NEXT: li a0, 0 ; RV32XQCI-NEXT: ret ; RV32XQCI-NEXT: .LBB8_2: # %if.then ; RV32XQCI-NEXT: addi sp, sp, -16 ; RV32XQCI-NEXT: sw ra, 12(sp) # 4-byte Folded Spill ; RV32XQCI-NEXT: call abort ; ; RV64-LABEL: load_half: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(foo+8) ; RV64-NEXT: lhu a0, %lo(foo+8)(a0) ; RV64-NEXT: li a1, 140 ; RV64-NEXT: bne a0, a1, .LBB8_2 ; RV64-NEXT: # %bb.1: # %if.end ; RV64-NEXT: li a0, 0 ; RV64-NEXT: ret ; RV64-NEXT: .LBB8_2: # %if.then ; RV64-NEXT: addi sp, sp, -16 ; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill ; RV64-NEXT: call abort entry: %0 = load i16, ptr getelementptr inbounds ([6 x i16], ptr @foo, i32 0, i32 4), align 2 %cmp = icmp eq i16 %0, 140 br i1 %cmp, label %if.end, label %if.then if.then: tail call void @abort() unreachable if.end: ret i32 0 } declare void @abort() define dso_local void @one_store() local_unnamed_addr nounwind { ; RV32-LABEL: one_store: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(s+160) ; RV32-NEXT: li a1, 10 ; RV32-NEXT: sw a1, %lo(s+160)(a0) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: one_store: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, s+160 ; RV32XQCI-NEXT: li a1, 10 ; RV32XQCI-NEXT: sw a1, 0(a0) ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: one_store: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(s+160) ; RV64-NEXT: li a1, 10 ; RV64-NEXT: sw a1, %lo(s+160)(a0) ; RV64-NEXT: ret entry: store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4 ret void } define ptr @neg_offset() { ; RV32-LABEL: neg_offset: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar-8191) ; RV32-NEXT: addi a0, a0, %lo(bar-8191) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: neg_offset: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar-8191 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: neg_offset: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar-8191) ; RV64-NEXT: addi a0, a0, %lo(bar-8191) ; RV64-NEXT: ret ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i32 -8191) } ; This uses an LUI+ADDI on RV64 that does not produce a simm32. For RV32, we'll ; truncate the offset. define ptr @neg_offset_not_simm32() { ; RV32-LABEL: neg_offset_not_simm32: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar+2147482283) ; RV32-NEXT: addi a0, a0, %lo(bar+2147482283) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: neg_offset_not_simm32: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar+2147482283 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: neg_offset_not_simm32: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar) ; RV64-NEXT: addi a0, a0, %lo(bar) ; RV64-NEXT: lui a1, 524288 ; RV64-NEXT: addi a1, a1, -1365 ; RV64-NEXT: add a0, a0, a1 ; RV64-NEXT: ret ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 -2147485013) } define ptr @offset_addi_addi() { ; RV32-LABEL: offset_addi_addi: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar+3211) ; RV32-NEXT: addi a0, a0, %lo(bar+3211) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: offset_addi_addi: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar+3211 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: offset_addi_addi: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar+3211) ; RV64-NEXT: addi a0, a0, %lo(bar+3211) ; RV64-NEXT: ret ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211) } define ptr @offset_addi_addi_neg() { ; RV32-LABEL: offset_addi_addi_neg: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar-4000) ; RV32-NEXT: addi a0, a0, %lo(bar-4000) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: offset_addi_addi_neg: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar-4000 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: offset_addi_addi_neg: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar-4000) ; RV64-NEXT: addi a0, a0, %lo(bar-4000) ; RV64-NEXT: ret ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 -4000) } ; With Zba the constant 6424 is created with LI+SH2ADD. define ptr @offset_sh2add() { ; RV32-LABEL: offset_sh2add: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar+6424) ; RV32-NEXT: addi a0, a0, %lo(bar+6424) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: offset_sh2add: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar+6424 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: offset_sh2add: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar+6424) ; RV64-NEXT: addi a0, a0, %lo(bar+6424) ; RV64-NEXT: ret ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 6424) } ; With Zba the constant 12848 is created with LI+SH3ADD. define ptr @offset_sh3add() { ; RV32-LABEL: offset_sh3add: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar+12848) ; RV32-NEXT: addi a0, a0, %lo(bar+12848) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: offset_sh3add: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar+12848 ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: offset_sh3add: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar+12848) ; RV64-NEXT: addi a0, a0, %lo(bar+12848) ; RV64-NEXT: ret ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 12848) } define dso_local void @read_modify_write() local_unnamed_addr nounwind { ; RV32-LABEL: read_modify_write: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(s+160) ; RV32-NEXT: lw a1, %lo(s+160)(a0) ; RV32-NEXT: addi a1, a1, 10 ; RV32-NEXT: sw a1, %lo(s+160)(a0) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: read_modify_write: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, s+160 ; RV32XQCI-NEXT: lw a1, 0(a0) ; RV32XQCI-NEXT: addi a1, a1, 10 ; RV32XQCI-NEXT: sw a1, 0(a0) ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: read_modify_write: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(s+160) ; RV64-NEXT: lw a1, %lo(s+160)(a0) ; RV64-NEXT: addi a1, a1, 10 ; RV64-NEXT: sw a1, %lo(s+160)(a0) ; RV64-NEXT: ret entry: %x = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4 %y = add i32 %x, 10 store i32 %y, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4 ret void } define dso_local void @rmw_with_control_flow() nounwind { ; RV32-LABEL: rmw_with_control_flow: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(s+164) ; RV32-NEXT: lw a1, %lo(s+164)(a0) ; RV32-NEXT: blez a1, .LBB17_2 ; RV32-NEXT: # %bb.1: # %if.then ; RV32-NEXT: li a1, 10 ; RV32-NEXT: sw a1, %lo(s+164)(a0) ; RV32-NEXT: .LBB17_2: # %if.end ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: rmw_with_control_flow: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, s+164 ; RV32XQCI-NEXT: lw a1, 0(a0) ; RV32XQCI-NEXT: blez a1, .LBB17_2 ; RV32XQCI-NEXT: # %bb.1: # %if.then ; RV32XQCI-NEXT: li a1, 10 ; RV32XQCI-NEXT: sw a1, 0(a0) ; RV32XQCI-NEXT: .LBB17_2: # %if.end ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: rmw_with_control_flow: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(s+164) ; RV64-NEXT: lw a1, %lo(s+164)(a0) ; RV64-NEXT: blez a1, .LBB17_2 ; RV64-NEXT: # %bb.1: # %if.then ; RV64-NEXT: li a1, 10 ; RV64-NEXT: sw a1, %lo(s+164)(a0) ; RV64-NEXT: .LBB17_2: # %if.end ; RV64-NEXT: ret entry: %0 = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4 %cmp = icmp sgt i32 %0, 0 br i1 %cmp, label %if.then, label %if.end if.then: ; preds = %entry store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4 br label %if.end if.end: ; preds = %if.then, %entry ret void } %struct.foo = type { i32, ptr } @f = global %struct.foo zeroinitializer, align 8 ; Test the case where the store value and base pointer are the same register. define void @self_store() { ; RV32-LABEL: self_store: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(f) ; RV32-NEXT: addi a0, a0, %lo(f) ; RV32-NEXT: sw a0, 4(a0) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: self_store: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, f ; RV32XQCI-NEXT: sw a0, 4(a0) ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: self_store: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(f) ; RV64-NEXT: addi a0, a0, %lo(f) ; RV64-NEXT: sd a0, 8(a0) ; RV64-NEXT: ret store ptr @f, ptr getelementptr inbounds (%struct.foo, ptr @f, i64 0, i32 1), align 8 ret void } define void @store_addi_addi() { ; RV32-LABEL: store_addi_addi: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar+3211) ; RV32-NEXT: li a1, 10 ; RV32-NEXT: sb a1, %lo(bar+3211)(a0) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: store_addi_addi: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar+3211 ; RV32XQCI-NEXT: li a1, 10 ; RV32XQCI-NEXT: sb a1, 0(a0) ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: store_addi_addi: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar+3211) ; RV64-NEXT: li a1, 10 ; RV64-NEXT: sb a1, %lo(bar+3211)(a0) ; RV64-NEXT: ret store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211) ret void } define void @store_addi_addi_neg() { ; RV32-LABEL: store_addi_addi_neg: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar-4000) ; RV32-NEXT: li a1, 10 ; RV32-NEXT: sb a1, %lo(bar-4000)(a0) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: store_addi_addi_neg: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar-4000 ; RV32XQCI-NEXT: li a1, 10 ; RV32XQCI-NEXT: sb a1, 0(a0) ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: store_addi_addi_neg: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar-4000) ; RV64-NEXT: li a1, 10 ; RV64-NEXT: sb a1, %lo(bar-4000)(a0) ; RV64-NEXT: ret store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 -4000) ret void } ; With Zba the constant 6424 is created with LI+SH2ADD. define void @store_sh2add() { ; RV32-LABEL: store_sh2add: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar+6424) ; RV32-NEXT: li a1, 10 ; RV32-NEXT: sb a1, %lo(bar+6424)(a0) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: store_sh2add: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar+6424 ; RV32XQCI-NEXT: li a1, 10 ; RV32XQCI-NEXT: sb a1, 0(a0) ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: store_sh2add: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar+6424) ; RV64-NEXT: li a1, 10 ; RV64-NEXT: sb a1, %lo(bar+6424)(a0) ; RV64-NEXT: ret store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 6424) ret void } ; With Zba the constant 12848 is created with LI+SH3ADD. define void @store_sh3add() { ; RV32-LABEL: store_sh3add: ; RV32: # %bb.0: ; RV32-NEXT: lui a0, %hi(bar+12848) ; RV32-NEXT: li a1, 10 ; RV32-NEXT: sb a1, %lo(bar+12848)(a0) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: store_sh3add: ; RV32XQCI: # %bb.0: ; RV32XQCI-NEXT: qc.e.li a0, bar+12848 ; RV32XQCI-NEXT: li a1, 10 ; RV32XQCI-NEXT: sb a1, 0(a0) ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: store_sh3add: ; RV64: # %bb.0: ; RV64-NEXT: lui a0, %hi(bar+12848) ; RV64-NEXT: li a1, 10 ; RV64-NEXT: sb a1, %lo(bar+12848)(a0) ; RV64-NEXT: ret store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 12848) ret void } define dso_local void @rmw_addi_addi() nounwind { ; RV32-LABEL: rmw_addi_addi: ; RV32: # %bb.0: # %entry ; RV32-NEXT: lui a0, %hi(bar+3211) ; RV32-NEXT: lbu a1, %lo(bar+3211)(a0) ; RV32-NEXT: addi a1, a1, 10 ; RV32-NEXT: sb a1, %lo(bar+3211)(a0) ; RV32-NEXT: ret ; ; RV32XQCI-LABEL: rmw_addi_addi: ; RV32XQCI: # %bb.0: # %entry ; RV32XQCI-NEXT: qc.e.li a0, bar+3211 ; RV32XQCI-NEXT: lbu a1, 0(a0) ; RV32XQCI-NEXT: addi a1, a1, 10 ; RV32XQCI-NEXT: sb a1, 0(a0) ; RV32XQCI-NEXT: ret ; ; RV64-LABEL: rmw_addi_addi: ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a0, %hi(bar+3211) ; RV64-NEXT: lbu a1, %lo(bar+3211)(a0) ; RV64-NEXT: addi a1, a1, 10 ; RV64-NEXT: sb a1, %lo(bar+3211)(a0) ; RV64-NEXT: ret entry: %0 = load i8, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211) %1 = add i8 %0, 10 store i8 %1, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211) br label %if.end if.end: ; preds = %if.then, %entry ret void }