diff options
Diffstat (limited to 'test/CodeGen/RISCV')
27 files changed, 4645 insertions, 0 deletions
diff --git a/test/CodeGen/RISCV/addc-adde-sube-subc.ll b/test/CodeGen/RISCV/addc-adde-sube-subc.ll new file mode 100644 index 0000000000000..fd22e310f10ad --- /dev/null +++ b/test/CodeGen/RISCV/addc-adde-sube-subc.ll @@ -0,0 +1,44 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +; Ensure that the ISDOpcodes ADDC, ADDE, SUBC, SUBE are handled correctly + +define i64 @addc_adde(i64 %a, i64 %b) { +; RV32I-LABEL: addc_adde: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: add a1, a1, a3 +; RV32I-NEXT: add a2, a0, a2 +; RV32I-NEXT: sltu a0, a2, a0 +; RV32I-NEXT: add a1, a1, a0 +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = add i64 %a, %b + ret i64 %1 +} + +define i64 @subc_sube(i64 %a, i64 %b) { +; RV32I-LABEL: subc_sube: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sub a1, a1, a3 +; RV32I-NEXT: sltu a3, a0, a2 +; RV32I-NEXT: sub a1, a1, a3 +; RV32I-NEXT: sub a0, a0, a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sub i64 %a, %b + ret i64 %1 +} diff --git a/test/CodeGen/RISCV/alloca.ll b/test/CodeGen/RISCV/alloca.ll new file mode 100644 index 0000000000000..1472e8a302c3a --- /dev/null +++ b/test/CodeGen/RISCV/alloca.ll @@ -0,0 +1,65 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +declare void @notdead(i8*) + +; These tests must ensure the stack pointer is restored using the frame +; pointer + +define void @simple_alloca(i32 %n) nounwind { +; RV32I-LABEL: simple_alloca: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a0, a0, 15 +; RV32I-NEXT: andi a0, a0, -16 +; RV32I-NEXT: sub a0, sp, a0 +; RV32I-NEXT: mv sp, a0 +; RV32I-NEXT: lui a1, %hi(notdead) +; RV32I-NEXT: addi a1, a1, %lo(notdead) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: addi sp, s0, -16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = alloca i8, i32 %n + call void @notdead(i8* %1) + ret void +} + +declare i8* @llvm.stacksave() +declare void @llvm.stackrestore(i8*) + +define void @scoped_alloca(i32 %n) nounwind { +; RV32I-LABEL: scoped_alloca: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: sw s1, 4(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: mv s1, sp +; RV32I-NEXT: addi a0, a0, 15 +; RV32I-NEXT: andi a0, a0, -16 +; RV32I-NEXT: sub a0, sp, a0 +; RV32I-NEXT: mv sp, a0 +; RV32I-NEXT: lui a1, %hi(notdead) +; RV32I-NEXT: addi a1, a1, %lo(notdead) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: mv sp, s1 +; RV32I-NEXT: addi sp, s0, -16 +; RV32I-NEXT: lw s1, 4(sp) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %sp = call i8* @llvm.stacksave() + %addr = alloca i8, i32 %n + call void @notdead(i8* %addr) + call void @llvm.stackrestore(i8* %sp) + ret void +} diff --git a/test/CodeGen/RISCV/alu32.ll b/test/CodeGen/RISCV/alu32.ll new file mode 100644 index 0000000000000..eb85413fa516d --- /dev/null +++ b/test/CodeGen/RISCV/alu32.ll @@ -0,0 +1,319 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +; These tests are each targeted at a particular RISC-V ALU instruction. Other +; files in this folder exercise LLVM IR instructions that don't directly match a +; RISC-V instruction + +; Register-immediate instructions + +define i32 @addi(i32 %a) nounwind { +; RV32I-LABEL: addi: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = add i32 %a, 1 + ret i32 %1 +} + +define i32 @slti(i32 %a) nounwind { +; RV32I-LABEL: slti: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slti a0, a0, 2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp slt i32 %a, 2 + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @sltiu(i32 %a) nounwind { +; RV32I-LABEL: sltiu: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sltiu a0, a0, 3 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp ult i32 %a, 3 + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @xori(i32 %a) nounwind { +; RV32I-LABEL: xori: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: xori a0, a0, 4 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = xor i32 %a, 4 + ret i32 %1 +} + +define i32 @ori(i32 %a) nounwind { +; RV32I-LABEL: ori: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: ori a0, a0, 5 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = or i32 %a, 5 + ret i32 %1 +} + +define i32 @andi(i32 %a) nounwind { +; RV32I-LABEL: andi: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 6 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = and i32 %a, 6 + ret i32 %1 +} + +define i32 @slli(i32 %a) nounwind { +; RV32I-LABEL: slli: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slli a0, a0, 7 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = shl i32 %a, 7 + ret i32 %1 +} + +define i32 @srli(i32 %a) nounwind { +; RV32I-LABEL: srli: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: srli a0, a0, 8 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = lshr i32 %a, 8 + ret i32 %1 +} + +define i32 @srai(i32 %a) nounwind { +; RV32I-LABEL: srai: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: srai a0, a0, 9 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = ashr i32 %a, 9 + ret i32 %1 +} + +; Register-register instructions + +define i32 @add(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: add: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = add i32 %a, %b + ret i32 %1 +} + +define i32 @sub(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: sub: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sub i32 %a, %b + ret i32 %1 +} + +define i32 @sll(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: sll: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sll a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = shl i32 %a, %b + ret i32 %1 +} + +define i32 @slt(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: slt: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slt a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp slt i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @sltu(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: sltu: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sltu a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp ult i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @xor(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: xor: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = xor i32 %a, %b + ret i32 %1 +} + +define i32 @srl(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: srl: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: srl a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = lshr i32 %a, %b + ret i32 %1 +} + +define i32 @sra(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: sra: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sra a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = ashr i32 %a, %b + ret i32 %1 +} + +define i32 @or(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: or: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = or i32 %a, %b + ret i32 %1 +} + +define i32 @and(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: and: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = and i32 %a, %b + ret i32 %1 +} diff --git a/test/CodeGen/RISCV/bare-select.ll b/test/CodeGen/RISCV/bare-select.ll new file mode 100644 index 0000000000000..6fd72fdfa2a76 --- /dev/null +++ b/test/CodeGen/RISCV/bare-select.ll @@ -0,0 +1,24 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +define i32 @bare_select(i1 %a, i32 %b, i32 %c) { +; RV32I-LABEL: bare_select: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 1 +; RV32I-NEXT: bnez a0, .LBB0_2 +; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: mv a1, a2 +; RV32I-NEXT: .LBB0_2: +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = select i1 %a, i32 %b, i32 %c + ret i32 %1 +} diff --git a/test/CodeGen/RISCV/blockaddress.ll b/test/CodeGen/RISCV/blockaddress.ll new file mode 100644 index 0000000000000..8d74de752f37e --- /dev/null +++ b/test/CodeGen/RISCV/blockaddress.ll @@ -0,0 +1,33 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +@addr = global i8* null + +define void @test_blockaddress() nounwind { +; RV32I-LABEL: test_blockaddress: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(addr) +; RV32I-NEXT: addi a0, a0, %lo(addr) +; RV32I-NEXT: lui a1, %hi(.Ltmp0) +; RV32I-NEXT: addi a1, a1, %lo(.Ltmp0) +; RV32I-NEXT: sw a1, 0(a0) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: jr a0 +; RV32I-NEXT: .Ltmp0: # Block address taken +; RV32I-NEXT: .LBB0_1: # %block +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + store volatile i8* blockaddress(@test_blockaddress, %block), i8** @addr + %val = load volatile i8*, i8** @addr + indirectbr i8* %val, [label %block] + +block: + ret void +} diff --git a/test/CodeGen/RISCV/branch.ll b/test/CodeGen/RISCV/branch.ll new file mode 100644 index 0000000000000..5c89cbe313ac0 --- /dev/null +++ b/test/CodeGen/RISCV/branch.ll @@ -0,0 +1,128 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +define void @foo(i32 %a, i32 *%b, i1 %c) { +; RV32I-LABEL: foo: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: beq a3, a0, .LBB0_12 +; RV32I-NEXT: j .LBB0_1 +; RV32I-NEXT: .LBB0_1: # %test2 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: bne a3, a0, .LBB0_12 +; RV32I-NEXT: j .LBB0_2 +; RV32I-NEXT: .LBB0_2: # %test3 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: blt a3, a0, .LBB0_12 +; RV32I-NEXT: j .LBB0_3 +; RV32I-NEXT: .LBB0_3: # %test4 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: bge a3, a0, .LBB0_12 +; RV32I-NEXT: j .LBB0_4 +; RV32I-NEXT: .LBB0_4: # %test5 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: bltu a3, a0, .LBB0_12 +; RV32I-NEXT: j .LBB0_5 +; RV32I-NEXT: .LBB0_5: # %test6 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: bgeu a3, a0, .LBB0_12 +; RV32I-NEXT: j .LBB0_6 +; RV32I-NEXT: .LBB0_6: # %test7 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: blt a0, a3, .LBB0_12 +; RV32I-NEXT: j .LBB0_7 +; RV32I-NEXT: .LBB0_7: # %test8 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: bge a0, a3, .LBB0_12 +; RV32I-NEXT: j .LBB0_8 +; RV32I-NEXT: .LBB0_8: # %test9 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: bltu a0, a3, .LBB0_12 +; RV32I-NEXT: j .LBB0_9 +; RV32I-NEXT: .LBB0_9: # %test10 +; RV32I-NEXT: lw a3, 0(a1) +; RV32I-NEXT: bgeu a0, a3, .LBB0_12 +; RV32I-NEXT: j .LBB0_10 +; RV32I-NEXT: .LBB0_10: # %test11 +; RV32I-NEXT: lw a0, 0(a1) +; RV32I-NEXT: andi a0, a2, 1 +; RV32I-NEXT: bnez a0, .LBB0_12 +; RV32I-NEXT: j .LBB0_11 +; RV32I-NEXT: .LBB0_11: # %test12 +; RV32I-NEXT: lw a0, 0(a1) +; RV32I-NEXT: .LBB0_12: # %end +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + + %val1 = load volatile i32, i32* %b + %tst1 = icmp eq i32 %val1, %a + br i1 %tst1, label %end, label %test2 + +test2: + %val2 = load volatile i32, i32* %b + %tst2 = icmp ne i32 %val2, %a + br i1 %tst2, label %end, label %test3 + +test3: + %val3 = load volatile i32, i32* %b + %tst3 = icmp slt i32 %val3, %a + br i1 %tst3, label %end, label %test4 + +test4: + %val4 = load volatile i32, i32* %b + %tst4 = icmp sge i32 %val4, %a + br i1 %tst4, label %end, label %test5 + +test5: + %val5 = load volatile i32, i32* %b + %tst5 = icmp ult i32 %val5, %a + br i1 %tst5, label %end, label %test6 + +test6: + %val6 = load volatile i32, i32* %b + %tst6 = icmp uge i32 %val6, %a + br i1 %tst6, label %end, label %test7 + +; Check for condition codes that don't have a matching instruction + +test7: + %val7 = load volatile i32, i32* %b + %tst7 = icmp sgt i32 %val7, %a + br i1 %tst7, label %end, label %test8 + +test8: + %val8 = load volatile i32, i32* %b + %tst8 = icmp sle i32 %val8, %a + br i1 %tst8, label %end, label %test9 + +test9: + %val9 = load volatile i32, i32* %b + %tst9 = icmp ugt i32 %val9, %a + br i1 %tst9, label %end, label %test10 + +test10: + %val10 = load volatile i32, i32* %b + %tst10 = icmp ule i32 %val10, %a + br i1 %tst10, label %end, label %test11 + +; Check the case of a branch where the condition was generated in another +; function + +test11: + %val11 = load volatile i32, i32* %b + br i1 %c, label %end, label %test12 + +test12: + %val12 = load volatile i32, i32* %b + br label %end + +end: + ret void +} diff --git a/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll b/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll new file mode 100644 index 0000000000000..dd1ae9f00a7af --- /dev/null +++ b/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll @@ -0,0 +1,614 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +declare i16 @llvm.bswap.i16(i16) +declare i32 @llvm.bswap.i32(i32) +declare i64 @llvm.bswap.i64(i64) +declare i8 @llvm.cttz.i8(i8, i1) +declare i16 @llvm.cttz.i16(i16, i1) +declare i32 @llvm.cttz.i32(i32, i1) +declare i64 @llvm.cttz.i64(i64, i1) +declare i32 @llvm.ctlz.i32(i32, i1) +declare i32 @llvm.ctpop.i32(i32) + +define i16 @test_bswap_i16(i16 %a) nounwind { +; RV32I-LABEL: test_bswap_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, 4080 +; RV32I-NEXT: mv a1, a1 +; RV32I-NEXT: slli a2, a0, 8 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: srli a0, a0, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i16 @llvm.bswap.i16(i16 %a) + ret i16 %tmp +} + +define i32 @test_bswap_i32(i32 %a) nounwind { +; RV32I-LABEL: test_bswap_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, 16 +; RV32I-NEXT: addi a1, a1, -256 +; RV32I-NEXT: srli a2, a0, 8 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: srli a2, a0, 24 +; RV32I-NEXT: or a1, a1, a2 +; RV32I-NEXT: lui a2, 4080 +; RV32I-NEXT: mv a2, a2 +; RV32I-NEXT: slli a3, a0, 8 +; RV32I-NEXT: and a2, a3, a2 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: or a0, a0, a2 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i32 @llvm.bswap.i32(i32 %a) + ret i32 %tmp +} + +define i64 @test_bswap_i64(i64 %a) nounwind { +; RV32I-LABEL: test_bswap_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a2, 16 +; RV32I-NEXT: addi a3, a2, -256 +; RV32I-NEXT: srli a2, a1, 8 +; RV32I-NEXT: and a2, a2, a3 +; RV32I-NEXT: srli a4, a1, 24 +; RV32I-NEXT: or a2, a2, a4 +; RV32I-NEXT: lui a4, 4080 +; RV32I-NEXT: mv a4, a4 +; RV32I-NEXT: slli a5, a1, 8 +; RV32I-NEXT: and a5, a5, a4 +; RV32I-NEXT: slli a1, a1, 24 +; RV32I-NEXT: or a1, a1, a5 +; RV32I-NEXT: or a2, a1, a2 +; RV32I-NEXT: srli a1, a0, 8 +; RV32I-NEXT: and a1, a1, a3 +; RV32I-NEXT: srli a3, a0, 24 +; RV32I-NEXT: or a1, a1, a3 +; RV32I-NEXT: slli a3, a0, 8 +; RV32I-NEXT: and a3, a3, a4 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: or a0, a0, a3 +; RV32I-NEXT: or a1, a0, a1 +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i64 @llvm.bswap.i64(i64 %a) + ret i64 %tmp +} + +define i8 @test_cttz_i8(i8 %a) nounwind { +; RV32I-LABEL: test_cttz_i8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: mv a1, a0 +; RV32I-NEXT: addi a0, zero, 8 +; RV32I-NEXT: andi a2, a1, 255 +; RV32I-NEXT: beqz a2, .LBB3_2 +; RV32I-NEXT: j .LBB3_1 +; RV32I-NEXT: .LBB3_1: # %cond.false +; RV32I-NEXT: addi a0, a1, -1 +; RV32I-NEXT: not a1, a1 +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi a1, a1, 1365 +; RV32I-NEXT: srli a2, a0, 1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi a1, a1, 819 +; RV32I-NEXT: and a2, a0, a1 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: add a0, a2, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi a1, a1, -241 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi a1, a1, 257 +; RV32I-NEXT: lui a2, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: .LBB3_2: # %cond.end +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i8 @llvm.cttz.i8(i8 %a, i1 false) + ret i8 %tmp +} + +define i16 @test_cttz_i16(i16 %a) nounwind { +; RV32I-LABEL: test_cttz_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: mv a1, a0 +; RV32I-NEXT: addi a0, zero, 16 +; RV32I-NEXT: lui a2, 16 +; RV32I-NEXT: addi a2, a2, -1 +; RV32I-NEXT: and a2, a1, a2 +; RV32I-NEXT: beqz a2, .LBB4_2 +; RV32I-NEXT: j .LBB4_1 +; RV32I-NEXT: .LBB4_1: # %cond.false +; RV32I-NEXT: addi a0, a1, -1 +; RV32I-NEXT: not a1, a1 +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi a1, a1, 1365 +; RV32I-NEXT: srli a2, a0, 1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi a1, a1, 819 +; RV32I-NEXT: and a2, a0, a1 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: add a0, a2, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi a1, a1, -241 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi a1, a1, 257 +; RV32I-NEXT: lui a2, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: .LBB4_2: # %cond.end +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i16 @llvm.cttz.i16(i16 %a, i1 false) + ret i16 %tmp +} + +define i32 @test_cttz_i32(i32 %a) nounwind { +; RV32I-LABEL: test_cttz_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: mv a1, a0 +; RV32I-NEXT: addi a0, zero, 32 +; RV32I-NEXT: beqz a1, .LBB5_2 +; RV32I-NEXT: j .LBB5_1 +; RV32I-NEXT: .LBB5_1: # %cond.false +; RV32I-NEXT: addi a0, a1, -1 +; RV32I-NEXT: not a1, a1 +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi a1, a1, 1365 +; RV32I-NEXT: srli a2, a0, 1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi a1, a1, 819 +; RV32I-NEXT: and a2, a0, a1 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: add a0, a2, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi a1, a1, -241 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi a1, a1, 257 +; RV32I-NEXT: lui a2, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: .LBB5_2: # %cond.end +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i32 @llvm.cttz.i32(i32 %a, i1 false) + ret i32 %tmp +} + +define i32 @test_ctlz_i32(i32 %a) nounwind { +; RV32I-LABEL: test_ctlz_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: mv a1, a0 +; RV32I-NEXT: addi a0, zero, 32 +; RV32I-NEXT: beqz a1, .LBB6_2 +; RV32I-NEXT: j .LBB6_1 +; RV32I-NEXT: .LBB6_1: # %cond.false +; RV32I-NEXT: srli a0, a1, 1 +; RV32I-NEXT: or a0, a1, a0 +; RV32I-NEXT: srli a1, a0, 2 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: srli a1, a0, 8 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: srli a1, a0, 16 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi a1, a1, 1365 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: srli a2, a0, 1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi a1, a1, 819 +; RV32I-NEXT: and a2, a0, a1 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: add a0, a2, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi a1, a1, -241 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi a1, a1, 257 +; RV32I-NEXT: lui a2, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: .LBB6_2: # %cond.end +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i32 @llvm.ctlz.i32(i32 %a, i1 false) + ret i32 %tmp +} + +define i64 @test_cttz_i64(i64 %a) nounwind { +; RV32I-LABEL: test_cttz_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -48 +; RV32I-NEXT: sw ra, 44(sp) +; RV32I-NEXT: sw s0, 40(sp) +; RV32I-NEXT: sw s1, 36(sp) +; RV32I-NEXT: sw s2, 32(sp) +; RV32I-NEXT: sw s3, 28(sp) +; RV32I-NEXT: sw s4, 24(sp) +; RV32I-NEXT: sw s5, 20(sp) +; RV32I-NEXT: sw s6, 16(sp) +; RV32I-NEXT: sw s7, 12(sp) +; RV32I-NEXT: addi s0, sp, 48 +; RV32I-NEXT: mv s1, a1 +; RV32I-NEXT: mv s2, a0 +; RV32I-NEXT: addi a0, s2, -1 +; RV32I-NEXT: not a1, s2 +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi s4, a1, 1365 +; RV32I-NEXT: srli a1, a0, 1 +; RV32I-NEXT: and a1, a1, s4 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi s5, a1, 819 +; RV32I-NEXT: and a1, a0, s5 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, s5 +; RV32I-NEXT: add a0, a1, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi s3, a1, 257 +; RV32I-NEXT: lui a1, %hi(__mulsi3) +; RV32I-NEXT: addi s6, a1, %lo(__mulsi3) +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi s7, a1, -241 +; RV32I-NEXT: and a0, a0, s7 +; RV32I-NEXT: mv a1, s3 +; RV32I-NEXT: jalr s6 +; RV32I-NEXT: addi a1, s1, -1 +; RV32I-NEXT: not a2, s1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: srli a2, a1, 1 +; RV32I-NEXT: and a2, a2, s4 +; RV32I-NEXT: sub a1, a1, a2 +; RV32I-NEXT: and a2, a1, s5 +; RV32I-NEXT: srli a1, a1, 2 +; RV32I-NEXT: and a1, a1, s5 +; RV32I-NEXT: add a1, a2, a1 +; RV32I-NEXT: srli a2, a1, 4 +; RV32I-NEXT: add a1, a1, a2 +; RV32I-NEXT: and a1, a1, s7 +; RV32I-NEXT: srli s1, a0, 24 +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: mv a1, s3 +; RV32I-NEXT: jalr s6 +; RV32I-NEXT: bnez s2, .LBB7_2 +; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: addi s1, a0, 32 +; RV32I-NEXT: .LBB7_2: +; RV32I-NEXT: mv a0, s1 +; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: lw s7, 12(sp) +; RV32I-NEXT: lw s6, 16(sp) +; RV32I-NEXT: lw s5, 20(sp) +; RV32I-NEXT: lw s4, 24(sp) +; RV32I-NEXT: lw s3, 28(sp) +; RV32I-NEXT: lw s2, 32(sp) +; RV32I-NEXT: lw s1, 36(sp) +; RV32I-NEXT: lw s0, 40(sp) +; RV32I-NEXT: lw ra, 44(sp) +; RV32I-NEXT: addi sp, sp, 48 +; RV32I-NEXT: ret + %tmp = call i64 @llvm.cttz.i64(i64 %a, i1 false) + ret i64 %tmp +} + +define i8 @test_cttz_i8_zero_undef(i8 %a) nounwind { +; RV32I-LABEL: test_cttz_i8_zero_undef: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a1, a0, -1 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi a1, a1, 1365 +; RV32I-NEXT: srli a2, a0, 1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi a1, a1, 819 +; RV32I-NEXT: and a2, a0, a1 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: add a0, a2, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi a1, a1, -241 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi a1, a1, 257 +; RV32I-NEXT: lui a2, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i8 @llvm.cttz.i8(i8 %a, i1 true) + ret i8 %tmp +} + +define i16 @test_cttz_i16_zero_undef(i16 %a) nounwind { +; RV32I-LABEL: test_cttz_i16_zero_undef: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a1, a0, -1 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi a1, a1, 1365 +; RV32I-NEXT: srli a2, a0, 1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi a1, a1, 819 +; RV32I-NEXT: and a2, a0, a1 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: add a0, a2, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi a1, a1, -241 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi a1, a1, 257 +; RV32I-NEXT: lui a2, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i16 @llvm.cttz.i16(i16 %a, i1 true) + ret i16 %tmp +} + +define i32 @test_cttz_i32_zero_undef(i32 %a) nounwind { +; RV32I-LABEL: test_cttz_i32_zero_undef: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a1, a0, -1 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi a1, a1, 1365 +; RV32I-NEXT: srli a2, a0, 1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi a1, a1, 819 +; RV32I-NEXT: and a2, a0, a1 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: add a0, a2, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi a1, a1, -241 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi a1, a1, 257 +; RV32I-NEXT: lui a2, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %tmp = call i32 @llvm.cttz.i32(i32 %a, i1 true) + ret i32 %tmp +} + +define i64 @test_cttz_i64_zero_undef(i64 %a) nounwind { +; RV32I-LABEL: test_cttz_i64_zero_undef: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -48 +; RV32I-NEXT: sw ra, 44(sp) +; RV32I-NEXT: sw s0, 40(sp) +; RV32I-NEXT: sw s1, 36(sp) +; RV32I-NEXT: sw s2, 32(sp) +; RV32I-NEXT: sw s3, 28(sp) +; RV32I-NEXT: sw s4, 24(sp) +; RV32I-NEXT: sw s5, 20(sp) +; RV32I-NEXT: sw s6, 16(sp) +; RV32I-NEXT: sw s7, 12(sp) +; RV32I-NEXT: addi s0, sp, 48 +; RV32I-NEXT: mv s1, a1 +; RV32I-NEXT: mv s2, a0 +; RV32I-NEXT: addi a0, s2, -1 +; RV32I-NEXT: not a1, s2 +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi s4, a1, 1365 +; RV32I-NEXT: srli a1, a0, 1 +; RV32I-NEXT: and a1, a1, s4 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi s5, a1, 819 +; RV32I-NEXT: and a1, a0, s5 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, s5 +; RV32I-NEXT: add a0, a1, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi s3, a1, 257 +; RV32I-NEXT: lui a1, %hi(__mulsi3) +; RV32I-NEXT: addi s6, a1, %lo(__mulsi3) +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi s7, a1, -241 +; RV32I-NEXT: and a0, a0, s7 +; RV32I-NEXT: mv a1, s3 +; RV32I-NEXT: jalr s6 +; RV32I-NEXT: addi a1, s1, -1 +; RV32I-NEXT: not a2, s1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: srli a2, a1, 1 +; RV32I-NEXT: and a2, a2, s4 +; RV32I-NEXT: sub a1, a1, a2 +; RV32I-NEXT: and a2, a1, s5 +; RV32I-NEXT: srli a1, a1, 2 +; RV32I-NEXT: and a1, a1, s5 +; RV32I-NEXT: add a1, a2, a1 +; RV32I-NEXT: srli a2, a1, 4 +; RV32I-NEXT: add a1, a1, a2 +; RV32I-NEXT: and a1, a1, s7 +; RV32I-NEXT: srli s1, a0, 24 +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: mv a1, s3 +; RV32I-NEXT: jalr s6 +; RV32I-NEXT: bnez s2, .LBB11_2 +; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: addi s1, a0, 32 +; RV32I-NEXT: .LBB11_2: +; RV32I-NEXT: mv a0, s1 +; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: lw s7, 12(sp) +; RV32I-NEXT: lw s6, 16(sp) +; RV32I-NEXT: lw s5, 20(sp) +; RV32I-NEXT: lw s4, 24(sp) +; RV32I-NEXT: lw s3, 28(sp) +; RV32I-NEXT: lw s2, 32(sp) +; RV32I-NEXT: lw s1, 36(sp) +; RV32I-NEXT: lw s0, 40(sp) +; RV32I-NEXT: lw ra, 44(sp) +; RV32I-NEXT: addi sp, sp, 48 +; RV32I-NEXT: ret + %tmp = call i64 @llvm.cttz.i64(i64 %a, i1 true) + ret i64 %tmp +} + +define i32 @test_ctpop_i32(i32 %a) nounwind { +; RV32I-LABEL: test_ctpop_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, 349525 +; RV32I-NEXT: addi a1, a1, 1365 +; RV32I-NEXT: srli a2, a0, 1 +; RV32I-NEXT: and a1, a2, a1 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi a1, a1, 819 +; RV32I-NEXT: and a2, a0, a1 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: add a0, a2, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi a1, a1, -241 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi a1, a1, 257 +; RV32I-NEXT: lui a2, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call i32 @llvm.ctpop.i32(i32 %a) + ret i32 %1 +} diff --git a/test/CodeGen/RISCV/byval.ll b/test/CodeGen/RISCV/byval.ll new file mode 100644 index 0000000000000..c2760e981b711 --- /dev/null +++ b/test/CodeGen/RISCV/byval.ll @@ -0,0 +1,61 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +%struct.Foo = type { i32, i32, i32, i16, i8 } +@foo = global %struct.Foo { i32 1, i32 2, i32 3, i16 4, i8 5 }, align 4 + +define i32 @callee(%struct.Foo* byval %f) nounwind { +; RV32I-LABEL: callee: +; RV32I: # %bb.0: # %entry +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +entry: + %0 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i32 0, i32 0 + %1 = load i32, i32* %0, align 4 + ret i32 %1 +} + + +define void @caller() nounwind { +; RV32I-LABEL: caller: +; RV32I: # %bb.0: # %entry +; RV32I-NEXT: addi sp, sp, -32 +; RV32I-NEXT: sw ra, 28(sp) +; RV32I-NEXT: sw s0, 24(sp) +; RV32I-NEXT: addi s0, sp, 32 +; RV32I-NEXT: lui a0, %hi(foo+12) +; RV32I-NEXT: addi a0, a0, %lo(foo+12) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -12(s0) +; RV32I-NEXT: lui a0, %hi(foo+8) +; RV32I-NEXT: addi a0, a0, %lo(foo+8) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -16(s0) +; RV32I-NEXT: lui a0, %hi(foo+4) +; RV32I-NEXT: addi a0, a0, %lo(foo+4) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -20(s0) +; RV32I-NEXT: lui a0, %hi(foo) +; RV32I-NEXT: addi a0, a0, %lo(foo) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -24(s0) +; RV32I-NEXT: lui a0, %hi(callee) +; RV32I-NEXT: addi a1, a0, %lo(callee) +; RV32I-NEXT: addi a0, s0, -24 +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 24(sp) +; RV32I-NEXT: lw ra, 28(sp) +; RV32I-NEXT: addi sp, sp, 32 +; RV32I-NEXT: ret +entry: + %call = call i32 @callee(%struct.Foo* byval @foo) + ret void +} diff --git a/test/CodeGen/RISCV/calling-conv-sext-zext.ll b/test/CodeGen/RISCV/calling-conv-sext-zext.ll new file mode 100644 index 0000000000000..6babf9c6d46d3 --- /dev/null +++ b/test/CodeGen/RISCV/calling-conv-sext-zext.ll @@ -0,0 +1,497 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +define zeroext i8 @uint8_arg_to_uint8_ret(i8 zeroext %a) nounwind { +; RV32I-LABEL: uint8_arg_to_uint8_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i8 %a +} + +declare void @receive_uint8(i8 zeroext) + +define void @pass_uint8_as_uint8(i8 zeroext %a) nounwind { +; RV32I-LABEL: pass_uint8_as_uint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(receive_uint8) +; RV32I-NEXT: addi a1, a1, %lo(receive_uint8) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + call void @receive_uint8(i8 zeroext %a) + ret void +} + +declare zeroext i8 @return_uint8() + +define zeroext i8 @ret_callresult_uint8_as_uint8() nounwind { +; RV32I-LABEL: ret_callresult_uint8_as_uint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(return_uint8) +; RV32I-NEXT: addi a0, a0, %lo(return_uint8) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call zeroext i8 @return_uint8() + ret i8 %1 +} + +define signext i8 @uint8_arg_to_sint8_ret(i8 zeroext %a) nounwind { +; RV32I-LABEL: uint8_arg_to_sint8_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: srai a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i8 %a +} + +declare void @receive_sint8(i8 signext) + +define void @pass_uint8_as_sint8(i8 zeroext %a) nounwind { +; RV32I-LABEL: pass_uint8_as_sint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(receive_sint8) +; RV32I-NEXT: addi a1, a1, %lo(receive_sint8) +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: srai a0, a0, 24 +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + + call void @receive_sint8(i8 signext %a) + ret void +} + +define signext i8 @ret_callresult_uint8_as_sint8() nounwind { +; RV32I-LABEL: ret_callresult_uint8_as_sint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(return_uint8) +; RV32I-NEXT: addi a0, a0, %lo(return_uint8) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: srai a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call zeroext i8 @return_uint8() + ret i8 %1 +} + +define signext i32 @uint8_arg_to_anyint32_ret(i8 zeroext %a) nounwind { +; RV32I-LABEL: uint8_arg_to_anyint32_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i8 %a to i32 + ret i32 %1 +} + +declare void @receive_anyint32(i32 signext) + +define void @pass_uint8_as_anyint32(i8 zeroext %a) nounwind { +; RV32I-LABEL: pass_uint8_as_anyint32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(receive_anyint32) +; RV32I-NEXT: addi a1, a1, %lo(receive_anyint32) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i8 %a to i32 + call void @receive_anyint32(i32 signext %1) + ret void +} + +define signext i32 @ret_callresult_uint8_as_anyint32() nounwind { +; RV32I-LABEL: ret_callresult_uint8_as_anyint32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(return_uint8) +; RV32I-NEXT: addi a0, a0, %lo(return_uint8) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call zeroext i8 @return_uint8() + %2 = zext i8 %1 to i32 + ret i32 %2 +} + +define zeroext i8 @sint8_arg_to_uint8_ret(i8 signext %a) nounwind { +; RV32I-LABEL: sint8_arg_to_uint8_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i8 %a +} + +define void @pass_sint8_as_uint8(i8 signext %a) nounwind { +; RV32I-LABEL: pass_sint8_as_uint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: lui a1, %hi(receive_uint8) +; RV32I-NEXT: addi a1, a1, %lo(receive_uint8) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + call void @receive_uint8(i8 zeroext %a) + ret void +} + +declare signext i8 @return_sint8() + +define zeroext i8 @ret_callresult_sint8_as_uint8() nounwind { +; RV32I-LABEL: ret_callresult_sint8_as_uint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(return_sint8) +; RV32I-NEXT: addi a0, a0, %lo(return_sint8) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call signext i8 @return_sint8() + ret i8 %1 +} + +define signext i8 @sint8_arg_to_sint8_ret(i8 signext %a) nounwind { +; RV32I-LABEL: sint8_arg_to_sint8_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i8 %a +} + +define void @pass_sint8_as_sint8(i8 signext %a) nounwind { +; RV32I-LABEL: pass_sint8_as_sint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(receive_sint8) +; RV32I-NEXT: addi a1, a1, %lo(receive_sint8) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + call void @receive_sint8(i8 signext %a) + ret void +} + +define signext i8 @ret_callresult_sint8_as_sint8() nounwind { +; RV32I-LABEL: ret_callresult_sint8_as_sint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(return_sint8) +; RV32I-NEXT: addi a0, a0, %lo(return_sint8) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call signext i8 @return_sint8() + ret i8 %1 +} + +define signext i32 @sint8_arg_to_anyint32_ret(i8 signext %a) nounwind { +; RV32I-LABEL: sint8_arg_to_anyint32_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i8 %a to i32 + ret i32 %1 +} + +define void @pass_sint8_as_anyint32(i8 signext %a) nounwind { +; RV32I-LABEL: pass_sint8_as_anyint32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(receive_anyint32) +; RV32I-NEXT: addi a1, a1, %lo(receive_anyint32) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i8 %a to i32 + call void @receive_anyint32(i32 signext %1) + ret void +} + +define signext i32 @ret_callresult_sint8_as_anyint32() nounwind { +; RV32I-LABEL: ret_callresult_sint8_as_anyint32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(return_sint8) +; RV32I-NEXT: addi a0, a0, %lo(return_sint8) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call signext i8 @return_sint8() + %2 = sext i8 %1 to i32 + ret i32 %2 +} + +define zeroext i8 @anyint32_arg_to_uint8_ret(i32 signext %a) nounwind { +; RV32I-LABEL: anyint32_arg_to_uint8_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i32 %a to i8 + ret i8 %1 +} + +define void @pass_anyint32_as_uint8(i32 signext %a) nounwind { +; RV32I-LABEL: pass_anyint32_as_uint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: lui a1, %hi(receive_uint8) +; RV32I-NEXT: addi a1, a1, %lo(receive_uint8) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i32 %a to i8 + call void @receive_uint8(i8 zeroext %1) + ret void +} + +declare signext i32 @return_anyint32() + +define zeroext i8 @ret_callresult_anyint32_as_uint8() nounwind { +; RV32I-LABEL: ret_callresult_anyint32_as_uint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(return_anyint32) +; RV32I-NEXT: addi a0, a0, %lo(return_anyint32) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call signext i32 @return_anyint32() + %2 = trunc i32 %1 to i8 + ret i8 %2 +} + +define signext i8 @anyint32_arg_to_sint8_ret(i32 signext %a) nounwind { +; RV32I-LABEL: anyint32_arg_to_sint8_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: srai a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i32 %a to i8 + ret i8 %1 +} + +define void @pass_anyint32_as_sint8(i32 signext %a) nounwind { +; RV32I-LABEL: pass_anyint32_as_sint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(receive_sint8) +; RV32I-NEXT: addi a1, a1, %lo(receive_sint8) +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: srai a0, a0, 24 +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i32 %a to i8 + call void @receive_sint8(i8 signext %1) + ret void +} + +define signext i8 @ret_callresult_anyint32_as_sint8() nounwind { +; RV32I-LABEL: ret_callresult_anyint32_as_sint8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(return_anyint32) +; RV32I-NEXT: addi a0, a0, %lo(return_anyint32) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: srai a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call signext i32 @return_anyint32() + %2 = trunc i32 %1 to i8 + ret i8 %2 +} + +define signext i32 @anyint32_arg_to_anyint32_ret(i32 signext %a) nounwind { +; RV32I-LABEL: anyint32_arg_to_anyint32_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i32 %a +} + +define void @pass_anyint32_as_anyint32(i32 signext %a) nounwind { +; RV32I-LABEL: pass_anyint32_as_anyint32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(receive_anyint32) +; RV32I-NEXT: addi a1, a1, %lo(receive_anyint32) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + call void @receive_anyint32(i32 signext %a) + ret void +} + +define signext i32 @ret_callresult_anyint32_as_anyint32() nounwind { +; RV32I-LABEL: ret_callresult_anyint32_as_anyint32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(return_anyint32) +; RV32I-NEXT: addi a0, a0, %lo(return_anyint32) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call signext i32 @return_anyint32() + ret i32 %1 +} + diff --git a/test/CodeGen/RISCV/calling-conv.ll b/test/CodeGen/RISCV/calling-conv.ll new file mode 100644 index 0000000000000..7e1736576bd8c --- /dev/null +++ b/test/CodeGen/RISCV/calling-conv.ll @@ -0,0 +1,719 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +; As well as calling convention details, we check that ra and fp are +; consistently stored to fp-4 and fp-8. + +; Check that on RV32, i64 and double are passed in a pair of registers. Unlike +; the convention for varargs, this need not be an aligned pair. + +define i32 @callee_scalars(i32 %a, i64 %b, i32 %c, i32 %d, double %e) nounwind { +; RV32I-LABEL: callee_scalars: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -32 +; RV32I-NEXT: sw ra, 28(sp) +; RV32I-NEXT: sw s0, 24(sp) +; RV32I-NEXT: sw s1, 20(sp) +; RV32I-NEXT: sw s2, 16(sp) +; RV32I-NEXT: sw s3, 12(sp) +; RV32I-NEXT: sw s4, 8(sp) +; RV32I-NEXT: addi s0, sp, 32 +; RV32I-NEXT: mv s1, a4 +; RV32I-NEXT: mv s2, a3 +; RV32I-NEXT: mv s3, a1 +; RV32I-NEXT: mv s4, a0 +; RV32I-NEXT: lui a0, %hi(__fixdfsi) +; RV32I-NEXT: addi a2, a0, %lo(__fixdfsi) +; RV32I-NEXT: mv a0, a5 +; RV32I-NEXT: mv a1, a6 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: add a1, s4, s3 +; RV32I-NEXT: add a1, a1, s2 +; RV32I-NEXT: add a1, a1, s1 +; RV32I-NEXT: add a0, a1, a0 +; RV32I-NEXT: lw s4, 8(sp) +; RV32I-NEXT: lw s3, 12(sp) +; RV32I-NEXT: lw s2, 16(sp) +; RV32I-NEXT: lw s1, 20(sp) +; RV32I-NEXT: lw s0, 24(sp) +; RV32I-NEXT: lw ra, 28(sp) +; RV32I-NEXT: addi sp, sp, 32 +; RV32I-NEXT: ret + %b_trunc = trunc i64 %b to i32 + %e_fptosi = fptosi double %e to i32 + %1 = add i32 %a, %b_trunc + %2 = add i32 %1, %c + %3 = add i32 %2, %d + %4 = add i32 %3, %e_fptosi + ret i32 %4 +} + +define i32 @caller_scalars() nounwind { +; RV32I-LABEL: caller_scalars: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, 262464 +; RV32I-NEXT: mv a6, a0 +; RV32I-NEXT: lui a0, %hi(callee_scalars) +; RV32I-NEXT: addi a7, a0, %lo(callee_scalars) +; RV32I-NEXT: addi a0, zero, 1 +; RV32I-NEXT: addi a1, zero, 2 +; RV32I-NEXT: addi a3, zero, 3 +; RV32I-NEXT: addi a4, zero, 4 +; RV32I-NEXT: mv a2, zero +; RV32I-NEXT: mv a5, zero +; RV32I-NEXT: jalr a7 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call i32 @callee_scalars(i32 1, i64 2, i32 3, i32 4, double 5.000000e+00) + ret i32 %1 +} + +; Check that i128 and fp128 are passed indirectly + +define i32 @callee_large_scalars(i128 %a, fp128 %b) nounwind { +; RV32I-LABEL: callee_large_scalars: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a2, 12(a1) +; RV32I-NEXT: lw a3, 12(a0) +; RV32I-NEXT: xor a2, a3, a2 +; RV32I-NEXT: lw a3, 4(a1) +; RV32I-NEXT: lw a4, 4(a0) +; RV32I-NEXT: xor a3, a4, a3 +; RV32I-NEXT: or a2, a3, a2 +; RV32I-NEXT: lw a3, 8(a1) +; RV32I-NEXT: lw a4, 8(a0) +; RV32I-NEXT: xor a3, a4, a3 +; RV32I-NEXT: lw a1, 0(a1) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: or a0, a0, a3 +; RV32I-NEXT: or a0, a0, a2 +; RV32I-NEXT: xor a0, a0, zero +; RV32I-NEXT: seqz a0, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %b_bitcast = bitcast fp128 %b to i128 + %1 = icmp eq i128 %a, %b_bitcast + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @caller_large_scalars() nounwind { +; RV32I-LABEL: caller_large_scalars: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -48 +; RV32I-NEXT: sw ra, 44(sp) +; RV32I-NEXT: sw s0, 40(sp) +; RV32I-NEXT: addi s0, sp, 48 +; RV32I-NEXT: sw zero, -40(s0) +; RV32I-NEXT: sw zero, -44(s0) +; RV32I-NEXT: sw zero, -48(s0) +; RV32I-NEXT: sw zero, -12(s0) +; RV32I-NEXT: sw zero, -16(s0) +; RV32I-NEXT: sw zero, -20(s0) +; RV32I-NEXT: addi a0, zero, 1 +; RV32I-NEXT: sw a0, -24(s0) +; RV32I-NEXT: lui a0, 524272 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: sw a0, -36(s0) +; RV32I-NEXT: lui a0, %hi(callee_large_scalars) +; RV32I-NEXT: addi a2, a0, %lo(callee_large_scalars) +; RV32I-NEXT: addi a0, s0, -24 +; RV32I-NEXT: addi a1, s0, -48 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 40(sp) +; RV32I-NEXT: lw ra, 44(sp) +; RV32I-NEXT: addi sp, sp, 48 +; RV32I-NEXT: ret + %1 = call i32 @callee_large_scalars(i128 1, fp128 0xL00000000000000007FFF000000000000) + ret i32 %1 +} + +; Must keep define on a single line due to an update_llc_test_checks.py limitation +define i32 @callee_large_scalars_exhausted_regs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i128 %h, i32 %i, fp128 %j) nounwind { +; Check that arguments larger than 2*xlen are handled correctly when their +; address is passed on the stack rather than in memory +; RV32I-LABEL: callee_large_scalars_exhausted_regs: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a0, 4(s0) +; RV32I-NEXT: lw a1, 12(a0) +; RV32I-NEXT: lw a2, 12(a7) +; RV32I-NEXT: xor a1, a2, a1 +; RV32I-NEXT: lw a2, 4(a0) +; RV32I-NEXT: lw a3, 4(a7) +; RV32I-NEXT: xor a2, a3, a2 +; RV32I-NEXT: or a1, a2, a1 +; RV32I-NEXT: lw a2, 8(a0) +; RV32I-NEXT: lw a3, 8(a7) +; RV32I-NEXT: xor a2, a3, a2 +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: lw a3, 0(a7) +; RV32I-NEXT: xor a0, a3, a0 +; RV32I-NEXT: or a0, a0, a2 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: xor a0, a0, zero +; RV32I-NEXT: seqz a0, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %j_bitcast = bitcast fp128 %j to i128 + %1 = icmp eq i128 %h, %j_bitcast + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @caller_large_scalars_exhausted_regs() nounwind { +; RV32I-LABEL: caller_large_scalars_exhausted_regs: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -64 +; RV32I-NEXT: sw ra, 60(sp) +; RV32I-NEXT: sw s0, 56(sp) +; RV32I-NEXT: addi s0, sp, 64 +; RV32I-NEXT: addi a0, s0, -48 +; RV32I-NEXT: sw a0, 4(sp) +; RV32I-NEXT: addi a0, zero, 9 +; RV32I-NEXT: sw a0, 0(sp) +; RV32I-NEXT: sw zero, -40(s0) +; RV32I-NEXT: sw zero, -44(s0) +; RV32I-NEXT: sw zero, -48(s0) +; RV32I-NEXT: sw zero, -12(s0) +; RV32I-NEXT: sw zero, -16(s0) +; RV32I-NEXT: sw zero, -20(s0) +; RV32I-NEXT: addi a0, zero, 8 +; RV32I-NEXT: sw a0, -24(s0) +; RV32I-NEXT: lui a0, 524272 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: sw a0, -36(s0) +; RV32I-NEXT: lui a0, %hi(callee_large_scalars_exhausted_regs) +; RV32I-NEXT: addi t0, a0, %lo(callee_large_scalars_exhausted_regs) +; RV32I-NEXT: addi a0, zero, 1 +; RV32I-NEXT: addi a1, zero, 2 +; RV32I-NEXT: addi a2, zero, 3 +; RV32I-NEXT: addi a3, zero, 4 +; RV32I-NEXT: addi a4, zero, 5 +; RV32I-NEXT: addi a5, zero, 6 +; RV32I-NEXT: addi a6, zero, 7 +; RV32I-NEXT: addi a7, s0, -24 +; RV32I-NEXT: jalr t0 +; RV32I-NEXT: lw s0, 56(sp) +; RV32I-NEXT: lw ra, 60(sp) +; RV32I-NEXT: addi sp, sp, 64 +; RV32I-NEXT: ret + %1 = call i32 @callee_large_scalars_exhausted_regs( + i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i128 8, i32 9, + fp128 0xL00000000000000007FFF000000000000) + ret i32 %1 +} + +; Ensure that libcalls generated in the middle-end obey the calling convention + +define i32 @caller_mixed_scalar_libcalls(i64 %a) nounwind { +; RV32I-LABEL: caller_mixed_scalar_libcalls: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -32 +; RV32I-NEXT: sw ra, 28(sp) +; RV32I-NEXT: sw s0, 24(sp) +; RV32I-NEXT: addi s0, sp, 32 +; RV32I-NEXT: mv a2, a1 +; RV32I-NEXT: mv a1, a0 +; RV32I-NEXT: lui a0, %hi(__floatditf) +; RV32I-NEXT: addi a3, a0, %lo(__floatditf) +; RV32I-NEXT: addi a0, s0, -24 +; RV32I-NEXT: jalr a3 +; RV32I-NEXT: lw a0, -24(s0) +; RV32I-NEXT: lw s0, 24(sp) +; RV32I-NEXT: lw ra, 28(sp) +; RV32I-NEXT: addi sp, sp, 32 +; RV32I-NEXT: ret + %1 = sitofp i64 %a to fp128 + %2 = bitcast fp128 %1 to i128 + %3 = trunc i128 %2 to i32 + ret i32 %3 +} + +; Check that the stack is used once the GPRs are exhausted + +define i32 @callee_many_scalars(i8 %a, i16 %b, i32 %c, i64 %d, i32 %e, i32 %f, i64 %g, i32 %h) nounwind { +; RV32I-LABEL: callee_many_scalars: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw t0, 0(s0) +; RV32I-NEXT: xor a4, a4, t0 +; RV32I-NEXT: xor a3, a3, a7 +; RV32I-NEXT: or a3, a3, a4 +; RV32I-NEXT: xor a3, a3, zero +; RV32I-NEXT: lui a4, 16 +; RV32I-NEXT: addi a4, a4, -1 +; RV32I-NEXT: and a1, a1, a4 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: add a0, a0, a2 +; RV32I-NEXT: seqz a1, a3 +; RV32I-NEXT: add a0, a1, a0 +; RV32I-NEXT: add a0, a0, a5 +; RV32I-NEXT: add a0, a0, a6 +; RV32I-NEXT: lw a1, 4(s0) +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %a_ext = zext i8 %a to i32 + %b_ext = zext i16 %b to i32 + %1 = add i32 %a_ext, %b_ext + %2 = add i32 %1, %c + %3 = icmp eq i64 %d, %g + %4 = zext i1 %3 to i32 + %5 = add i32 %4, %2 + %6 = add i32 %5, %e + %7 = add i32 %6, %f + %8 = add i32 %7, %h + ret i32 %8 +} + +define i32 @caller_many_scalars() nounwind { +; RV32I-LABEL: caller_many_scalars: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -32 +; RV32I-NEXT: sw ra, 28(sp) +; RV32I-NEXT: sw s0, 24(sp) +; RV32I-NEXT: addi s0, sp, 32 +; RV32I-NEXT: addi a0, zero, 8 +; RV32I-NEXT: sw a0, 4(sp) +; RV32I-NEXT: sw zero, 0(sp) +; RV32I-NEXT: lui a0, %hi(callee_many_scalars) +; RV32I-NEXT: addi t0, a0, %lo(callee_many_scalars) +; RV32I-NEXT: addi a0, zero, 1 +; RV32I-NEXT: addi a1, zero, 2 +; RV32I-NEXT: addi a2, zero, 3 +; RV32I-NEXT: addi a3, zero, 4 +; RV32I-NEXT: addi a5, zero, 5 +; RV32I-NEXT: addi a6, zero, 6 +; RV32I-NEXT: addi a7, zero, 7 +; RV32I-NEXT: mv a4, zero +; RV32I-NEXT: jalr t0 +; RV32I-NEXT: lw s0, 24(sp) +; RV32I-NEXT: lw ra, 28(sp) +; RV32I-NEXT: addi sp, sp, 32 +; RV32I-NEXT: ret + %1 = call i32 @callee_many_scalars(i8 1, i16 2, i32 3, i64 4, i32 5, i32 6, i64 7, i32 8) + ret i32 %1 +} + +; Check passing of coerced integer arrays + +%struct.small = type { i32, i32* } + +define i32 @callee_small_coerced_struct([2 x i32] %a.coerce) nounwind { +; RV32I-LABEL: callee_small_coerced_struct: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: seqz a0, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = extractvalue [2 x i32] %a.coerce, 0 + %2 = extractvalue [2 x i32] %a.coerce, 1 + %3 = icmp eq i32 %1, %2 + %4 = zext i1 %3 to i32 + ret i32 %4 +} + +define i32 @caller_small_coerced_struct() nounwind { +; RV32I-LABEL: caller_small_coerced_struct: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(callee_small_coerced_struct) +; RV32I-NEXT: addi a2, a0, %lo(callee_small_coerced_struct) +; RV32I-NEXT: addi a0, zero, 1 +; RV32I-NEXT: addi a1, zero, 2 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call i32 @callee_small_coerced_struct([2 x i32] [i32 1, i32 2]) + ret i32 %1 +} + +; Check large struct arguments, which are passed byval + +%struct.large = type { i32, i32, i32, i32 } + +define i32 @callee_large_struct(%struct.large* byval align 4 %a) nounwind { +; RV32I-LABEL: callee_large_struct: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a1, 12(a0) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = getelementptr inbounds %struct.large, %struct.large* %a, i32 0, i32 0 + %2 = getelementptr inbounds %struct.large, %struct.large* %a, i32 0, i32 3 + %3 = load i32, i32* %1 + %4 = load i32, i32* %2 + %5 = add i32 %3, %4 + ret i32 %5 +} + +define i32 @caller_large_struct() nounwind { +; RV32I-LABEL: caller_large_struct: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -48 +; RV32I-NEXT: sw ra, 44(sp) +; RV32I-NEXT: sw s0, 40(sp) +; RV32I-NEXT: addi s0, sp, 48 +; RV32I-NEXT: addi a0, zero, 1 +; RV32I-NEXT: sw a0, -24(s0) +; RV32I-NEXT: sw a0, -40(s0) +; RV32I-NEXT: addi a0, zero, 2 +; RV32I-NEXT: sw a0, -20(s0) +; RV32I-NEXT: sw a0, -36(s0) +; RV32I-NEXT: addi a0, zero, 3 +; RV32I-NEXT: sw a0, -16(s0) +; RV32I-NEXT: sw a0, -32(s0) +; RV32I-NEXT: addi a0, zero, 4 +; RV32I-NEXT: sw a0, -12(s0) +; RV32I-NEXT: sw a0, -28(s0) +; RV32I-NEXT: lui a0, %hi(callee_large_struct) +; RV32I-NEXT: addi a1, a0, %lo(callee_large_struct) +; RV32I-NEXT: addi a0, s0, -40 +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 40(sp) +; RV32I-NEXT: lw ra, 44(sp) +; RV32I-NEXT: addi sp, sp, 48 +; RV32I-NEXT: ret + %ls = alloca %struct.large, align 4 + %1 = bitcast %struct.large* %ls to i8* + %a = getelementptr inbounds %struct.large, %struct.large* %ls, i32 0, i32 0 + store i32 1, i32* %a + %b = getelementptr inbounds %struct.large, %struct.large* %ls, i32 0, i32 1 + store i32 2, i32* %b + %c = getelementptr inbounds %struct.large, %struct.large* %ls, i32 0, i32 2 + store i32 3, i32* %c + %d = getelementptr inbounds %struct.large, %struct.large* %ls, i32 0, i32 3 + store i32 4, i32* %d + %2 = call i32 @callee_large_struct(%struct.large* byval align 4 %ls) + ret i32 %2 +} + +; Check 2x*xlen values are aligned appropriately when passed on the stack +; Must keep define on a single line due to an update_llc_test_checks.py limitation +define i32 @callee_aligned_stack(i32 %a, i32 %b, fp128 %c, i32 %d, i32 %e, i64 %f, i32 %g, i32 %h, double %i, i32 %j, [2 x i32] %k) nounwind { +; The double should be 8-byte aligned on the stack, but the two-element array +; should only be 4-byte aligned +; RV32I-LABEL: callee_aligned_stack: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a0, 0(a2) +; RV32I-NEXT: add a0, a0, a7 +; RV32I-NEXT: lw a1, 0(s0) +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw a1, 8(s0) +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw a1, 16(s0) +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw a1, 20(s0) +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = bitcast fp128 %c to i128 + %2 = trunc i128 %1 to i32 + %3 = add i32 %2, %g + %4 = add i32 %3, %h + %5 = bitcast double %i to i64 + %6 = trunc i64 %5 to i32 + %7 = add i32 %4, %6 + %8 = add i32 %7, %j + %9 = extractvalue [2 x i32] %k, 0 + %10 = add i32 %8, %9 + ret i32 %10 +} + +define void @caller_aligned_stack() nounwind { +; The double should be 8-byte aligned on the stack, but the two-element array +; should only be 4-byte aligned +; RV32I-LABEL: caller_aligned_stack: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -64 +; RV32I-NEXT: sw ra, 60(sp) +; RV32I-NEXT: sw s0, 56(sp) +; RV32I-NEXT: addi s0, sp, 64 +; RV32I-NEXT: addi a0, zero, 18 +; RV32I-NEXT: sw a0, 24(sp) +; RV32I-NEXT: addi a0, zero, 17 +; RV32I-NEXT: sw a0, 20(sp) +; RV32I-NEXT: addi a0, zero, 16 +; RV32I-NEXT: sw a0, 16(sp) +; RV32I-NEXT: lui a0, 262236 +; RV32I-NEXT: addi a0, a0, 655 +; RV32I-NEXT: sw a0, 12(sp) +; RV32I-NEXT: lui a0, 377487 +; RV32I-NEXT: addi a0, a0, 1475 +; RV32I-NEXT: sw a0, 8(sp) +; RV32I-NEXT: addi a0, zero, 15 +; RV32I-NEXT: sw a0, 0(sp) +; RV32I-NEXT: lui a0, 262153 +; RV32I-NEXT: addi a0, a0, 491 +; RV32I-NEXT: sw a0, -20(s0) +; RV32I-NEXT: lui a0, 545260 +; RV32I-NEXT: addi a0, a0, -1967 +; RV32I-NEXT: sw a0, -24(s0) +; RV32I-NEXT: lui a0, 964690 +; RV32I-NEXT: addi a0, a0, -328 +; RV32I-NEXT: sw a0, -28(s0) +; RV32I-NEXT: lui a0, 335544 +; RV32I-NEXT: addi a0, a0, 1311 +; RV32I-NEXT: sw a0, -32(s0) +; RV32I-NEXT: lui a0, 688509 +; RV32I-NEXT: addi a5, a0, -2048 +; RV32I-NEXT: lui a0, %hi(callee_aligned_stack) +; RV32I-NEXT: addi t0, a0, %lo(callee_aligned_stack) +; RV32I-NEXT: addi a0, zero, 1 +; RV32I-NEXT: addi a1, zero, 11 +; RV32I-NEXT: addi a2, s0, -32 +; RV32I-NEXT: addi a3, zero, 12 +; RV32I-NEXT: addi a4, zero, 13 +; RV32I-NEXT: addi a6, zero, 4 +; RV32I-NEXT: addi a7, zero, 14 +; RV32I-NEXT: jalr t0 +; RV32I-NEXT: lw s0, 56(sp) +; RV32I-NEXT: lw ra, 60(sp) +; RV32I-NEXT: addi sp, sp, 64 +; RV32I-NEXT: ret + %1 = call i32 @callee_aligned_stack(i32 1, i32 11, + fp128 0xLEB851EB851EB851F400091EB851EB851, i32 12, i32 13, + i64 20000000000, i32 14, i32 15, double 2.720000e+00, i32 16, + [2 x i32] [i32 17, i32 18]) + ret void +} + +; Check return of 2x xlen scalars + +define i64 @callee_small_scalar_ret() nounwind { +; RV32I-LABEL: callee_small_scalar_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, 466866 +; RV32I-NEXT: addi a0, a0, 1677 +; RV32I-NEXT: addi a1, zero, 287 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i64 1234567898765 +} + +define i32 @caller_small_scalar_ret() nounwind { +; RV32I-LABEL: caller_small_scalar_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(callee_small_scalar_ret) +; RV32I-NEXT: addi a0, a0, %lo(callee_small_scalar_ret) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: lui a2, 56 +; RV32I-NEXT: addi a2, a2, 580 +; RV32I-NEXT: xor a1, a1, a2 +; RV32I-NEXT: lui a2, 200614 +; RV32I-NEXT: addi a2, a2, 647 +; RV32I-NEXT: xor a0, a0, a2 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: xor a0, a0, zero +; RV32I-NEXT: seqz a0, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call i64 @callee_small_scalar_ret() + %2 = icmp eq i64 987654321234567, %1 + %3 = zext i1 %2 to i32 + ret i32 %3 +} + +; Check return of 2x xlen structs + +define %struct.small @callee_small_struct_ret() nounwind { +; RV32I-LABEL: callee_small_struct_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a0, zero, 1 +; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret %struct.small { i32 1, i32* null } +} + +define i32 @caller_small_struct_ret() nounwind { +; RV32I-LABEL: caller_small_struct_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(callee_small_struct_ret) +; RV32I-NEXT: addi a0, a0, %lo(callee_small_struct_ret) +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call %struct.small @callee_small_struct_ret() + %2 = extractvalue %struct.small %1, 0 + %3 = extractvalue %struct.small %1, 1 + %4 = ptrtoint i32* %3 to i32 + %5 = add i32 %2, %4 + ret i32 %5 +} + +; Check return of >2x xlen scalars + +define fp128 @callee_large_scalar_ret() nounwind { +; RV32I-LABEL: callee_large_scalar_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, 524272 +; RV32I-NEXT: mv a1, a1 +; RV32I-NEXT: sw a1, 12(a0) +; RV32I-NEXT: sw zero, 8(a0) +; RV32I-NEXT: sw zero, 4(a0) +; RV32I-NEXT: sw zero, 0(a0) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret fp128 0xL00000000000000007FFF000000000000 +} + +define void @caller_large_scalar_ret() nounwind { +; RV32I-LABEL: caller_large_scalar_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -32 +; RV32I-NEXT: sw ra, 28(sp) +; RV32I-NEXT: sw s0, 24(sp) +; RV32I-NEXT: addi s0, sp, 32 +; RV32I-NEXT: lui a0, %hi(callee_large_scalar_ret) +; RV32I-NEXT: addi a1, a0, %lo(callee_large_scalar_ret) +; RV32I-NEXT: addi a0, s0, -32 +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 24(sp) +; RV32I-NEXT: lw ra, 28(sp) +; RV32I-NEXT: addi sp, sp, 32 +; RV32I-NEXT: ret + %1 = call fp128 @callee_large_scalar_ret() + ret void +} + +; Check return of >2x xlen structs + +define void @callee_large_struct_ret(%struct.large* noalias sret %agg.result) nounwind { +; RV32I-LABEL: callee_large_struct_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a1, zero, 2 +; RV32I-NEXT: sw a1, 4(a0) +; RV32I-NEXT: addi a1, zero, 1 +; RV32I-NEXT: sw a1, 0(a0) +; RV32I-NEXT: addi a1, zero, 3 +; RV32I-NEXT: sw a1, 8(a0) +; RV32I-NEXT: addi a1, zero, 4 +; RV32I-NEXT: sw a1, 12(a0) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %a = getelementptr inbounds %struct.large, %struct.large* %agg.result, i32 0, i32 0 + store i32 1, i32* %a, align 4 + %b = getelementptr inbounds %struct.large, %struct.large* %agg.result, i32 0, i32 1 + store i32 2, i32* %b, align 4 + %c = getelementptr inbounds %struct.large, %struct.large* %agg.result, i32 0, i32 2 + store i32 3, i32* %c, align 4 + %d = getelementptr inbounds %struct.large, %struct.large* %agg.result, i32 0, i32 3 + store i32 4, i32* %d, align 4 + ret void +} + +define i32 @caller_large_struct_ret() nounwind { +; RV32I-LABEL: caller_large_struct_ret: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -32 +; RV32I-NEXT: sw ra, 28(sp) +; RV32I-NEXT: sw s0, 24(sp) +; RV32I-NEXT: addi s0, sp, 32 +; RV32I-NEXT: lui a0, %hi(callee_large_struct_ret) +; RV32I-NEXT: addi a1, a0, %lo(callee_large_struct_ret) +; RV32I-NEXT: addi a0, s0, -24 +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw a0, -12(s0) +; RV32I-NEXT: lw a1, -24(s0) +; RV32I-NEXT: add a0, a1, a0 +; RV32I-NEXT: lw s0, 24(sp) +; RV32I-NEXT: lw ra, 28(sp) +; RV32I-NEXT: addi sp, sp, 32 +; RV32I-NEXT: ret + %1 = alloca %struct.large + call void @callee_large_struct_ret(%struct.large* sret %1) + %2 = getelementptr inbounds %struct.large, %struct.large* %1, i32 0, i32 0 + %3 = load i32, i32* %2 + %4 = getelementptr inbounds %struct.large, %struct.large* %1, i32 0, i32 3 + %5 = load i32, i32* %4 + %6 = add i32 %3, %5 + ret i32 %6 +} diff --git a/test/CodeGen/RISCV/calls.ll b/test/CodeGen/RISCV/calls.ll new file mode 100644 index 0000000000000..05418da48a92a --- /dev/null +++ b/test/CodeGen/RISCV/calls.ll @@ -0,0 +1,197 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +declare i32 @external_function(i32) + +define i32 @test_call_external(i32 %a) nounwind { +; RV32I-LABEL: test_call_external: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(external_function) +; RV32I-NEXT: addi a1, a1, %lo(external_function) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call i32 @external_function(i32 %a) + ret i32 %1 +} + +define i32 @defined_function(i32 %a) nounwind { +; RV32I-LABEL: defined_function: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = add i32 %a, 1 + ret i32 %1 +} + +define i32 @test_call_defined(i32 %a) nounwind { +; RV32I-LABEL: test_call_defined: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(defined_function) +; RV32I-NEXT: addi a1, a1, %lo(defined_function) +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call i32 @defined_function(i32 %a) + ret i32 %1 +} + +define i32 @test_call_indirect(i32 (i32)* %a, i32 %b) nounwind { +; RV32I-LABEL: test_call_indirect: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: mv a2, a0 +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call i32 %a(i32 %b) + ret i32 %1 +} + +; Ensure that calls to fastcc functions aren't rejected. Such calls may be +; introduced when compiling with optimisation. + +define fastcc i32 @fastcc_function(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: fastcc_function: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = add i32 %a, %b + ret i32 %1 +} + +define i32 @test_call_fastcc(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: test_call_fastcc: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: sw s1, 4(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: mv s1, a0 +; RV32I-NEXT: lui a0, %hi(fastcc_function) +; RV32I-NEXT: addi a2, a0, %lo(fastcc_function) +; RV32I-NEXT: mv a0, s1 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: mv a0, s1 +; RV32I-NEXT: lw s1, 4(sp) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = call fastcc i32 @fastcc_function(i32 %a, i32 %b) + ret i32 %a +} + +declare i32 @external_many_args(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) nounwind + +define i32 @test_call_external_many_args(i32 %a) nounwind { +; RV32I-LABEL: test_call_external_many_args: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -32 +; RV32I-NEXT: sw ra, 28(sp) +; RV32I-NEXT: sw s0, 24(sp) +; RV32I-NEXT: sw s1, 20(sp) +; RV32I-NEXT: addi s0, sp, 32 +; RV32I-NEXT: mv s1, a0 +; RV32I-NEXT: sw s1, 4(sp) +; RV32I-NEXT: sw s1, 0(sp) +; RV32I-NEXT: lui a0, %hi(external_many_args) +; RV32I-NEXT: addi t0, a0, %lo(external_many_args) +; RV32I-NEXT: mv a0, s1 +; RV32I-NEXT: mv a1, s1 +; RV32I-NEXT: mv a2, s1 +; RV32I-NEXT: mv a3, s1 +; RV32I-NEXT: mv a4, s1 +; RV32I-NEXT: mv a5, s1 +; RV32I-NEXT: mv a6, s1 +; RV32I-NEXT: mv a7, s1 +; RV32I-NEXT: jalr t0 +; RV32I-NEXT: mv a0, s1 +; RV32I-NEXT: lw s1, 20(sp) +; RV32I-NEXT: lw s0, 24(sp) +; RV32I-NEXT: lw ra, 28(sp) +; RV32I-NEXT: addi sp, sp, 32 +; RV32I-NEXT: ret + %1 = call i32 @external_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, + i32 %a, i32 %a, i32 %a, i32 %a, i32 %a) + ret i32 %a +} + +define i32 @defined_many_args(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 %j) nounwind { +; RV32I-LABEL: defined_many_args: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a0, 4(s0) +; RV32I-NEXT: addi a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %added = add i32 %j, 1 + ret i32 %added +} + +define i32 @test_call_defined_many_args(i32 %a) nounwind { +; RV32I-LABEL: test_call_defined_many_args: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -32 +; RV32I-NEXT: sw ra, 28(sp) +; RV32I-NEXT: sw s0, 24(sp) +; RV32I-NEXT: addi s0, sp, 32 +; RV32I-NEXT: sw a0, 4(sp) +; RV32I-NEXT: sw a0, 0(sp) +; RV32I-NEXT: lui a1, %hi(defined_many_args) +; RV32I-NEXT: addi t0, a1, %lo(defined_many_args) +; RV32I-NEXT: mv a1, a0 +; RV32I-NEXT: mv a2, a0 +; RV32I-NEXT: mv a3, a0 +; RV32I-NEXT: mv a4, a0 +; RV32I-NEXT: mv a5, a0 +; RV32I-NEXT: mv a6, a0 +; RV32I-NEXT: mv a7, a0 +; RV32I-NEXT: jalr t0 +; RV32I-NEXT: lw s0, 24(sp) +; RV32I-NEXT: lw ra, 28(sp) +; RV32I-NEXT: addi sp, sp, 32 +; RV32I-NEXT: ret + %1 = call i32 @defined_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, + i32 %a, i32 %a, i32 %a, i32 %a, i32 %a) + ret i32 %1 +} diff --git a/test/CodeGen/RISCV/div.ll b/test/CodeGen/RISCV/div.ll new file mode 100644 index 0000000000000..570f4520b5d97 --- /dev/null +++ b/test/CodeGen/RISCV/div.ll @@ -0,0 +1,188 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +define i32 @udiv(i32 %a, i32 %b) { +; RV32I-LABEL: udiv: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a2, %hi(__udivsi3) +; RV32I-NEXT: addi a2, a2, %lo(__udivsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = udiv i32 %a, %b + ret i32 %1 +} + +define i32 @udiv_constant(i32 %a) { +; RV32I-LABEL: udiv_constant: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(__udivsi3) +; RV32I-NEXT: addi a2, a1, %lo(__udivsi3) +; RV32I-NEXT: addi a1, zero, 5 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = udiv i32 %a, 5 + ret i32 %1 +} + +define i32 @udiv_pow2(i32 %a) { +; RV32I-LABEL: udiv_pow2: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: srli a0, a0, 3 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = udiv i32 %a, 8 + ret i32 %1 +} + +define i64 @udiv64(i64 %a, i64 %b) { +; RV32I-LABEL: udiv64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a4, %hi(__udivdi3) +; RV32I-NEXT: addi a4, a4, %lo(__udivdi3) +; RV32I-NEXT: jalr a4 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = udiv i64 %a, %b + ret i64 %1 +} + +define i64 @udiv64_constant(i64 %a) { +; RV32I-LABEL: udiv64_constant: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a2, %hi(__udivdi3) +; RV32I-NEXT: addi a4, a2, %lo(__udivdi3) +; RV32I-NEXT: addi a2, zero, 5 +; RV32I-NEXT: mv a3, zero +; RV32I-NEXT: jalr a4 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = udiv i64 %a, 5 + ret i64 %1 +} + +define i32 @sdiv(i32 %a, i32 %b) { +; RV32I-LABEL: sdiv: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a2, %hi(__divsi3) +; RV32I-NEXT: addi a2, a2, %lo(__divsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sdiv i32 %a, %b + ret i32 %1 +} + +define i32 @sdiv_constant(i32 %a) { +; RV32I-LABEL: sdiv_constant: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(__divsi3) +; RV32I-NEXT: addi a2, a1, %lo(__divsi3) +; RV32I-NEXT: addi a1, zero, 5 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sdiv i32 %a, 5 + ret i32 %1 +} + +define i32 @sdiv_pow2(i32 %a) { +; RV32I-LABEL: sdiv_pow2: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: srai a1, a0, 31 +; RV32I-NEXT: srli a1, a1, 29 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: srai a0, a0, 3 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sdiv i32 %a, 8 + ret i32 %1 +} + +define i64 @sdiv64(i64 %a, i64 %b) { +; RV32I-LABEL: sdiv64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a4, %hi(__divdi3) +; RV32I-NEXT: addi a4, a4, %lo(__divdi3) +; RV32I-NEXT: jalr a4 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sdiv i64 %a, %b + ret i64 %1 +} + +define i64 @sdiv64_constant(i64 %a) { +; RV32I-LABEL: sdiv64_constant: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a2, %hi(__divdi3) +; RV32I-NEXT: addi a4, a2, %lo(__divdi3) +; RV32I-NEXT: addi a2, zero, 5 +; RV32I-NEXT: mv a3, zero +; RV32I-NEXT: jalr a4 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sdiv i64 %a, 5 + ret i64 %1 +} diff --git a/test/CodeGen/RISCV/fp128.ll b/test/CodeGen/RISCV/fp128.ll new file mode 100644 index 0000000000000..5afb5afe07e8c --- /dev/null +++ b/test/CodeGen/RISCV/fp128.ll @@ -0,0 +1,134 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +@x = local_unnamed_addr global fp128 0xL00000000000000007FFF000000000000, align 16 +@y = local_unnamed_addr global fp128 0xL00000000000000007FFF000000000000, align 16 + +; Besides anything else, these tests help verify that libcall ABI lowering +; works correctly + +define i32 @test_load_and_cmp() nounwind { +; RV32I-LABEL: test_load_and_cmp: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -48 +; RV32I-NEXT: sw ra, 44(sp) +; RV32I-NEXT: sw s0, 40(sp) +; RV32I-NEXT: addi s0, sp, 48 +; RV32I-NEXT: lui a0, %hi(y+12) +; RV32I-NEXT: addi a0, a0, %lo(y+12) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -28(s0) +; RV32I-NEXT: lui a0, %hi(y+8) +; RV32I-NEXT: addi a0, a0, %lo(y+8) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -32(s0) +; RV32I-NEXT: lui a0, %hi(y+4) +; RV32I-NEXT: addi a0, a0, %lo(y+4) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -36(s0) +; RV32I-NEXT: lui a0, %hi(y) +; RV32I-NEXT: addi a0, a0, %lo(y) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -40(s0) +; RV32I-NEXT: lui a0, %hi(x+12) +; RV32I-NEXT: addi a0, a0, %lo(x+12) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -12(s0) +; RV32I-NEXT: lui a0, %hi(x+8) +; RV32I-NEXT: addi a0, a0, %lo(x+8) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -16(s0) +; RV32I-NEXT: lui a0, %hi(x+4) +; RV32I-NEXT: addi a0, a0, %lo(x+4) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -20(s0) +; RV32I-NEXT: lui a0, %hi(x) +; RV32I-NEXT: addi a0, a0, %lo(x) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -24(s0) +; RV32I-NEXT: lui a0, %hi(__netf2) +; RV32I-NEXT: addi a2, a0, %lo(__netf2) +; RV32I-NEXT: addi a0, s0, -24 +; RV32I-NEXT: addi a1, s0, -40 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: xor a0, a0, zero +; RV32I-NEXT: snez a0, a0 +; RV32I-NEXT: lw s0, 40(sp) +; RV32I-NEXT: lw ra, 44(sp) +; RV32I-NEXT: addi sp, sp, 48 +; RV32I-NEXT: ret + %1 = load fp128, fp128* @x, align 16 + %2 = load fp128, fp128* @y, align 16 + %cmp = fcmp une fp128 %1, %2 + %3 = zext i1 %cmp to i32 + ret i32 %3 +} + +define i32 @test_add_and_fptosi() nounwind { +; RV32I-LABEL: test_add_and_fptosi: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -80 +; RV32I-NEXT: sw ra, 76(sp) +; RV32I-NEXT: sw s0, 72(sp) +; RV32I-NEXT: addi s0, sp, 80 +; RV32I-NEXT: lui a0, %hi(y+12) +; RV32I-NEXT: addi a0, a0, %lo(y+12) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -44(s0) +; RV32I-NEXT: lui a0, %hi(y+8) +; RV32I-NEXT: addi a0, a0, %lo(y+8) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -48(s0) +; RV32I-NEXT: lui a0, %hi(y+4) +; RV32I-NEXT: addi a0, a0, %lo(y+4) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -52(s0) +; RV32I-NEXT: lui a0, %hi(y) +; RV32I-NEXT: addi a0, a0, %lo(y) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -56(s0) +; RV32I-NEXT: lui a0, %hi(x+12) +; RV32I-NEXT: addi a0, a0, %lo(x+12) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -28(s0) +; RV32I-NEXT: lui a0, %hi(x+8) +; RV32I-NEXT: addi a0, a0, %lo(x+8) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -32(s0) +; RV32I-NEXT: lui a0, %hi(x+4) +; RV32I-NEXT: addi a0, a0, %lo(x+4) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -36(s0) +; RV32I-NEXT: lui a0, %hi(x) +; RV32I-NEXT: addi a0, a0, %lo(x) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: sw a0, -40(s0) +; RV32I-NEXT: lui a0, %hi(__addtf3) +; RV32I-NEXT: addi a3, a0, %lo(__addtf3) +; RV32I-NEXT: addi a0, s0, -24 +; RV32I-NEXT: addi a1, s0, -40 +; RV32I-NEXT: addi a2, s0, -56 +; RV32I-NEXT: jalr a3 +; RV32I-NEXT: lw a0, -12(s0) +; RV32I-NEXT: sw a0, -60(s0) +; RV32I-NEXT: lw a0, -16(s0) +; RV32I-NEXT: sw a0, -64(s0) +; RV32I-NEXT: lw a0, -20(s0) +; RV32I-NEXT: sw a0, -68(s0) +; RV32I-NEXT: lw a0, -24(s0) +; RV32I-NEXT: sw a0, -72(s0) +; RV32I-NEXT: lui a0, %hi(__fixtfsi) +; RV32I-NEXT: addi a1, a0, %lo(__fixtfsi) +; RV32I-NEXT: addi a0, s0, -72 +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: lw s0, 72(sp) +; RV32I-NEXT: lw ra, 76(sp) +; RV32I-NEXT: addi sp, sp, 80 +; RV32I-NEXT: ret + %1 = load fp128, fp128* @x, align 16 + %2 = load fp128, fp128* @y, align 16 + %3 = fadd fp128 %1, %2 + %4 = fptosi fp128 %3 to i32 + ret i32 %4 +} diff --git a/test/CodeGen/RISCV/frame.ll b/test/CodeGen/RISCV/frame.ll new file mode 100644 index 0000000000000..0c9f59fd302c9 --- /dev/null +++ b/test/CodeGen/RISCV/frame.ll @@ -0,0 +1,38 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +%struct.key_t = type { i32, [16 x i8] } + +define i32 @test() nounwind { +; RV32I-LABEL: test: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -32 +; RV32I-NEXT: sw ra, 28(sp) +; RV32I-NEXT: sw s0, 24(sp) +; RV32I-NEXT: addi s0, sp, 32 +; RV32I-NEXT: sw zero, -16(s0) +; RV32I-NEXT: sw zero, -20(s0) +; RV32I-NEXT: sw zero, -24(s0) +; RV32I-NEXT: sw zero, -28(s0) +; RV32I-NEXT: sw zero, -32(s0) +; RV32I-NEXT: lui a0, %hi(test1) +; RV32I-NEXT: addi a1, a0, %lo(test1) +; RV32I-NEXT: addi a0, s0, -28 +; RV32I-NEXT: jalr a1 +; RV32I-NEXT: mv a0, zero +; RV32I-NEXT: lw s0, 24(sp) +; RV32I-NEXT: lw ra, 28(sp) +; RV32I-NEXT: addi sp, sp, 32 +; RV32I-NEXT: ret + %key = alloca %struct.key_t, align 4 + %1 = bitcast %struct.key_t* %key to i8* + call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 20, i32 4, i1 false) + %2 = getelementptr inbounds %struct.key_t, %struct.key_t* %key, i64 0, i32 1, i64 0 + call void @test1(i8* %2) #3 + ret i32 0 +} + +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) + +declare void @test1(i8*) diff --git a/test/CodeGen/RISCV/i32-icmp.ll b/test/CodeGen/RISCV/i32-icmp.ll new file mode 100644 index 0000000000000..112d31b124252 --- /dev/null +++ b/test/CodeGen/RISCV/i32-icmp.ll @@ -0,0 +1,184 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +; TODO: check the generated instructions for the equivalent of seqz, snez, +; sltz, sgtz map to something simple + +define i32 @icmp_eq(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_eq: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: seqz a0, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp eq i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @icmp_ne(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_ne: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: snez a0, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp ne i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @icmp_ugt(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_ugt: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sltu a0, a1, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp ugt i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @icmp_uge(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_uge: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sltu a0, a0, a1 +; RV32I-NEXT: xori a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp uge i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @icmp_ult(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_ult: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sltu a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp ult i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @icmp_ule(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_ule: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sltu a0, a1, a0 +; RV32I-NEXT: xori a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp ule i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @icmp_sgt(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_sgt: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slt a0, a1, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp sgt i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @icmp_sge(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_sge: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slt a0, a0, a1 +; RV32I-NEXT: xori a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp sge i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @icmp_slt(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_slt: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slt a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp slt i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +define i32 @icmp_sle(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: icmp_sle: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slt a0, a1, a0 +; RV32I-NEXT: xori a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp sle i32 %a, %b + %2 = zext i1 %1 to i32 + ret i32 %2 +} + +; TODO: check variants with an immediate? diff --git a/test/CodeGen/RISCV/imm.ll b/test/CodeGen/RISCV/imm.ll new file mode 100644 index 0000000000000..6741c3cb04a5c --- /dev/null +++ b/test/CodeGen/RISCV/imm.ll @@ -0,0 +1,82 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +; Materializing constants + +define i32 @zero() nounwind { +; RV32I-LABEL: zero: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: mv a0, zero +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i32 0 +} + +define i32 @pos_small() nounwind { +; RV32I-LABEL: pos_small: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a0, zero, 2047 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i32 2047 +} + +define i32 @neg_small() nounwind { +; RV32I-LABEL: neg_small: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a0, zero, -2048 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i32 -2048 +} + +define i32 @pos_i32() nounwind { +; RV32I-LABEL: pos_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, 423811 +; RV32I-NEXT: addi a0, a0, -1297 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i32 1735928559 +} + +define i32 @neg_i32() nounwind { +; RV32I-LABEL: neg_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, 912092 +; RV32I-NEXT: addi a0, a0, -273 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ret i32 -559038737 +} diff --git a/test/CodeGen/RISCV/indirectbr.ll b/test/CodeGen/RISCV/indirectbr.ll new file mode 100644 index 0000000000000..47ce5c18c32d2 --- /dev/null +++ b/test/CodeGen/RISCV/indirectbr.ll @@ -0,0 +1,46 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +define i32 @indirectbr(i8* %target) nounwind { +; RV32I-LABEL: indirectbr: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: jr a0 +; RV32I-NEXT: .LBB0_1: # %ret +; RV32I-NEXT: mv a0, zero +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + indirectbr i8* %target, [label %test_label] +test_label: + br label %ret +ret: + ret i32 0 +} + +define i32 @indirectbr_with_offset(i8* %a) nounwind { +; RV32I-LABEL: indirectbr_with_offset: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: jalr zero, a0, 1380 +; RV32I-NEXT: .LBB1_1: # %ret +; RV32I-NEXT: mv a0, zero +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %target = getelementptr inbounds i8, i8* %a, i32 1380 + indirectbr i8* %target, [label %test_label] +test_label: + br label %ret +ret: + ret i32 0 +} diff --git a/test/CodeGen/RISCV/jumptable.ll b/test/CodeGen/RISCV/jumptable.ll new file mode 100644 index 0000000000000..8240f43805cbd --- /dev/null +++ b/test/CodeGen/RISCV/jumptable.ll @@ -0,0 +1,70 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +define void @jt(i32 %in, i32* %out) { +; RV32I-LABEL: jt: +; RV32I: # %bb.0: # %entry +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a2, zero, 2 +; RV32I-NEXT: blt a2, a0, .LBB0_3 +; RV32I-NEXT: j .LBB0_1 +; RV32I-NEXT: .LBB0_1: # %entry +; RV32I-NEXT: addi a3, zero, 1 +; RV32I-NEXT: beq a0, a3, .LBB0_5 +; RV32I-NEXT: j .LBB0_2 +; RV32I-NEXT: .LBB0_2: # %entry +; RV32I-NEXT: beq a0, a2, .LBB0_6 +; RV32I-NEXT: j .LBB0_9 +; RV32I-NEXT: .LBB0_6: # %bb2 +; RV32I-NEXT: addi a0, zero, 3 +; RV32I-NEXT: sw a0, 0(a1) +; RV32I-NEXT: j .LBB0_9 +; RV32I-NEXT: .LBB0_3: # %entry +; RV32I-NEXT: addi a3, zero, 3 +; RV32I-NEXT: beq a0, a3, .LBB0_7 +; RV32I-NEXT: j .LBB0_4 +; RV32I-NEXT: .LBB0_4: # %entry +; RV32I-NEXT: addi a2, zero, 4 +; RV32I-NEXT: beq a0, a2, .LBB0_8 +; RV32I-NEXT: j .LBB0_9 +; RV32I-NEXT: .LBB0_8: # %bb4 +; RV32I-NEXT: addi a0, zero, 1 +; RV32I-NEXT: sw a0, 0(a1) +; RV32I-NEXT: .LBB0_9: # %exit +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; RV32I-NEXT: .LBB0_5: # %bb1 +; RV32I-NEXT: addi a0, zero, 4 +; RV32I-NEXT: sw a0, 0(a1) +; RV32I-NEXT: j .LBB0_9 +; RV32I-NEXT: .LBB0_7: # %bb3 +; RV32I-NEXT: sw a2, 0(a1) +; RV32I-NEXT: j .LBB0_9 +entry: + switch i32 %in, label %exit [ + i32 1, label %bb1 + i32 2, label %bb2 + i32 3, label %bb3 + i32 4, label %bb4 + ] +bb1: + store i32 4, i32* %out + br label %exit +bb2: + store i32 3, i32* %out + br label %exit +bb3: + store i32 2, i32* %out + br label %exit +bb4: + store i32 1, i32* %out + br label %exit +exit: + ret void +} diff --git a/test/CodeGen/RISCV/lit.local.cfg b/test/CodeGen/RISCV/lit.local.cfg new file mode 100644 index 0000000000000..c63820126f8ca --- /dev/null +++ b/test/CodeGen/RISCV/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'RISCV' in config.root.targets: + config.unsupported = True diff --git a/test/CodeGen/RISCV/mem.ll b/test/CodeGen/RISCV/mem.ll new file mode 100644 index 0000000000000..4875ce2f299cc --- /dev/null +++ b/test/CodeGen/RISCV/mem.ll @@ -0,0 +1,286 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +; Check indexed and unindexed, sext, zext and anyext loads + +define i32 @lb(i8 *%a) nounwind { +; RV32I-LABEL: lb: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lb a1, 0(a0) +; RV32I-NEXT: lb a0, 1(a0) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = getelementptr i8, i8* %a, i32 1 + %2 = load i8, i8* %1 + %3 = sext i8 %2 to i32 + ; the unused load will produce an anyext for selection + %4 = load volatile i8, i8* %a + ret i32 %3 +} + +define i32 @lh(i16 *%a) nounwind { +; RV32I-LABEL: lh: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lh a1, 0(a0) +; RV32I-NEXT: lh a0, 4(a0) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = getelementptr i16, i16* %a, i32 2 + %2 = load i16, i16* %1 + %3 = sext i16 %2 to i32 + ; the unused load will produce an anyext for selection + %4 = load volatile i16, i16* %a + ret i32 %3 +} + +define i32 @lw(i32 *%a) nounwind { +; RV32I-LABEL: lw: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a1, 0(a0) +; RV32I-NEXT: lw a0, 12(a0) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = getelementptr i32, i32* %a, i32 3 + %2 = load i32, i32* %1 + %3 = load volatile i32, i32* %a + ret i32 %2 +} + +define i32 @lbu(i8 *%a) nounwind { +; RV32I-LABEL: lbu: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lbu a1, 0(a0) +; RV32I-NEXT: lbu a0, 4(a0) +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = getelementptr i8, i8* %a, i32 4 + %2 = load i8, i8* %1 + %3 = zext i8 %2 to i32 + %4 = load volatile i8, i8* %a + %5 = zext i8 %4 to i32 + %6 = add i32 %3, %5 + ret i32 %6 +} + +define i32 @lhu(i16 *%a) nounwind { +; RV32I-LABEL: lhu: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lhu a1, 0(a0) +; RV32I-NEXT: lhu a0, 10(a0) +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = getelementptr i16, i16* %a, i32 5 + %2 = load i16, i16* %1 + %3 = zext i16 %2 to i32 + %4 = load volatile i16, i16* %a + %5 = zext i16 %4 to i32 + %6 = add i32 %3, %5 + ret i32 %6 +} + +; Check indexed and unindexed stores + +define void @sb(i8 *%a, i8 %b) nounwind { +; RV32I-LABEL: sb: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sb a1, 6(a0) +; RV32I-NEXT: sb a1, 0(a0) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + store i8 %b, i8* %a + %1 = getelementptr i8, i8* %a, i32 6 + store i8 %b, i8* %1 + ret void +} + +define void @sh(i16 *%a, i16 %b) nounwind { +; RV32I-LABEL: sh: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sh a1, 14(a0) +; RV32I-NEXT: sh a1, 0(a0) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + store i16 %b, i16* %a + %1 = getelementptr i16, i16* %a, i32 7 + store i16 %b, i16* %1 + ret void +} + +define void @sw(i32 *%a, i32 %b) nounwind { +; RV32I-LABEL: sw: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: sw a1, 32(a0) +; RV32I-NEXT: sw a1, 0(a0) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + store i32 %b, i32* %a + %1 = getelementptr i32, i32* %a, i32 8 + store i32 %b, i32* %1 + ret void +} + +; Check load and store to an i1 location +define i32 @load_sext_zext_anyext_i1(i1 *%a) nounwind { +; RV32I-LABEL: load_sext_zext_anyext_i1: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lb a1, 0(a0) +; RV32I-NEXT: lbu a1, 1(a0) +; RV32I-NEXT: lbu a0, 2(a0) +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ; sextload i1 + %1 = getelementptr i1, i1* %a, i32 1 + %2 = load i1, i1* %1 + %3 = sext i1 %2 to i32 + ; zextload i1 + %4 = getelementptr i1, i1* %a, i32 2 + %5 = load i1, i1* %4 + %6 = zext i1 %5 to i32 + %7 = add i32 %3, %6 + ; extload i1 (anyext). Produced as the load is unused. + %8 = load volatile i1, i1* %a + ret i32 %7 +} + +define i16 @load_sext_zext_anyext_i1_i16(i1 *%a) nounwind { +; RV32I-LABEL: load_sext_zext_anyext_i1_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lb a1, 0(a0) +; RV32I-NEXT: lbu a1, 1(a0) +; RV32I-NEXT: lbu a0, 2(a0) +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + ; sextload i1 + %1 = getelementptr i1, i1* %a, i32 1 + %2 = load i1, i1* %1 + %3 = sext i1 %2 to i16 + ; zextload i1 + %4 = getelementptr i1, i1* %a, i32 2 + %5 = load i1, i1* %4 + %6 = zext i1 %5 to i16 + %7 = add i16 %3, %6 + ; extload i1 (anyext). Produced as the load is unused. + %8 = load volatile i1, i1* %a + ret i16 %7 +} + +; Check load and store to a global +@G = global i32 0 + +define i32 @lw_sw_global(i32 %a) nounwind { +; TODO: the addi should be folded in to the lw/sw operations +; RV32I-LABEL: lw_sw_global: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(G) +; RV32I-NEXT: addi a2, a1, %lo(G) +; RV32I-NEXT: lw a1, 0(a2) +; RV32I-NEXT: sw a0, 0(a2) +; RV32I-NEXT: lui a2, %hi(G+36) +; RV32I-NEXT: addi a2, a2, %lo(G+36) +; RV32I-NEXT: lw a3, 0(a2) +; RV32I-NEXT: sw a0, 0(a2) +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = load volatile i32, i32* @G + store i32 %a, i32* @G + %2 = getelementptr i32, i32* @G, i32 9 + %3 = load volatile i32, i32* %2 + store i32 %a, i32* %2 + ret i32 %1 +} + +; Ensure that 1 is added to the high 20 bits if bit 11 of the low part is 1 +define i32 @lw_sw_constant(i32 %a) nounwind { +; TODO: the addi should be folded in to the lw/sw +; RV32I-LABEL: lw_sw_constant: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, 912092 +; RV32I-NEXT: addi a2, a1, -273 +; RV32I-NEXT: lw a1, 0(a2) +; RV32I-NEXT: sw a0, 0(a2) +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = inttoptr i32 3735928559 to i32* + %2 = load volatile i32, i32* %1 + store i32 %a, i32* %1 + ret i32 %2 +} diff --git a/test/CodeGen/RISCV/mul.ll b/test/CodeGen/RISCV/mul.ll new file mode 100644 index 0000000000000..e86f835cf38fb --- /dev/null +++ b/test/CodeGen/RISCV/mul.ll @@ -0,0 +1,113 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +define i32 @square(i32 %a) { +; RV32I-LABEL: square: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a1, %lo(__mulsi3) +; RV32I-NEXT: mv a1, a0 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = mul i32 %a, %a + ret i32 %1 +} + +define i32 @mul(i32 %a, i32 %b) { +; RV32I-LABEL: mul: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a2, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = mul i32 %a, %b + ret i32 %1 +} + +define i32 @mul_constant(i32 %a) { +; RV32I-LABEL: mul_constant: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, %hi(__mulsi3) +; RV32I-NEXT: addi a2, a1, %lo(__mulsi3) +; RV32I-NEXT: addi a1, zero, 5 +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = mul i32 %a, 5 + ret i32 %1 +} + +define i32 @mul_pow2(i32 %a) { +; RV32I-LABEL: mul_pow2: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slli a0, a0, 3 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = mul i32 %a, 8 + ret i32 %1 +} + +define i64 @mul64(i64 %a, i64 %b) { +; RV32I-LABEL: mul64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a4, %hi(__muldi3) +; RV32I-NEXT: addi a4, a4, %lo(__muldi3) +; RV32I-NEXT: jalr a4 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = mul i64 %a, %b + ret i64 %1 +} + +define i64 @mul64_constant(i64 %a) { +; RV32I-LABEL: mul64_constant: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a2, %hi(__muldi3) +; RV32I-NEXT: addi a4, a2, %lo(__muldi3) +; RV32I-NEXT: addi a2, zero, 5 +; RV32I-NEXT: mv a3, zero +; RV32I-NEXT: jalr a4 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = mul i64 %a, 5 + ret i64 %1 +} diff --git a/test/CodeGen/RISCV/rem.ll b/test/CodeGen/RISCV/rem.ll new file mode 100644 index 0000000000000..3f8f7ebea966d --- /dev/null +++ b/test/CodeGen/RISCV/rem.ll @@ -0,0 +1,39 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +define i32 @urem(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: urem: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a2, %hi(__umodsi3) +; RV32I-NEXT: addi a2, a2, %lo(__umodsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = urem i32 %a, %b + ret i32 %1 +} + +define i32 @srem(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: srem: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a2, %hi(__modsi3) +; RV32I-NEXT: addi a2, a2, %lo(__modsi3) +; RV32I-NEXT: jalr a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = srem i32 %a, %b + ret i32 %1 +} diff --git a/test/CodeGen/RISCV/rotl-rotr.ll b/test/CodeGen/RISCV/rotl-rotr.ll new file mode 100644 index 0000000000000..cf434eb4a6c76 --- /dev/null +++ b/test/CodeGen/RISCV/rotl-rotr.ll @@ -0,0 +1,52 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +; These IR sequences will generate ISD::ROTL and ISD::ROTR nodes, that the +; RISC-V backend must be able to select + +define i32 @rotl(i32 %x, i32 %y) { +; RV32I-LABEL: rotl: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a2, zero, 32 +; RV32I-NEXT: sub a2, a2, a1 +; RV32I-NEXT: sll a1, a0, a1 +; RV32I-NEXT: srl a0, a0, a2 +; RV32I-NEXT: or a0, a1, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %z = sub i32 32, %y + %b = shl i32 %x, %y + %c = lshr i32 %x, %z + %d = or i32 %b, %c + ret i32 %d +} + +define i32 @rotr(i32 %x, i32 %y) { +; RV32I-LABEL: rotr: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a2, zero, 32 +; RV32I-NEXT: sub a2, a2, a1 +; RV32I-NEXT: srl a1, a0, a1 +; RV32I-NEXT: sll a0, a0, a2 +; RV32I-NEXT: or a0, a1, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %z = sub i32 32, %y + %b = lshr i32 %x, %y + %c = shl i32 %x, %z + %d = or i32 %b, %c + ret i32 %d +} diff --git a/test/CodeGen/RISCV/select-cc.ll b/test/CodeGen/RISCV/select-cc.ll new file mode 100644 index 0000000000000..1bdc8cba18721 --- /dev/null +++ b/test/CodeGen/RISCV/select-cc.ll @@ -0,0 +1,107 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +define i32 @foo(i32 %a, i32 *%b) { +; RV32I-LABEL: foo: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: beq a0, a2, .LBB0_2 +; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: .LBB0_2: +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: bne a0, a2, .LBB0_4 +; RV32I-NEXT: # %bb.3: +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: .LBB0_4: +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: bltu a2, a0, .LBB0_6 +; RV32I-NEXT: # %bb.5: +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: .LBB0_6: +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: bgeu a0, a2, .LBB0_8 +; RV32I-NEXT: # %bb.7: +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: .LBB0_8: +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: bltu a0, a2, .LBB0_10 +; RV32I-NEXT: # %bb.9: +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: .LBB0_10: +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: bgeu a2, a0, .LBB0_12 +; RV32I-NEXT: # %bb.11: +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: .LBB0_12: +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: blt a2, a0, .LBB0_14 +; RV32I-NEXT: # %bb.13: +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: .LBB0_14: +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: bge a0, a2, .LBB0_16 +; RV32I-NEXT: # %bb.15: +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: .LBB0_16: +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: blt a0, a2, .LBB0_18 +; RV32I-NEXT: # %bb.17: +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: .LBB0_18: +; RV32I-NEXT: lw a1, 0(a1) +; RV32I-NEXT: bge a1, a0, .LBB0_20 +; RV32I-NEXT: # %bb.19: +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: .LBB0_20: +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %val1 = load volatile i32, i32* %b + %tst1 = icmp eq i32 %a, %val1 + %val2 = select i1 %tst1, i32 %a, i32 %val1 + + %val3 = load volatile i32, i32* %b + %tst2 = icmp ne i32 %val2, %val3 + %val4 = select i1 %tst2, i32 %val2, i32 %val3 + + %val5 = load volatile i32, i32* %b + %tst3 = icmp ugt i32 %val4, %val5 + %val6 = select i1 %tst3, i32 %val4, i32 %val5 + + %val7 = load volatile i32, i32* %b + %tst4 = icmp uge i32 %val6, %val7 + %val8 = select i1 %tst4, i32 %val6, i32 %val7 + + %val9 = load volatile i32, i32* %b + %tst5 = icmp ult i32 %val8, %val9 + %val10 = select i1 %tst5, i32 %val8, i32 %val9 + + %val11 = load volatile i32, i32* %b + %tst6 = icmp ule i32 %val10, %val11 + %val12 = select i1 %tst6, i32 %val10, i32 %val11 + + %val13 = load volatile i32, i32* %b + %tst7 = icmp sgt i32 %val12, %val13 + %val14 = select i1 %tst7, i32 %val12, i32 %val13 + + %val15 = load volatile i32, i32* %b + %tst8 = icmp sge i32 %val14, %val15 + %val16 = select i1 %tst8, i32 %val14, i32 %val15 + + %val17 = load volatile i32, i32* %b + %tst9 = icmp slt i32 %val16, %val17 + %val18 = select i1 %tst9, i32 %val16, i32 %val17 + + %val19 = load volatile i32, i32* %b + %tst10 = icmp sle i32 %val18, %val19 + %val20 = select i1 %tst10, i32 %val18, i32 %val19 + + ret i32 %val20 +} diff --git a/test/CodeGen/RISCV/sext-zext-trunc.ll b/test/CodeGen/RISCV/sext-zext-trunc.ll new file mode 100644 index 0000000000000..9b9eda0244e48 --- /dev/null +++ b/test/CodeGen/RISCV/sext-zext-trunc.ll @@ -0,0 +1,495 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +define i8 @sext_i1_to_i8(i1 %a) { +; RV32I-LABEL: sext_i1_to_i8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 1 +; RV32I-NEXT: neg a0, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i1 %a to i8 + ret i8 %1 +} + +define i16 @sext_i1_to_i16(i1 %a) { +; RV32I-LABEL: sext_i1_to_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 1 +; RV32I-NEXT: neg a0, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i1 %a to i16 + ret i16 %1 +} + +define i32 @sext_i1_to_i32(i1 %a) { +; RV32I-LABEL: sext_i1_to_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 1 +; RV32I-NEXT: neg a0, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i1 %a to i32 + ret i32 %1 +} + +define i64 @sext_i1_to_i64(i1 %a) { +; RV32I-LABEL: sext_i1_to_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 1 +; RV32I-NEXT: neg a0, a0 +; RV32I-NEXT: mv a1, a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i1 %a to i64 + ret i64 %1 +} + +define i16 @sext_i8_to_i16(i8 %a) { +; RV32I-LABEL: sext_i8_to_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: srai a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i8 %a to i16 + ret i16 %1 +} + +define i32 @sext_i8_to_i32(i8 %a) { +; RV32I-LABEL: sext_i8_to_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slli a0, a0, 24 +; RV32I-NEXT: srai a0, a0, 24 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i8 %a to i32 + ret i32 %1 +} + +define i64 @sext_i8_to_i64(i8 %a) { +; RV32I-LABEL: sext_i8_to_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slli a1, a0, 24 +; RV32I-NEXT: srai a0, a1, 24 +; RV32I-NEXT: srai a1, a1, 31 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i8 %a to i64 + ret i64 %1 +} + +define i32 @sext_i16_to_i32(i16 %a) { +; RV32I-LABEL: sext_i16_to_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slli a0, a0, 16 +; RV32I-NEXT: srai a0, a0, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i16 %a to i32 + ret i32 %1 +} + +define i64 @sext_i16_to_i64(i16 %a) { +; RV32I-LABEL: sext_i16_to_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: slli a1, a0, 16 +; RV32I-NEXT: srai a0, a1, 16 +; RV32I-NEXT: srai a1, a1, 31 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i16 %a to i64 + ret i64 %1 +} + +define i64 @sext_i32_to_i64(i32 %a) { +; RV32I-LABEL: sext_i32_to_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: srai a1, a0, 31 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = sext i32 %a to i64 + ret i64 %1 +} + +define i8 @zext_i1_to_i8(i1 %a) { +; RV32I-LABEL: zext_i1_to_i8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i1 %a to i8 + ret i8 %1 +} + +define i16 @zext_i1_to_i16(i1 %a) { +; RV32I-LABEL: zext_i1_to_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i1 %a to i16 + ret i16 %1 +} + +define i32 @zext_i1_to_i32(i1 %a) { +; RV32I-LABEL: zext_i1_to_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i1 %a to i32 + ret i32 %1 +} + +define i64 @zext_i1_to_i64(i1 %a) { +; RV32I-LABEL: zext_i1_to_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 1 +; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i1 %a to i64 + ret i64 %1 +} + +define i16 @zext_i8_to_i16(i8 %a) { +; RV32I-LABEL: zext_i8_to_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i8 %a to i16 + ret i16 %1 +} + +define i32 @zext_i8_to_i32(i8 %a) { +; RV32I-LABEL: zext_i8_to_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i8 %a to i32 + ret i32 %1 +} + +define i64 @zext_i8_to_i64(i8 %a) { +; RV32I-LABEL: zext_i8_to_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: andi a0, a0, 255 +; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i8 %a to i64 + ret i64 %1 +} + +define i32 @zext_i16_to_i32(i16 %a) { +; RV32I-LABEL: zext_i16_to_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, 16 +; RV32I-NEXT: addi a1, a1, -1 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i16 %a to i32 + ret i32 %1 +} + +define i64 @zext_i16_to_i64(i16 %a) { +; RV32I-LABEL: zext_i16_to_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a1, 16 +; RV32I-NEXT: addi a1, a1, -1 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i16 %a to i64 + ret i64 %1 +} + +define i64 @zext_i32_to_i64(i32 %a) { +; RV32I-LABEL: zext_i32_to_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = zext i32 %a to i64 + ret i64 %1 +} + +; TODO: should the trunc tests explicitly ensure no code is generated before +; jalr? + +define i1 @trunc_i8_to_i1(i8 %a) { +; RV32I-LABEL: trunc_i8_to_i1: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i8 %a to i1 + ret i1 %1 +} + +define i1 @trunc_i16_to_i1(i16 %a) { +; RV32I-LABEL: trunc_i16_to_i1: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i16 %a to i1 + ret i1 %1 +} + +define i1 @trunc_i32_to_i1(i32 %a) { +; RV32I-LABEL: trunc_i32_to_i1: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i32 %a to i1 + ret i1 %1 +} + +define i1 @trunc_i64_to_i1(i64 %a) { +; RV32I-LABEL: trunc_i64_to_i1: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i64 %a to i1 + ret i1 %1 +} + +define i8 @trunc_i16_to_i8(i16 %a) { +; RV32I-LABEL: trunc_i16_to_i8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i16 %a to i8 + ret i8 %1 +} + +define i8 @trunc_i32_to_i8(i32 %a) { +; RV32I-LABEL: trunc_i32_to_i8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i32 %a to i8 + ret i8 %1 +} + +define i8 @trunc_i64_to_i8(i64 %a) { +; RV32I-LABEL: trunc_i64_to_i8: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i64 %a to i8 + ret i8 %1 +} + +define i16 @trunc_i32_to_i16(i32 %a) { +; RV32I-LABEL: trunc_i32_to_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i32 %a to i16 + ret i16 %1 +} + +define i16 @trunc_i64_to_i16(i64 %a) { +; RV32I-LABEL: trunc_i64_to_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i64 %a to i16 + ret i16 %1 +} + +define i32 @trunc_i64_to_i32(i64 %a) { +; RV32I-LABEL: trunc_i64_to_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = trunc i64 %a to i32 + ret i32 %1 +} diff --git a/test/CodeGen/RISCV/shifts.ll b/test/CodeGen/RISCV/shifts.ll new file mode 100644 index 0000000000000..c6d8646f28bc3 --- /dev/null +++ b/test/CodeGen/RISCV/shifts.ll @@ -0,0 +1,60 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +; Basic shift support is tested as part of ALU.ll. This file ensures that +; shifts which may not be supported natively are lowered properly. + +define i64 @lshr64(i64 %a, i64 %b) nounwind { +; RV32I-LABEL: lshr64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a3, %hi(__lshrdi3) +; RV32I-NEXT: addi a3, a3, %lo(__lshrdi3) +; RV32I-NEXT: jalr a3 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = lshr i64 %a, %b + ret i64 %1 +} + +define i64 @ashr64(i64 %a, i64 %b) nounwind { +; RV32I-LABEL: ashr64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a3, %hi(__ashrdi3) +; RV32I-NEXT: addi a3, a3, %lo(__ashrdi3) +; RV32I-NEXT: jalr a3 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = ashr i64 %a, %b + ret i64 %1 +} + +define i64 @shl64(i64 %a, i64 %b) nounwind { +; RV32I-LABEL: shl64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a3, %hi(__ashldi3) +; RV32I-NEXT: addi a3, a3, %lo(__ashldi3) +; RV32I-NEXT: jalr a3 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = shl i64 %a, %b + ret i64 %1 +} diff --git a/test/CodeGen/RISCV/wide-mem.ll b/test/CodeGen/RISCV/wide-mem.ll new file mode 100644 index 0000000000000..cd5c1d26b981e --- /dev/null +++ b/test/CodeGen/RISCV/wide-mem.ll @@ -0,0 +1,48 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +; Check load/store operations on values wider than what is natively supported + +define i64 @load_i64(i64 *%a) nounwind { +; RV32I-LABEL: load_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lw a2, 0(a0) +; RV32I-NEXT: lw a1, 4(a0) +; RV32I-NEXT: mv a0, a2 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = load i64, i64* %a + ret i64 %1 +} + +@val64 = local_unnamed_addr global i64 2863311530, align 8 + +; TODO: codegen on this should be improved. It shouldn't be necessary to +; generate two addi +define i64 @load_i64_global() nounwind { +; RV32I-LABEL: load_i64_global: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: lui a0, %hi(val64) +; RV32I-NEXT: addi a0, a0, %lo(val64) +; RV32I-NEXT: lw a0, 0(a0) +; RV32I-NEXT: lui a1, %hi(val64+4) +; RV32I-NEXT: addi a1, a1, %lo(val64+4) +; RV32I-NEXT: lw a1, 0(a1) +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = load i64, i64* @val64 + ret i64 %1 +} |
