authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-11-21 20:31:58+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-11-30 17:56:01+01:00
log2be0d5bbca5a261533b96dbc0e7bc400000e6e07
tree5af7e57d44eda6510e37848eb4ae8f6d886e0c7d
parent71038c42f554da86ee23c9c448d39e457d5818eb
signaturelock-open Commit is signed but in an unrecognized format.

wasm: add support packed structs in lowerConstant

When lowering constants of packed structs, which are smaller than 65 bits, we lower the value to an integer rather than store it in the constant data section. This allows us to use an immediate value, for quick loads and stores.

1 files changed, 27 insertions(+), 6 deletions(-)

src/arch/wasm/CodeGen.zig+27-6
......@@ -1119,13 +1119,14 @@ fn genFunc(func: *CodeGen) InnerError!void {
11191119 try func.addTag(.dbg_prologue_end);
11201120
11211121 try func.branches.append(func.gpa, .{});
1122 // clean up outer branch
1123 defer {
1124 var outer_branch = func.branches.pop();
1125 outer_branch.deinit(func.gpa);
1126 }
11221127 // Generate MIR for function body
11231128 try func.genBody(func.air.getMainBody());
11241129
1125 // clean up outer branch
1126 var outer_branch = func.branches.pop();
1127 outer_branch.deinit(func.gpa);
1128
11291130 // In case we have a return value, but the last instruction is a noreturn (such as a while loop)
11301131 // we emit an unreachable instruction to tell the stack validator that part will never be reached.
11311132 if (func_type.returns.len != 0 and func.air.instructions.len > 0) {
......@@ -1607,10 +1608,18 @@ fn isByRef(ty: Type, target: std.Target) bool {
16071608
16081609 .Array,
16091610 .Vector,
1610 .Struct,
16111611 .Frame,
16121612 .Union,
16131613 => return ty.hasRuntimeBitsIgnoreComptime(),
1614 .Struct => {
1615 if (ty.castTag(.@"struct")) |struct_ty| {
1616 const struct_obj = struct_ty.data;
1617 if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) {
1618 return isByRef(struct_obj.backing_int_ty, target);
1619 }
1620 }
1621 return ty.hasRuntimeBitsIgnoreComptime();
1622 },
16141623 .Int => return ty.intInfo(target).bits > 64,
16151624 .Float => return ty.floatBits(target) > 64,
16161625 .ErrorUnion => {
......@@ -2134,7 +2143,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
21342143 const len = @intCast(u32, ty.abiSize(func.target));
21352144 return func.memcpy(lhs, rhs, .{ .imm32 = len });
21362145 },
2137 .Struct, .Array, .Union, .Vector => {
2146 .Struct, .Array, .Union, .Vector => if (isByRef(ty, func.target)) {
21382147 const len = @intCast(u32, ty.abiSize(func.target));
21392148 return func.memcpy(lhs, rhs, .{ .imm32 = len });
21402149 },
......@@ -2689,6 +2698,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
26892698 const is_pl = val.tag() == .opt_payload;
26902699 return WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 };
26912700 },
2701 .Struct => {
2702 const struct_obj = ty.castTag(.@"struct").?.data;
2703 assert(struct_obj.layout == .Packed);
2704 var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer
2705 val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0);
2706 var payload: Value.Payload.U64 = .{
2707 .base = .{ .tag = .int_u64 },
2708 .data = std.mem.readIntLittle(u64, &buf),
2709 };
2710 const int_val = Value.initPayload(&payload.base);
2711 return func.lowerConstant(int_val, struct_obj.backing_int_ty);
2712 },
26922713 else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}),
26932714 }
26942715}