| author | |
| committer | |
| log | dc1f50e505105cabe1ed53951ca612778d6019ee |
| tree | b0d91b810a6643028fc088d0af849b29dfeee632 |
| parent | a933a59ced8175a513ff123c3496b1b563d58453 |
| parent | 0aee40bd13fa72ac4ca41e133440917c0ed94ffb |
| signature |
Bitcast fixes for self-hosted native backends9 files changed, 137 insertions(+), 24 deletions(-)
src/arch/aarch64/CodeGen.zig+19-2| ... | ... | @@ -3958,7 +3958,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3958 | 3958 | |
| 3959 | 3959 | switch (value) { |
| 3960 | 3960 | .dead => unreachable, |
| 3961 | .undef => unreachable, | |
| 3961 | .undef => { | |
| 3962 | try self.genSetReg(value_ty, addr_reg, value); | |
| 3963 | }, | |
| 3962 | 3964 | .register => |value_reg| { |
| 3963 | 3965 | log.debug("store: register {} to {}", .{ value_reg, addr_reg }); |
| 3964 | 3966 | try self.genStrRegister(value_reg, addr_reg, value_ty); |
| ... | ... | @@ -5870,7 +5872,22 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 5870 | 5872 | |
| 5871 | 5873 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 5872 | 5874 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5873 | const result = try self.resolveInst(ty_op.operand); | |
| 5875 | const result = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 5876 | const operand = try self.resolveInst(ty_op.operand); | |
| 5877 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; | |
| 5878 | ||
| 5879 | const operand_lock = switch (operand) { | |
| 5880 | .register => |reg| self.register_manager.lockReg(reg), | |
| 5881 | .register_with_overflow => |rwo| self.register_manager.lockReg(rwo.reg), | |
| 5882 | else => null, | |
| 5883 | }; | |
| 5884 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | |
| 5885 | ||
| 5886 | const dest_ty = self.air.typeOfIndex(inst); | |
| 5887 | const dest = try self.allocRegOrMem(dest_ty, true, inst); | |
| 5888 | try self.setRegOrMem(dest_ty, dest, operand); | |
| 5889 | break :result dest; | |
| 5890 | }; | |
| 5874 | 5891 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 5875 | 5892 | } |
| 5876 | 5893 |
src/arch/arm/CodeGen.zig+21-2| ... | ... | @@ -2765,7 +2765,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2765 | 2765 | |
| 2766 | 2766 | switch (value) { |
| 2767 | 2767 | .dead => unreachable, |
| 2768 | .undef => unreachable, | |
| 2768 | .undef => { | |
| 2769 | try self.genSetReg(value_ty, addr_reg, value); | |
| 2770 | }, | |
| 2769 | 2771 | .register => |value_reg| { |
| 2770 | 2772 | try self.genStrRegister(value_reg, addr_reg, value_ty); |
| 2771 | 2773 | }, |
| ... | ... | @@ -5816,7 +5818,24 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 5816 | 5818 | |
| 5817 | 5819 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 5818 | 5820 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5819 | const result = try self.resolveInst(ty_op.operand); | |
| 5821 | const result = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 5822 | const operand = try self.resolveInst(ty_op.operand); | |
| 5823 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; | |
| 5824 | ||
| 5825 | const operand_lock = switch (operand) { | |
| 5826 | .register, | |
| 5827 | .register_c_flag, | |
| 5828 | .register_v_flag, | |
| 5829 | => |reg| self.register_manager.lockReg(reg), | |
| 5830 | else => null, | |
| 5831 | }; | |
| 5832 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | |
| 5833 | ||
| 5834 | const dest_ty = self.air.typeOfIndex(inst); | |
| 5835 | const dest = try self.allocRegOrMem(dest_ty, true, inst); | |
| 5836 | try self.setRegOrMem(dest_ty, dest, operand); | |
| 5837 | break :result dest; | |
| 5838 | }; | |
| 5820 | 5839 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 5821 | 5840 | } |
| 5822 | 5841 |
src/arch/riscv64/CodeGen.zig+14-1| ... | ... | @@ -2338,7 +2338,20 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 2338 | 2338 | |
| 2339 | 2339 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2340 | 2340 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2341 | const result = try self.resolveInst(ty_op.operand); | |
| 2341 | const result = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 2342 | const operand = try self.resolveInst(ty_op.operand); | |
| 2343 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; | |
| 2344 | ||
| 2345 | const operand_lock = switch (operand) { | |
| 2346 | .register => |reg| self.register_manager.lockReg(reg), | |
| 2347 | else => null, | |
| 2348 | }; | |
| 2349 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | |
| 2350 | ||
| 2351 | const dest = try self.allocRegOrMem(inst, true); | |
| 2352 | try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand); | |
| 2353 | break :result dest; | |
| 2354 | }; | |
| 2342 | 2355 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2343 | 2356 | } |
| 2344 | 2357 |
src/arch/sparc64/CodeGen.zig+15-1| ... | ... | @@ -1091,7 +1091,21 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void |
| 1091 | 1091 | |
| 1092 | 1092 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1093 | 1093 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1094 | const result = try self.resolveInst(ty_op.operand); | |
| 1094 | const result = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 1095 | const operand = try self.resolveInst(ty_op.operand); | |
| 1096 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; | |
| 1097 | ||
| 1098 | const operand_lock = switch (operand) { | |
| 1099 | .register => |reg| self.register_manager.lockReg(reg), | |
| 1100 | .register_with_overflow => |rwo| self.register_manager.lockReg(rwo.reg), | |
| 1101 | else => null, | |
| 1102 | }; | |
| 1103 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | |
| 1104 | ||
| 1105 | const dest = try self.allocRegOrMem(inst, true); | |
| 1106 | try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand); | |
| 1107 | break :result dest; | |
| 1108 | }; | |
| 1095 | 1109 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1096 | 1110 | } |
| 1097 | 1111 |
src/arch/x86_64/CodeGen.zig+57-10| ... | ... | @@ -920,9 +920,6 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 920 | 920 | const mod = self.bin_file.options.module.?; |
| 921 | 921 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 922 | 922 | }; |
| 923 | const abi_align = elem_ty.abiAlignment(self.target.*); | |
| 924 | if (abi_align > self.stack_align) | |
| 925 | self.stack_align = abi_align; | |
| 926 | 923 | |
| 927 | 924 | if (reg_ok) { |
| 928 | 925 | switch (elem_ty.zigTypeTag()) { |
| ... | ... | @@ -951,6 +948,10 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 951 | 948 | }, |
| 952 | 949 | } |
| 953 | 950 | } |
| 951 | ||
| 952 | const abi_align = elem_ty.abiAlignment(self.target.*); | |
| 953 | if (abi_align > self.stack_align) | |
| 954 | self.stack_align = abi_align; | |
| 954 | 955 | const stack_offset = try self.allocMem(inst, abi_size, abi_align); |
| 955 | 956 | return MCValue{ .stack_offset = @intCast(i32, stack_offset) }; |
| 956 | 957 | } |
| ... | ... | @@ -990,7 +991,7 @@ fn revertState(self: *Self, state: State) void { |
| 990 | 991 | |
| 991 | 992 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 992 | 993 | const stack_mcv = try self.allocRegOrMem(inst, false); |
| 993 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); | |
| 994 | log.debug("spilling %{d} to stack mcv {any}", .{ inst, stack_mcv }); | |
| 994 | 995 | const reg_mcv = self.getResolvedInstValue(inst); |
| 995 | 996 | switch (reg_mcv) { |
| 996 | 997 | .register => |other| { |
| ... | ... | @@ -1016,7 +1017,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void { |
| 1016 | 1017 | }; |
| 1017 | 1018 | |
| 1018 | 1019 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); |
| 1019 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); | |
| 1020 | log.debug("spilling %{d} to mcv {any}", .{ inst_to_save, new_mcv }); | |
| 1020 | 1021 | |
| 1021 | 1022 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1022 | 1023 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); |
| ... | ... | @@ -2114,6 +2115,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 2114 | 2115 | }; |
| 2115 | 2116 | break :result dst_mcv; |
| 2116 | 2117 | }; |
| 2118 | log.debug("airSliceLen(%{d}): {}", .{ inst, result }); | |
| 2117 | 2119 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2118 | 2120 | } |
| 2119 | 2121 | |
| ... | ... | @@ -2641,6 +2643,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2641 | 2643 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2642 | 2644 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2643 | 2645 | const elem_ty = self.air.typeOfIndex(inst); |
| 2646 | const elem_size = elem_ty.abiSize(self.target.*); | |
| 2644 | 2647 | const result: MCValue = result: { |
| 2645 | 2648 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) |
| 2646 | 2649 | break :result MCValue.none; |
| ... | ... | @@ -2651,13 +2654,14 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2651 | 2654 | break :result MCValue.dead; |
| 2652 | 2655 | |
| 2653 | 2656 | const dst_mcv: MCValue = blk: { |
| 2654 | if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) { | |
| 2657 | if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) { | |
| 2655 | 2658 | // The MCValue that holds the pointer can be re-used as the value. |
| 2656 | 2659 | break :blk ptr; |
| 2657 | 2660 | } else { |
| 2658 | 2661 | break :blk try self.allocRegOrMem(inst, true); |
| 2659 | 2662 | } |
| 2660 | 2663 | }; |
| 2664 | log.debug("airLoad(%{d}): {} <- {}", .{ inst, dst_mcv, ptr }); | |
| 2661 | 2665 | try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand)); |
| 2662 | 2666 | break :result dst_mcv; |
| 2663 | 2667 | }; |
| ... | ... | @@ -2728,10 +2732,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2728 | 2732 | |
| 2729 | 2733 | switch (value) { |
| 2730 | 2734 | .none => unreachable, |
| 2731 | .undef => unreachable, | |
| 2732 | 2735 | .dead => unreachable, |
| 2733 | 2736 | .unreach => unreachable, |
| 2734 | 2737 | .eflags => unreachable, |
| 2738 | .undef => { | |
| 2739 | try self.genSetReg(value_ty, reg, value); | |
| 2740 | }, | |
| 2735 | 2741 | .immediate => |imm| { |
| 2736 | 2742 | switch (abi_size) { |
| 2737 | 2743 | 1, 2, 4 => { |
| ... | ... | @@ -2773,6 +2779,30 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2773 | 2779 | .register => |src_reg| { |
| 2774 | 2780 | try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0); |
| 2775 | 2781 | }, |
| 2782 | .register_overflow => |ro| { | |
| 2783 | const ro_reg_lock = self.register_manager.lockReg(ro.reg); | |
| 2784 | defer if (ro_reg_lock) |lock| self.register_manager.unlockReg(lock); | |
| 2785 | ||
| 2786 | const wrapped_ty = value_ty.structFieldType(0); | |
| 2787 | try self.genInlineMemcpyRegisterRegister(wrapped_ty, reg, ro.reg, 0); | |
| 2788 | ||
| 2789 | const overflow_bit_ty = value_ty.structFieldType(1); | |
| 2790 | const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*); | |
| 2791 | const tmp_reg = try self.register_manager.allocReg(null, gp); | |
| 2792 | _ = try self.addInst(.{ | |
| 2793 | .tag = .cond_set_byte, | |
| 2794 | .ops = Mir.Inst.Ops.encode(.{ | |
| 2795 | .reg1 = tmp_reg.to8(), | |
| 2796 | }), | |
| 2797 | .data = .{ .cc = ro.eflags }, | |
| 2798 | }); | |
| 2799 | try self.genInlineMemcpyRegisterRegister( | |
| 2800 | overflow_bit_ty, | |
| 2801 | reg, | |
| 2802 | tmp_reg, | |
| 2803 | -@intCast(i32, overflow_bit_offset), | |
| 2804 | ); | |
| 2805 | }, | |
| 2776 | 2806 | .linker_load, |
| 2777 | 2807 | .memory, |
| 2778 | 2808 | .stack_offset, |
| ... | ... | @@ -2787,8 +2817,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2787 | 2817 | .dest_stack_base = reg.to64(), |
| 2788 | 2818 | }); |
| 2789 | 2819 | }, |
| 2790 | else => |other| { | |
| 2791 | return self.fail("TODO implement set pointee with {}", .{other}); | |
| 2820 | .ptr_stack_offset => { | |
| 2821 | const tmp_reg = try self.copyToTmpRegister(value_ty, value); | |
| 2822 | return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); | |
| 2792 | 2823 | }, |
| 2793 | 2824 | } |
| 2794 | 2825 | }, |
| ... | ... | @@ -2902,6 +2933,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 2902 | 2933 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 2903 | 2934 | const value = try self.resolveInst(bin_op.rhs); |
| 2904 | 2935 | const value_ty = self.air.typeOf(bin_op.rhs); |
| 2936 | log.debug("airStore(%{d}): {} <- {}", .{ inst, ptr, value }); | |
| 2905 | 2937 | try self.store(ptr, value, ptr_ty, value_ty); |
| 2906 | 2938 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2907 | 2939 | } |
| ... | ... | @@ -6321,7 +6353,22 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 6321 | 6353 | |
| 6322 | 6354 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 6323 | 6355 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6324 | const result = try self.resolveInst(ty_op.operand); | |
| 6356 | const result = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 6357 | const operand = try self.resolveInst(ty_op.operand); | |
| 6358 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; | |
| 6359 | ||
| 6360 | const operand_lock = switch (operand) { | |
| 6361 | .register => |reg| self.register_manager.lockReg(reg), | |
| 6362 | .register_overflow => |ro| self.register_manager.lockReg(ro.reg), | |
| 6363 | else => null, | |
| 6364 | }; | |
| 6365 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | |
| 6366 | ||
| 6367 | const dest = try self.allocRegOrMem(inst, true); | |
| 6368 | try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand); | |
| 6369 | break :result dest; | |
| 6370 | }; | |
| 6371 | log.debug("airBitCast(%{d}): {}", .{ inst, result }); | |
| 6325 | 6372 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 6326 | 6373 | } |
| 6327 | 6374 |
test/behavior/basic.zig+1| ... | ... | @@ -387,6 +387,7 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { |
| 387 | 387 | } |
| 388 | 388 | |
| 389 | 389 | test "take address of parameter" { |
| 390 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 390 | 391 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 391 | 392 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 392 | 393 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/const_slice_child.zig+1| ... | ... | @@ -9,6 +9,7 @@ var argv: [*]const [*]const u8 = undefined; |
| 9 | 9 | test "const slice child" { |
| 10 | 10 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 11 | 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 12 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 12 | 13 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 13 | 14 | |
| 14 | 15 | const strs = [_][*]const u8{ "one", "two", "three" }; |
test/behavior/eval.zig+1| ... | ... | @@ -1338,6 +1338,7 @@ test "lazy sizeof is resolved in division" { |
| 1338 | 1338 | |
| 1339 | 1339 | test "lazy value is resolved as slice operand" { |
| 1340 | 1340 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1341 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1341 | 1342 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1342 | 1343 | |
| 1343 | 1344 | const A = struct { a: u32 }; |
test/tests.zig+8-8| ... | ... | @@ -58,14 +58,14 @@ const test_targets = blk: { |
| 58 | 58 | .link_libc = true, |
| 59 | 59 | .backend = .stage2_c, |
| 60 | 60 | }, |
| 61 | //.{ | |
| 62 | // .target = .{ | |
| 63 | // .cpu_arch = .x86_64, | |
| 64 | // .os_tag = .linux, | |
| 65 | // .abi = .none, | |
| 66 | // }, | |
| 67 | // .backend = .stage2_x86_64, | |
| 68 | //}, | |
| 61 | .{ | |
| 62 | .target = .{ | |
| 63 | .cpu_arch = .x86_64, | |
| 64 | .os_tag = .linux, | |
| 65 | .abi = .none, | |
| 66 | }, | |
| 67 | .backend = .stage2_x86_64, | |
| 68 | }, | |
| 69 | 69 | .{ |
| 70 | 70 | .target = .{ |
| 71 | 71 | .cpu_arch = .aarch64, |