[SystemZ] Support the kernel back chain.
In order to build the Linux kernel, the back chain must be supported with
packed-stack. The back chain is then stored topmost in the register save
area.
Review: Ulrich Weigand
Differential Revision: https://reviews.llvm.org/D74506
GitOrigin-RevId: 82879c2913da69ef2deadee9d075140a84eb6e8c
diff --git a/test/CodeGen/SystemZ/frame-23.ll b/test/CodeGen/SystemZ/frame-23.ll
new file mode 100644
index 0000000..e1c8b2b
--- /dev/null
+++ b/test/CodeGen/SystemZ/frame-23.ll
@@ -0,0 +1,20 @@
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+;
+; Test backchain with packed-stack, which requires soft-float.
+
+attributes #0 = { nounwind "backchain" "packed-stack" "use-soft-float"="true" }
+define i64 @fun0(i64 %a) #0 {
+; CHECK-LABEL: fun0:
+; CHECK: stmg %r14, %r15, 136(%r15)
+; CHECK-NEXT: lgr %r1, %r15
+; CHECK-NEXT: aghi %r15, -24
+; CHECK-NEXT: stg %r1, 152(%r15)
+; CHECK-NEXT: brasl %r14, foo@PLT
+; CHECK-NEXT: lmg %r14, %r15, 160(%r15)
+; CHECK-NEXT: br %r14
+entry:
+ %call = call i64 @foo(i64 %a)
+ ret i64 %call
+}
+
+declare i64 @foo(i64)
diff --git a/test/CodeGen/SystemZ/frame-24.ll b/test/CodeGen/SystemZ/frame-24.ll
new file mode 100644
index 0000000..37ba7eee
--- /dev/null
+++ b/test/CodeGen/SystemZ/frame-24.ll
@@ -0,0 +1,72 @@
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+;
+; Test saving of vararg registers and backchain with packed stack.
+
+%struct.__va_list_tag = type { i64, i64, i8*, i8* }
+declare void @llvm.va_start(i8*)
+
+attributes #0 = { nounwind "packed-stack"="true" }
+define void @fun0(i64 %g0, double %d0, i64 %n, ...) #0 {
+; CHECK-LABEL: fun0:
+; CHECK: stmg %r4, %r15, 32(%r15)
+; CHECK-NEXT: aghi %r15, -192
+; CHECK-NEXT: std %f2, 328(%r15)
+; CHECK-NEXT: std %f4, 336(%r15)
+; CHECK-NEXT: std %f6, 344(%r15)
+; CHECK-NEXT: la %r0, 352(%r15)
+; CHECK-NEXT: stg %r0, 176(%r15)
+; CHECK-NEXT: la %r0, 192(%r15)
+; CHECK-NEXT: stg %r0, 184(%r15)
+; CHECK-NEXT: mvghi 160(%r15), 2
+; CHECK-NEXT: mvghi 168(%r15), 1
+; CHECK-NEXT: lmg %r6, %r15, 240(%r15)
+; CHECK-NEXT: br %r14
+entry:
+ %vl = alloca [1 x %struct.__va_list_tag], align 8
+ %0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8*
+ call void @llvm.va_start(i8* nonnull %0)
+ ret void
+}
+
+attributes #1 = { nounwind "packed-stack"="true" "use-soft-float"="true" }
+define void @fun1(i64 %g0, double %d0, i64 %n, ...) #1 {
+; CHECK-LABEL: fun1:
+; CHECK: stmg %r5, %r15, 72(%r15)
+; CHECK-NEXT: aghi %r15, -160
+; CHECK-NEXT: la %r0, 192(%r15)
+; CHECK-NEXT: stg %r0, 184(%r15)
+; CHECK-NEXT: la %r0, 320(%r15)
+; CHECK-NEXT: stg %r0, 176(%r15)
+; CHECK-NEXT: mvghi 168(%r15), 0
+; CHECK-NEXT: mvghi 160(%r15), 3
+; CHECK-NEXT: lmg %r6, %r15, 240(%r15)
+; CHECK-NEXT: br %r14
+entry:
+ %vl = alloca [1 x %struct.__va_list_tag], align 8
+ %0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8*
+ call void @llvm.va_start(i8* nonnull %0)
+ ret void
+}
+
+attributes #2 = { nounwind "packed-stack"="true" "use-soft-float"="true" "backchain"}
+define void @fun2(i64 %g0, double %d0, i64 %n, ...) #2 {
+; CHECK-LABEL: fun2:
+; CHECK: stmg %r5, %r15, 64(%r15)
+; CHECK-NEXT: lgr %r1, %r15
+; CHECK-NEXT: aghi %r15, -168
+; CHECK-NEXT: stg %r1, 152(%r15)
+; CHECK-NEXT: la %r0, 192(%r15)
+; CHECK-NEXT: stg %r0, 184(%r15)
+; CHECK-NEXT: la %r0, 328(%r15)
+; CHECK-NEXT: stg %r0, 176(%r15)
+; CHECK-NEXT: mvghi 168(%r15), 0
+; CHECK-NEXT: mvghi 160(%r15), 3
+; CHECK-NEXT: lmg %r6, %r15, 240(%r15)
+; CHECK-NEXT: br %r14
+entry:
+ %vl = alloca [1 x %struct.__va_list_tag], align 8
+ %0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8*
+ call void @llvm.va_start(i8* nonnull %0)
+ ret void
+}
+
diff --git a/test/CodeGen/SystemZ/frameaddr-02.ll b/test/CodeGen/SystemZ/frameaddr-02.ll
new file mode 100644
index 0000000..f1b62f6
--- /dev/null
+++ b/test/CodeGen/SystemZ/frameaddr-02.ll
@@ -0,0 +1,54 @@
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+
+; Test lowering of @llvm.frameaddress with packed-stack.
+
+; With back chain
+attributes #0 = { nounwind "packed-stack" "backchain" "use-soft-float"="true" }
+define i8* @fp0() #0 {
+entry:
+; CHECK-LABEL: fp0:
+; CHECK: la %r2, 152(%r15)
+; CHECK-NEXT: br %r14
+ %0 = tail call i8* @llvm.frameaddress(i32 0)
+ ret i8* %0
+}
+
+define i8* @fp0f() #0 {
+entry:
+; CHECK-LABEL: fp0f:
+; CHECK: lgr %r1, %r15
+; CHECK-NEXT: aghi %r15, -16
+; CHECK-NEXT: stg %r1, 152(%r15)
+; CHECK-NEXT: la %r2, 168(%r15)
+; CHECK-NEXT: aghi %r15, 16
+; CHECK-NEXT: br %r14
+ %0 = alloca i64, align 8
+ %1 = tail call i8* @llvm.frameaddress(i32 0)
+ ret i8* %1
+}
+
+; Without back chain
+
+attributes #1 = { nounwind "packed-stack" }
+define i8* @fp1() #1 {
+entry:
+; CHECK-LABEL: fp1:
+; CHECK: lghi %r2, 0
+; CHECK-NEXT: br %r14
+ %0 = tail call i8* @llvm.frameaddress(i32 0)
+ ret i8* %0
+}
+
+define i8* @fp1f() #1 {
+entry:
+; CHECK-LABEL: fp1f:
+; CHECK: aghi %r15, -8
+; CHECK-NEXT: lghi %r2, 0
+; CHECK-NEXT: aghi %r15, 8
+; CHECK-NEXT: br %r14
+ %0 = alloca i64, align 8
+ %1 = tail call i8* @llvm.frameaddress(i32 0)
+ ret i8* %1
+}
+
+declare i8* @llvm.frameaddress(i32) nounwind readnone