authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-05 20:51:11+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-14 22:09:43+01:00
log8204ad193788f55b7fb5c5a2dd9a1902d964ed70
treef74bb6e1b8296816c53f7ff3463baa0d338f3950
parent82f91adbb4ef77e8a2b05da923bb1d0c9c3a8262
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement slice_len and slice_elem_val


3 files changed, 225 insertions(+), 13 deletions(-)

src/arch/aarch64/CodeGen.zig+186-5
......@@ -1164,7 +1164,20 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
11641164
11651165fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
11661166 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1167 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch});
1167 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1168 const mcv = try self.resolveInst(ty_op.operand);
1169 switch (mcv) {
1170 .dead, .unreach => unreachable,
1171 .register => unreachable, // a slice doesn't fit in one register
1172 .stack_offset => |off| {
1173 break :result MCValue{ .stack_offset = off + 8 };
1174 },
1175 .memory => |addr| {
1176 break :result MCValue{ .memory = addr + 8 };
1177 },
1178 else => return self.fail("TODO implement slice_len for {}", .{mcv}),
1179 }
1180 };
11681181 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11691182}
11701183
......@@ -1183,10 +1196,114 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
11831196fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
11841197 const is_volatile = false; // TODO
11851198 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1186 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch});
1199
1200 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1201 const result: MCValue = result: {
1202 const slice_mcv = try self.resolveInst(bin_op.lhs);
1203
1204 // TODO optimize for the case where the index is a constant,
1205 // i.e. index_mcv == .immediate
1206 const index_mcv = try self.resolveInst(bin_op.rhs);
1207 const index_is_register = index_mcv == .register;
1208
1209 const slice_ty = self.air.typeOf(bin_op.lhs);
1210 const elem_ty = slice_ty.childType();
1211 const elem_size = elem_ty.abiSize(self.target.*);
1212
1213 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1214 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
1215
1216 if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register});
1217 defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register});
1218
1219 const base_mcv: MCValue = switch (slice_mcv) {
1220 .stack_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_offset = off + 8 }) },
1221 else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}),
1222 };
1223 self.register_manager.freezeRegs(&.{base_mcv.register});
1224
1225 // TODO implement optimized ldr for airSliceElemVal
1226 const dst_mcv = try self.allocRegOrMem(inst, true);
1227
1228 const offset_mcv = try self.genMulConstant(bin_op.rhs, @intCast(u32, elem_size));
1229 assert(offset_mcv == .register); // result of multiplication should always be register
1230 self.register_manager.freezeRegs(&.{offset_mcv.register});
1231
1232 const addr_reg = try self.register_manager.allocReg(null);
1233 self.register_manager.freezeRegs(&.{addr_reg});
1234 defer self.register_manager.unfreezeRegs(&.{addr_reg});
1235
1236 _ = try self.addInst(.{
1237 .tag = .add_shifted_register,
1238 .data = .{ .rrr_imm6_shift = .{
1239 .rd = addr_reg,
1240 .rn = base_mcv.register,
1241 .rm = offset_mcv.register,
1242 .imm6 = 0,
1243 .shift = .lsl,
1244 } },
1245 });
1246
1247 // At this point in time, neither the base register
1248 // nor the offset register contains any valuable data
1249 // anymore.
1250 self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
1251
1252 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1253
1254 break :result dst_mcv;
1255 };
11871256 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
11881257}
11891258
1259fn genMulConstant(self: *Self, op: Air.Inst.Ref, imm: u32) !MCValue {
1260 const lhs = try self.resolveInst(op);
1261 const rhs = MCValue{ .immediate = imm };
1262
1263 const lhs_is_register = lhs == .register;
1264
1265 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
1266 defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register});
1267
1268 // Destination must be a register
1269 // LHS must be a register
1270 // RHS must be a register
1271 var dst_mcv: MCValue = undefined;
1272 var lhs_mcv: MCValue = lhs;
1273 var rhs_mcv: MCValue = rhs;
1274
1275 // Allocate registers for operands and/or destination
1276 // Allocate 1 or 2 registers
1277 if (lhs_is_register) {
1278 // Move RHS to register
1279 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };
1280 rhs_mcv = dst_mcv;
1281 } else {
1282 // Move LHS and RHS to register
1283 const regs = try self.register_manager.allocRegs(2, .{ null, null });
1284 lhs_mcv = MCValue{ .register = regs[0] };
1285 rhs_mcv = MCValue{ .register = regs[1] };
1286 dst_mcv = lhs_mcv;
1287 }
1288
1289 // Move the operands to the newly allocated registers
1290 if (!lhs_is_register) {
1291 try self.genSetReg(self.air.typeOf(op), lhs_mcv.register, lhs);
1292 }
1293 try self.genSetReg(Type.initTag(.usize), rhs_mcv.register, rhs);
1294
1295 _ = try self.addInst(.{
1296 .tag = .mul,
1297 .data = .{ .rrr = .{
1298 .rd = dst_mcv.register,
1299 .rn = lhs_mcv.register,
1300 .rm = rhs_mcv.register,
1301 } },
1302 });
1303
1304 return dst_mcv;
1305}
1306
11901307fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
11911308 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
11921309 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
......@@ -1310,6 +1427,16 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
13101427 .undef => unreachable,
13111428 .compare_flags_signed, .compare_flags_unsigned => unreachable,
13121429 .embedded_in_code => unreachable,
1430 .register => |dst_reg| {
1431 _ = try self.addInst(.{
1432 .tag = .ldr_immediate,
1433 .data = .{ .load_store_register_immediate = .{
1434 .rt = dst_reg,
1435 .rn = addr_reg,
1436 .offset = Instruction.LoadStoreOffset.none.immediate,
1437 } },
1438 });
1439 },
13131440 .stack_offset => |off| {
13141441 if (elem_ty.abiSize(self.target.*) <= 8) {
13151442 const tmp_reg = try self.register_manager.allocReg(null);
......@@ -2590,8 +2717,61 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
25902717 if (stack_offset == off)
25912718 return; // Copy stack variable to itself; nothing to do.
25922719
2593 const reg = try self.copyToTmpRegister(ty, mcv);
2594 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2720 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2721 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2722 if (ty.abiSize(self.target.*) <= ptr_bytes) {
2723 const reg = try self.copyToTmpRegister(ty, mcv);
2724 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2725 } else {
2726 // TODO optimize the register allocation
2727 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null });
2728 self.register_manager.freezeRegs(&regs);
2729 defer self.register_manager.unfreezeRegs(&regs);
2730
2731 const src_reg = regs[0];
2732 const dst_reg = regs[1];
2733 const len_reg = regs[2];
2734 const count_reg = regs[3];
2735 const tmp_reg = regs[4];
2736
2737 // sub src_reg, fp, #off
2738 const adj_src_offset = off + @intCast(u32, ty.abiSize(self.target.*));
2739 const src_offset = math.cast(u12, adj_src_offset) catch return self.fail("TODO load: larger stack offsets", .{});
2740 _ = try self.addInst(.{
2741 .tag = .sub_immediate,
2742 .data = .{ .rr_imm12_sh = .{
2743 .rd = src_reg,
2744 .rn = .x29,
2745 .imm12 = src_offset,
2746 } },
2747 });
2748
2749 // sub dst_reg, fp, #stack_offset
2750 const adj_dst_off = stack_offset + @intCast(u32, ty.abiSize(self.target.*));
2751 const dst_offset = math.cast(u12, adj_dst_off) catch return self.fail("TODO load: larger stack offsets", .{});
2752 _ = try self.addInst(.{
2753 .tag = .sub_immediate,
2754 .data = .{ .rr_imm12_sh = .{
2755 .rd = dst_reg,
2756 .rn = .x29,
2757 .imm12 = dst_offset,
2758 } },
2759 });
2760
2761 // mov len, #elem_size
2762 const elem_size = @intCast(u32, ty.abiSize(self.target.*));
2763 const len_imm = math.cast(u16, elem_size) catch return self.fail("TODO load: larger stack offsets", .{});
2764 _ = try self.addInst(.{
2765 .tag = .movk,
2766 .data = .{ .r_imm16_sh = .{
2767 .rd = len_reg,
2768 .imm16 = len_imm,
2769 } },
2770 });
2771
2772 // memcpy(src, dst, len)
2773 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
2774 }
25952775 },
25962776 }
25972777}
......@@ -2711,7 +2891,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
27112891 } },
27122892 });
27132893 },
2714 else => return self.fail("TODO implement genSetReg other types abi_size={}", .{abi_size}),
2894 3 => return self.fail("TODO implement genSetReg types size 3", .{}),
2895 else => unreachable,
27152896 }
27162897 },
27172898 else => return self.fail("TODO implement genSetReg for aarch64 {}", .{mcv}),
src/arch/aarch64/Emit.zig+26-7
......@@ -91,6 +91,7 @@ pub fn emitMir(
9191
9292 .call_extern => try emit.mirCallExtern(inst),
9393
94 .add_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
9495 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
9596
9697 .cset => try emit.mirConditionalSelect(inst),
......@@ -132,6 +133,8 @@ pub fn emitMir(
132133 .movk => try emit.mirMoveWideImmediate(inst),
133134 .movz => try emit.mirMoveWideImmediate(inst),
134135
136 .mul => try emit.mirDataProcessing3Source(inst),
137
135138 .nop => try emit.mirNop(),
136139
137140 .push_regs => try emit.mirPushPopRegs(inst),
......@@ -201,6 +204,12 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
201204 return 5 * 4;
202205 }
203206 },
207 .pop_regs, .push_regs => {
208 const reg_list = emit.mir.instructions.items(.data)[inst].reg_list;
209 const number_of_regs = @popCount(u32, reg_list);
210 const number_of_insts = std.math.divCeil(u6, number_of_regs, 2) catch unreachable;
211 return number_of_insts * 4;
212 },
204213 .call_extern => return 4,
205214 .dbg_line,
206215 .dbg_epilogue_begin,
......@@ -565,15 +574,15 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
565574fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
566575 const tag = emit.mir.instructions.items(.tag)[inst];
567576 const rrr_imm6_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_shift;
577 const rd = rrr_imm6_shift.rd;
578 const rn = rrr_imm6_shift.rn;
579 const rm = rrr_imm6_shift.rm;
580 const shift = rrr_imm6_shift.shift;
581 const imm6 = rrr_imm6_shift.imm6;
568582
569583 switch (tag) {
570 .cmp_shifted_register => try emit.writeInstruction(Instruction.subsShiftedRegister(
571 rrr_imm6_shift.rd,
572 rrr_imm6_shift.rn,
573 rrr_imm6_shift.rm,
574 rrr_imm6_shift.shift,
575 rrr_imm6_shift.imm6,
576 )),
584 .cmp_shifted_register => try emit.writeInstruction(Instruction.subsShiftedRegister(rd, rn, rm, shift, imm6)),
585 .add_shifted_register => try emit.writeInstruction(Instruction.addShiftedRegister(rd, rn, rm, shift, imm6)),
577586 else => unreachable,
578587 }
579588}
......@@ -802,6 +811,16 @@ fn mirMoveWideImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
802811 }
803812}
804813
814fn mirDataProcessing3Source(emit: *Emit, inst: Mir.Inst.Index) !void {
815 const tag = emit.mir.instructions.items(.tag)[inst];
816 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
817
818 switch (tag) {
819 .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)),
820 else => unreachable,
821 }
822}
823
805824fn mirNop(emit: *Emit) !void {
806825 try emit.writeInstruction(Instruction.nop());
807826}
src/arch/aarch64/Mir.zig+13-1
......@@ -26,6 +26,8 @@ pub const Inst = struct {
2626 pub const Tag = enum(u16) {
2727 /// Add (immediate)
2828 add_immediate,
29 /// Add (shifted register)
30 add_shifted_register,
2931 /// Branch conditionally
3032 b_cond,
3133 /// Branch
......@@ -82,6 +84,8 @@ pub const Inst = struct {
8284 movk,
8385 /// Move wide with zero
8486 movz,
87 /// Multiply
88 mul,
8589 /// No Operation
8690 nop,
8791 /// Pseudo-instruction: Pop multiple registers
......@@ -187,6 +191,14 @@ pub const Inst = struct {
187191 imm12: u12,
188192 sh: u1 = 0,
189193 },
194 /// Two registers
195 ///
196 /// Used by e.g. mul
197 rrr: struct {
198 rd: Register,
199 rn: Register,
200 rm: Register,
201 },
190202 /// Three registers and a shift (shift type and 6-bit amount)
191203 ///
192204 /// Used by e.g. cmp_shifted_register
......@@ -208,7 +220,7 @@ pub const Inst = struct {
208220 },
209221 /// Two registers and a LoadStoreOffsetImmediate
210222 ///
211 /// Used by e.g. str_register
223 /// Used by e.g. str_immediate
212224 load_store_register_immediate: struct {
213225 rt: Register,
214226 rn: Register,