| author | |
| committer | |
| log | 3051fab97cbe89f3be8ec2aab36ca0e60fd953f9 |
| tree | d8599199275f0e61944c94d9f55d37c3f183857d |
| parent | 4e0779813b5a25755f6a5f12e8ec05304abb2337 |
| signature | Commit is signed but in an unrecognized format. |
- Fixed missing airRetPtr implementation
- Fixed wrong pop_regs order
- Fixed wrong source and destination register in store3 files changed, 84 insertions(+), 38 deletions(-)
lib/test_runner.zig+1| ... | ... | @@ -130,6 +130,7 @@ pub fn main2() anyerror!void { |
| 130 | 130 | } |
| 131 | 131 | if (builtin.zig_backend == .stage2_wasm or |
| 132 | 132 | builtin.zig_backend == .stage2_x86_64 or |
| 133 | builtin.zig_backend == .stage2_aarch64 or | |
| 133 | 134 | builtin.zig_backend == .stage2_llvm or |
| 134 | 135 | builtin.zig_backend == .stage2_c) |
| 135 | 136 | { |
src/arch/aarch64/CodeGen.zig+45-7| ... | ... | @@ -1016,8 +1016,27 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 1016 | 1016 | } |
| 1017 | 1017 | |
| 1018 | 1018 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1019 | const stack_offset = try self.allocMemPtr(inst); | |
| 1020 | return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); | |
| 1019 | const result: MCValue = switch (self.ret_mcv) { | |
| 1020 | .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, | |
| 1021 | .stack_offset => blk: { | |
| 1022 | // self.ret_mcv is an address to where this function | |
| 1023 | // should store its result into | |
| 1024 | const ret_ty = self.fn_type.fnReturnType(); | |
| 1025 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 1026 | .base = .{ .tag = .single_mut_pointer }, | |
| 1027 | .data = ret_ty, | |
| 1028 | }; | |
| 1029 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 1030 | ||
| 1031 | // addr_reg will contain the address of where to store the | |
| 1032 | // result into | |
| 1033 | const addr_reg = try self.copyToTmpRegister(ptr_ty, self.ret_mcv); | |
| 1034 | break :blk .{ .register = addr_reg }; | |
| 1035 | }, | |
| 1036 | else => unreachable, // invalid return result | |
| 1037 | }; | |
| 1038 | ||
| 1039 | return self.finishAir(inst, result, .{ .none, .none, .none }); | |
| 1021 | 1040 | } |
| 1022 | 1041 | |
| 1023 | 1042 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -3631,6 +3650,7 @@ fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type |
| 3631 | 3650 | } |
| 3632 | 3651 | |
| 3633 | 3652 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| 3653 | log.debug("store: storing {} to {}", .{ value, ptr }); | |
| 3634 | 3654 | const abi_size = value_ty.abiSize(self.target.*); |
| 3635 | 3655 | |
| 3636 | 3656 | switch (ptr) { |
| ... | ... | @@ -3655,6 +3675,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3655 | 3675 | .dead => unreachable, |
| 3656 | 3676 | .undef => unreachable, |
| 3657 | 3677 | .register => |value_reg| { |
| 3678 | log.debug("store: register {} to {}", .{ value_reg, addr_reg }); | |
| 3658 | 3679 | try self.genStrRegister(value_reg, addr_reg, value_ty); |
| 3659 | 3680 | }, |
| 3660 | 3681 | else => { |
| ... | ... | @@ -3673,8 +3694,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3673 | 3694 | self.register_manager.unlockReg(reg); |
| 3674 | 3695 | }; |
| 3675 | 3696 | |
| 3676 | const src_reg = addr_reg; | |
| 3677 | const dst_reg = regs[0]; | |
| 3697 | const src_reg = regs[0]; | |
| 3698 | const dst_reg = addr_reg; | |
| 3678 | 3699 | const len_reg = regs[1]; |
| 3679 | 3700 | const count_reg = regs[2]; |
| 3680 | 3701 | const tmp_reg = regs[3]; |
| ... | ... | @@ -3684,7 +3705,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3684 | 3705 | // sub src_reg, fp, #off |
| 3685 | 3706 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| 3686 | 3707 | }, |
| 3687 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }), | |
| 3688 | 3708 | .stack_argument_offset => |off| { |
| 3689 | 3709 | _ = try self.addInst(.{ |
| 3690 | 3710 | .tag = .ldr_ptr_stack_argument, |
| ... | ... | @@ -3694,6 +3714,24 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3694 | 3714 | } }, |
| 3695 | 3715 | }); |
| 3696 | 3716 | }, |
| 3717 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }), | |
| 3718 | .linker_load => |load_struct| { | |
| 3719 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { | |
| 3720 | .got => .load_memory_ptr_got, | |
| 3721 | .direct => .load_memory_ptr_direct, | |
| 3722 | }; | |
| 3723 | const mod = self.bin_file.options.module.?; | |
| 3724 | _ = try self.addInst(.{ | |
| 3725 | .tag = tag, | |
| 3726 | .data = .{ | |
| 3727 | .payload = try self.addExtra(Mir.LoadMemoryPie{ | |
| 3728 | .register = @enumToInt(src_reg), | |
| 3729 | .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index, | |
| 3730 | .sym_index = load_struct.sym_index, | |
| 3731 | }), | |
| 3732 | }, | |
| 3733 | }); | |
| 3734 | }, | |
| 3697 | 3735 | else => return self.fail("TODO store {} to register", .{value}), |
| 3698 | 3736 | } |
| 3699 | 3737 | |
| ... | ... | @@ -4428,7 +4466,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4428 | 4466 | if (else_value == .dead) |
| 4429 | 4467 | continue; |
| 4430 | 4468 | // The instruction is only overridden in the else branch. |
| 4431 | var i: usize = self.branch_stack.items.len - 2; | |
| 4469 | var i: usize = self.branch_stack.items.len - 1; | |
| 4432 | 4470 | while (true) { |
| 4433 | 4471 | i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead? |
| 4434 | 4472 | if (self.branch_stack.items[i].inst_table.get(else_key)) |mcv| { |
| ... | ... | @@ -4455,7 +4493,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4455 | 4493 | if (then_value == .dead) |
| 4456 | 4494 | continue; |
| 4457 | 4495 | const parent_mcv = blk: { |
| 4458 | var i: usize = self.branch_stack.items.len - 2; | |
| 4496 | var i: usize = self.branch_stack.items.len - 1; | |
| 4459 | 4497 | while (true) { |
| 4460 | 4498 | i -= 1; |
| 4461 | 4499 | if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| { |
src/arch/aarch64/Emit.zig+38-31| ... | ... | @@ -1191,42 +1191,50 @@ fn mirNop(emit: *Emit) !void { |
| 1191 | 1191 | try emit.writeInstruction(Instruction.nop()); |
| 1192 | 1192 | } |
| 1193 | 1193 | |
| 1194 | fn regListIsSet(reg_list: u32, reg: Register) bool { | |
| 1195 | return reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0; | |
| 1196 | } | |
| 1197 | ||
| 1194 | 1198 | fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 1195 | 1199 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 1196 | 1200 | const reg_list = emit.mir.instructions.items(.data)[inst].reg_list; |
| 1197 | 1201 | |
| 1198 | if (reg_list & @as(u32, 1) << 31 != 0) return emit.fail("xzr is not a valid register for {}", .{tag}); | |
| 1202 | if (regListIsSet(reg_list, .xzr)) return emit.fail("xzr is not a valid register for {}", .{tag}); | |
| 1199 | 1203 | |
| 1200 | 1204 | // sp must be aligned at all times, so we only use stp and ldp |
| 1201 | // instructions for minimal instruction count. However, if we do | |
| 1202 | // not have an even number of registers, we use str and ldr | |
| 1205 | // instructions for minimal instruction count. | |
| 1206 | // | |
| 1207 | // However, if we have an odd number of registers, for pop_regs we | |
| 1208 | // use one ldr instruction followed by zero or more ldp | |
| 1209 | // instructions; for push_regs we use zero or more stp | |
| 1210 | // instructions followed by one str instruction. | |
| 1203 | 1211 | const number_of_regs = @popCount(reg_list); |
| 1212 | const odd_number_of_regs = number_of_regs % 2 != 0; | |
| 1204 | 1213 | |
| 1205 | 1214 | switch (tag) { |
| 1206 | 1215 | .pop_regs => { |
| 1207 | 1216 | var i: u6 = 32; |
| 1208 | 1217 | var count: u6 = 0; |
| 1209 | var other_reg: Register = undefined; | |
| 1218 | var other_reg: ?Register = null; | |
| 1210 | 1219 | while (i > 0) : (i -= 1) { |
| 1211 | 1220 | const reg = @intToEnum(Register, i - 1); |
| 1212 | if (reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0) { | |
| 1213 | if (count % 2 == 0) { | |
| 1214 | if (count == number_of_regs - 1) { | |
| 1215 | try emit.writeInstruction(Instruction.ldr( | |
| 1216 | reg, | |
| 1217 | .sp, | |
| 1218 | Instruction.LoadStoreOffset.imm_post_index(16), | |
| 1219 | )); | |
| 1220 | } else { | |
| 1221 | other_reg = reg; | |
| 1222 | } | |
| 1223 | } else { | |
| 1221 | if (regListIsSet(reg_list, reg)) { | |
| 1222 | if (count == 0 and odd_number_of_regs) { | |
| 1223 | try emit.writeInstruction(Instruction.ldr( | |
| 1224 | reg, | |
| 1225 | .sp, | |
| 1226 | Instruction.LoadStoreOffset.imm_post_index(16), | |
| 1227 | )); | |
| 1228 | } else if (other_reg) |r| { | |
| 1224 | 1229 | try emit.writeInstruction(Instruction.ldp( |
| 1225 | 1230 | reg, |
| 1226 | other_reg, | |
| 1231 | r, | |
| 1227 | 1232 | .sp, |
| 1228 | 1233 | Instruction.LoadStorePairOffset.post_index(16), |
| 1229 | 1234 | )); |
| 1235 | other_reg = null; | |
| 1236 | } else { | |
| 1237 | other_reg = reg; | |
| 1230 | 1238 | } |
| 1231 | 1239 | count += 1; |
| 1232 | 1240 | } |
| ... | ... | @@ -1236,27 +1244,26 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 1236 | 1244 | .push_regs => { |
| 1237 | 1245 | var i: u6 = 0; |
| 1238 | 1246 | var count: u6 = 0; |
| 1239 | var other_reg: Register = undefined; | |
| 1247 | var other_reg: ?Register = null; | |
| 1240 | 1248 | while (i < 32) : (i += 1) { |
| 1241 | 1249 | const reg = @intToEnum(Register, i); |
| 1242 | if (reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0) { | |
| 1243 | if (count % 2 == 0) { | |
| 1244 | if (count == number_of_regs - 1) { | |
| 1245 | try emit.writeInstruction(Instruction.str( | |
| 1246 | reg, | |
| 1247 | .sp, | |
| 1248 | Instruction.LoadStoreOffset.imm_pre_index(-16), | |
| 1249 | )); | |
| 1250 | } else { | |
| 1251 | other_reg = reg; | |
| 1252 | } | |
| 1253 | } else { | |
| 1250 | if (regListIsSet(reg_list, reg)) { | |
| 1251 | if (count == number_of_regs - 1 and odd_number_of_regs) { | |
| 1252 | try emit.writeInstruction(Instruction.str( | |
| 1253 | reg, | |
| 1254 | .sp, | |
| 1255 | Instruction.LoadStoreOffset.imm_pre_index(-16), | |
| 1256 | )); | |
| 1257 | } else if (other_reg) |r| { | |
| 1254 | 1258 | try emit.writeInstruction(Instruction.stp( |
| 1255 | other_reg, | |
| 1259 | r, | |
| 1256 | 1260 | reg, |
| 1257 | 1261 | .sp, |
| 1258 | 1262 | Instruction.LoadStorePairOffset.pre_index(-16), |
| 1259 | 1263 | )); |
| 1264 | other_reg = null; | |
| 1265 | } else { | |
| 1266 | other_reg = reg; | |
| 1260 | 1267 | } |
| 1261 | 1268 | count += 1; |
| 1262 | 1269 | } |