| ... | ... | @@ -1164,7 +1164,20 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1164 | 1164 | |
| 1165 | 1165 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1166 | 1166 | 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 | }; |
| 1168 | 1181 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1169 | 1182 | } |
| 1170 | 1183 | |
| ... | ... | @@ -1183,10 +1196,114 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1183 | 1196 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1184 | 1197 | const is_volatile = false; // TODO |
| 1185 | 1198 | 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 | }; |
| 1187 | 1256 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1188 | 1257 | } |
| 1189 | 1258 | |
| 1259 | fn 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 | |
| 1190 | 1307 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1191 | 1308 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1192 | 1309 | 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 |
| 1310 | 1427 | .undef => unreachable, |
| 1311 | 1428 | .compare_flags_signed, .compare_flags_unsigned => unreachable, |
| 1312 | 1429 | .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 | }, |
| 1313 | 1440 | .stack_offset => |off| { |
| 1314 | 1441 | if (elem_ty.abiSize(self.target.*) <= 8) { |
| 1315 | 1442 | 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 |
| 2590 | 2717 | if (stack_offset == off) |
| 2591 | 2718 | return; // Copy stack variable to itself; nothing to do. |
| 2592 | 2719 | |
| 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 | } |
| 2595 | 2775 | }, |
| 2596 | 2776 | } |
| 2597 | 2777 | } |
| ... | ... | @@ -2711,7 +2891,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2711 | 2891 | } }, |
| 2712 | 2892 | }); |
| 2713 | 2893 | }, |
| 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, |
| 2715 | 2896 | } |
| 2716 | 2897 | }, |
| 2717 | 2898 | else => return self.fail("TODO implement genSetReg for aarch64 {}", .{mcv}), |