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{...@@ -341,7 +341,7 @@ const InnerError = error{
341 AlreadyReported,341 AlreadyReported,
342 /// Compiler implementation could not handle a large integer.342 /// Compiler implementation could not handle a large integer.
343 Overflow,343 Overflow,
344} || link.File.UpdateDebugInfoError;344};
345345
346pub fn deinit(cg: *CodeGen) void {346pub fn deinit(cg: *CodeGen) void {
347 const gpa = cg.gpa;347 const gpa = cg.gpa;
...@@ -1577,7 +1577,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1577,7 +1577,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1577 .int_from_ptr => cg.airIntFromPtr(inst),1577 .int_from_ptr => cg.airIntFromPtr(inst),
15781578
1579 .bit_cast => cg.airBitcast(inst),1579 .bit_cast => cg.airBitcast(inst),
1580 .union_from_enum => cg.airBitcast(inst),1580 .union_from_enum => cg.airUnionFromEnum(inst),
15811581
1582 .int_cast => {1582 .int_cast => {
1583 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;1583 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 {...@@ -5570,6 +5570,21 @@ fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5570 return cg.finishAir(inst, result, &.{ty_op.operand});5570 return cg.finishAir(inst, result, &.{ty_op.operand});
5571}5571}
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
5573fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5588fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5574 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5589 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5575 const operand = try cg.resolveInst(ty_op.operand);5590 const operand = try cg.resolveInst(ty_op.operand);
...@@ -5581,25 +5596,62 @@ fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5581,25 +5596,62 @@ fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5581 return cg.finishAir(inst, result, &.{ty_op.operand});5596 return cg.finishAir(inst, result, &.{ty_op.operand});
5582}5597}
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
5584fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!?WValue {5621fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!?WValue {
5585 const zcu = cg.pt.zcu;5622 const zcu = cg.pt.zcu;
5586 const bit_size = src_ty.bitSize(zcu);5623 const src_class = cg.bitcastClass(src_ty);
5587 const dest_signed = if (dest_ty.isAbiInt(zcu)) IntType.fromType(cg, dest_ty).is_signed else false;5624 const dest_class = cg.bitcastClass(dest_ty);
5588 const src_signed = if (src_ty.isAbiInt(zcu)) IntType.fromType(cg, src_ty).is_signed else false;5625 const src_by_ref = isByRef(src_ty, zcu, cg.target);
5589 const needs_wrapping = (src_signed != dest_signed) and5626 const dest_by_ref = isByRef(dest_ty, zcu, cg.target);
5590 bit_size != 32 and bit_size != 64 and bit_size != 128;5627
55915628 const needs_wrapping = switch (dest_class) {
5592 if (src_ty.isAnyFloat()) {5629 .int => |dest_int| dest_int.bits != cg.intBackingBits(dest_int.bits) and
5593 const float_ty: FloatType = .fromType(cg, src_ty);5630 switch (src_class) {
5594 switch (float_ty) {5631 .int => |src_int| src_int.is_signed != dest_int.is_signed,
5595 .f16, .f80, .f128 => {5632 .float, .aggregate => true,
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 }
5602 },5633 },
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),
5603 .f32 => {5655 .f32 => {
5604 try cg.emitWValue(operand);5656 try cg.emitWValue(operand);
5605 try cg.addTag(.i32_reinterpret_f32);5657 try cg.addTag(.i32_reinterpret_f32);
...@@ -5610,19 +5662,15 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro...@@ -5610,19 +5662,15 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro
5610 try cg.addTag(.i64_reinterpret_f64);5662 try cg.addTag(.i64_reinterpret_f64);
5611 return .stack;5663 return .stack;
5612 },5664 },
5613 }5665 .f80, .f128 => unreachable,
5666 },
5667 .int => {},
5668 .aggregate => unreachable,
5614 }5669 }
56155670
5616 if (dest_ty.isAnyFloat()) {5671 switch (dest_class) {
5617 const float_ty: FloatType = .fromType(cg, dest_ty);5672 .float => |float_ty| switch (float_ty) {
5618 switch (float_ty) {5673 .f16 => return null,
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 },
5626 .f32 => {5674 .f32 => {
5627 try cg.emitWValue(operand);5675 try cg.emitWValue(operand);
5628 try cg.addTag(.f32_reinterpret_i32);5676 try cg.addTag(.f32_reinterpret_i32);
...@@ -5633,40 +5681,17 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro...@@ -5633,40 +5681,17 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro
5633 try cg.addTag(.f64_reinterpret_i64);5681 try cg.addTag(.f64_reinterpret_i64);
5634 return .stack;5682 return .stack;
5635 },5683 },
5636 }5684 .f80, .f128 => unreachable,
5637 }5685 },
56385686 .int => {},
5639 if (isByRef(src_ty, zcu, cg.target) and !isByRef(dest_ty, zcu, cg.target)) {5687 .aggregate => unreachable,
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 }
5658 }5688 }
56595689
5660 if (needs_wrapping) {5690 if (needs_wrapping) {
5661 const int_ty: IntType = .fromType(cg, dest_ty);5691 return try cg.intWrap(dest_class.int, operand);
5662 return try cg.intWrap(int_ty, operand);
5663 }5692 }
56645693
5665 return switch (operand) {5694 return null;
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 };
5670}5695}
56715696
5672fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5697fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -6992,8 +7017,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6992,8 +7017,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6992 }7017 }
6993 break :result result_ptr;7018 break :result result_ptr;
6994 } else {7019 } else {
6995 const operand = try cg.resolveInst(extra.init);7020 unreachable;
6996 break :result (try cg.bitcast(union_ty, field_ty, operand)) orelse cg.reuseOperand(extra.init, operand);
6997 }7021 }
6998 };7022 };
69997023