Commit fb0028a0d7
src/arch/mips/abi.zig
@@ -0,0 +1,86 @@
+const std = @import("std");
+const Type = @import("../../Type.zig");
+const Zcu = @import("../../Zcu.zig");
+const assert = std.debug.assert;
+
+pub const Class = union(enum) {
+ memory,
+ byval,
+ i32_array: u8,
+};
+
+pub const Context = enum { ret, arg };
+
+pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
+ const target = zcu.getTarget();
+ std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
+
+ const max_direct_size = target.ptrBitWidth() * 2;
+ switch (ty.zigTypeTag(zcu)) {
+ .@"struct" => {
+ const bit_size = ty.bitSize(zcu);
+ if (ty.containerLayout(zcu) == .@"packed") {
+ if (bit_size > max_direct_size) return .memory;
+ return .byval;
+ }
+ if (bit_size > max_direct_size) return .memory;
+ // TODO: for bit_size <= 32 using byval is more correct, but that needs inreg argument attribute
+ const count = @as(u8, @intCast(std.mem.alignForward(u64, bit_size, 32) / 32));
+ return .{ .i32_array = count };
+ },
+ .@"union" => {
+ const bit_size = ty.bitSize(zcu);
+ if (ty.containerLayout(zcu) == .@"packed") {
+ if (bit_size > max_direct_size) return .memory;
+ return .byval;
+ }
+ if (bit_size > max_direct_size) return .memory;
+
+ return .byval;
+ },
+ .bool => return .byval,
+ .float => return .byval,
+ .int, .@"enum", .error_set => {
+ const bit_size = ty.bitSize(zcu);
+ if (bit_size > max_direct_size) return .memory;
+ return .byval;
+ },
+ .vector => {
+ const elem_type = ty.elemType2(zcu);
+ switch (elem_type.zigTypeTag(zcu)) {
+ .bool, .int => {
+ const bit_size = ty.bitSize(zcu);
+ if (ctx == .ret and bit_size > 128) return .memory;
+ if (bit_size > 512) return .memory;
+ // TODO: byval vector arguments with non power of 2 size need inreg attribute
+ return .byval;
+ },
+ .float => return .memory,
+ else => unreachable,
+ }
+ },
+ .optional => {
+ std.debug.assert(ty.isPtrLikeOptional(zcu));
+ return .byval;
+ },
+ .pointer => {
+ std.debug.assert(!ty.isSlice(zcu));
+ return .byval;
+ },
+ .error_union,
+ .frame,
+ .@"anyframe",
+ .noreturn,
+ .void,
+ .type,
+ .comptime_float,
+ .comptime_int,
+ .undefined,
+ .null,
+ .@"fn",
+ .@"opaque",
+ .enum_literal,
+ .array,
+ => unreachable,
+ }
+}
src/codegen/llvm.zig
@@ -26,6 +26,7 @@ const wasm_c_abi = @import("../arch/wasm/abi.zig");
const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
const arm_c_abi = @import("../arch/arm/abi.zig");
const riscv_c_abi = @import("../arch/riscv64/abi.zig");
+const mips_c_abi = @import("../arch/mips/abi.zig");
const dev = @import("../dev.zig");
const target_util = @import("../target.zig");
@@ -11681,7 +11682,10 @@ fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: std.Targe
return switch (fn_info.cc) {
.Unspecified, .Inline => returnTypeByRef(zcu, target, return_type),
.C => switch (target.cpu.arch) {
- .mips, .mipsel => false,
+ .mips, .mipsel => switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {
+ .memory, .i32_array => true,
+ .byval => false,
+ },
.x86 => isByRef(return_type, zcu),
.x86_64 => switch (target.os.tag) {
.windows => x86_64_abi.classifyWindows(return_type, zcu) == .memory,
@@ -11732,7 +11736,12 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu
.C => {
switch (target.cpu.arch) {
- .mips, .mipsel => return o.lowerType(return_type),
+ .mips, .mipsel => {
+ switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {
+ .memory, .i32_array => return .void,
+ .byval => return o.lowerType(return_type),
+ }
+ },
.x86 => return if (isByRef(return_type, zcu)) .void else o.lowerType(return_type),
.x86_64 => switch (target.os.tag) {
.windows => return lowerWin64FnRetTy(o, fn_info),
@@ -11978,7 +11987,14 @@ const ParamTypeIterator = struct {
.mips, .mipsel => {
it.zig_index += 1;
it.llvm_index += 1;
- return .byval;
+ switch (mips_c_abi.classifyType(ty, zcu, .arg)) {
+ .memory => {
+ it.byval_attr = true;
+ return .byref;
+ },
+ .byval => return .byval,
+ .i32_array => |size| return Lowering{ .i32_array = size },
+ }
},
.x86_64 => switch (target.os.tag) {
.windows => return it.nextWin64(ty),
test/c_abi/cfuncs.c
@@ -2657,7 +2657,7 @@ void run_c_tests(void) {
}
#endif
-#if !defined(__mips__) && !defined(ZIG_PPC32)
+#if !defined(ZIG_PPC32)
{
struct Struct_u64_u64 s = zig_ret_struct_u64_u64();
assert_or_panic(s.a == 1);
@@ -2708,7 +2708,7 @@ void run_c_tests(void) {
#endif
#if !defined __i386__ && !defined __arm__ && !defined __aarch64__ && \
- !defined __mips__ && !defined __powerpc__ && !defined ZIG_RISCV64
+ !defined __powerpc__ && !defined ZIG_RISCV64
{
struct SmallStructInts s = {1, 2, 3, 4};
zig_small_struct_ints(s);
@@ -2716,7 +2716,7 @@ void run_c_tests(void) {
#endif
#if !defined __arm__ && !defined __aarch64__ && \
- !defined __mips__ && !defined __powerpc__ && !defined ZIG_RISCV64
+ !defined __powerpc__ && !defined ZIG_RISCV64
{
struct MedStructInts s = {1, 2, 3};
zig_med_struct_ints(s);
@@ -2741,7 +2741,7 @@ void run_c_tests(void) {
zig_small_packed_struct(s);
}
-#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
+#if !defined __i386__ && !defined __arm__ && \
!defined ZIG_PPC32 && !defined _ARCH_PPC64
{
struct SplitStructInts s = {1234, 100, 1337};
@@ -2756,7 +2756,7 @@ void run_c_tests(void) {
}
#endif
-#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
+#if !defined __i386__ && !defined __arm__ && \
!defined ZIG_PPC32 && !defined _ARCH_PPC64
{
struct SplitStructMixed s = {1234, 100, 1337.0f};
@@ -2764,7 +2764,7 @@ void run_c_tests(void) {
}
#endif
-#if !defined __mips__ && !defined ZIG_PPC32
+#if !defined ZIG_PPC32
{
struct BigStruct s = {30, 31, 32, 33, 34};
struct BigStruct res = zig_big_struct_both(s);
@@ -2784,7 +2784,7 @@ void run_c_tests(void) {
}
#endif
-#if !defined __mips__ && !defined ZIG_PPC32
+#if !defined ZIG_PPC32
{
struct FloatRect r1 = {1, 21, 16, 4};
struct FloatRect r2 = {178, 189, 21, 15};
test/c_abi/main.zig
@@ -322,7 +322,7 @@ extern fn c_struct_u64_u64_7(usize, usize, usize, usize, usize, usize, usize, St
extern fn c_struct_u64_u64_8(usize, usize, usize, usize, usize, usize, usize, usize, Struct_u64_u64) void;
test "C ABI struct u64 u64" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
const s = c_ret_struct_u64_u64();
@@ -359,7 +359,7 @@ extern fn c_ret_struct_f32f32_f32() Struct_f32f32_f32;
extern fn c_struct_f32f32_f32(Struct_f32f32_f32) void;
test "C ABI struct {f32,f32} f32" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
const s = c_ret_struct_f32f32_f32();
@@ -389,7 +389,7 @@ extern fn c_ret_struct_f32_f32f32() Struct_f32_f32f32;
extern fn c_struct_f32_f32f32(Struct_f32_f32f32) void;
test "C ABI struct f32 {f32,f32}" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
const s = c_ret_struct_f32_f32f32();
@@ -424,7 +424,7 @@ extern fn c_ret_struct_u32_union_u32_u32u32() Struct_u32_Union_u32_u32u32;
extern fn c_struct_u32_union_u32_u32u32(Struct_u32_Union_u32_u32u32) void;
test "C ABI struct{u32,union{u32,struct{u32,u32}}}" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
const s = c_ret_struct_u32_union_u32_u32u32();
@@ -444,7 +444,7 @@ const BigStruct = extern struct {
extern fn c_big_struct(BigStruct) void;
test "C ABI big struct" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
const s = BigStruct{
@@ -503,7 +503,7 @@ extern fn c_med_struct_mixed(MedStructMixed) void;
extern fn c_ret_med_struct_mixed() MedStructMixed;
test "C ABI medium struct of ints and floats" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
const s = MedStructMixed{
@@ -535,7 +535,7 @@ extern fn c_ret_small_struct_ints() SmallStructInts;
test "C ABI small struct of ints" {
if (builtin.cpu.arch == .x86) return error.SkipZigTest;
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
const s = SmallStructInts{
@@ -568,7 +568,7 @@ extern fn c_med_struct_ints(MedStructInts) void;
extern fn c_ret_med_struct_ints() MedStructInts;
test "C ABI medium struct of ints" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
const s = MedStructInts{
@@ -646,7 +646,7 @@ extern fn c_split_struct_ints(SplitStructInt) void;
test "C ABI split struct of ints" {
if (builtin.cpu.arch == .x86) return error.SkipZigTest;
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
const s = SplitStructInt{
@@ -673,7 +673,7 @@ extern fn c_ret_split_struct_mixed() SplitStructMixed;
test "C ABI split struct of ints and floats" {
if (builtin.cpu.arch == .x86) return error.SkipZigTest;
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
const s = SplitStructMixed{
@@ -700,7 +700,7 @@ extern fn c_multiple_struct_ints(Rect, Rect) void;
extern fn c_multiple_struct_floats(FloatRect, FloatRect) void;
test "C ABI sret and byval together" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
const s = BigStruct{
@@ -752,7 +752,7 @@ const Vector5 = extern struct {
extern fn c_big_struct_floats(Vector5) void;
test "C ABI structs of floats as parameter" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
const v3 = Vector3{
@@ -828,7 +828,7 @@ export fn zig_multiple_struct_floats(x: FloatRect, y: FloatRect) void {
}
test "C ABI structs of floats as multiple parameters" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
const r1 = FloatRect{
@@ -941,7 +941,7 @@ extern fn c_ret_struct_with_array() StructWithArray;
test "Struct with array as padding." {
if (builtin.cpu.arch == .x86) return error.SkipZigTest;
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2 });
@@ -966,7 +966,7 @@ extern fn c_float_array_struct(FloatArrayStruct) void;
extern fn c_ret_float_array_struct() FloatArrayStruct;
test "Float array like struct" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
c_float_array_struct(.{
@@ -1031,7 +1031,7 @@ extern fn c_ret_big_vec() BigVec;
test "big simd vector" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64() and builtin.mode != .Debug) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .macos and builtin.mode != .Debug) return error.SkipZigTest;
@@ -5340,7 +5340,7 @@ extern fn c_ptr_size_float_struct(Vector2) void;
extern fn c_ret_ptr_size_float_struct() Vector2;
test "C ABI pointer sized float struct" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
@@ -5362,25 +5362,25 @@ pub inline fn expectOk(c_err: c_int) !void {
/// Tests for Double + Char struct
const DC = extern struct { v1: f64, v2: u8 };
test "DC: Zig passes to C" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectOk(c_assert_DC(.{ .v1 = -0.25, .v2 = 15 }));
}
test "DC: Zig returns to C" {
- if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64() and builtin.mode != .Debug) return error.SkipZigTest;
if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectOk(c_assert_ret_DC());
}
test "DC: C passes to Zig" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectOk(c_send_DC());
}
test "DC: C returns to Zig" {
- if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64() and builtin.mode != .Debug) return error.SkipZigTest;
if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectEqual(DC{ .v1 = -0.25, .v2 = 15 }, c_ret_DC());
@@ -5406,12 +5406,12 @@ const CFF = extern struct { v1: u8, v2: f32, v3: f32 };
test "CFF: Zig passes to C" {
if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectOk(c_assert_CFF(.{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 }));
}
test "CFF: Zig returns to C" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectOk(c_assert_ret_CFF());
}
@@ -5419,7 +5419,7 @@ test "CFF: C passes to Zig" {
if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
if (builtin.cpu.arch.isRISCV() and builtin.mode != .Debug) return error.SkipZigTest;
if (builtin.cpu.arch == .aarch64 and builtin.mode != .Debug) return error.SkipZigTest;
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectOk(c_send_CFF());
@@ -5427,7 +5427,7 @@ test "CFF: C passes to Zig" {
test "CFF: C returns to Zig" {
if (builtin.cpu.arch == .aarch64 and builtin.mode != .Debug) return error.SkipZigTest;
if (builtin.cpu.arch.isRISCV() and builtin.mode != .Debug) return error.SkipZigTest;
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectEqual(CFF{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 }, c_ret_CFF());
}
@@ -5451,22 +5451,22 @@ pub export fn zig_ret_CFF() CFF {
const PD = extern struct { v1: ?*anyopaque, v2: f64 };
test "PD: Zig passes to C" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectOk(c_assert_PD(.{ .v1 = null, .v2 = 0.5 }));
}
test "PD: Zig returns to C" {
- if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64() and builtin.mode != .Debug) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectOk(c_assert_ret_PD());
}
test "PD: C passes to Zig" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectOk(c_send_PD());
}
test "PD: C returns to Zig" {
- if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64() and builtin.mode != .Debug) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
try expectEqual(PD{ .v1 = null, .v2 = 0.5 }, c_ret_PD());
}
@@ -5520,7 +5520,7 @@ const ByVal = extern struct {
extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void;
test "C function that takes byval struct called via function pointer" {
- if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64() and builtin.mode != .Debug) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
var fn_ptr = &c_func_ptr_byval;
@@ -5551,7 +5551,7 @@ const f16_struct = extern struct {
};
extern fn c_f16_struct(f16_struct) f16_struct;
test "f16 struct" {
- if (builtin.target.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.target.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.target.cpu.arch.isPowerPC32()) return error.SkipZigTest;
if (builtin.cpu.arch.isARM() and builtin.mode != .Debug) return error.SkipZigTest;
@@ -5666,7 +5666,7 @@ const Coord2 = extern struct {
extern fn stdcall_coord2(Coord2, Coord2, Coord2) callconv(stdcall_callconv) Coord2;
test "Stdcall ABI structs" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
const res = stdcall_coord2(
@@ -5751,7 +5751,7 @@ const byval_tail_callsite_attr = struct {
};
test "byval tail callsite attribute" {
- if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
// Originally reported at https://github.com/ziglang/zig/issues/16290