| ... | ... | @@ -10396,12 +10396,7 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool |
| 10396 | 10396 | .mips, .mipsel => return false, |
| 10397 | 10397 | .x86_64 => switch (target.os.tag) { |
| 10398 | 10398 | .windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory, |
| 10399 | | else => { |
| 10400 | | const class = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret); |
| 10401 | | if (class[0] == .memory) return true; |
| 10402 | | if (class[0] == .x87 and class[2] != .none) return true; |
| 10403 | | return false; |
| 10404 | | }, |
| 10399 | else => return firstParamSRetSystemV(fn_info.return_type, target), |
| 10405 | 10400 | }, |
| 10406 | 10401 | .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect, |
| 10407 | 10402 | .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory, |
| ... | ... | @@ -10413,11 +10408,20 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool |
| 10413 | 10408 | .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, target) == .memory, |
| 10414 | 10409 | else => return false, // TODO investigate C ABI for other architectures |
| 10415 | 10410 | }, |
| 10411 | .SysV => return firstParamSRetSystemV(fn_info.return_type, target), |
| 10412 | .Win64 => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory, |
| 10416 | 10413 | .Stdcall => return !isScalar(fn_info.return_type), |
| 10417 | 10414 | else => return false, |
| 10418 | 10415 | } |
| 10419 | 10416 | } |
| 10420 | 10417 | |
| 10418 | fn firstParamSRetSystemV(ty: Type, target: std.Target) bool { |
| 10419 | const class = x86_64_abi.classifySystemV(ty, target, .ret); |
| 10420 | if (class[0] == .memory) return true; |
| 10421 | if (class[0] == .x87 and class[2] != .none) return true; |
| 10422 | return false; |
| 10423 | } |
| 10424 | |
| 10421 | 10425 | /// In order to support the C calling convention, some return types need to be lowered |
| 10422 | 10426 | /// completely differently in the function prototype to honor the C ABI, and then |
| 10423 | 10427 | /// be effectively bitcasted to the actual return type. |
| ... | ... | @@ -10442,77 +10446,14 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10442 | 10446 | } |
| 10443 | 10447 | }, |
| 10444 | 10448 | .C => { |
| 10445 | | const is_scalar = isScalar(fn_info.return_type); |
| 10446 | 10449 | switch (target.cpu.arch) { |
| 10447 | 10450 | .mips, .mipsel => return dg.lowerType(fn_info.return_type), |
| 10448 | 10451 | .x86_64 => switch (target.os.tag) { |
| 10449 | | .windows => switch (x86_64_abi.classifyWindows(fn_info.return_type, target)) { |
| 10450 | | .integer => { |
| 10451 | | if (is_scalar) { |
| 10452 | | return dg.lowerType(fn_info.return_type); |
| 10453 | | } else { |
| 10454 | | const abi_size = fn_info.return_type.abiSize(target); |
| 10455 | | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10456 | | } |
| 10457 | | }, |
| 10458 | | .win_i128 => return dg.context.intType(64).vectorType(2), |
| 10459 | | .memory => return dg.context.voidType(), |
| 10460 | | .sse => return dg.lowerType(fn_info.return_type), |
| 10461 | | else => unreachable, |
| 10462 | | }, |
| 10463 | | else => { |
| 10464 | | if (is_scalar) { |
| 10465 | | return dg.lowerType(fn_info.return_type); |
| 10466 | | } |
| 10467 | | const classes = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret); |
| 10468 | | if (classes[0] == .memory) { |
| 10469 | | return dg.context.voidType(); |
| 10470 | | } |
| 10471 | | var llvm_types_buffer: [8]*llvm.Type = undefined; |
| 10472 | | var llvm_types_index: u32 = 0; |
| 10473 | | for (classes) |class| { |
| 10474 | | switch (class) { |
| 10475 | | .integer => { |
| 10476 | | llvm_types_buffer[llvm_types_index] = dg.context.intType(64); |
| 10477 | | llvm_types_index += 1; |
| 10478 | | }, |
| 10479 | | .sse, .sseup => { |
| 10480 | | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); |
| 10481 | | llvm_types_index += 1; |
| 10482 | | }, |
| 10483 | | .float => { |
| 10484 | | llvm_types_buffer[llvm_types_index] = dg.context.floatType(); |
| 10485 | | llvm_types_index += 1; |
| 10486 | | }, |
| 10487 | | .float_combine => { |
| 10488 | | llvm_types_buffer[llvm_types_index] = dg.context.floatType().vectorType(2); |
| 10489 | | llvm_types_index += 1; |
| 10490 | | }, |
| 10491 | | .x87 => { |
| 10492 | | if (llvm_types_index != 0 or classes[2] != .none) { |
| 10493 | | return dg.context.voidType(); |
| 10494 | | } |
| 10495 | | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); |
| 10496 | | llvm_types_index += 1; |
| 10497 | | }, |
| 10498 | | .x87up => continue, |
| 10499 | | .complex_x87 => { |
| 10500 | | @panic("TODO"); |
| 10501 | | }, |
| 10502 | | .memory => unreachable, // handled above |
| 10503 | | .win_i128 => unreachable, // windows only |
| 10504 | | .none => break, |
| 10505 | | } |
| 10506 | | } |
| 10507 | | if (classes[0] == .integer and classes[1] == .none) { |
| 10508 | | const abi_size = fn_info.return_type.abiSize(target); |
| 10509 | | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10510 | | } |
| 10511 | | return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False); |
| 10512 | | }, |
| 10452 | .windows => return lowerWin64FnRetTy(dg, fn_info), |
| 10453 | else => return lowerSystemVFnRetTy(dg, fn_info), |
| 10513 | 10454 | }, |
| 10514 | 10455 | .wasm32 => { |
| 10515 | | if (is_scalar) { |
| 10456 | if (isScalar(fn_info.return_type)) { |
| 10516 | 10457 | return dg.lowerType(fn_info.return_type); |
| 10517 | 10458 | } |
| 10518 | 10459 | const classes = wasm_c_abi.classifyType(fn_info.return_type, target); |
| ... | ... | @@ -10569,6 +10510,8 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10569 | 10510 | else => return dg.lowerType(fn_info.return_type), |
| 10570 | 10511 | } |
| 10571 | 10512 | }, |
| 10513 | .Win64 => return lowerWin64FnRetTy(dg, fn_info), |
| 10514 | .SysV => return lowerSystemVFnRetTy(dg, fn_info), |
| 10572 | 10515 | .Stdcall => { |
| 10573 | 10516 | if (isScalar(fn_info.return_type)) { |
| 10574 | 10517 | return dg.lowerType(fn_info.return_type); |
| ... | ... | @@ -10580,6 +10523,76 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10580 | 10523 | } |
| 10581 | 10524 | } |
| 10582 | 10525 | |
| 10526 | fn lowerWin64FnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10527 | const target = dg.module.getTarget(); |
| 10528 | switch (x86_64_abi.classifyWindows(fn_info.return_type, target)) { |
| 10529 | .integer => { |
| 10530 | if (isScalar(fn_info.return_type)) { |
| 10531 | return dg.lowerType(fn_info.return_type); |
| 10532 | } else { |
| 10533 | const abi_size = fn_info.return_type.abiSize(target); |
| 10534 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10535 | } |
| 10536 | }, |
| 10537 | .win_i128 => return dg.context.intType(64).vectorType(2), |
| 10538 | .memory => return dg.context.voidType(), |
| 10539 | .sse => return dg.lowerType(fn_info.return_type), |
| 10540 | else => unreachable, |
| 10541 | } |
| 10542 | } |
| 10543 | |
| 10544 | fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10545 | if (isScalar(fn_info.return_type)) { |
| 10546 | return dg.lowerType(fn_info.return_type); |
| 10547 | } |
| 10548 | const target = dg.module.getTarget(); |
| 10549 | const classes = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret); |
| 10550 | if (classes[0] == .memory) { |
| 10551 | return dg.context.voidType(); |
| 10552 | } |
| 10553 | var llvm_types_buffer: [8]*llvm.Type = undefined; |
| 10554 | var llvm_types_index: u32 = 0; |
| 10555 | for (classes) |class| { |
| 10556 | switch (class) { |
| 10557 | .integer => { |
| 10558 | llvm_types_buffer[llvm_types_index] = dg.context.intType(64); |
| 10559 | llvm_types_index += 1; |
| 10560 | }, |
| 10561 | .sse, .sseup => { |
| 10562 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); |
| 10563 | llvm_types_index += 1; |
| 10564 | }, |
| 10565 | .float => { |
| 10566 | llvm_types_buffer[llvm_types_index] = dg.context.floatType(); |
| 10567 | llvm_types_index += 1; |
| 10568 | }, |
| 10569 | .float_combine => { |
| 10570 | llvm_types_buffer[llvm_types_index] = dg.context.floatType().vectorType(2); |
| 10571 | llvm_types_index += 1; |
| 10572 | }, |
| 10573 | .x87 => { |
| 10574 | if (llvm_types_index != 0 or classes[2] != .none) { |
| 10575 | return dg.context.voidType(); |
| 10576 | } |
| 10577 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); |
| 10578 | llvm_types_index += 1; |
| 10579 | }, |
| 10580 | .x87up => continue, |
| 10581 | .complex_x87 => { |
| 10582 | @panic("TODO"); |
| 10583 | }, |
| 10584 | .memory => unreachable, // handled above |
| 10585 | .win_i128 => unreachable, // windows only |
| 10586 | .none => break, |
| 10587 | } |
| 10588 | } |
| 10589 | if (classes[0] == .integer and classes[1] == .none) { |
| 10590 | const abi_size = fn_info.return_type.abiSize(target); |
| 10591 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10592 | } |
| 10593 | return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False); |
| 10594 | } |
| 10595 | |
| 10583 | 10596 | const ParamTypeIterator = struct { |
| 10584 | 10597 | dg: *DeclGen, |
| 10585 | 10598 | fn_info: Type.Payload.Function.Data, |
| ... | ... | @@ -10629,7 +10642,6 @@ const ParamTypeIterator = struct { |
| 10629 | 10642 | it.zig_index += 1; |
| 10630 | 10643 | return .no_bits; |
| 10631 | 10644 | } |
| 10632 | | const dg = it.dg; |
| 10633 | 10645 | switch (it.fn_info.cc) { |
| 10634 | 10646 | .Unspecified, .Inline => { |
| 10635 | 10647 | it.zig_index += 1; |
| ... | ... | @@ -10648,7 +10660,6 @@ const ParamTypeIterator = struct { |
| 10648 | 10660 | @panic("TODO implement async function lowering in the LLVM backend"); |
| 10649 | 10661 | }, |
| 10650 | 10662 | .C => { |
| 10651 | | const is_scalar = isScalar(ty); |
| 10652 | 10663 | switch (it.target.cpu.arch) { |
| 10653 | 10664 | .mips, .mipsel => { |
| 10654 | 10665 | it.zig_index += 1; |
| ... | ... | @@ -10656,99 +10667,13 @@ const ParamTypeIterator = struct { |
| 10656 | 10667 | return .byval; |
| 10657 | 10668 | }, |
| 10658 | 10669 | .x86_64 => switch (it.target.os.tag) { |
| 10659 | | .windows => switch (x86_64_abi.classifyWindows(ty, it.target)) { |
| 10660 | | .integer => { |
| 10661 | | if (is_scalar) { |
| 10662 | | it.zig_index += 1; |
| 10663 | | it.llvm_index += 1; |
| 10664 | | return .byval; |
| 10665 | | } else { |
| 10666 | | it.zig_index += 1; |
| 10667 | | it.llvm_index += 1; |
| 10668 | | return .abi_sized_int; |
| 10669 | | } |
| 10670 | | }, |
| 10671 | | .win_i128 => { |
| 10672 | | it.zig_index += 1; |
| 10673 | | it.llvm_index += 1; |
| 10674 | | return .byref; |
| 10675 | | }, |
| 10676 | | .memory => { |
| 10677 | | it.zig_index += 1; |
| 10678 | | it.llvm_index += 1; |
| 10679 | | return .byref_mut; |
| 10680 | | }, |
| 10681 | | .sse => { |
| 10682 | | it.zig_index += 1; |
| 10683 | | it.llvm_index += 1; |
| 10684 | | return .byval; |
| 10685 | | }, |
| 10686 | | else => unreachable, |
| 10687 | | }, |
| 10688 | | else => { |
| 10689 | | const classes = x86_64_abi.classifySystemV(ty, it.target, .arg); |
| 10690 | | if (classes[0] == .memory) { |
| 10691 | | it.zig_index += 1; |
| 10692 | | it.llvm_index += 1; |
| 10693 | | it.byval_attr = true; |
| 10694 | | return .byref; |
| 10695 | | } |
| 10696 | | if (is_scalar) { |
| 10697 | | it.zig_index += 1; |
| 10698 | | it.llvm_index += 1; |
| 10699 | | return .byval; |
| 10700 | | } |
| 10701 | | var llvm_types_buffer: [8]*llvm.Type = undefined; |
| 10702 | | var llvm_types_index: u32 = 0; |
| 10703 | | for (classes) |class| { |
| 10704 | | switch (class) { |
| 10705 | | .integer => { |
| 10706 | | llvm_types_buffer[llvm_types_index] = dg.context.intType(64); |
| 10707 | | llvm_types_index += 1; |
| 10708 | | }, |
| 10709 | | .sse, .sseup => { |
| 10710 | | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); |
| 10711 | | llvm_types_index += 1; |
| 10712 | | }, |
| 10713 | | .float => { |
| 10714 | | llvm_types_buffer[llvm_types_index] = dg.context.floatType(); |
| 10715 | | llvm_types_index += 1; |
| 10716 | | }, |
| 10717 | | .float_combine => { |
| 10718 | | llvm_types_buffer[llvm_types_index] = dg.context.floatType().vectorType(2); |
| 10719 | | llvm_types_index += 1; |
| 10720 | | }, |
| 10721 | | .x87 => { |
| 10722 | | it.zig_index += 1; |
| 10723 | | it.llvm_index += 1; |
| 10724 | | it.byval_attr = true; |
| 10725 | | return .byref; |
| 10726 | | }, |
| 10727 | | .x87up => unreachable, |
| 10728 | | .complex_x87 => { |
| 10729 | | @panic("TODO"); |
| 10730 | | }, |
| 10731 | | .memory => unreachable, // handled above |
| 10732 | | .win_i128 => unreachable, // windows only |
| 10733 | | .none => break, |
| 10734 | | } |
| 10735 | | } |
| 10736 | | if (classes[0] == .integer and classes[1] == .none) { |
| 10737 | | it.zig_index += 1; |
| 10738 | | it.llvm_index += 1; |
| 10739 | | return .abi_sized_int; |
| 10740 | | } |
| 10741 | | it.llvm_types_buffer = llvm_types_buffer; |
| 10742 | | it.llvm_types_len = llvm_types_index; |
| 10743 | | it.llvm_index += llvm_types_index; |
| 10744 | | it.zig_index += 1; |
| 10745 | | return .multiple_llvm_types; |
| 10746 | | }, |
| 10670 | .windows => return it.nextWin64(ty), |
| 10671 | else => return it.nextSystemV(ty), |
| 10747 | 10672 | }, |
| 10748 | 10673 | .wasm32 => { |
| 10749 | 10674 | it.zig_index += 1; |
| 10750 | 10675 | it.llvm_index += 1; |
| 10751 | | if (is_scalar) { |
| 10676 | if (isScalar(ty)) { |
| 10752 | 10677 | return .byval; |
| 10753 | 10678 | } |
| 10754 | 10679 | const classes = wasm_c_abi.classifyType(ty, it.target); |
| ... | ... | @@ -10766,7 +10691,7 @@ const ParamTypeIterator = struct { |
| 10766 | 10691 | .byval => return .byval, |
| 10767 | 10692 | .integer => { |
| 10768 | 10693 | it.llvm_types_len = 1; |
| 10769 | | it.llvm_types_buffer[0] = dg.context.intType(64); |
| 10694 | it.llvm_types_buffer[0] = it.dg.context.intType(64); |
| 10770 | 10695 | return .multiple_llvm_types; |
| 10771 | 10696 | }, |
| 10772 | 10697 | .double_integer => return Lowering{ .i64_array = 2 }, |
| ... | ... | @@ -10806,6 +10731,8 @@ const ParamTypeIterator = struct { |
| 10806 | 10731 | }, |
| 10807 | 10732 | } |
| 10808 | 10733 | }, |
| 10734 | .Win64 => return it.nextWin64(ty), |
| 10735 | .SysV => return it.nextSystemV(ty), |
| 10809 | 10736 | .Stdcall => { |
| 10810 | 10737 | it.zig_index += 1; |
| 10811 | 10738 | it.llvm_index += 1; |
| ... | ... | @@ -10824,6 +10751,98 @@ const ParamTypeIterator = struct { |
| 10824 | 10751 | }, |
| 10825 | 10752 | } |
| 10826 | 10753 | } |
| 10754 | |
| 10755 | fn nextWin64(it: *ParamTypeIterator, ty: Type) ?Lowering { |
| 10756 | switch (x86_64_abi.classifyWindows(ty, it.target)) { |
| 10757 | .integer => { |
| 10758 | if (isScalar(ty)) { |
| 10759 | it.zig_index += 1; |
| 10760 | it.llvm_index += 1; |
| 10761 | return .byval; |
| 10762 | } else { |
| 10763 | it.zig_index += 1; |
| 10764 | it.llvm_index += 1; |
| 10765 | return .abi_sized_int; |
| 10766 | } |
| 10767 | }, |
| 10768 | .win_i128 => { |
| 10769 | it.zig_index += 1; |
| 10770 | it.llvm_index += 1; |
| 10771 | return .byref; |
| 10772 | }, |
| 10773 | .memory => { |
| 10774 | it.zig_index += 1; |
| 10775 | it.llvm_index += 1; |
| 10776 | return .byref_mut; |
| 10777 | }, |
| 10778 | .sse => { |
| 10779 | it.zig_index += 1; |
| 10780 | it.llvm_index += 1; |
| 10781 | return .byval; |
| 10782 | }, |
| 10783 | else => unreachable, |
| 10784 | } |
| 10785 | } |
| 10786 | |
| 10787 | fn nextSystemV(it: *ParamTypeIterator, ty: Type) ?Lowering { |
| 10788 | const classes = x86_64_abi.classifySystemV(ty, it.target, .arg); |
| 10789 | if (classes[0] == .memory) { |
| 10790 | it.zig_index += 1; |
| 10791 | it.llvm_index += 1; |
| 10792 | it.byval_attr = true; |
| 10793 | return .byref; |
| 10794 | } |
| 10795 | if (isScalar(ty)) { |
| 10796 | it.zig_index += 1; |
| 10797 | it.llvm_index += 1; |
| 10798 | return .byval; |
| 10799 | } |
| 10800 | var llvm_types_buffer: [8]*llvm.Type = undefined; |
| 10801 | var llvm_types_index: u32 = 0; |
| 10802 | for (classes) |class| { |
| 10803 | switch (class) { |
| 10804 | .integer => { |
| 10805 | llvm_types_buffer[llvm_types_index] = it.dg.context.intType(64); |
| 10806 | llvm_types_index += 1; |
| 10807 | }, |
| 10808 | .sse, .sseup => { |
| 10809 | llvm_types_buffer[llvm_types_index] = it.dg.context.doubleType(); |
| 10810 | llvm_types_index += 1; |
| 10811 | }, |
| 10812 | .float => { |
| 10813 | llvm_types_buffer[llvm_types_index] = it.dg.context.floatType(); |
| 10814 | llvm_types_index += 1; |
| 10815 | }, |
| 10816 | .float_combine => { |
| 10817 | llvm_types_buffer[llvm_types_index] = it.dg.context.floatType().vectorType(2); |
| 10818 | llvm_types_index += 1; |
| 10819 | }, |
| 10820 | .x87 => { |
| 10821 | it.zig_index += 1; |
| 10822 | it.llvm_index += 1; |
| 10823 | it.byval_attr = true; |
| 10824 | return .byref; |
| 10825 | }, |
| 10826 | .x87up => unreachable, |
| 10827 | .complex_x87 => { |
| 10828 | @panic("TODO"); |
| 10829 | }, |
| 10830 | .memory => unreachable, // handled above |
| 10831 | .win_i128 => unreachable, // windows only |
| 10832 | .none => break, |
| 10833 | } |
| 10834 | } |
| 10835 | if (classes[0] == .integer and classes[1] == .none) { |
| 10836 | it.zig_index += 1; |
| 10837 | it.llvm_index += 1; |
| 10838 | return .abi_sized_int; |
| 10839 | } |
| 10840 | it.llvm_types_buffer = llvm_types_buffer; |
| 10841 | it.llvm_types_len = llvm_types_index; |
| 10842 | it.llvm_index += llvm_types_index; |
| 10843 | it.zig_index += 1; |
| 10844 | return .multiple_llvm_types; |
| 10845 | } |
| 10827 | 10846 | }; |
| 10828 | 10847 | |
| 10829 | 10848 | fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTypeIterator { |