1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
; FIXME: Add tests for global-isel/fast-isel.
; RUN: llc < %s -mtriple=arm64-windows | FileCheck %s
; Returns <= 8 bytes should be in X0.
%struct.S1 = type { i32, i32 }
define dso_local i64 @"?f1"() {
entry:
; CHECK-LABEL: f1
; CHECK-DAG: str xzr, [sp, #8]
; CHECK-DAG: mov x0, xzr
%retval = alloca %struct.S1, align 4
%a = getelementptr inbounds %struct.S1, %struct.S1* %retval, i32 0, i32 0
store i32 0, i32* %a, align 4
%b = getelementptr inbounds %struct.S1, %struct.S1* %retval, i32 0, i32 1
store i32 0, i32* %b, align 4
%0 = bitcast %struct.S1* %retval to i64*
%1 = load i64, i64* %0, align 4
ret i64 %1
}
; Returns <= 16 bytes should be in X0/X1.
%struct.S2 = type { i32, i32, i32, i32 }
define dso_local [2 x i64] @"?f2"() {
entry:
; FIXME: Missed optimization, the entire SP push/pop could be removed
; CHECK-LABEL: f2
; CHECK: sub sp, sp, #16
; CHECK-NEXT: .seh_stackalloc 16
; CHECK-NEXT: .seh_endprologue
; CHECK-DAG: stp xzr, xzr, [sp]
; CHECK-DAG: mov x0, xzr
; CHECK-DAG: mov x1, xzr
; CHECK: .seh_startepilogue
; CHECK-NEXT: add sp, sp, #16
%retval = alloca %struct.S2, align 4
%a = getelementptr inbounds %struct.S2, %struct.S2* %retval, i32 0, i32 0
store i32 0, i32* %a, align 4
%b = getelementptr inbounds %struct.S2, %struct.S2* %retval, i32 0, i32 1
store i32 0, i32* %b, align 4
%c = getelementptr inbounds %struct.S2, %struct.S2* %retval, i32 0, i32 2
store i32 0, i32* %c, align 4
%d = getelementptr inbounds %struct.S2, %struct.S2* %retval, i32 0, i32 3
store i32 0, i32* %d, align 4
%0 = bitcast %struct.S2* %retval to [2 x i64]*
%1 = load [2 x i64], [2 x i64]* %0, align 4
ret [2 x i64] %1
}
; Arguments > 16 bytes should be passed in X8.
%struct.S3 = type { i32, i32, i32, i32, i32 }
define dso_local void @"?f3"(%struct.S3* noalias sret(%struct.S3) %agg.result) {
entry:
; CHECK-LABEL: f3
; CHECK: stp xzr, xzr, [x8]
; CHECK: str wzr, [x8, #16]
%a = getelementptr inbounds %struct.S3, %struct.S3* %agg.result, i32 0, i32 0
store i32 0, i32* %a, align 4
%b = getelementptr inbounds %struct.S3, %struct.S3* %agg.result, i32 0, i32 1
store i32 0, i32* %b, align 4
%c = getelementptr inbounds %struct.S3, %struct.S3* %agg.result, i32 0, i32 2
store i32 0, i32* %c, align 4
%d = getelementptr inbounds %struct.S3, %struct.S3* %agg.result, i32 0, i32 3
store i32 0, i32* %d, align 4
%e = getelementptr inbounds %struct.S3, %struct.S3* %agg.result, i32 0, i32 4
store i32 0, i32* %e, align 4
ret void
}
; InReg arguments to non-instance methods must be passed in X0 and returns in
; X0.
%class.B = type { i32 }
define dso_local void @"?f4"(%class.B* inreg noalias nocapture sret(%class.B) %agg.result) {
entry:
; CHECK-LABEL: f4
; CHECK: mov w8, #1
; CHECK: str w8, [x0]
%X.i = getelementptr inbounds %class.B, %class.B* %agg.result, i64 0, i32 0
store i32 1, i32* %X.i, align 4
ret void
}
; InReg arguments to instance methods must be passed in X1 and returns in X0.
%class.C = type { i8 }
%class.A = type { i8 }
define dso_local void @"?inst@C"(%class.C* %this, %class.A* inreg noalias sret(%class.A) %agg.result) {
entry:
; CHECK-LABEL: inst@C
; CHECK-DAG: mov x0, x1
; CHECK-DAG: str x8, [sp, #8]
%this.addr = alloca %class.C*, align 8
store %class.C* %this, %class.C** %this.addr, align 8
%this1 = load %class.C*, %class.C** %this.addr, align 8
ret void
}
; The following tests correspond to tests in
; clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
; Pod is a trivial HFA
%struct.Pod = type { [2 x double] }
; Not an aggregate according to C++14 spec => not HFA according to MSVC
%struct.NotCXX14Aggregate = type { %struct.Pod }
; NotPod is a C++14 aggregate. But not HFA, because it contains
; NotCXX14Aggregate (which itself is not HFA because it's not a C++14
; aggregate).
%struct.NotPod = type { %struct.NotCXX14Aggregate }
; CHECK-LABEL: copy_pod:
define dso_local %struct.Pod @copy_pod(%struct.Pod* %x) {
%x1 = load %struct.Pod, %struct.Pod* %x, align 8
ret %struct.Pod %x1
; CHECK: ldp d0, d1, [x0]
}
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg)
; CHECK-LABEL: copy_notcxx14aggregate:
define dso_local void
@copy_notcxx14aggregate(%struct.NotCXX14Aggregate* inreg noalias sret(%struct.NotCXX14Aggregate) align 8 %agg.result,
%struct.NotCXX14Aggregate* %x) {
%1 = bitcast %struct.NotCXX14Aggregate* %agg.result to i8*
%2 = bitcast %struct.NotCXX14Aggregate* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %1, i8* align 8 %2, i64 16, i1 false)
ret void
; CHECK: str q0, [x0]
}
; CHECK-LABEL: copy_notpod:
define dso_local [2 x i64] @copy_notpod(%struct.NotPod* %x) {
%x1 = bitcast %struct.NotPod* %x to [2 x i64]*
%x2 = load [2 x i64], [2 x i64]* %x1
ret [2 x i64] %x2
; CHECK: ldp x8, x1, [x0]
; CHECK: mov x0, x8
}
@Pod = external global %struct.Pod
; CHECK-LABEL: call_copy_pod:
define void @call_copy_pod() {
%x = call %struct.Pod @copy_pod(%struct.Pod* @Pod)
store %struct.Pod %x, %struct.Pod* @Pod
ret void
; CHECK: bl copy_pod
; CHECK-NEXT: str d0, [{{.*}}]
; CHECK-NEXT: str d1, [{{.*}}]
}
@NotCXX14Aggregate = external global %struct.NotCXX14Aggregate
; CHECK-LABEL: call_copy_notcxx14aggregate:
define void @call_copy_notcxx14aggregate() {
%x = alloca %struct.NotCXX14Aggregate
call void @copy_notcxx14aggregate(%struct.NotCXX14Aggregate* %x, %struct.NotCXX14Aggregate* @NotCXX14Aggregate)
%x1 = load %struct.NotCXX14Aggregate, %struct.NotCXX14Aggregate* %x
store %struct.NotCXX14Aggregate %x1, %struct.NotCXX14Aggregate* @NotCXX14Aggregate
ret void
; CHECK: bl copy_notcxx14aggregate
; CHECK-NEXT: ldp {{.*}}, {{.*}}, [sp]
}
@NotPod = external global %struct.NotPod
; CHECK-LABEL: call_copy_notpod:
define void @call_copy_notpod() {
%x = call [2 x i64] @copy_notpod(%struct.NotPod* @NotPod)
%notpod = bitcast %struct.NotPod* @NotPod to [2 x i64]*
store [2 x i64] %x, [2 x i64]* %notpod
ret void
; CHECK: bl copy_notpod
; CHECK-NEXT: stp x0, x1, [{{.*}}]
}
|