mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
b0c6c4df1d
This patch adds the support required for using the __riscv_save and __riscv_restore libcalls to implement a size-optimization for prologue and epilogue code, whereby the spill and restore code of callee-saved registers is implemented by common functions to reduce code duplication. Logic is also included to ensure that if both this optimization and shrink wrapping are enabled then the prologue and epilogue code can be safely inserted into the basic blocks chosen by shrink wrapping. Differential Revision: https://reviews.llvm.org/D62686
300 lines
9.2 KiB
LLVM
300 lines
9.2 KiB
LLVM
; RUN: llc -mtriple=riscv32 < %s | FileCheck %s -check-prefix=RV32I
|
|
; RUN: llc -mtriple=riscv64 < %s | FileCheck %s -check-prefix=RV64I
|
|
; RUN: llc -mtriple=riscv32 -mattr=+save-restore < %s | FileCheck %s -check-prefix=RV32I-SR
|
|
; RUN: llc -mtriple=riscv64 -mattr=+save-restore < %s | FileCheck %s -check-prefix=RV64I-SR
|
|
; RUN: llc -mtriple=riscv32 -mattr=+f,+save-restore -target-abi=ilp32f < %s | FileCheck %s -check-prefix=RV32I-FP-SR
|
|
; RUN: llc -mtriple=riscv64 -mattr=+f,+d,+save-restore -target-abi=lp64d < %s | FileCheck %s -check-prefix=RV64I-FP-SR
|
|
|
|
; Check that the correct save/restore libcalls are generated.
|
|
|
|
@var0 = global [18 x i32] zeroinitializer
|
|
@var1 = global [24 x i32] zeroinitializer
|
|
@var2 = global [30 x i32] zeroinitializer
|
|
|
|
define void @callee_saved0() nounwind {
|
|
; RV32I-LABEL: callee_saved0:
|
|
; RV32I-NOT: call t0, __riscv_save
|
|
; RV32I-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-LABEL: callee_saved0:
|
|
; RV64I-NOT: call t0, __riscv_save
|
|
; RV64I-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-SR-LABEL: callee_saved0:
|
|
; RV32I-SR: call t0, __riscv_save_5
|
|
; RV32I-SR: tail __riscv_restore_5
|
|
;
|
|
; RV64I-SR-LABEL: callee_saved0:
|
|
; RV64I-SR: call t0, __riscv_save_5
|
|
; RV64I-SR: tail __riscv_restore_5
|
|
;
|
|
; RV32I-FP-SR-LABEL: callee_saved0:
|
|
; RV32I-FP-SR: call t0, __riscv_save_5
|
|
; RV32I-FP-SR: tail __riscv_restore_5
|
|
;
|
|
; RV64I-FP-SR-LABEL: callee_saved0:
|
|
; RV64I-FP-SR: call t0, __riscv_save_5
|
|
; RV64I-FP-SR: tail __riscv_restore_5
|
|
%val = load [18 x i32], [18 x i32]* @var0
|
|
store volatile [18 x i32] %val, [18 x i32]* @var0
|
|
ret void
|
|
}
|
|
|
|
define void @callee_saved1() nounwind {
|
|
; RV32I-LABEL: callee_saved1:
|
|
; RV32I-NOT: call t0, __riscv_save
|
|
; RV32I-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-LABEL: callee_saved1:
|
|
; RV64I-NOT: call t0, __riscv_save
|
|
; RV64I-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-SR-LABEL: callee_saved1:
|
|
; RV32I-SR: call t0, __riscv_save_11
|
|
; RV32I-SR: tail __riscv_restore_11
|
|
;
|
|
; RV64I-SR-LABEL: callee_saved1:
|
|
; RV64I-SR: call t0, __riscv_save_11
|
|
; RV64I-SR: tail __riscv_restore_11
|
|
;
|
|
; RV32I-FP-SR-LABEL: callee_saved1:
|
|
; RV32I-FP-SR: call t0, __riscv_save_11
|
|
; RV32I-FP-SR: tail __riscv_restore_11
|
|
;
|
|
; RV64I-FP-SR-LABEL: callee_saved1:
|
|
; RV64I-FP-SR: call t0, __riscv_save_11
|
|
; RV64I-FP-SR: tail __riscv_restore_11
|
|
%val = load [24 x i32], [24 x i32]* @var1
|
|
store volatile [24 x i32] %val, [24 x i32]* @var1
|
|
ret void
|
|
}
|
|
|
|
define void @callee_saved2() nounwind {
|
|
; RV32I-LABEL: callee_saved2:
|
|
; RV32I-NOT: call t0, __riscv_save
|
|
; RV32I-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-LABEL: callee_saved2:
|
|
; RV64I-NOT: call t0, __riscv_save
|
|
; RV64I-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-SR-LABEL: callee_saved2:
|
|
; RV32I-SR: call t0, __riscv_save_12
|
|
; RV32I-SR: tail __riscv_restore_12
|
|
;
|
|
; RV64I-SR-LABEL: callee_saved2:
|
|
; RV64I-SR: call t0, __riscv_save_12
|
|
; RV64I-SR: tail __riscv_restore_12
|
|
;
|
|
; RV32I-FP-SR-LABEL: callee_saved2:
|
|
; RV32I-FP-SR: call t0, __riscv_save_12
|
|
; RV32I-FP-SR: tail __riscv_restore_12
|
|
;
|
|
; RV64I-FP-SR-LABEL: callee_saved2:
|
|
; RV64I-FP-SR: call t0, __riscv_save_12
|
|
; RV64I-FP-SR: tail __riscv_restore_12
|
|
%val = load [30 x i32], [30 x i32]* @var2
|
|
store volatile [30 x i32] %val, [30 x i32]* @var2
|
|
ret void
|
|
}
|
|
|
|
; Check that floating point callee saved registers are still manually saved and
|
|
; restored.
|
|
|
|
define void @callee_saved_fp() nounwind {
|
|
; RV32I-LABEL: callee_saved_fp:
|
|
; RV32I-NOT: call t0, __riscv_save
|
|
; RV32I-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-LABEL: callee_saved_fp:
|
|
; RV64I-NOT: call t0, __riscv_save
|
|
; RV64I-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-SR-LABEL: callee_saved_fp:
|
|
; RV32I-SR: call t0, __riscv_save_7
|
|
; RV32I-SR: tail __riscv_restore_7
|
|
;
|
|
; RV64I-SR-LABEL: callee_saved_fp:
|
|
; RV64I-SR: call t0, __riscv_save_7
|
|
; RV64I-SR: tail __riscv_restore_7
|
|
;
|
|
; RV32I-FP-SR-LABEL: callee_saved_fp:
|
|
; RV32I-FP-SR: call t0, __riscv_save_7
|
|
; RV32I-FP-SR-NEXT: addi sp, sp, -16
|
|
; RV32I-FP-SR-NEXT: fsw fs0, 12(sp)
|
|
; RV32I-FP-SR: flw fs0, 12(sp)
|
|
; RV32I-FP-SR-NEXT: addi sp, sp, 16
|
|
; RV32I-FP-SR-NEXT: tail __riscv_restore_7
|
|
;
|
|
; RV64I-FP-SR-LABEL: callee_saved_fp:
|
|
; RV64I-FP-SR: call t0, __riscv_save_7
|
|
; RV64I-FP-SR-NEXT: addi sp, sp, -16
|
|
; RV64I-FP-SR-NEXT: fsd fs0, 8(sp)
|
|
; RV64I-FP-SR: fld fs0, 8(sp)
|
|
; RV64I-FP-SR-NEXT: addi sp, sp, 16
|
|
; RV64I-FP-SR-NEXT: tail __riscv_restore_7
|
|
call void asm sideeffect "", "~{f8},~{x9},~{x18},~{x19},~{x20},~{x21},~{x22}"()
|
|
ret void
|
|
}
|
|
|
|
; Check that preserving tail calls is preferred over save/restore
|
|
|
|
declare i32 @tail_callee(i32 %i)
|
|
|
|
define i32 @tail_call(i32 %i) nounwind {
|
|
; RV32I-LABEL: tail_call:
|
|
; RV32I-NOT: call t0, __riscv_save
|
|
; RV32I: tail tail_callee
|
|
; RV32I-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-LABEL: tail_call:
|
|
; RV64I-NOT: call t0, __riscv_save
|
|
; RV64I: tail tail_callee
|
|
; RV64I-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-SR-LABEL: tail_call:
|
|
; RV32I-SR-NOT: call t0, __riscv_save
|
|
; RV32I-SR: tail tail_callee
|
|
; RV32I-SR-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-SR-LABEL: tail_call:
|
|
; RV64I-SR-NOT: call t0, __riscv_save
|
|
; RV64I-SR: tail tail_callee
|
|
; RV64I-SR-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-FP-SR-LABEL: tail_call:
|
|
; RV32I-FP-SR-NOT: call t0, __riscv_save
|
|
; RV32I-FP-SR: tail tail_callee
|
|
; RV32I-FP-SR-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-FP-SR-LABEL: tail_call:
|
|
; RV64I-FP-SR-NOT: call t0, __riscv_save
|
|
; RV64I-FP-SR: tail tail_callee
|
|
; RV64I-FP-SR-NOT: tail __riscv_restore
|
|
entry:
|
|
%val = load [18 x i32], [18 x i32]* @var0
|
|
store volatile [18 x i32] %val, [18 x i32]* @var0
|
|
%r = tail call i32 @tail_callee(i32 %i)
|
|
ret i32 %r
|
|
}
|
|
|
|
; Check that functions with varargs do not use save/restore code
|
|
|
|
declare void @llvm.va_start(i8*)
|
|
declare void @llvm.va_end(i8*)
|
|
|
|
define i32 @varargs(i8* %fmt, ...) nounwind {
|
|
; RV32I-LABEL: varargs:
|
|
; RV32I-NOT: call t0, __riscv_save
|
|
; RV32I-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-LABEL: varargs:
|
|
; RV64I-NOT: call t0, __riscv_save
|
|
; RV64I-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-SR-LABEL: varargs:
|
|
; RV32I-SR-NOT: call t0, __riscv_save
|
|
; RV32I-SR-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-SR-LABEL: varargs:
|
|
; RV64I-SR-NOT: call t0, __riscv_save
|
|
; RV64I-SR-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-FP-SR-LABEL: varargs:
|
|
; RV32I-FP-SR-NOT: call t0, __riscv_save
|
|
; RV32I-FP-SR-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-FP-SR-LABEL: varargs:
|
|
; RV64I-FP-SR-NOT: call t0, __riscv_save
|
|
; RV64I-FP-SR-NOT: tail __riscv_restore
|
|
%va = alloca i8*, align 4
|
|
%1 = bitcast i8** %va to i8*
|
|
call void @llvm.va_start(i8* %1)
|
|
%argp.cur = load i8*, i8** %va, align 4
|
|
%argp.next = getelementptr inbounds i8, i8* %argp.cur, i32 4
|
|
store i8* %argp.next, i8** %va, align 4
|
|
%2 = bitcast i8* %argp.cur to i32*
|
|
%3 = load i32, i32* %2, align 4
|
|
call void @llvm.va_end(i8* %1)
|
|
ret i32 %3
|
|
}
|
|
|
|
define void @many_args(i32, i32, i32, i32, i32, i32, i32, i32, i32) nounwind {
|
|
; RV32I-LABEL: many_args:
|
|
; RV32I-NOT: call t0, __riscv_save
|
|
; RV32I-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-LABEL: many_args:
|
|
; RV64I-NOT: call t0, __riscv_save
|
|
; RV64I-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-SR-LABEL: many_args:
|
|
; RV32I-SR: call t0, __riscv_save_5
|
|
; RV32I-SR: tail __riscv_restore_5
|
|
;
|
|
; RV64I-SR-LABEL: many_args:
|
|
; RV64I-SR: call t0, __riscv_save_5
|
|
; RV64I-SR: tail __riscv_restore_5
|
|
;
|
|
; RV32I-FP-SR-LABEL: many_args:
|
|
; RV32I-FP-SR: call t0, __riscv_save_5
|
|
; RV32I-FP-SR: tail __riscv_restore_5
|
|
;
|
|
; RV64I-FP-SR-LABEL: many_args:
|
|
; RV64I-FP-SR: call t0, __riscv_save_5
|
|
; RV64I-FP-SR: tail __riscv_restore_5
|
|
entry:
|
|
%val = load [18 x i32], [18 x i32]* @var0
|
|
store volatile [18 x i32] %val, [18 x i32]* @var0
|
|
ret void
|
|
}
|
|
|
|
; Check that dynamic allocation calculations remain correct
|
|
|
|
declare i8* @llvm.stacksave()
|
|
declare void @llvm.stackrestore(i8*)
|
|
declare void @notdead(i8*)
|
|
|
|
define void @alloca(i32 %n) nounwind {
|
|
; RV32I-LABEL: alloca:
|
|
; RV32I-NOT: call t0, __riscv_save
|
|
; RV32I: addi s0, sp, 16
|
|
; RV32I: addi sp, s0, -16
|
|
; RV32I-NOT: tail __riscv_restore
|
|
;
|
|
; RV64I-LABEL: alloca:
|
|
; RV64I-NOT: call t0, __riscv_save
|
|
; RV64I: addi s0, sp, 32
|
|
; RV64I: addi sp, s0, -32
|
|
; RV64I-NOT: tail __riscv_restore
|
|
;
|
|
; RV32I-SR-LABEL: alloca:
|
|
; RV32I-SR: call t0, __riscv_save_2
|
|
; RV32I-SR: addi s0, sp, 16
|
|
; RV32I-SR: addi sp, s0, -16
|
|
; RV32I-SR: tail __riscv_restore_2
|
|
;
|
|
; RV64I-SR-LABEL: alloca:
|
|
; RV64I-SR: call t0, __riscv_save_2
|
|
; RV64I-SR: addi s0, sp, 32
|
|
; RV64I-SR: addi sp, s0, -32
|
|
; RV64I-SR: tail __riscv_restore_2
|
|
;
|
|
; RV32I-FP-SR-LABEL: alloca:
|
|
; RV32I-FP-SR: call t0, __riscv_save_2
|
|
; RV32I-FP-SR: addi s0, sp, 16
|
|
; RV32I-FP-SR: addi sp, s0, -16
|
|
; RV32I-FP-SR: tail __riscv_restore_2
|
|
;
|
|
; RV64I-FP-SR-LABEL: alloca:
|
|
; RV64I-FP-SR: call t0, __riscv_save_2
|
|
; RV64I-FP-SR: addi s0, sp, 32
|
|
; RV64I-FP-SR: addi sp, s0, -32
|
|
; RV64I-FP-SR: tail __riscv_restore_2
|
|
%sp = call i8* @llvm.stacksave()
|
|
%addr = alloca i8, i32 %n
|
|
call void @notdead(i8* %addr)
|
|
call void @llvm.stackrestore(i8* %sp)
|
|
ret void
|
|
}
|