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 {...@@ -1119,13 +1119,14 @@ fn genFunc(func: *CodeGen) InnerError!void {
1119 try func.addTag(.dbg_prologue_end);1119 try func.addTag(.dbg_prologue_end);
11201120
1121 try func.branches.append(func.gpa, .{});1121 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 }
1122 // Generate MIR for function body1127 // Generate MIR for function body
1123 try func.genBody(func.air.getMainBody());1128 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
1129 // In case we have a return value, but the last instruction is a noreturn (such as a while loop)1130 // In case we have a return value, but the last instruction is a noreturn (such as a while loop)
1130 // we emit an unreachable instruction to tell the stack validator that part will never be reached.1131 // we emit an unreachable instruction to tell the stack validator that part will never be reached.
1131 if (func_type.returns.len != 0 and func.air.instructions.len > 0) {1132 if (func_type.returns.len != 0 and func.air.instructions.len > 0) {
...@@ -1607,10 +1608,18 @@ fn isByRef(ty: Type, target: std.Target) bool {...@@ -1607,10 +1608,18 @@ fn isByRef(ty: Type, target: std.Target) bool {
16071608
1608 .Array,1609 .Array,
1609 .Vector,1610 .Vector,
1610 .Struct,
1611 .Frame,1611 .Frame,
1612 .Union,1612 .Union,
1613 => return ty.hasRuntimeBitsIgnoreComptime(),1613 => 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 },
1614 .Int => return ty.intInfo(target).bits > 64,1623 .Int => return ty.intInfo(target).bits > 64,
1615 .Float => return ty.floatBits(target) > 64,1624 .Float => return ty.floatBits(target) > 64,
1616 .ErrorUnion => {1625 .ErrorUnion => {
...@@ -2134,7 +2143,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2134,7 +2143,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2134 const len = @intCast(u32, ty.abiSize(func.target));2143 const len = @intCast(u32, ty.abiSize(func.target));
2135 return func.memcpy(lhs, rhs, .{ .imm32 = len });2144 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2136 },2145 },
2137 .Struct, .Array, .Union, .Vector => {2146 .Struct, .Array, .Union, .Vector => if (isByRef(ty, func.target)) {
2138 const len = @intCast(u32, ty.abiSize(func.target));2147 const len = @intCast(u32, ty.abiSize(func.target));
2139 return func.memcpy(lhs, rhs, .{ .imm32 = len });2148 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2140 },2149 },
...@@ -2689,6 +2698,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -2689,6 +2698,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
2689 const is_pl = val.tag() == .opt_payload;2698 const is_pl = val.tag() == .opt_payload;
2690 return WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 };2699 return WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 };
2691 },2700 },
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 },
2692 else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}),2713 else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}),
2693 }2714 }
2694}2715}