authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-07-16 10:30:29+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-07-17 05:27:06+02:00
logf1d454d535c96a1b1eee74a026a231af106448fb
treedc11194110c520378e59c6548fe36030b3e5de42
parent301afca49d40e5cce7d7c221c3f2a46511dcdc80

stage2-wasm: remove invariant for padding bits for f16, f80 + rework bitcast


1 files changed, 84 insertions(+), 60 deletions(-)

src/codegen/wasm/CodeGen.zig+84-60
......@@ -341,7 +341,7 @@ const InnerError = error{
341341 AlreadyReported,
342342 /// Compiler implementation could not handle a large integer.
343343 Overflow,
344} || link.File.UpdateDebugInfoError;
344};
345345
346346pub fn deinit(cg: *CodeGen) void {
347347 const gpa = cg.gpa;
......@@ -1577,7 +1577,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
15771577 .int_from_ptr => cg.airIntFromPtr(inst),
15781578
15791579 .bit_cast => cg.airBitcast(inst),
1580 .union_from_enum => cg.airBitcast(inst),
1580 .union_from_enum => cg.airUnionFromEnum(inst),
15811581
15821582 .int_cast => {
15831583 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
......@@ -5570,6 +5570,21 @@ fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
55705570 return cg.finishAir(inst, result, &.{ty_op.operand});
55715571}
55725572
5573fn airUnionFromEnum(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5574 const zcu = cg.pt.zcu;
5575 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5576
5577 const union_ty = cg.typeOfIndex(inst);
5578 const enum_ty = cg.typeOf(ty_op.operand);
5579 const layout = union_ty.unionGetLayout(zcu);
5580
5581 const enum_value = try cg.resolveInst(ty_op.operand);
5582 const result = try cg.allocStack(union_ty);
5583 try cg.store(result, enum_value, enum_ty, @intCast(layout.tagOffset()));
5584
5585 return cg.finishAir(inst, result, &.{ty_op.operand});
5586}
5587
55735588fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
55745589 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
55755590 const operand = try cg.resolveInst(ty_op.operand);
......@@ -5581,25 +5596,62 @@ fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
55815596 return cg.finishAir(inst, result, &.{ty_op.operand});
55825597}
55835598
5599const BitcastClass = union(enum) {
5600 int: IntType,
5601 float: FloatType,
5602 aggregate, // arrays and vectors.
5603};
5604
5605fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {
5606 const zcu = cg.pt.zcu;
5607 return switch (ty.zigTypeTag(zcu)) {
5608 .bool,
5609 .int,
5610 .@"enum",
5611 .error_set,
5612 .@"struct",
5613 .@"union",
5614 => .{ .int = .fromType(cg, ty) },
5615 .float => .{ .float = .fromType(cg, ty) },
5616 .array, .vector => .aggregate,
5617 else => unreachable,
5618 };
5619}
5620
55845621fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!?WValue {
55855622 const zcu = cg.pt.zcu;
5586 const bit_size = src_ty.bitSize(zcu);
5587 const dest_signed = if (dest_ty.isAbiInt(zcu)) IntType.fromType(cg, dest_ty).is_signed else false;
5588 const src_signed = if (src_ty.isAbiInt(zcu)) IntType.fromType(cg, src_ty).is_signed else false;
5589 const needs_wrapping = (src_signed != dest_signed) and
5590 bit_size != 32 and bit_size != 64 and bit_size != 128;
5591
5592 if (src_ty.isAnyFloat()) {
5593 const float_ty: FloatType = .fromType(cg, src_ty);
5594 switch (float_ty) {
5595 .f16, .f80, .f128 => {
5596 if (dest_signed) {
5597 const int_ty: IntType = .fromType(cg, dest_ty);
5598 return try cg.intWrap(int_ty, operand);
5599 } else {
5600 return null;
5601 }
5623 const src_class = cg.bitcastClass(src_ty);
5624 const dest_class = cg.bitcastClass(dest_ty);
5625 const src_by_ref = isByRef(src_ty, zcu, cg.target);
5626 const dest_by_ref = isByRef(dest_ty, zcu, cg.target);
5627
5628 const needs_wrapping = switch (dest_class) {
5629 .int => |dest_int| dest_int.bits != cg.intBackingBits(dest_int.bits) and
5630 switch (src_class) {
5631 .int => |src_int| src_int.is_signed != dest_int.is_signed,
5632 .float, .aggregate => true,
56025633 },
5634 .float, .aggregate => false,
5635 };
5636
5637 if (src_by_ref and dest_by_ref) {
5638 if (needs_wrapping) return try cg.intWrap(dest_class.int, operand);
5639 return null;
5640 }
5641
5642 if (dest_by_ref) {
5643 const result = try cg.allocStack(src_ty);
5644 try cg.store(result, operand, src_ty, 0);
5645 return result;
5646 }
5647
5648 if (src_by_ref) {
5649 return try cg.load(operand, dest_ty, 0);
5650 }
5651
5652 switch (src_class) {
5653 .float => |float_ty| switch (float_ty) {
5654 .f16 => return try cg.intWrap(dest_class.int, operand),
56035655 .f32 => {
56045656 try cg.emitWValue(operand);
56055657 try cg.addTag(.i32_reinterpret_f32);
......@@ -5610,19 +5662,15 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro
56105662 try cg.addTag(.i64_reinterpret_f64);
56115663 return .stack;
56125664 },
5613 }
5665 .f80, .f128 => unreachable,
5666 },
5667 .int => {},
5668 .aggregate => unreachable,
56145669 }
56155670
5616 if (dest_ty.isAnyFloat()) {
5617 const float_ty: FloatType = .fromType(cg, dest_ty);
5618 switch (float_ty) {
5619 .f16, .f80, .f128 => {
5620 if (src_signed) {
5621 return try cg.intWrap(.{ .bits = @intCast(bit_size), .is_signed = false }, operand);
5622 } else {
5623 return null;
5624 }
5625 },
5671 switch (dest_class) {
5672 .float => |float_ty| switch (float_ty) {
5673 .f16 => return null,
56265674 .f32 => {
56275675 try cg.emitWValue(operand);
56285676 try cg.addTag(.f32_reinterpret_i32);
......@@ -5633,40 +5681,17 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro
56335681 try cg.addTag(.f64_reinterpret_i64);
56345682 return .stack;
56355683 },
5636 }
5637 }
5638
5639 if (isByRef(src_ty, zcu, cg.target) and !isByRef(dest_ty, zcu, cg.target)) {
5640 const loaded_memory = try cg.load(operand, dest_ty, 0);
5641 if (needs_wrapping) {
5642 const int_ty: IntType = .fromType(cg, dest_ty);
5643 return try cg.intWrap(int_ty, loaded_memory);
5644 } else {
5645 return loaded_memory;
5646 }
5647 }
5648
5649 if (!isByRef(src_ty, zcu, cg.target) and isByRef(dest_ty, zcu, cg.target)) {
5650 const stack_memory = try cg.allocStack(dest_ty);
5651 try cg.store(stack_memory, operand, src_ty, 0);
5652 if (needs_wrapping) {
5653 const int_ty: IntType = .fromType(cg, dest_ty);
5654 return try cg.intWrap(int_ty, stack_memory);
5655 } else {
5656 return stack_memory;
5657 }
5684 .f80, .f128 => unreachable,
5685 },
5686 .int => {},
5687 .aggregate => unreachable,
56585688 }
56595689
56605690 if (needs_wrapping) {
5661 const int_ty: IntType = .fromType(cg, dest_ty);
5662 return try cg.intWrap(int_ty, operand);
5691 return try cg.intWrap(dest_class.int, operand);
56635692 }
56645693
5665 return switch (operand) {
5666 // for stack offset, return a pointer to this offset.
5667 .stack_offset => try cg.buildPointerOffset(operand, 0, .new),
5668 else => null, // caller should use cg.reuseOperand, if returnes for AIR
5669 };
5694 return null;
56705695}
56715696
56725697fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
......@@ -6992,8 +7017,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
69927017 }
69937018 break :result result_ptr;
69947019 } else {
6995 const operand = try cg.resolveInst(extra.init);
6996 break :result (try cg.bitcast(union_ty, field_ty, operand)) orelse cg.reuseOperand(extra.init, operand);
7020 unreachable;
69977021 }
69987022 };
69997023