| author | |
| committer | |
| log | ce14bc7176f9e441064ffdde2d85e35fd78977f2 |
| tree | 3b1d25c042403d9e6d071bfd6de71b0b6ec4b21a |
| parent | 95eb711ca8c0843ede117f61025c5eda0102f845 |
| parent | 36c4037144bdc3d80530205c0e2e9c31bee0f114 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
stage1: Follow the C ABI for return types3 files changed, 151 insertions(+), 0 deletions(-)
src/stage1/codegen.cpp+47| ... | ... | @@ -487,6 +487,53 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 487 | 487 | addLLVMFnAttr(llvm_fn, "noreturn"); |
| 488 | 488 | } |
| 489 | 489 | |
| 490 | if (!calling_convention_allows_zig_types(cc)) { | |
| 491 | // A simplistic and desperate attempt at making the compiler respect the | |
| 492 | // target ABI for return types. | |
| 493 | // This is just enough to avoid miscompiling the test suite, it will be | |
| 494 | // better in stage2. | |
| 495 | ZigType *int_type = return_type->id == ZigTypeIdInt ? return_type : | |
| 496 | return_type->id == ZigTypeIdEnum ? return_type->data.enumeration.tag_int_type : | |
| 497 | nullptr; | |
| 498 | ||
| 499 | if (int_type != nullptr) { | |
| 500 | const bool is_signed = int_type->data.integral.is_signed; | |
| 501 | const uint32_t bit_width = int_type->data.integral.bit_count; | |
| 502 | bool should_extend = false; | |
| 503 | ||
| 504 | // Rough equivalent of Clang's isPromotableIntegerType. | |
| 505 | switch (bit_width) { | |
| 506 | case 1: // bool | |
| 507 | case 8: // {un,}signed char | |
| 508 | case 16: // {un,}signed short | |
| 509 | should_extend = true; | |
| 510 | break; | |
| 511 | default: | |
| 512 | break; | |
| 513 | } | |
| 514 | ||
| 515 | switch (g->zig_target->arch) { | |
| 516 | case ZigLLVM_sparcv9: | |
| 517 | case ZigLLVM_riscv64: | |
| 518 | case ZigLLVM_ppc64: | |
| 519 | case ZigLLVM_ppc64le: | |
| 520 | // Always extend to the register width. | |
| 521 | should_extend = bit_width < 64; | |
| 522 | break; | |
| 523 | default: | |
| 524 | break; | |
| 525 | } | |
| 526 | ||
| 527 | // {zero,sign}-extend the result. | |
| 528 | if (should_extend) { | |
| 529 | if (is_signed) | |
| 530 | addLLVMAttr(llvm_fn, 0, "signext"); | |
| 531 | else | |
| 532 | addLLVMAttr(llvm_fn, 0, "zeroext"); | |
| 533 | } | |
| 534 | } | |
| 535 | } | |
| 536 | ||
| 490 | 537 | if (fn->body_node != nullptr) { |
| 491 | 538 | maybe_export_dll(g, llvm_fn, linkage); |
| 492 | 539 |
test/stage1/c_abi/cfuncs.c+52| ... | ... | @@ -24,6 +24,16 @@ void zig_f32(float); |
| 24 | 24 | void zig_f64(double); |
| 25 | 25 | void zig_five_floats(float, float, float, float, float); |
| 26 | 26 | |
| 27 | bool zig_ret_bool(); | |
| 28 | uint8_t zig_ret_u8(); | |
| 29 | uint16_t zig_ret_u16(); | |
| 30 | uint32_t zig_ret_u32(); | |
| 31 | uint64_t zig_ret_u64(); | |
| 32 | int8_t zig_ret_i8(); | |
| 33 | int16_t zig_ret_i16(); | |
| 34 | int32_t zig_ret_i32(); | |
| 35 | int64_t zig_ret_i64(); | |
| 36 | ||
| 27 | 37 | void zig_ptr(void *); |
| 28 | 38 | |
| 29 | 39 | void zig_bool(bool); |
| ... | ... | @@ -119,6 +129,20 @@ void run_c_tests(void) { |
| 119 | 129 | assert_or_panic(res.d == 23); |
| 120 | 130 | assert_or_panic(res.e == 24); |
| 121 | 131 | } |
| 132 | ||
| 133 | { | |
| 134 | assert_or_panic(zig_ret_bool() == 1); | |
| 135 | ||
| 136 | assert_or_panic(zig_ret_u8() == 0xff); | |
| 137 | assert_or_panic(zig_ret_u16() == 0xffff); | |
| 138 | assert_or_panic(zig_ret_u32() == 0xffffffff); | |
| 139 | assert_or_panic(zig_ret_u64() == 0xffffffffffffffff); | |
| 140 | ||
| 141 | assert_or_panic(zig_ret_i8() == -1); | |
| 142 | assert_or_panic(zig_ret_i16() == -1); | |
| 143 | assert_or_panic(zig_ret_i32() == -1); | |
| 144 | assert_or_panic(zig_ret_i64() == -1); | |
| 145 | } | |
| 122 | 146 | } |
| 123 | 147 | |
| 124 | 148 | void c_u8(uint8_t x) { |
| ... | ... | @@ -236,3 +260,31 @@ void c_big_struct_floats(Vector5 vec) { |
| 236 | 260 | assert_or_panic(vec.w == 69); |
| 237 | 261 | assert_or_panic(vec.q == 55); |
| 238 | 262 | } |
| 263 | ||
| 264 | bool c_ret_bool() { | |
| 265 | return 1; | |
| 266 | } | |
| 267 | uint8_t c_ret_u8() { | |
| 268 | return 0xff; | |
| 269 | } | |
| 270 | uint16_t c_ret_u16() { | |
| 271 | return 0xffff; | |
| 272 | } | |
| 273 | uint32_t c_ret_u32() { | |
| 274 | return 0xffffffff; | |
| 275 | } | |
| 276 | uint64_t c_ret_u64() { | |
| 277 | return 0xffffffffffffffff; | |
| 278 | } | |
| 279 | int8_t c_ret_i8() { | |
| 280 | return -1; | |
| 281 | } | |
| 282 | int16_t c_ret_i16() { | |
| 283 | return -1; | |
| 284 | } | |
| 285 | int32_t c_ret_i32() { | |
| 286 | return -1; | |
| 287 | } | |
| 288 | int64_t c_ret_i64() { | |
| 289 | return -1; | |
| 290 | } |
test/stage1/c_abi/main.zig+52| ... | ... | @@ -284,3 +284,55 @@ test "C ABI structs of floats as parameter" { |
| 284 | 284 | }; |
| 285 | 285 | c_big_struct_floats(v5); |
| 286 | 286 | } |
| 287 | ||
| 288 | export fn zig_ret_bool() bool { | |
| 289 | return true; | |
| 290 | } | |
| 291 | export fn zig_ret_u8() u8 { | |
| 292 | return 0xff; | |
| 293 | } | |
| 294 | export fn zig_ret_u16() u16 { | |
| 295 | return 0xffff; | |
| 296 | } | |
| 297 | export fn zig_ret_u32() u32 { | |
| 298 | return 0xffffffff; | |
| 299 | } | |
| 300 | export fn zig_ret_u64() u64 { | |
| 301 | return 0xffffffffffffffff; | |
| 302 | } | |
| 303 | export fn zig_ret_i8() i8 { | |
| 304 | return -1; | |
| 305 | } | |
| 306 | export fn zig_ret_i16() i16 { | |
| 307 | return -1; | |
| 308 | } | |
| 309 | export fn zig_ret_i32() i32 { | |
| 310 | return -1; | |
| 311 | } | |
| 312 | export fn zig_ret_i64() i64 { | |
| 313 | return -1; | |
| 314 | } | |
| 315 | ||
| 316 | extern fn c_ret_bool() bool; | |
| 317 | extern fn c_ret_u8() u8; | |
| 318 | extern fn c_ret_u16() u16; | |
| 319 | extern fn c_ret_u32() u32; | |
| 320 | extern fn c_ret_u64() u64; | |
| 321 | extern fn c_ret_i8() i8; | |
| 322 | extern fn c_ret_i16() i16; | |
| 323 | extern fn c_ret_i32() i32; | |
| 324 | extern fn c_ret_i64() i64; | |
| 325 | ||
| 326 | test "C ABI integer return types" { | |
| 327 | expect(c_ret_bool() == true); | |
| 328 | ||
| 329 | expect(c_ret_u8() == 0xff); | |
| 330 | expect(c_ret_u16() == 0xffff); | |
| 331 | expect(c_ret_u32() == 0xffffffff); | |
| 332 | expect(c_ret_u64() == 0xffffffffffffffff); | |
| 333 | ||
| 334 | expect(c_ret_i8() == -1); | |
| 335 | expect(c_ret_i16() == -1); | |
| 336 | expect(c_ret_i32() == -1); | |
| 337 | expect(c_ret_i64() == -1); | |
| 338 | } |