| ... | ... | @@ -1329,59 +1329,49 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1329 | 1329 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1330 | 1330 | } |
| 1331 | 1331 | |
| 1332 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| 1333 | const reg = try self.register_manager.allocReg(null, &.{}); |
| 1334 | try self.genSetReg(index_ty, reg, index); |
| 1335 | try self.genIMulOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size }); |
| 1336 | return reg; |
| 1337 | } |
| 1338 | |
| 1332 | 1339 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1333 | 1340 | const is_volatile = false; // TODO |
| 1334 | 1341 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1335 | 1342 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { |
| 1336 | 1343 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 1337 | 1344 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 1338 | | |
| 1339 | 1345 | const elem_ty = slice_ty.childType(); |
| 1340 | 1346 | const elem_size = elem_ty.abiSize(self.target.*); |
| 1341 | | |
| 1342 | 1347 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1343 | 1348 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| 1344 | | |
| 1345 | | const offset_reg = blk: { |
| 1346 | | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1347 | | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 1348 | | const offset_reg = try self.register_manager.allocReg(null, &.{}); |
| 1349 | | try self.genSetReg(index_ty, offset_reg, index_mcv); |
| 1350 | | try self.genIMulOpMir(index_ty, .{ .register = offset_reg }, .{ .immediate = elem_size }); |
| 1351 | | break :blk offset_reg; |
| 1352 | | }; |
| 1353 | | |
| 1354 | | const dst_mcv = blk: { |
| 1355 | | switch (slice_mcv) { |
| 1356 | | .stack_offset => |off| { |
| 1357 | | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1358 | | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); |
| 1359 | | // mov reg, [rbp - 8] |
| 1360 | | _ = try self.addInst(.{ |
| 1361 | | .tag = .mov, |
| 1362 | | .ops = (Mir.Ops{ |
| 1363 | | .reg1 = addr_reg.to64(), |
| 1364 | | .reg2 = .rbp, |
| 1365 | | .flags = 0b01, |
| 1366 | | }).encode(), |
| 1367 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) }, |
| 1368 | | }); |
| 1369 | | // add addr, offset |
| 1370 | | _ = try self.addInst(.{ |
| 1371 | | .tag = .add, |
| 1372 | | .ops = (Mir.Ops{ |
| 1373 | | .reg1 = addr_reg.to64(), |
| 1374 | | .reg2 = offset_reg.to64(), |
| 1375 | | }).encode(), |
| 1376 | | .data = undefined, |
| 1377 | | }); |
| 1378 | | try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type); |
| 1379 | | break :blk dst_mcv; |
| 1380 | | }, |
| 1381 | | else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}), |
| 1382 | | } |
| 1383 | | }; |
| 1384 | | |
| 1349 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1350 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 1351 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); |
| 1352 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); |
| 1353 | switch (slice_mcv) { |
| 1354 | .stack_offset => |off| { |
| 1355 | // mov reg, [rbp - 8] |
| 1356 | _ = try self.addInst(.{ |
| 1357 | .tag = .mov, |
| 1358 | .ops = (Mir.Ops{ |
| 1359 | .reg1 = addr_reg.to64(), |
| 1360 | .reg2 = .rbp, |
| 1361 | .flags = 0b01, |
| 1362 | }).encode(), |
| 1363 | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) }, |
| 1364 | }); |
| 1365 | }, |
| 1366 | else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}), |
| 1367 | } |
| 1368 | // TODO we could allocate register here, but need to except addr register and potentially |
| 1369 | // offset register. |
| 1370 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1371 | try self.genBinMathOpMir(.add, slice_ptr_field_type, .unsigned, .{ .register = addr_reg.to64() }, .{ |
| 1372 | .register = offset_reg.to64(), |
| 1373 | }); |
| 1374 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, slice_ptr_field_type); |
| 1385 | 1375 | break :result dst_mcv; |
| 1386 | 1376 | }; |
| 1387 | 1377 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | ... | @@ -1399,10 +1389,43 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1399 | 1389 | |
| 1400 | 1390 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1401 | 1391 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1402 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1403 | | .dead |
| 1404 | | else |
| 1405 | | return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch}); |
| 1392 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1393 | const array_ty = self.air.typeOf(bin_op.lhs); |
| 1394 | const array = try self.resolveInst(bin_op.lhs); |
| 1395 | const array_abi_size = array_ty.abiSize(self.target.*); |
| 1396 | const elem_ty = array_ty.childType(); |
| 1397 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 1398 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1399 | const index = try self.resolveInst(bin_op.rhs); |
| 1400 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 1401 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); |
| 1402 | switch (array) { |
| 1403 | .stack_offset => |off| { |
| 1404 | // lea reg, [rbp] |
| 1405 | _ = try self.addInst(.{ |
| 1406 | .tag = .lea, |
| 1407 | .ops = (Mir.Ops{ |
| 1408 | .reg1 = addr_reg.to64(), |
| 1409 | .reg2 = .rbp, |
| 1410 | }).encode(), |
| 1411 | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + array_abi_size)) }, |
| 1412 | }); |
| 1413 | }, |
| 1414 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), |
| 1415 | } |
| 1416 | // TODO we could allocate register here, but need to except addr register and potentially |
| 1417 | // offset register. |
| 1418 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1419 | try self.genBinMathOpMir( |
| 1420 | .add, |
| 1421 | array_ty, |
| 1422 | .unsigned, |
| 1423 | .{ .register = addr_reg.to64() }, |
| 1424 | .{ .register = offset_reg.to64() }, |
| 1425 | ); |
| 1426 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty); |
| 1427 | break :result dst_mcv; |
| 1428 | }; |
| 1406 | 1429 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1407 | 1430 | } |
| 1408 | 1431 | |
| ... | ... | @@ -1419,10 +1442,27 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1419 | 1442 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1420 | 1443 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1421 | 1444 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1422 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1423 | | .dead |
| 1424 | | else |
| 1425 | | return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch}); |
| 1445 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1446 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 1447 | const ptr = try self.resolveInst(extra.lhs); |
| 1448 | const elem_ty = ptr_ty.elemType2(); |
| 1449 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 1450 | const index_ty = self.air.typeOf(extra.rhs); |
| 1451 | const index = try self.resolveInst(extra.rhs); |
| 1452 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 1453 | const dst_mcv = blk: { |
| 1454 | switch (ptr) { |
| 1455 | .ptr_stack_offset => { |
| 1456 | const reg = try self.register_manager.allocReg(inst, &.{offset_reg}); |
| 1457 | try self.genSetReg(ptr_ty, reg, ptr); |
| 1458 | break :blk .{ .register = reg }; |
| 1459 | }, |
| 1460 | else => return self.fail("TODO implement ptr_elem_ptr when ptr is {}", .{ptr}), |
| 1461 | } |
| 1462 | }; |
| 1463 | try self.genBinMathOpMir(.add, ptr_ty, .unsigned, dst_mcv, .{ .register = offset_reg }); |
| 1464 | break :result dst_mcv; |
| 1465 | }; |
| 1426 | 1466 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1427 | 1467 | } |
| 1428 | 1468 | |
| ... | ... | @@ -3742,12 +3782,12 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 3742 | 3782 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3743 | 3783 | const ptr_ty = self.air.typeOf(ty_op.operand); |
| 3744 | 3784 | const ptr = try self.resolveInst(ty_op.operand); |
| 3785 | const array_ty = ptr_ty.childType(); |
| 3786 | const array_len = array_ty.arrayLenIncludingSentinel(); |
| 3745 | 3787 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 3746 | 3788 | const stack_offset = try self.allocMem(inst, 16, 16); |
| 3747 | | const array_ty = ptr_ty.childType(); |
| 3748 | | const array_len = array_ty.arrayLenIncludingSentinel(); |
| 3749 | 3789 | try self.genSetStack(ptr_ty, stack_offset + 8, ptr); |
| 3750 | | try self.genSetStack(Type.initTag(.u64), stack_offset + 16, .{ .immediate = array_len }); |
| 3790 | try self.genSetStack(Type.initTag(.u64), stack_offset, .{ .immediate = array_len }); |
| 3751 | 3791 | break :blk .{ .stack_offset = stack_offset }; |
| 3752 | 3792 | }; |
| 3753 | 3793 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |