Skip to content

Commit

Permalink
Merge pull request #13718 from Luukdegram/wasm-packed
Browse files Browse the repository at this point in the history
stage2: Wasm - Implement packed structs
  • Loading branch information
andrewrk authored Dec 1, 2022
2 parents 34fa6a1 + 090deae commit 94e751a
Show file tree
Hide file tree
Showing 10 changed files with 471 additions and 215 deletions.
584 changes: 416 additions & 168 deletions src/arch/wasm/CodeGen.zig

Large diffs are not rendered by default.

22 changes: 16 additions & 6 deletions src/arch/wasm/abi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,25 @@ pub fn classifyType(ty: Type, target: Target) [2]Class {
pub fn scalarType(ty: Type, target: std.Target) Type {
switch (ty.zigTypeTag()) {
.Struct => {
std.debug.assert(ty.structFieldCount() == 1);
return scalarType(ty.structFieldType(0), target);
switch (ty.containerLayout()) {
.Packed => {
const struct_obj = ty.castTag(.@"struct").?.data;
return scalarType(struct_obj.backing_int_ty, target);
},
else => {
std.debug.assert(ty.structFieldCount() == 1);
return scalarType(ty.structFieldType(0), target);
},
}
},
.Union => {
const layout = ty.unionGetLayout(target);
if (layout.payload_size == 0 and layout.tag_size != 0) {
return scalarType(ty.unionTagTypeSafety().?, target);
if (ty.containerLayout() != .Packed) {
const layout = ty.unionGetLayout(target);
if (layout.payload_size == 0 and layout.tag_size != 0) {
return scalarType(ty.unionTagTypeSafety().?, target);
}
std.debug.assert(ty.unionFields().count() == 1);
}
std.debug.assert(ty.unionFields().count() == 1);
return scalarType(ty.unionFields().values()[0].ty, target);
},
else => return ty,
Expand Down
44 changes: 36 additions & 8 deletions src/codegen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -556,14 +556,42 @@ pub fn generateSymbol(
},
.Struct => {
if (typed_value.ty.containerLayout() == .Packed) {
return Result{
.fail = try ErrorMsg.create(
bin_file.allocator,
src_loc,
"TODO implement generateSymbol for packed struct",
.{},
),
};
const struct_obj = typed_value.ty.castTag(.@"struct").?.data;
const fields = struct_obj.fields.values();
const field_vals = typed_value.val.castTag(.aggregate).?.data;
const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow;
const current_pos = code.items.len;
const mod = bin_file.options.module.?;
try code.resize(current_pos + abi_size);
var bits: u16 = 0;

for (field_vals) |field_val, index| {
const field_ty = fields[index].ty;
// pointer may point to a decl which must be marked used
// but can also result in a relocation. Therefore we handle those seperately.
if (field_ty.zigTypeTag() == .Pointer) {
const field_size = math.cast(usize, field_ty.abiSize(target)) orelse return error.Overflow;
var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size);
defer tmp_list.deinit();
switch (try generateSymbol(bin_file, src_loc, .{
.ty = field_ty,
.val = field_val,
}, &tmp_list, debug_output, reloc_info)) {
.appended => {
mem.copy(u8, code.items[current_pos..], tmp_list.items);
},
.externally_managed => |external_slice| {
mem.copy(u8, code.items[current_pos..], external_slice);
},
.fail => |em| return Result{ .fail = em },
}
} else {
field_val.writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits);
}
bits += @intCast(u16, field_ty.bitSize(target));
}

return Result{ .appended = {} };
}

const struct_begin = code.items.len;
Expand Down
5 changes: 3 additions & 2 deletions src/link/Wasm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1841,8 +1841,9 @@ fn setupStart(wasm: *Wasm) !void {
/// Sets up the memory section of the wasm module, as well as the stack.
fn setupMemory(wasm: *Wasm) !void {
log.debug("Setting up memory layout", .{});
const page_size = 64 * 1024;
const stack_size = wasm.base.options.stack_size_override orelse page_size * 1;
const page_size = std.wasm.page_size; // 64kb
// Use the user-provided stack size or else we use 1MB by default
const stack_size = wasm.base.options.stack_size_override orelse page_size * 16;
const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention
// Always place the stack at the start by default
// unless the user specified the global-base flag
Expand Down
6 changes: 0 additions & 6 deletions test/behavior/bitcast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ test "@bitCast iX -> uX (32, 64)" {
}

test "@bitCast iX -> uX (8, 16, 128)" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
Expand Down Expand Up @@ -160,7 +159,6 @@ test "@bitCast packed structs at runtime and comptime" {
// stage1 gets the wrong answer for a lot of targets
return error.SkipZigTest;
}
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
Expand All @@ -187,7 +185,6 @@ test "@bitCast packed structs at runtime and comptime" {
}

test "@bitCast extern structs at runtime and comptime" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;

const Full = extern struct {
Expand Down Expand Up @@ -218,7 +215,6 @@ test "@bitCast extern structs at runtime and comptime" {
}

test "bitcast packed struct to integer and back" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
Expand Down Expand Up @@ -257,8 +253,6 @@ test "implicit cast to error union by returning" {
}

test "bitcast packed struct literal to byte" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;

const Foo = packed struct {
value: u8,
};
Expand Down
1 change: 0 additions & 1 deletion test/behavior/bugs/12776.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const CPU = packed struct {
test {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;

var ram = try RAM.new();
Expand Down
1 change: 0 additions & 1 deletion test/behavior/bugs/9584.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ pub fn b(x: *X) !void {
}

test {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
Expand Down
2 changes: 0 additions & 2 deletions test/behavior/enum.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1146,8 +1146,6 @@ test "size of enum with only one tag which has explicit integer tag type" {
}

test "switch on an extern enum with negative value" {
if (@import("builtin").zig_backend == .stage2_wasm) return error.SkipZigTest;

const Foo = enum(c_int) {
Bar = -1,
};
Expand Down
9 changes: 0 additions & 9 deletions test/behavior/packed-struct.zig
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ test "consistent size of packed structs" {

test "correct sizeOf and offsets in packed structs" {
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
Expand Down Expand Up @@ -220,7 +219,6 @@ test "correct sizeOf and offsets in packed structs" {

test "nested packed structs" {
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
Expand Down Expand Up @@ -267,7 +265,6 @@ test "nested packed structs" {
}

test "regular in irregular packed struct" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
Expand All @@ -289,7 +286,6 @@ test "regular in irregular packed struct" {

test "byte-aligned field pointer offsets" {
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
Expand Down Expand Up @@ -395,7 +391,6 @@ test "load pointer from packed struct" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;

const A = struct {
index: u16,
Expand All @@ -413,7 +408,6 @@ test "load pointer from packed struct" {
}

test "@ptrToInt on a packed struct field" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
Expand All @@ -437,7 +431,6 @@ test "optional pointer in packed struct" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;

const T = packed struct { ptr: ?*const u8 };
var n: u8 = 0;
Expand Down Expand Up @@ -566,7 +559,6 @@ test "nested packed struct field access test" {
test "runtime init of unnamed packed struct type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;

var z: u8 = 123;
Expand All @@ -582,7 +574,6 @@ test "packed struct passed to callconv(.C) function" {
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;

const S = struct {
Expand Down
12 changes: 0 additions & 12 deletions test/behavior/struct.zig
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,6 @@ const APackedStruct = packed struct {

test "packed struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
Expand Down Expand Up @@ -460,7 +459,6 @@ test "packed struct 24bits" {

test "runtime struct initialization of bitfield" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
Expand Down Expand Up @@ -504,7 +502,6 @@ test "packed struct fields are ordered from LSB to MSB" {
return error.SkipZigTest;
}
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
Expand All @@ -525,7 +522,6 @@ test "packed struct fields are ordered from LSB to MSB" {

test "implicit cast packed struct field to const ptr" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
Expand All @@ -546,7 +542,6 @@ test "implicit cast packed struct field to const ptr" {
}

test "zero-bit field in packed struct" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO

Expand Down Expand Up @@ -591,7 +586,6 @@ const bit_field_1 = BitField1{

test "bit field access" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
Expand Down Expand Up @@ -647,7 +641,6 @@ test "default struct initialization fields" {

test "packed array 24bits" {
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
Expand Down Expand Up @@ -735,7 +728,6 @@ const FooArrayOfAligned = packed struct {
};

test "pointer to packed struct member in a stack variable" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
Expand All @@ -754,7 +746,6 @@ test "pointer to packed struct member in a stack variable" {
}

test "packed struct with u0 field access" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO

Expand Down Expand Up @@ -864,7 +855,6 @@ test "non-packed struct with u128 entry in union" {
}

test "packed struct field passed to generic function" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
Expand Down Expand Up @@ -1298,7 +1288,6 @@ test "packed struct aggregate init" {
// stage1 fails this test on mips
return error.SkipZigTest;
}
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
Expand All @@ -1319,7 +1308,6 @@ test "packed struct aggregate init" {
}

test "packed struct field access via pointer" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
Expand Down

0 comments on commit 94e751a

Please sign in to comment.