authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-19 22:43:59-04:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-21 08:49:54+01:00
log3f4569bf187bfe296323aee6fbb59ab374041243
tree8a8a92c78f3c248774932daf7351c4a185fcb308
parent6c453dd806d9a0207b1f1e64adfc38eca0c38f16

codegen: fix backend breakage due to optional layout change


3 files changed, 65 insertions(+), 67 deletions(-)

src/arch/aarch64/CodeGen.zig+46-36
...@@ -3011,41 +3011,16 @@ fn optionalPayload(self: *Self, inst: Air.Inst.Index, mcv: MCValue, optional_ty:...@@ -3011,41 +3011,16 @@ fn optionalPayload(self: *Self, inst: Air.Inst.Index, mcv: MCValue, optional_ty:
3011 return MCValue{ .register = reg };3011 return MCValue{ .register = reg };
3012 }3012 }
30133013
3014 const offset = @intCast(u32, optional_ty.abiSize(self.target.*) - payload_ty.abiSize(self.target.*));
3015 switch (mcv) {3014 switch (mcv) {
3016 .register => |source_reg| {3015 .register => {
3017 // TODO should we reuse the operand here?3016 // TODO should we reuse the operand here?
3018 const raw_reg = try self.register_manager.allocReg(inst, gp);3017 const raw_reg = try self.register_manager.allocReg(inst, gp);
3019 const dest_reg = raw_reg.toX();3018 const dest_reg = raw_reg.toX();
30203019
3021 const shift = @intCast(u6, offset * 8);3020 try self.genSetReg(payload_ty, dest_reg, mcv);
3022 if (shift == 0) {
3023 try self.genSetReg(payload_ty, dest_reg, mcv);
3024 } else {
3025 _ = try self.addInst(.{
3026 .tag = if (payload_ty.isSignedInt())
3027 Mir.Inst.Tag.asr_immediate
3028 else
3029 Mir.Inst.Tag.lsr_immediate,
3030 .data = .{ .rr_shift = .{
3031 .rd = dest_reg,
3032 .rn = source_reg.toX(),
3033 .shift = shift,
3034 } },
3035 });
3036 }
3037
3038 return MCValue{ .register = self.registerAlias(dest_reg, payload_ty) };3021 return MCValue{ .register = self.registerAlias(dest_reg, payload_ty) };
3039 },3022 },
3040 .stack_argument_offset => |off| {3023 .stack_argument_offset, .stack_offset, .memory => return mcv,
3041 return MCValue{ .stack_argument_offset = off + offset };
3042 },
3043 .stack_offset => |off| {
3044 return MCValue{ .stack_offset = off - offset };
3045 },
3046 .memory => |addr| {
3047 return MCValue{ .memory = addr + offset };
3048 },
3049 else => unreachable, // invalid MCValue for an error union3024 else => unreachable, // invalid MCValue for an error union
3050 }3025 }
3051}3026}
...@@ -3289,12 +3264,11 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {...@@ -3289,12 +3264,11 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
32893264
3290 const optional_abi_size = @intCast(u32, optional_ty.abiSize(self.target.*));3265 const optional_abi_size = @intCast(u32, optional_ty.abiSize(self.target.*));
3291 const optional_abi_align = optional_ty.abiAlignment(self.target.*);3266 const optional_abi_align = optional_ty.abiAlignment(self.target.*);
3292 const payload_abi_size = @intCast(u32, payload_ty.abiSize(self.target.*));3267 const offset = @intCast(u32, payload_ty.abiSize(self.target.*));
3293 const offset = optional_abi_size - payload_abi_size;
32943268
3295 const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst);3269 const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst);
3296 try self.genSetStack(Type.bool, stack_offset, .{ .immediate = 1 });3270 try self.genSetStack(payload_ty, stack_offset, operand);
3297 try self.genSetStack(payload_ty, stack_offset - @intCast(u32, offset), operand);3271 try self.genSetStack(Type.bool, stack_offset - offset, .{ .immediate = 1 });
32983272
3299 break :result MCValue{ .stack_offset = stack_offset };3273 break :result MCValue{ .stack_offset = stack_offset };
3300 };3274 };
...@@ -4834,13 +4808,49 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4834,13 +4808,49 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4834}4808}
48354809
4836fn isNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue {4810fn isNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue {
4837 const sentinel_ty: Type = if (!operand_ty.isPtrLikeOptional()) blk: {4811 const sentinel: struct { ty: Type, bind: ReadArg.Bind } = if (!operand_ty.isPtrLikeOptional()) blk: {
4838 var buf: Type.Payload.ElemType = undefined;4812 var buf: Type.Payload.ElemType = undefined;
4839 const payload_ty = operand_ty.optionalChild(&buf);4813 const payload_ty = operand_ty.optionalChild(&buf);
4840 break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime()) Type.bool else operand_ty;4814 if (!payload_ty.hasRuntimeBitsIgnoreComptime())
4841 } else operand_ty;4815 break :blk .{ .ty = operand_ty, .bind = operand_bind };
4816
4817 const offset = @intCast(u32, payload_ty.abiSize(self.target.*));
4818 const operand_mcv = try operand_bind.resolveToMcv(self);
4819 const new_mcv: MCValue = switch (operand_mcv) {
4820 .register => |source_reg| new: {
4821 // TODO should we reuse the operand here?
4822 const raw_reg = try self.register_manager.allocReg(null, gp);
4823 const dest_reg = raw_reg.toX();
4824
4825 const shift = @intCast(u6, offset * 8);
4826 if (shift == 0) {
4827 try self.genSetReg(payload_ty, dest_reg, operand_mcv);
4828 } else {
4829 _ = try self.addInst(.{
4830 .tag = if (payload_ty.isSignedInt())
4831 Mir.Inst.Tag.asr_immediate
4832 else
4833 Mir.Inst.Tag.lsr_immediate,
4834 .data = .{ .rr_shift = .{
4835 .rd = dest_reg,
4836 .rn = source_reg.toX(),
4837 .shift = shift,
4838 } },
4839 });
4840 }
4841
4842 break :new .{ .register = self.registerAlias(dest_reg, payload_ty) };
4843 },
4844 .stack_argument_offset => |off| .{ .stack_argument_offset = off + offset },
4845 .stack_offset => |off| .{ .stack_offset = off - offset },
4846 .memory => |addr| .{ .memory = addr + offset },
4847 else => unreachable, // invalid MCValue for an optional
4848 };
4849
4850 break :blk .{ .ty = Type.bool, .bind = .{ .mcv = new_mcv } };
4851 } else .{ .ty = operand_ty, .bind = operand_bind };
4842 const imm_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 0 } };4852 const imm_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 0 } };
4843 return self.cmp(operand_bind, imm_bind, sentinel_ty, .eq);4853 return self.cmp(sentinel.bind, imm_bind, sentinel.ty, .eq);
4844}4854}
48454855
4846fn isNonNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue {4856fn isNonNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue {
src/arch/wasm/CodeGen.zig+18-31
...@@ -2715,20 +2715,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError...@@ -2715,20 +2715,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError
2715 },2715 },
2716 .opt_payload_ptr => {2716 .opt_payload_ptr => {
2717 const payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;2717 const payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
2718 const parent_ptr = try func.lowerParentPtr(payload_ptr.container_ptr, payload_ptr.container_ty);2718 return func.lowerParentPtr(payload_ptr.container_ptr, payload_ptr.container_ty);
2719 var buf: Type.Payload.ElemType = undefined;
2720 const payload_ty = payload_ptr.container_ty.optionalChild(&buf);
2721 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.optionalReprIsPayload()) {
2722 return parent_ptr;
2723 }
2724
2725 const abi_size = payload_ptr.container_ty.abiSize(func.target);
2726 const offset = abi_size - payload_ty.abiSize(func.target);
2727
2728 return WValue{ .memory_offset = .{
2729 .pointer = parent_ptr.memory,
2730 .offset = @intCast(u32, offset),
2731 } };
2732 },2719 },
2733 else => |tag| return func.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}),2720 else => |tag| return func.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}),
2734 }2721 }
...@@ -2889,7 +2876,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -2889,7 +2876,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
2889 }2876 }
2890 } else {2877 } else {
2891 const is_pl = val.tag() == .opt_payload;2878 const is_pl = val.tag() == .opt_payload;
2892 return WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 };2879 return WValue{ .imm32 = @boolToInt(is_pl) };
2893 },2880 },
2894 .Struct => {2881 .Struct => {
2895 const struct_obj = ty.castTag(.@"struct").?.data;2882 const struct_obj = ty.castTag(.@"struct").?.data;
...@@ -3882,7 +3869,11 @@ fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcod...@@ -3882,7 +3869,11 @@ fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcod
3882 // When payload is zero-bits, we can treat operand as a value, rather than3869 // When payload is zero-bits, we can treat operand as a value, rather than
3883 // a pointer to the stack value3870 // a pointer to the stack value
3884 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {3871 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
3885 try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 });3872 const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse {
3873 const module = func.bin_file.base.options.module.?;
3874 return func.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(module)});
3875 };
3876 try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = 1 });
3886 }3877 }
3887 } else if (payload_ty.isSlice()) {3878 } else if (payload_ty.isSlice()) {
3888 switch (func.arch()) {3879 switch (func.arch()) {
...@@ -3911,13 +3902,11 @@ fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3911,13 +3902,11 @@ fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3911 const operand = try func.resolveInst(ty_op.operand);3902 const operand = try func.resolveInst(ty_op.operand);
3912 if (opt_ty.optionalReprIsPayload()) break :result func.reuseOperand(ty_op.operand, operand);3903 if (opt_ty.optionalReprIsPayload()) break :result func.reuseOperand(ty_op.operand, operand);
39133904
3914 const offset = opt_ty.abiSize(func.target) - payload_ty.abiSize(func.target);
3915
3916 if (isByRef(payload_ty, func.target)) {3905 if (isByRef(payload_ty, func.target)) {
3917 break :result try func.buildPointerOffset(operand, offset, .new);3906 break :result try func.buildPointerOffset(operand, 0, .new);
3918 }3907 }
39193908
3920 const payload = try func.load(operand, payload_ty, @intCast(u32, offset));3909 const payload = try func.load(operand, payload_ty, 0);
3921 break :result try payload.toLocal(func, payload_ty);3910 break :result try payload.toLocal(func, payload_ty);
3922 };3911 };
3923 func.finishAir(inst, result, &.{ty_op.operand});3912 func.finishAir(inst, result, &.{ty_op.operand});
...@@ -3936,8 +3925,7 @@ fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3936,8 +3925,7 @@ fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3936 break :result func.reuseOperand(ty_op.operand, operand);3925 break :result func.reuseOperand(ty_op.operand, operand);
3937 }3926 }
39383927
3939 const offset = opt_ty.abiSize(func.target) - payload_ty.abiSize(func.target);3928 break :result try func.buildPointerOffset(operand, 0, .new);
3940 break :result try func.buildPointerOffset(operand, offset, .new);
3941 };3929 };
3942 func.finishAir(inst, result, &.{ty_op.operand});3930 func.finishAir(inst, result, &.{ty_op.operand});
3943}3931}
...@@ -3956,16 +3944,16 @@ fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi...@@ -3956,16 +3944,16 @@ fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi
3956 return func.finishAir(inst, operand, &.{ty_op.operand});3944 return func.finishAir(inst, operand, &.{ty_op.operand});
3957 }3945 }
39583946
3959 const offset = std.math.cast(u32, opt_ty.abiSize(func.target) - payload_ty.abiSize(func.target)) orelse {3947 const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse {
3960 const module = func.bin_file.base.options.module.?;3948 const module = func.bin_file.base.options.module.?;
3961 return func.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(module)});3949 return func.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(module)});
3962 };3950 };
39633951
3964 try func.emitWValue(operand);3952 try func.emitWValue(operand);
3965 try func.addImm32(1);3953 try func.addImm32(1);
3966 try func.addMemArg(.i32_store8, .{ .offset = operand.offset(), .alignment = 1 });3954 try func.addMemArg(.i32_store8, .{ .offset = operand.offset() + offset, .alignment = 1 });
39673955
3968 const result = try func.buildPointerOffset(operand, offset, .new);3956 const result = try func.buildPointerOffset(operand, 0, .new);
3969 return func.finishAir(inst, result, &.{ty_op.operand});3957 return func.finishAir(inst, result, &.{ty_op.operand});
3970}3958}
39713959
...@@ -3988,7 +3976,7 @@ fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3988,7 +3976,7 @@ fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3988 if (op_ty.optionalReprIsPayload()) {3976 if (op_ty.optionalReprIsPayload()) {
3989 break :result func.reuseOperand(ty_op.operand, operand);3977 break :result func.reuseOperand(ty_op.operand, operand);
3990 }3978 }
3991 const offset = std.math.cast(u32, op_ty.abiSize(func.target) - payload_ty.abiSize(func.target)) orelse {3979 const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse {
3992 const module = func.bin_file.base.options.module.?;3980 const module = func.bin_file.base.options.module.?;
3993 return func.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(module)});3981 return func.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(module)});
3994 };3982 };
...@@ -3997,9 +3985,9 @@ fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3997,9 +3985,9 @@ fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3997 const result_ptr = try func.allocStack(op_ty);3985 const result_ptr = try func.allocStack(op_ty);
3998 try func.emitWValue(result_ptr);3986 try func.emitWValue(result_ptr);
3999 try func.addImm32(1);3987 try func.addImm32(1);
4000 try func.addMemArg(.i32_store8, .{ .offset = result_ptr.offset(), .alignment = 1 });3988 try func.addMemArg(.i32_store8, .{ .offset = result_ptr.offset() + offset, .alignment = 1 });
40013989
4002 const payload_ptr = try func.buildPointerOffset(result_ptr, offset, .new);3990 const payload_ptr = try func.buildPointerOffset(result_ptr, 0, .new);
4003 try func.store(payload_ptr, operand, payload_ty, 0);3991 try func.store(payload_ptr, operand, payload_ty, 0);
4004 break :result result_ptr;3992 break :result result_ptr;
4005 };3993 };
...@@ -4719,7 +4707,6 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:...@@ -4719,7 +4707,6 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:
4719 assert(op == .eq or op == .neq);4707 assert(op == .eq or op == .neq);
4720 var buf: Type.Payload.ElemType = undefined;4708 var buf: Type.Payload.ElemType = undefined;
4721 const payload_ty = operand_ty.optionalChild(&buf);4709 const payload_ty = operand_ty.optionalChild(&buf);
4722 const offset = @intCast(u32, operand_ty.abiSize(func.target) - payload_ty.abiSize(func.target));
47234710
4724 // We store the final result in here that will be validated4711 // We store the final result in here that will be validated
4725 // if the optional is truly equal.4712 // if the optional is truly equal.
...@@ -4732,8 +4719,8 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:...@@ -4732,8 +4719,8 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:
4732 try func.addTag(.i32_ne); // inverse so we can exit early4719 try func.addTag(.i32_ne); // inverse so we can exit early
4733 try func.addLabel(.br_if, 0);4720 try func.addLabel(.br_if, 0);
47344721
4735 _ = try func.load(lhs, payload_ty, offset);4722 _ = try func.load(lhs, payload_ty, 0);
4736 _ = try func.load(rhs, payload_ty, offset);4723 _ = try func.load(rhs, payload_ty, 0);
4737 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, func.target) });4724 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, func.target) });
4738 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));4725 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));
4739 try func.addLabel(.br_if, 0);4726 try func.addLabel(.br_if, 0);
test/behavior/error.zig+1
...@@ -874,6 +874,7 @@ test "field access of anyerror results in smaller error set" {...@@ -874,6 +874,7 @@ test "field access of anyerror results in smaller error set" {
874}874}
875875
876test "optional error union return type" {876test "optional error union return type" {
877 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
877 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO878 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
878879
879 const S = struct {880 const S = struct {