aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGen/RISCV
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGen/RISCV')
-rw-r--r--test/CodeGen/RISCV/addc-adde-sube-subc.ll44
-rw-r--r--test/CodeGen/RISCV/alloca.ll65
-rw-r--r--test/CodeGen/RISCV/alu32.ll319
-rw-r--r--test/CodeGen/RISCV/bare-select.ll24
-rw-r--r--test/CodeGen/RISCV/blockaddress.ll33
-rw-r--r--test/CodeGen/RISCV/branch.ll128
-rw-r--r--test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll614
-rw-r--r--test/CodeGen/RISCV/byval.ll61
-rw-r--r--test/CodeGen/RISCV/calling-conv-sext-zext.ll497
-rw-r--r--test/CodeGen/RISCV/calling-conv.ll719
-rw-r--r--test/CodeGen/RISCV/calls.ll197
-rw-r--r--test/CodeGen/RISCV/div.ll188
-rw-r--r--test/CodeGen/RISCV/fp128.ll134
-rw-r--r--test/CodeGen/RISCV/frame.ll38
-rw-r--r--test/CodeGen/RISCV/i32-icmp.ll184
-rw-r--r--test/CodeGen/RISCV/imm.ll82
-rw-r--r--test/CodeGen/RISCV/indirectbr.ll46
-rw-r--r--test/CodeGen/RISCV/jumptable.ll70
-rw-r--r--test/CodeGen/RISCV/lit.local.cfg2
-rw-r--r--test/CodeGen/RISCV/mem.ll286
-rw-r--r--test/CodeGen/RISCV/mul.ll113
-rw-r--r--test/CodeGen/RISCV/rem.ll39
-rw-r--r--test/CodeGen/RISCV/rotl-rotr.ll52
-rw-r--r--test/CodeGen/RISCV/select-cc.ll107
-rw-r--r--test/CodeGen/RISCV/sext-zext-trunc.ll495
-rw-r--r--test/CodeGen/RISCV/shifts.ll60
-rw-r--r--test/CodeGen/RISCV/wide-mem.ll48
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
+}