[RISCV] Add custom CC_RISCV calling convention and improved call support
The TableGen-based calling convention definitions are inflexible, while
writing a function to implement the calling convention is very
straight-forward, and allows difficult cases to be handled more easily. With
this patch adds support for:
* Passing large scalars according to the RV32I calling convention
* Byval arguments
* Passing values on the stack when the argument registers are exhausted
The custom CC_RISCV calling convention is also used for returns.
This patch also documents the ABI lowering that a language frontend is
expected to perform. I would like to work to simplify these requirements over
time, but this will require further discussion within the LLVM community.
We add PendingArgFlags CCState, as a companion to PendingLocs.
The PendingLocs vector is used by a number of backends to handle arguments
that are split during legalisation. However CCValAssign doesn't keep track of
the original argument alignment. Therefore, add a PendingArgFlags vector which
can be used to keep track of the ISD::ArgFlagsTy for every value added to
PendingLocs.
Differential Revision: https://reviews.llvm.org/D39898
llvm-svn: 320359
diff --git a/llvm/test/CodeGen/RISCV/calls.ll b/llvm/test/CodeGen/RISCV/calls.ll
index 3fba88d..4299d46 100644
--- a/llvm/test/CodeGen/RISCV/calls.ll
+++ b/llvm/test/CodeGen/RISCV/calls.ll
@@ -52,7 +52,7 @@
; RV32I-NEXT: lw ra, 12(sp)
; RV32I-NEXT: addi sp, sp, 16
; RV32I-NEXT: jalr zero, ra, 0
- %1 = call i32 @defined_function(i32 %a) nounwind
+ %1 = call i32 @defined_function(i32 %a)
ret i32 %1
}
@@ -115,3 +115,83 @@
%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: addi s1, a0, 0
+; 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: addi a0, s1, 0
+; RV32I-NEXT: addi a1, s1, 0
+; RV32I-NEXT: addi a2, s1, 0
+; RV32I-NEXT: addi a3, s1, 0
+; RV32I-NEXT: addi a4, s1, 0
+; RV32I-NEXT: addi a5, s1, 0
+; RV32I-NEXT: addi a6, s1, 0
+; RV32I-NEXT: addi a7, s1, 0
+; RV32I-NEXT: jalr ra, t0, 0
+; RV32I-NEXT: addi a0, s1, 0
+; 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: jalr zero, ra, 0
+ %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: jalr zero, ra, 0
+ %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: addi a1, a0, 0
+; RV32I-NEXT: addi a2, a0, 0
+; RV32I-NEXT: addi a3, a0, 0
+; RV32I-NEXT: addi a4, a0, 0
+; RV32I-NEXT: addi a5, a0, 0
+; RV32I-NEXT: addi a6, a0, 0
+; RV32I-NEXT: addi a7, a0, 0
+; RV32I-NEXT: jalr ra, t0, 0
+; RV32I-NEXT: lw s0, 24(sp)
+; RV32I-NEXT: lw ra, 28(sp)
+; RV32I-NEXT: addi sp, sp, 32
+; RV32I-NEXT: jalr zero, ra, 0
+ %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
+}