| author | |
| committer | |
| log | ce14bc7176f9e441064ffdde2d85e35fd78977f2 |
| tree | 3b1d25c042403d9e6d071bfd6de71b0b6ec4b21a |
| parent | 95eb711ca8c0843ede117f61025c5eda0102f845 |
| parent | 36c4037144bdc3d80530205c0e2e9c31bee0f114 |
| signature |
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,6 +487,53 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 487 | addLLVMFnAttr(llvm_fn, "noreturn"); | 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 | if (fn->body_node != nullptr) { | 537 | if (fn->body_node != nullptr) { |
| 491 | maybe_export_dll(g, llvm_fn, linkage); | 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,6 +24,16 @@ void zig_f32(float); |
| 24 | void zig_f64(double); | 24 | void zig_f64(double); |
| 25 | void zig_five_floats(float, float, float, float, float); | 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 | void zig_ptr(void *); | 37 | void zig_ptr(void *); |
| 28 | 38 | ||
| 29 | void zig_bool(bool); | 39 | void zig_bool(bool); |
| ... | @@ -119,6 +129,20 @@ void run_c_tests(void) { | ... | @@ -119,6 +129,20 @@ void run_c_tests(void) { |
| 119 | assert_or_panic(res.d == 23); | 129 | assert_or_panic(res.d == 23); |
| 120 | assert_or_panic(res.e == 24); | 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 | void c_u8(uint8_t x) { | 148 | void c_u8(uint8_t x) { |
| ... | @@ -236,3 +260,31 @@ void c_big_struct_floats(Vector5 vec) { | ... | @@ -236,3 +260,31 @@ void c_big_struct_floats(Vector5 vec) { |
| 236 | assert_or_panic(vec.w == 69); | 260 | assert_or_panic(vec.w == 69); |
| 237 | assert_or_panic(vec.q == 55); | 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,3 +284,55 @@ test "C ABI structs of floats as parameter" { |
| 284 | }; | 284 | }; |
| 285 | c_big_struct_floats(v5); | 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 | } |