aboutsummaryrefslogtreecommitdiff
path: root/src/arch/x86_64/abi.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86_64/abi.zig')
-rw-r--r--src/arch/x86_64/abi.zig126
1 files changed, 35 insertions, 91 deletions
diff --git a/src/arch/x86_64/abi.zig b/src/arch/x86_64/abi.zig
index ff1a0ee520..69df5dbf4c 100644
--- a/src/arch/x86_64/abi.zig
+++ b/src/arch/x86_64/abi.zig
@@ -1,10 +1,3 @@
-const std = @import("std");
-const Type = @import("../../type.zig").Type;
-const Target = std.Target;
-const assert = std.debug.assert;
-const Register = @import("bits.zig").Register;
-const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
-
pub const Class = enum {
integer,
sse,
@@ -19,7 +12,7 @@ pub const Class = enum {
float_combine,
};
-pub fn classifyWindows(ty: Type, target: Target) Class {
+pub fn classifyWindows(ty: Type, mod: *Module) Class {
// https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017
// "There's a strict one-to-one correspondence between a function call's arguments
// and the registers used for those arguments. Any argument that doesn't fit in 8
@@ -28,7 +21,7 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
// "All floating point operations are done using the 16 XMM registers."
// "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed
// as if they were integers of the same size."
- switch (ty.zigTypeTag()) {
+ switch (ty.zigTypeTag(mod)) {
.Pointer,
.Int,
.Bool,
@@ -43,12 +36,12 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
.ErrorUnion,
.AnyFrame,
.Frame,
- => switch (ty.abiSize(target)) {
+ => switch (ty.abiSize(mod)) {
0 => unreachable,
1, 2, 4, 8 => return .integer,
- else => switch (ty.zigTypeTag()) {
+ else => switch (ty.zigTypeTag(mod)) {
.Int => return .win_i128,
- .Struct, .Union => if (ty.containerLayout() == .Packed) {
+ .Struct, .Union => if (ty.containerLayout(mod) == .Packed) {
return .win_i128;
} else {
return .memory;
@@ -75,14 +68,15 @@ pub const Context = enum { ret, arg, other };
/// There are a maximum of 8 possible return slots. Returned values are in
/// the beginning of the array; unused slots are filled with .none.
-pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
+pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
+ const target = mod.getTarget();
const memory_class = [_]Class{
.memory, .none, .none, .none,
.none, .none, .none, .none,
};
var result = [1]Class{.none} ** 8;
- switch (ty.zigTypeTag()) {
- .Pointer => switch (ty.ptrSize()) {
+ switch (ty.zigTypeTag(mod)) {
+ .Pointer => switch (ty.ptrSize(mod)) {
.Slice => {
result[0] = .integer;
result[1] = .integer;
@@ -94,7 +88,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
},
},
.Int, .Enum, .ErrorSet => {
- const bits = ty.intInfo(target).bits;
+ const bits = ty.intInfo(mod).bits;
if (bits <= 64) {
result[0] = .integer;
return result;
@@ -164,36 +158,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
else => unreachable,
},
.Vector => {
- const elem_ty = ty.childType();
- if (ctx == .arg) {
- const bit_size = ty.bitSize(target);
- if (bit_size > 128) {
- const has_avx512 = target.cpu.features.isEnabled(@enumToInt(std.Target.x86.Feature.avx512f));
- if (has_avx512 and bit_size <= 512) return .{
- .integer, .integer, .integer, .integer,
- .integer, .integer, .integer, .integer,
- };
- const has_avx = target.cpu.features.isEnabled(@enumToInt(std.Target.x86.Feature.avx));
- if (has_avx and bit_size <= 256) return .{
- .integer, .integer, .integer, .integer,
- .none, .none, .none, .none,
- };
- return memory_class;
- }
- if (bit_size > 80) return .{
- .integer, .integer, .none, .none,
- .none, .none, .none, .none,
- };
- if (bit_size > 64) return .{
- .x87, .none, .none, .none,
- .none, .none, .none, .none,
- };
- return .{
- .integer, .none, .none, .none,
- .none, .none, .none, .none,
- };
- }
- const bits = elem_ty.bitSize(target) * ty.arrayLen();
+ const elem_ty = ty.childType(mod);
+ const bits = elem_ty.bitSize(mod) * ty.arrayLen(mod);
if (bits <= 64) return .{
.sse, .none, .none, .none,
.none, .none, .none, .none,
@@ -202,6 +168,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
.sse, .sseup, .none, .none,
.none, .none, .none, .none,
};
+ if (ctx == .arg and !std.Target.x86.featureSetHas(target.cpu.features, .avx)) return memory_class;
if (bits <= 192) return .{
.sse, .sseup, .sseup, .none,
.none, .none, .none, .none,
@@ -210,6 +177,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
.sse, .sseup, .sseup, .sseup,
.none, .none, .none, .none,
};
+ if (ctx == .arg and !std.Target.x86.featureSetHas(target.cpu.features, .avx512f)) return memory_class;
if (bits <= 320) return .{
.sse, .sseup, .sseup, .sseup,
.sseup, .none, .none, .none,
@@ -230,7 +198,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
return memory_class;
},
.Optional => {
- if (ty.isPtrLikeOptional()) {
+ if (ty.isPtrLikeOptional(mod)) {
result[0] = .integer;
return result;
}
@@ -241,8 +209,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
// it contains unaligned fields, it has class MEMORY"
// "If the size of the aggregate exceeds a single eightbyte, each is classified
// separately.".
- const ty_size = ty.abiSize(target);
- if (ty.containerLayout() == .Packed) {
+ const ty_size = ty.abiSize(mod);
+ if (ty.containerLayout(mod) == .Packed) {
assert(ty_size <= 128);
result[0] = .integer;
if (ty_size > 64) result[1] = .integer;
@@ -253,15 +221,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
var result_i: usize = 0; // out of 8
var byte_i: usize = 0; // out of 8
- const fields = ty.structFields();
+ const fields = ty.structFields(mod);
for (fields.values()) |field| {
if (field.abi_align != 0) {
- if (field.abi_align < field.ty.abiAlignment(target)) {
+ if (field.abi_align < field.ty.abiAlignment(mod)) {
return memory_class;
}
}
- const field_size = field.ty.abiSize(target);
- const field_class_array = classifySystemV(field.ty, target, .other);
+ const field_size = field.ty.abiSize(mod);
+ const field_class_array = classifySystemV(field.ty, mod, .other);
const field_class = std.mem.sliceTo(&field_class_array, .none);
if (byte_i + field_size <= 8) {
// Combine this field with the previous one.
@@ -360,8 +328,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
// it contains unaligned fields, it has class MEMORY"
// "If the size of the aggregate exceeds a single eightbyte, each is classified
// separately.".
- const ty_size = ty.abiSize(target);
- if (ty.containerLayout() == .Packed) {
+ const ty_size = ty.abiSize(mod);
+ if (ty.containerLayout(mod) == .Packed) {
assert(ty_size <= 128);
result[0] = .integer;
if (ty_size > 64) result[1] = .integer;
@@ -370,15 +338,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
if (ty_size > 64)
return memory_class;
- const fields = ty.unionFields();
+ const fields = ty.unionFields(mod);
for (fields.values()) |field| {
if (field.abi_align != 0) {
- if (field.abi_align < field.ty.abiAlignment(target)) {
+ if (field.abi_align < field.ty.abiAlignment(mod)) {
return memory_class;
}
}
// Combine this field with the previous one.
- const field_class = classifySystemV(field.ty, target, .other);
+ const field_class = classifySystemV(field.ty, mod, .other);
for (&result, 0..) |*result_item, i| {
const field_item = field_class[i];
// "If both classes are equal, this is the resulting class."
@@ -452,7 +420,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
return result;
},
.Array => {
- const ty_size = ty.abiSize(target);
+ const ty_size = ty.abiSize(mod);
if (ty_size <= 64) {
result[0] = .integer;
return result;
@@ -553,10 +521,17 @@ pub const RegisterClass = struct {
};
};
+const builtin = @import("builtin");
+const std = @import("std");
+const Target = std.Target;
+const assert = std.debug.assert;
const testing = std.testing;
+
const Module = @import("../../Module.zig");
+const Register = @import("bits.zig").Register;
+const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
+const Type = @import("../../type.zig").Type;
const Value = @import("../../value.zig").Value;
-const builtin = @import("builtin");
fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field {
return .{
@@ -567,34 +542,3 @@ fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field {
.is_comptime = false,
};
}
-
-test "C_C_D" {
- var fields = Module.Struct.Fields{};
- // const C_C_D = extern struct { v1: i8, v2: i8, v3: f64 };
- try fields.ensureTotalCapacity(testing.allocator, 3);
- defer fields.deinit(testing.allocator);
- fields.putAssumeCapacity("v1", _field(.i8, 0));
- fields.putAssumeCapacity("v2", _field(.i8, 1));
- fields.putAssumeCapacity("v3", _field(.f64, 4));
-
- var C_C_D_struct = Module.Struct{
- .fields = fields,
- .namespace = undefined,
- .owner_decl = undefined,
- .zir_index = undefined,
- .layout = .Extern,
- .status = .fully_resolved,
- .known_non_opv = true,
- .is_tuple = false,
- };
- var C_C_D = Type.Payload.Struct{ .data = &C_C_D_struct };
-
- try testing.expectEqual(
- [_]Class{ .integer, .sse, .none, .none, .none, .none, .none, .none },
- classifySystemV(Type.initPayload(&C_C_D.base), builtin.target, .ret),
- );
- try testing.expectEqual(
- [_]Class{ .integer, .sse, .none, .none, .none, .none, .none, .none },
- classifySystemV(Type.initPayload(&C_C_D.base), builtin.target, .arg),
- );
-}