diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 91d3b3e7eb9d043d4bd383fb0caa148c1c1c4114..41a587754fde4148558bc49c6e2a815407e8d7c9 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -190,7 +190,7 @@ const WValue = union(enum) { switch (value) { .stack => { const new_local = try gen.allocLocal(ty); - try gen.addLabel(.local_set, new_local.local.value); + try gen.addLocal(.local_set, new_local.local.value); return new_local; }, .local, .stack_offset => return value, @@ -237,9 +237,6 @@ const Op = enum { call_indirect, drop, select, - local_get, - local_set, - local_tee, global_get, global_set, load, @@ -318,9 +315,6 @@ fn buildOpcode(args: OpcodeBuildArguments) std.wasm.Opcode { .call_indirect => unreachable, .drop => unreachable, .select => unreachable, - .local_get => unreachable, - .local_set => unreachable, - .local_tee => unreachable, .global_get => unreachable, .global_set => unreachable, @@ -681,13 +675,11 @@ test "Wasm - buildOpcode" { // Make sure buildOpcode is referenced, and test some examples const i32_const = buildOpcode(.{ .op = .@"const", .valtype1 = .i32 }); const end = buildOpcode(.{ .op = .end }); - const local_get = buildOpcode(.{ .op = .local_get }); const i64_extend32_s = buildOpcode(.{ .op = .extend, .valtype1 = .i64, .width = 32, .signedness = .signed }); const f64_reinterpret_i64 = buildOpcode(.{ .op = .reinterpret, .valtype1 = .f64, .valtype2 = .i64 }); try testing.expectEqual(@as(std.wasm.Opcode, .i32_const), i32_const); try testing.expectEqual(@as(std.wasm.Opcode, .end), end); - try testing.expectEqual(@as(std.wasm.Opcode, .local_get), local_get); try testing.expectEqual(@as(std.wasm.Opcode, .i64_extend32_s), i64_extend32_s); try testing.expectEqual(@as(std.wasm.Opcode, .f64_reinterpret_i64), f64_reinterpret_i64); } @@ -876,6 +868,10 @@ fn addLabel(cg: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void try cg.addInst(.{ .tag = tag, .data = .{ .label = label } }); } +fn addLocal(cg: *CodeGen, tag: Mir.Inst.Tag, local: u32) error{OutOfMemory}!void { + try cg.addInst(.{ .tag = tag, .data = .{ .local = local } }); +} + /// Accepts an unsigned 32bit integer rather than a signed integer to /// prevent us from having to bitcast multiple times as most values /// within codegen are represented as unsigned rather than signed. @@ -1015,7 +1011,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { switch (value) { .dead => unreachable, // reference to free'd `WValue` (missing reuseOperand?) .none, .stack => {}, // no-op - .local => |idx| try cg.addLabel(.local_get, idx.value), + .local => |idx| try cg.addLocal(.local_get, idx.value), .imm32 => |val| try cg.addImm32(val), .imm64 => |val| try cg.addImm64(val), .imm128 => |val| try cg.addImm128(val), @@ -1063,7 +1059,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { }); } }, - .stack_offset => try cg.addLabel(.local_get, cg.bottom_stack_value.local.value), // caller must ensure to address the offset + .stack_offset => try cg.addLocal(.local_get, cg.bottom_stack_value.local.value), // caller must ensure to address the offset } } @@ -1624,7 +1620,7 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { .wasm32 => try cg.addImm32(0), .wasm64 => try cg.addImm64(0), } - try cg.addLabel(.local_set, offset.local.value); + try cg.addLocal(.local_set, offset.local.value); // outer block to jump to when loop is done try cg.startBlock(.block, std.wasm.block_empty); @@ -1682,7 +1678,7 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { try cg.addTag(.i64_add); }, } - try cg.addLabel(.local_set, offset.local.value); + try cg.addLocal(.local_set, offset.local.value); try cg.addLabel(.br, 0); // jump to start of loop } try cg.endBlock(); // close off loop block @@ -1801,7 +1797,7 @@ fn buildPointerOffset(cg: *CodeGen, ptr_value: WValue, offset: u64, action: enum }, } } - try cg.addLabel(.local_set, result_ptr.local.value); + try cg.addLocal(.local_set, result_ptr.local.value); return result_ptr; } @@ -2228,14 +2224,14 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie // TODO: Make this less fragile and optimize } else if (zcu.typeToFunc(fn_ty).?.cc == .wasm_watc and ret_ty.zigTypeTag(zcu) == .@"struct" or ret_ty.zigTypeTag(zcu) == .@"union") { const result_local = try cg.allocLocal(ret_ty); - try cg.addLabel(.local_set, result_local.local.value); + try cg.addLocal(.local_set, result_local.local.value); const scalar_type = abi.scalarType(ret_ty, zcu); const result = try cg.allocStack(scalar_type); try cg.store(result, result_local, scalar_type, 0); break :result_value result; } else { const result_local = try cg.allocLocal(ret_ty); - try cg.addLabel(.local_set, result_local.local.value); + try cg.addLocal(.local_set, result_local.local.value); break :result_value result_local; } }; @@ -2817,7 +2813,7 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { var tmp = try cg.allocLocal(ty); defer tmp.free(cg); - try cg.addLabel(.local_tee, tmp.local.value); + try cg.addLocal(.local_tee, tmp.local.value); try cg.emitWValue(operand); try cg.addTag(.i32_xor); @@ -2833,7 +2829,7 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { var tmp = try cg.allocLocal(ty); defer tmp.free(cg); - try cg.addLabel(.local_tee, tmp.local.value); + try cg.addLocal(.local_tee, tmp.local.value); try cg.emitWValue(operand); try cg.addTag(.i64_xor); @@ -2852,7 +2848,7 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { var tmp = try cg.allocLocal(Type.u64); defer tmp.free(cg); - try cg.addLabel(.local_tee, tmp.local.value); + try cg.addLocal(.local_tee, tmp.local.value); try cg.store(.stack, .stack, Type.u64, mask.offset() + 0); try cg.emitWValue(tmp); try cg.store(.stack, .stack, Type.u64, mask.offset() + 8); @@ -3590,7 +3586,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.lowerToStack(operand); if (block.value != .none) { - try cg.addLabel(.local_set, block.value.local.value); + try cg.addLocal(.local_set, block.value.local.value); } } @@ -3625,7 +3621,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.emitWValue(operand); try cg.addTag(.i32_eqz); const not_tmp = try cg.allocLocal(operand_ty); - try cg.addLabel(.local_set, not_tmp.local.value); + try cg.addLocal(.local_set, not_tmp.local.value); break :result not_tmp; } else { const int_info = operand_ty.intInfo(zcu); @@ -4788,7 +4784,7 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) try cg.addTag(.i64_mul); }, } - try cg.addLabel(.local_set, new_len.local.value); + try cg.addLocal(.local_set, new_len.local.value); break :blk new_len; } else len, }; @@ -4805,7 +4801,7 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) .wasm32 => try cg.addTag(.i32_add), .wasm64 => try cg.addTag(.i64_add), } - try cg.addLabel(.local_set, end_ptr.local.value); + try cg.addLocal(.local_set, end_ptr.local.value); // outer block to jump to when loop is done try cg.startBlock(.block, std.wasm.block_empty); @@ -4835,7 +4831,7 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) try cg.addTag(.i64_add); }, } - try cg.addLabel(.local_set, new_ptr.local.value); + try cg.addLocal(.local_set, new_ptr.local.value); // end of loop try cg.addLabel(.br, 0); // jump to start of loop @@ -5216,7 +5212,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.addImm32(0) else try cg.addImm64(0); - try cg.addLabel(.local_set, result.local.value); + try cg.addLocal(.local_set, result.local.value); var current_bit: u16 = 0; for (elements, 0..) |elem, elem_index| { @@ -5243,7 +5239,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } else extended_val; // we ignore the result as we keep it on the stack to assign it directly to `result` _ = try cg.binOp(.stack, shifted, backing_type, .@"or"); - try cg.addLabel(.local_set, result.local.value); + try cg.addLocal(.local_set, result.local.value); current_bit += value_bit_size; } break :result_value result; @@ -5399,7 +5395,7 @@ fn cmpOptionals(cg: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: st try cg.addLabel(.br_if, 0); try cg.addImm32(1); - try cg.addLabel(.local_set, result.local.value); + try cg.addLocal(.local_set, result.local.value); try cg.endBlock(); try cg.emitWValue(result); @@ -5642,10 +5638,10 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const result = if (field_offset != 0) result: { const base = try cg.buildPointerOffset(field_ptr, 0, .new); - try cg.addLabel(.local_get, base.local.value); + try cg.addLocal(.local_get, base.local.value); try cg.addImm32(@intCast(field_offset)); try cg.addTag(.i32_sub); - try cg.addLabel(.local_set, base.local.value); + try cg.addLocal(.local_set, base.local.value); break :result base; } else cg.reuseOperand(extra.field_ptr, field_ptr); @@ -5676,7 +5672,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.emitWValue(slice_len); try cg.emitWValue(.{ .imm32 = @as(u32, @intCast(ptr_elem_ty.abiSize(zcu))) }); try cg.addTag(.i32_mul); - try cg.addLabel(.local_set, slice_len.local.value); + try cg.addLocal(.local_set, slice_len.local.value); } break :blk slice_len; }, @@ -5827,7 +5823,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } else { var tmp = try cg.allocLocal(Type.u64); defer tmp.free(cg); - try cg.addLabel(.local_tee, tmp.local.value); + try cg.addLocal(.local_tee, tmp.local.value); try cg.emitWValue(.{ .imm64 = 128 - bits }); if (ty.isSignedInt(zcu)) { try cg.addTag(.i64_shr_s); @@ -5835,7 +5831,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.addTag(.i64_shr_u); } try cg.store(.stack, .stack, Type.u64, result.offset() + 8); - try cg.addLabel(.local_get, tmp.local.value); + try cg.addLocal(.local_get, tmp.local.value); try cg.emitWValue(.{ .imm64 = bits - 64 }); try cg.addTag(.i64_shl); try cg.addTag(.i64_or); @@ -6042,7 +6038,7 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const res = try (try cg.trunc(bin_op, ty, new_ty)).toLocal(cg, ty); const res_upcast = try cg.intcast(res, ty, new_ty); _ = try cg.cmp(res_upcast, bin_op, new_ty, .neq); - try cg.addLabel(.local_set, overflow_bit.local.value); + try cg.addLocal(.local_set, overflow_bit.local.value); break :blk res; } else if (wasm_bits == 64) blk: { const new_ty = if (int_info.signedness == .signed) Type.i128 else Type.u128; @@ -6052,7 +6048,7 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const res = try (try cg.trunc(bin_op, ty, new_ty)).toLocal(cg, ty); const res_upcast = try cg.intcast(res, ty, new_ty); _ = try cg.cmp(res_upcast, bin_op, new_ty, .neq); - try cg.addLabel(.local_set, overflow_bit.local.value); + try cg.addLocal(.local_set, overflow_bit.local.value); break :blk res; } else if (int_info.bits == 128 and int_info.signedness == .unsigned) blk: { var lhs_lsb = try (try cg.load(lhs, Type.u64, 0)).toLocal(cg, Type.u64); @@ -6105,7 +6101,7 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { // result for overflow bit _ = try cg.binOp(cond_2, add_overflow, Type.bool, .@"or"); - try cg.addLabel(.local_set, overflow_bit.local.value); + try cg.addLocal(.local_set, overflow_bit.local.value); const tmp_result = try cg.allocStack(Type.u128); try cg.emitWValue(tmp_result); @@ -6122,7 +6118,7 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { &.{ lhs, rhs, overflow_ret }, ); _ = try cg.load(overflow_ret, Type.i32, 0); - try cg.addLabel(.local_set, overflow_bit.local.value); + try cg.addLocal(.local_set, overflow_bit.local.value); break :blk res; } else return cg.fail("TODO: @mulWithOverflow for {}", .{ty.fmt(pt)}); var bin_op_local = try mul.toLocal(cg, ty); @@ -6543,7 +6539,7 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { // tee leaves the value on the stack and stores it in a local. const quotient = try cg.allocLocal(ty); _ = try cg.binOp(lhs, rhs, ty, .div); - try cg.addLabel(.local_tee, quotient.local.value); + try cg.addLocal(.local_tee, quotient.local.value); // select takes a 32 bit value as the condition, so in the 64 bit case we use eqz to narrow // the 64 bit value we want to use as the condition to 32 bits. @@ -6704,7 +6700,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { var tmp = try cg.allocLocal(upcast_ty); defer tmp.free(cg); - try cg.addLabel(.local_set, tmp.local.value); + try cg.addLocal(.local_set, tmp.local.value); const imm_min: WValue = .{ .imm64 = ~@as(u64, 0) << @intCast(int_info.bits - 1) }; try cg.emitWValue(tmp); @@ -6850,13 +6846,13 @@ fn signedSat(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErro try cg.emitWValue(max_wvalue); _ = try cg.cmp(bin_result, max_wvalue, ext_ty, .lt); try cg.addTag(.select); - try cg.addLabel(.local_set, bin_result.local.value); // re-use local + try cg.addLocal(.local_set, bin_result.local.value); // re-use local try cg.emitWValue(bin_result); try cg.emitWValue(min_wvalue); _ = try cg.cmp(bin_result, min_wvalue, ext_ty, .gt); try cg.addTag(.select); - try cg.addLabel(.local_set, bin_result.local.value); // re-use local + try cg.addLocal(.local_set, bin_result.local.value); // re-use local return (try cg.wrapOperand(bin_result, ty)).toLocal(cg, ty); } else { const zero: WValue = switch (wasm_bits) { @@ -6874,7 +6870,7 @@ fn signedSat(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErro const cmp_bin_result = try cg.cmp(bin_result, lhs, ty, .lt); _ = try cg.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor. try cg.addTag(.select); - try cg.addLabel(.local_set, bin_result.local.value); // re-use local + try cg.addLocal(.local_set, bin_result.local.value); // re-use local return bin_result; } } @@ -6928,7 +6924,7 @@ fn airShlSat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.emitWValue(shl); _ = try cg.cmp(lhs, shr, ty, .neq); try cg.addTag(.select); - try cg.addLabel(.local_set, result.local.value); + try cg.addLocal(.local_set, result.local.value); } else { const shift_size = wasm_bits - int_info.bits; const shift_value: WValue = switch (wasm_bits) { @@ -6973,12 +6969,12 @@ fn airShlSat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.emitWValue(shl); _ = try cg.cmp(shl_res, shr, ext_ty, .neq); try cg.addTag(.select); - try cg.addLabel(.local_set, result.local.value); + try cg.addLocal(.local_set, result.local.value); var shift_result = try cg.binOp(result, shift_value, ext_ty, .shr); if (is_signed) { shift_result = try cg.wrapOperand(shift_result, ty); } - try cg.addLabel(.local_set, result.local.value); + try cg.addLocal(.local_set, result.local.value); } return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); @@ -7114,13 +7110,13 @@ fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { // 'false' branch (i.e. error set does not have value // ensure we set local to 0 in case the local was re-used. try cg.addImm32(0); - try cg.addLabel(.local_set, result.local.value); + try cg.addLocal(.local_set, result.local.value); try cg.addLabel(.br, 1); try cg.endBlock(); // 'true' branch try cg.addImm32(1); - try cg.addLabel(.local_set, result.local.value); + try cg.addLocal(.local_set, result.local.value); try cg.addLabel(.br, 0); try cg.endBlock(); @@ -7161,9 +7157,9 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { .offset = ptr_operand.offset(), .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?), }); - try cg.addLabel(.local_tee, val_local.local.value); + try cg.addLocal(.local_tee, val_local.local.value); _ = try cg.cmp(.stack, expected_val, ty, .eq); - try cg.addLabel(.local_set, cmp_result.local.value); + try cg.addLocal(.local_set, cmp_result.local.value); break :val val_local; } else val: { if (ty.abiSize(zcu) > 8) { @@ -7175,7 +7171,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.lowerToStack(new_val); try cg.emitWValue(ptr_val); _ = try cg.cmp(ptr_val, expected_val, ty, .eq); - try cg.addLabel(.local_tee, cmp_result.local.value); + try cg.addLocal(.local_tee, cmp_result.local.value); try cg.addTag(.select); try cg.store(.stack, .stack, ty, 0); @@ -7285,11 +7281,11 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { }, ); const select_res = try cg.allocLocal(ty); - try cg.addLabel(.local_tee, select_res.local.value); + try cg.addLocal(.local_tee, select_res.local.value); _ = try cg.cmp(.stack, value, ty, .neq); // leave on stack so we can use it for br_if try cg.emitWValue(select_res); - try cg.addLabel(.local_set, value.local.value); + try cg.addLocal(.local_set, value.local.value); try cg.addLabel(.br_if, 0); try cg.endBlock();