1 // RUN: %clang_cc1 -triple mips-unknown-linux -o - -O1 -emit-llvm %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 2 // RUN: %clang_cc1 -triple mipsel-unknown-linux -o - -O1 -emit-llvm %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 3 // RUN: %clang_cc1 -triple mips64-unknown-linux -o - -O1 -emit-llvm -target-abi n32 %s | FileCheck %s -check-prefix=ALL -check-prefix=N32 -check-prefix=NEW 4 // RUN: %clang_cc1 -triple mips64-unknown-linux -o - -O1 -emit-llvm -target-abi n32 %s | FileCheck %s -check-prefix=ALL -check-prefix=N32 -check-prefix=NEW 5 // RUN: %clang_cc1 -triple mips64-unknown-linux -o - -O1 -emit-llvm %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=NEW 6 // RUN: %clang_cc1 -triple mips64el-unknown-linux -o - -O1 -emit-llvm %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=NEW 7 8 #include <stdarg.h> 9 10 typedef int v4i32 __attribute__ ((__vector_size__ (16))); 11 12 int test_i32(char *fmt, ...) { 13 va_list va; 14 15 va_start(va, fmt); 16 int v = va_arg(va, int); 17 va_end(va); 18 19 return v; 20 } 21 22 // ALL-LABEL: define i32 @test_i32(i8*{{.*}} %fmt, ...) 23 // 24 // O32: %va = alloca i8*, align [[PTRALIGN:4]] 25 // N32: %va = alloca i8*, align [[PTRALIGN:4]] 26 // N64: %va = alloca i8*, align [[PTRALIGN:8]] 27 // 28 // ALL: [[VA1:%.+]] = bitcast i8** %va to i8* 29 // ALL: call void @llvm.va_start(i8* [[VA1]]) 30 // 31 // O32: [[TMP0:%.+]] = bitcast i8** %va to i32** 32 // O32: [[AP_CUR:%.+]] = load i32** [[TMP0]], align [[PTRALIGN]] 33 // NEW: [[TMP0:%.+]] = bitcast i8** %va to i64** 34 // NEW: [[AP_CUR:%.+]] = load i64** [[TMP0]], align [[PTRALIGN]] 35 // 36 // O32: [[AP_NEXT:%.+]] = getelementptr i32* [[AP_CUR]], i32 1 37 // NEW: [[AP_NEXT:%.+]] = getelementptr i64* [[AP_CUR]], {{i32|i64}} 1 38 // 39 // O32: store i32* [[AP_NEXT]], i32** [[TMP0]], align [[PTRALIGN]] 40 // NEW: store i64* [[AP_NEXT]], i64** [[TMP0]], align [[PTRALIGN]] 41 // 42 // O32: [[ARG1:%.+]] = load i32* [[AP_CUR]], align 4 43 // NEW: [[TMP2:%.+]] = load i64* [[AP_CUR]], align 8 44 // NEW: [[ARG1:%.+]] = trunc i64 [[TMP2]] to i32 45 // 46 // ALL: call void @llvm.va_end(i8* [[VA1]]) 47 // ALL: ret i32 [[ARG1]] 48 // ALL: } 49 50 int test_i32_2args(char *fmt, ...) { 51 va_list va; 52 53 va_start(va, fmt); 54 int v1 = va_arg(va, int); 55 int v2 = va_arg(va, int); 56 va_end(va); 57 58 return v1 + v2; 59 } 60 61 // ALL-LABEL: define i32 @test_i32_2args(i8*{{.*}} %fmt, ...) 62 // 63 // ALL: %va = alloca i8*, align [[PTRALIGN]] 64 // ALL: [[VA1:%.+]] = bitcast i8** %va to i8* 65 // ALL: call void @llvm.va_start(i8* [[VA1]]) 66 // 67 // O32: [[TMP0:%.+]] = bitcast i8** %va to i32** 68 // O32: [[AP_CUR:%.+]] = load i32** [[TMP0]], align [[PTRALIGN]] 69 // NEW: [[TMP0:%.+]] = bitcast i8** %va to i64** 70 // NEW: [[AP_CUR:%.+]] = load i64** [[TMP0]], align [[PTRALIGN]] 71 // 72 // O32: [[AP_NEXT1:%.+]] = getelementptr i32* [[AP_CUR]], i32 1 73 // NEW: [[AP_NEXT1:%.+]] = getelementptr i64* [[AP_CUR]], [[INTPTR_T:i32|i64]] 1 74 // 75 // O32: store i32* [[AP_NEXT1]], i32** [[TMP0]], align [[PTRALIGN]] 76 // FIXME: N32 optimised this store out. Why only for this ABI? 77 // N64: store i64* [[AP_NEXT1]], i64** [[TMP0]], align [[PTRALIGN]] 78 // 79 // O32: [[ARG1:%.+]] = load i32* [[AP_CUR]], align 4 80 // NEW: [[TMP3:%.+]] = load i64* [[AP_CUR]], align 8 81 // NEW: [[ARG1:%.+]] = trunc i64 [[TMP3]] to i32 82 // 83 // O32: [[AP_NEXT2:%.+]] = getelementptr i32* [[AP_CUR]], i32 2 84 // NEW: [[AP_NEXT2:%.+]] = getelementptr i64* [[AP_CUR]], [[INTPTR_T]] 2 85 // 86 // O32: store i32* [[AP_NEXT2]], i32** [[TMP0]], align [[PTRALIGN]] 87 // NEW: store i64* [[AP_NEXT2]], i64** [[TMP0]], align [[PTRALIGN]] 88 // 89 // O32: [[ARG2:%.+]] = load i32* [[AP_NEXT1]], align 4 90 // NEW: [[TMP4:%.+]] = load i64* [[AP_NEXT1]], align 8 91 // NEW: [[ARG2:%.+]] = trunc i64 [[TMP4]] to i32 92 // 93 // ALL: call void @llvm.va_end(i8* [[VA1]]) 94 // ALL: [[ADD:%.+]] = add nsw i32 [[ARG2]], [[ARG1]] 95 // ALL: ret i32 [[ADD]] 96 // ALL: } 97 98 long long test_i64(char *fmt, ...) { 99 va_list va; 100 101 va_start(va, fmt); 102 long long v = va_arg(va, long long); 103 va_end(va); 104 105 return v; 106 } 107 108 // ALL-LABEL: define i64 @test_i64(i8*{{.*}} %fmt, ...) 109 // 110 // ALL: %va = alloca i8*, align [[PTRALIGN]] 111 // ALL: [[VA1:%.+]] = bitcast i8** %va to i8* 112 // ALL: call void @llvm.va_start(i8* [[VA1]]) 113 // 114 // O32: [[AP_CUR:%.+]] = load i8** %va, align [[PTRALIGN]] 115 // NEW: [[TMP0:%.+]] = bitcast i8** %va to i64** 116 // NEW: [[AP_CUR:%.+]] = load i64** [[TMP0]], align [[PTRALIGN]] 117 // 118 // i64 is 8-byte aligned, while this is within O32's stack alignment there's no 119 // guarantee that the offset is still 8-byte aligned after earlier reads. 120 // O32: [[PTR0:%.+]] = ptrtoint i8* [[AP_CUR]] to [[INTPTR_T:i32]] 121 // O32: [[PTR1:%.+]] = add i32 [[PTR0]], 7 122 // O32: [[PTR2:%.+]] = and i32 [[PTR1]], -8 123 // O32: [[PTR3:%.+]] = inttoptr [[INTPTR_T]] [[PTR2]] to i64* 124 // O32: [[PTR4:%.+]] = inttoptr [[INTPTR_T]] [[PTR2]] to i8* 125 // 126 // O32: [[AP_NEXT:%.+]] = getelementptr i8* [[PTR4]], [[INTPTR_T]] 8 127 // NEW: [[AP_NEXT:%.+]] = getelementptr i64* [[AP_CUR]], [[INTPTR_T:i32|i64]] 1 128 // 129 // O32: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]] 130 // NEW: store i64* [[AP_NEXT]], i64** [[TMP0]], align [[PTRALIGN]] 131 // 132 // O32: [[ARG1:%.+]] = load i64* [[PTR3]], align 8 133 // NEW: [[ARG1:%.+]] = load i64* [[AP_CUR]], align 8 134 // 135 // ALL: call void @llvm.va_end(i8* [[VA1]]) 136 // ALL: ret i64 [[ARG1]] 137 // ALL: } 138 139 char *test_ptr(char *fmt, ...) { 140 va_list va; 141 142 va_start(va, fmt); 143 char *v = va_arg(va, char *); 144 va_end(va); 145 146 return v; 147 } 148 149 // ALL-LABEL: define i8* @test_ptr(i8*{{.*}} %fmt, ...) 150 // 151 // O32: %va = alloca i8*, align [[PTRALIGN:4]] 152 // N32: %va = alloca i8*, align [[PTRALIGN:4]] 153 // N64: %va = alloca i8*, align [[PTRALIGN:8]] 154 // 155 // ALL: [[VA1:%.+]] = bitcast i8** %va to i8* 156 // ALL: call void @llvm.va_start(i8* [[VA1]]) 157 // 158 // O32: [[TMP0:%.+]] = bitcast i8** %va to i8*** 159 // O32: [[AP_CUR:%.+]] = load i8*** [[TMP0]], align [[PTRALIGN]] 160 // N32 differs because the vararg is not a N32 pointer. It's been promoted to 64-bit. 161 // N32: [[TMP0:%.+]] = bitcast i8** %va to i64** 162 // N32: [[AP_CUR:%.+]] = load i64** [[TMP0]], align [[PTRALIGN]] 163 // N64: [[TMP0:%.+]] = bitcast i8** %va to i8*** 164 // N64: [[AP_CUR:%.+]] = load i8*** [[TMP0]], align [[PTRALIGN]] 165 // 166 // O32: [[AP_NEXT:%.+]] = getelementptr i8** [[AP_CUR]], i32 1 167 // N32 differs because the vararg is not a N32 pointer. It's been promoted to 64-bit. 168 // N32: [[AP_NEXT:%.+]] = getelementptr i64* [[AP_CUR]], {{i32|i64}} 1 169 // N64: [[AP_NEXT:%.+]] = getelementptr i8** [[AP_CUR]], {{i32|i64}} 1 170 // 171 // O32: store i8** [[AP_NEXT]], i8*** [[TMP0]], align [[PTRALIGN]] 172 // N32 differs because the vararg is not a N32 pointer. It's been promoted to 64-bit. 173 // N32: store i64* [[AP_NEXT]], i64** [[TMP0]], align [[PTRALIGN]] 174 // N64: store i8** [[AP_NEXT]], i8*** [[TMP0]], align [[PTRALIGN]] 175 // 176 // O32: [[ARG1:%.+]] = load i8** [[AP_CUR]], align 4 177 // N32 differs because the vararg is not a N32 pointer. It's been promoted to 178 // 64-bit so we must truncate the excess and bitcast to a N32 pointer. 179 // N32: [[TMP2:%.+]] = load i64* [[AP_CUR]], align 8 180 // N32: [[TMP3:%.+]] = trunc i64 [[TMP2]] to i32 181 // N32: [[ARG1:%.+]] = inttoptr i32 [[TMP3]] to i8* 182 // N64: [[ARG1:%.+]] = load i8** [[AP_CUR]], align 8 183 // 184 // ALL: call void @llvm.va_end(i8* [[VA1]]) 185 // ALL: ret i8* [[ARG1]] 186 // ALL: } 187 188 int test_v4i32(char *fmt, ...) { 189 va_list va; 190 191 va_start(va, fmt); 192 v4i32 v = va_arg(va, v4i32); 193 va_end(va); 194 195 return v[0]; 196 } 197 198 // ALL-LABEL: define i32 @test_v4i32(i8*{{.*}} %fmt, ...) 199 // 200 // ALL: %va = alloca i8*, align [[PTRALIGN]] 201 // ALL: [[VA1:%.+]] = bitcast i8** %va to i8* 202 // ALL: call void @llvm.va_start(i8* [[VA1]]) 203 // ALL: [[AP_CUR:%.+]] = load i8** %va, align [[PTRALIGN]] 204 // 205 // O32: [[PTR0:%.+]] = ptrtoint i8* [[AP_CUR]] to [[INTPTR_T:i32]] 206 // N32: [[PTR0:%.+]] = ptrtoint i8* [[AP_CUR]] to [[INTPTR_T:i32]] 207 // N64: [[PTR0:%.+]] = ptrtoint i8* [[AP_CUR]] to [[INTPTR_T:i64]] 208 // 209 // Vectors are 16-byte aligned, however the O32 ABI has a maximum alignment of 210 // 8-bytes since the base of the stack is 8-byte aligned. 211 // O32: [[PTR1:%.+]] = add i32 [[PTR0]], 7 212 // O32: [[PTR2:%.+]] = and i32 [[PTR1]], -8 213 // 214 // NEW: [[PTR1:%.+]] = add [[INTPTR_T]] [[PTR0]], 15 215 // NEW: [[PTR2:%.+]] = and [[INTPTR_T]] [[PTR1]], -16 216 // 217 // ALL: [[PTR3:%.+]] = inttoptr [[INTPTR_T]] [[PTR2]] to <4 x i32>* 218 // ALL: [[PTR4:%.+]] = inttoptr [[INTPTR_T]] [[PTR2]] to i8* 219 // ALL: [[AP_NEXT:%.+]] = getelementptr i8* [[PTR4]], [[INTPTR_T]] 16 220 // ALL: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]] 221 // ALL: [[PTR5:%.+]] = load <4 x i32>* [[PTR3]], align 16 222 // ALL: call void @llvm.va_end(i8* [[VA1]]) 223 // ALL: [[VECEXT:%.+]] = extractelement <4 x i32> [[PTR5]], i32 0 224 // ALL: ret i32 [[VECEXT]] 225 // ALL: } 226