authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-06 15:31:39+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-06 15:31:39+01:00
log0772fb0518902e06d1217b24fd11fe9ce40d295d
tree59bbc278ae29e790a9d2b36f60f2bb1e17198a43
parentb47530b9fef28d32747b0f6978ad4b71e5fc5df9
parent97e76bf36c7130a6d43032ab7d6f4e7451b075f4
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10518 from ziglang/stage2-x86_64-zig-test-fixes

stage2: fix x86_64 backend to actually correctly run Zig tests!

5 files changed, 577 insertions(+), 384 deletions(-)

src/arch/x86_64/CodeGen.zig+281-133
...@@ -1150,17 +1150,10 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1150,17 +1150,10 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
1150 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1150 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1151 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1151 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1152 const operand = try self.resolveInst(ty_op.operand);1152 const operand = try self.resolveInst(ty_op.operand);
1153 const dst_mcv: MCValue = blk: {1153 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1154 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {1154 break :result operand;
1155 break :blk operand;1155 }
1156 } else {1156 break :result try self.copyToNewRegister(inst, operand);
1157 break :blk try self.allocRegOrMem(inst, true);
1158 }
1159 };
1160 const ty = self.air.typeOf(ty_op.operand);
1161 var buf: Type.Payload.ElemType = undefined;
1162 try self.load(dst_mcv, operand, ty.optionalChild(&buf));
1163 break :result dst_mcv;
1164 };1157 };
1165 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1158 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1166}1159}
...@@ -1253,19 +1246,31 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1253,19 +1246,31 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
1253/// E to E!T1246/// E to E!T
1254fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {1247fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
1255 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1248 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1256 const result: MCValue = if (self.liveness.isUnused(inst))1249 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1257 .dead1250 const error_union_ty = self.air.getRefType(ty_op.ty);
1258 else1251 const payload_ty = error_union_ty.errorUnionPayload();
1259 return self.fail("TODO implement wrap errunion error for {}", .{self.target.cpu.arch});1252 const mcv = try self.resolveInst(ty_op.operand);
1253 if (!payload_ty.hasCodeGenBits()) break :result mcv;
1254
1255 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
1256 };
1260 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1257 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1261}1258}
12621259
1263fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {1260fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
1264 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1261 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1265 const result: MCValue = if (self.liveness.isUnused(inst))1262 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1266 .dead1263 const operand = try self.resolveInst(ty_op.operand);
1267 else1264 const dst_mcv: MCValue = blk: {
1268 return self.fail("TODO implement slice_ptr for {}", .{self.target.cpu.arch});1265 switch (operand) {
1266 .stack_offset => |off| {
1267 break :blk MCValue{ .stack_offset = off + 8 };
1268 },
1269 else => return self.fail("TODO implement slice_ptr for {}", .{operand}),
1270 }
1271 };
1272 break :result dst_mcv;
1273 };
1269 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1274 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1270}1275}
12711276
...@@ -1273,9 +1278,13 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -1273,9 +1278,13 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1273 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1278 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1274 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1279 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1275 const operand = try self.resolveInst(ty_op.operand);1280 const operand = try self.resolveInst(ty_op.operand);
1276 const dst_mcv: MCValue = switch (operand) {1281 const dst_mcv: MCValue = blk: {
1277 .stack_offset => |off| MCValue{ .stack_offset = off + 8 },1282 switch (operand) {
1278 else => return self.fail("TODO implement slice_len for {}", .{operand}),1283 .stack_offset => |off| {
1284 break :blk MCValue{ .stack_offset = off };
1285 },
1286 else => return self.fail("TODO implement slice_len for {}", .{operand}),
1287 }
1279 };1288 };
1280 break :result dst_mcv;1289 break :result dst_mcv;
1281 };1290 };
...@@ -1313,37 +1322,38 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1313,37 +1322,38 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1313 var buf: Type.SlicePtrFieldTypeBuffer = undefined;1322 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1314 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);1323 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
13151324
1316 const index_ty = self.air.typeOf(bin_op.rhs);1325 const offset_reg = blk: {
1317 const index_mcv: MCValue = blk: {1326 const index_ty = self.air.typeOf(bin_op.rhs);
1318 switch (try self.resolveInst(bin_op.rhs)) {1327 const index_mcv = try self.resolveInst(bin_op.rhs);
1319 .register => |reg| {1328 const offset_reg = try self.register_manager.allocReg(null, &.{});
1320 if (reg.to64() != .rcx) {1329 try self.genSetReg(index_ty, offset_reg, index_mcv);
1321 try self.register_manager.getReg(.rcx, inst);1330 try self.genIMulOpMir(index_ty, .{ .register = offset_reg }, .{ .immediate = elem_size });
1322 }1331 break :blk offset_reg;
1323 break :blk MCValue{ .register = .rcx };
1324 },
1325 else => return self.fail("TODO move index mcv into a register", .{}),
1326 }
1327 };1332 };
13281333
1329 try self.genIMulOpMir(index_ty, index_mcv, .{ .immediate = elem_size });
1330
1331 const dst_mcv = blk: {1334 const dst_mcv = blk: {
1332 switch (slice_mcv) {1335 switch (slice_mcv) {
1333 .stack_offset => |unadjusted_off| {1336 .stack_offset => |off| {
1334 const dst_mcv = try self.allocRegOrMem(inst, false);1337 const dst_mcv = try self.allocRegOrMem(inst, false);
1335 const addr_reg = try self.register_manager.allocReg(null, &.{index_mcv.register});1338 const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg});
1336 const slice_ptr_abi_size = @intCast(u32, slice_ptr_field_type.abiSize(self.target.*));1339 // mov reg, [rbp - 8]
1337 const off = unadjusted_off + elem_size;
1338 // lea reg, [rbp - 8 + rcx*1]
1339 _ = try self.addInst(.{1340 _ = try self.addInst(.{
1340 .tag = .lea,1341 .tag = .mov,
1341 .ops = (Mir.Ops{1342 .ops = (Mir.Ops{
1342 .reg1 = registerAlias(addr_reg, slice_ptr_abi_size),1343 .reg1 = addr_reg.to64(),
1343 .reg2 = .rbp,1344 .reg2 = .rbp,
1344 .flags = 0b11,1345 .flags = 0b01,
1346 }).encode(),
1347 .data = .{ .imm = -@intCast(i32, off + 16) },
1348 });
1349 // add addr, offset
1350 _ = try self.addInst(.{
1351 .tag = .add,
1352 .ops = (Mir.Ops{
1353 .reg1 = addr_reg.to64(),
1354 .reg2 = offset_reg.to64(),
1345 }).encode(),1355 }).encode(),
1346 .data = .{ .imm = -@intCast(i32, off) },1356 .data = undefined,
1347 });1357 });
1348 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);1358 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1349 break :blk dst_mcv;1359 break :blk dst_mcv;
...@@ -1471,6 +1481,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind...@@ -1471,6 +1481,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
14711481
1472fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void {1482fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void {
1473 const elem_ty = ptr_ty.elemType();1483 const elem_ty = ptr_ty.elemType();
1484 const abi_size = elem_ty.abiSize(self.target.*);
1474 switch (ptr) {1485 switch (ptr) {
1475 .none => unreachable,1486 .none => unreachable,
1476 .undef => unreachable,1487 .undef => unreachable,
...@@ -1478,7 +1489,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1478,7 +1489,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1478 .dead => unreachable,1489 .dead => unreachable,
1479 .compare_flags_unsigned => unreachable,1490 .compare_flags_unsigned => unreachable,
1480 .compare_flags_signed => unreachable,1491 .compare_flags_signed => unreachable,
1481 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),1492 .immediate => |imm| {
1493 try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm });
1494 },
1482 .ptr_stack_offset => |off| {1495 .ptr_stack_offset => |off| {
1483 try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off });1496 try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off });
1484 },1497 },
...@@ -1488,7 +1501,66 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1488,7 +1501,66 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1488 .embedded_in_code => {1501 .embedded_in_code => {
1489 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});1502 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
1490 },1503 },
1491 .register => |reg| try self.setRegOrMem(ptr_ty, dst_mcv, .{ .register = reg }),1504 .register => |reg| {
1505 switch (dst_mcv) {
1506 .dead => unreachable,
1507 .undef => unreachable,
1508 .compare_flags_unsigned => unreachable,
1509 .compare_flags_signed => unreachable,
1510 .embedded_in_code => unreachable,
1511 .register => |dst_reg| {
1512 // mov dst_reg, [reg]
1513 _ = try self.addInst(.{
1514 .tag = .mov,
1515 .ops = (Mir.Ops{
1516 .reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)),
1517 .reg2 = reg,
1518 .flags = 0b01,
1519 }).encode(),
1520 .data = .{ .imm = 0 },
1521 });
1522 },
1523 .stack_offset => |off| {
1524 if (abi_size <= 8) {
1525 const tmp_reg = try self.register_manager.allocReg(null, &.{reg});
1526 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
1527 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
1528 }
1529
1530 const regs = try self.register_manager.allocRegs(
1531 3,
1532 .{ null, null, null },
1533 &.{ reg, .rax, .rcx },
1534 );
1535 const addr_reg = regs[0];
1536 const count_reg = regs[1];
1537 const tmp_reg = regs[2];
1538
1539 _ = try self.addInst(.{
1540 .tag = .mov,
1541 .ops = (Mir.Ops{
1542 .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)),
1543 .reg2 = reg,
1544 }).encode(),
1545 .data = undefined,
1546 });
1547
1548 try self.register_manager.getReg(.rax, null);
1549 try self.register_manager.getReg(.rcx, null);
1550
1551 // TODO allow for abi size to be u64
1552 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
1553
1554 return self.genInlineMemcpy(
1555 -@intCast(i32, off + abi_size),
1556 registerAlias(addr_reg, @divExact(reg.size(), 8)),
1557 count_reg.to64(),
1558 tmp_reg.to8(),
1559 );
1560 },
1561 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),
1562 }
1563 },
1492 .memory => |addr| {1564 .memory => |addr| {
1493 const reg = try self.copyToTmpRegister(ptr_ty, .{ .memory = addr });1565 const reg = try self.copyToTmpRegister(ptr_ty, .{ .memory = addr });
1494 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);1566 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
...@@ -1525,11 +1597,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1525,11 +1597,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1525 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1597 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1526}1598}
15271599
1528fn airStore(self: *Self, inst: Air.Inst.Index) !void {1600fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
1529 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1601 _ = ptr_ty;
1530 const ptr = try self.resolveInst(bin_op.lhs);
1531 const value = try self.resolveInst(bin_op.rhs);
1532 const elem_ty = self.air.typeOf(bin_op.rhs);
1533 switch (ptr) {1602 switch (ptr) {
1534 .none => unreachable,1603 .none => unreachable,
1535 .undef => unreachable,1604 .undef => unreachable,
...@@ -1538,19 +1607,58 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {...@@ -1538,19 +1607,58 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1538 .compare_flags_unsigned => unreachable,1607 .compare_flags_unsigned => unreachable,
1539 .compare_flags_signed => unreachable,1608 .compare_flags_signed => unreachable,
1540 .immediate => |imm| {1609 .immediate => |imm| {
1541 try self.setRegOrMem(elem_ty, .{ .memory = imm }, value);1610 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
1542 },1611 },
1543 .ptr_stack_offset => |off| {1612 .ptr_stack_offset => |off| {
1544 try self.genSetStack(elem_ty, off, value);1613 try self.genSetStack(value_ty, off, value);
1545 },1614 },
1546 .ptr_embedded_in_code => |off| {1615 .ptr_embedded_in_code => |off| {
1547 try self.setRegOrMem(elem_ty, .{ .embedded_in_code = off }, value);1616 try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value);
1548 },1617 },
1549 .embedded_in_code => {1618 .embedded_in_code => {
1550 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});1619 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
1551 },1620 },
1552 .register => |reg| {1621 .register => |reg| {
1553 try self.genSetPtrReg(elem_ty, reg, value);1622 switch (value) {
1623 .none => unreachable,
1624 .undef => unreachable,
1625 .dead => unreachable,
1626 .unreach => unreachable,
1627 .compare_flags_unsigned => unreachable,
1628 .compare_flags_signed => unreachable,
1629 .immediate => |imm| {
1630 const abi_size = value_ty.abiSize(self.target.*);
1631 switch (abi_size) {
1632 1, 2, 4 => {
1633 // TODO this is wasteful!
1634 // introduce new MIR tag specifically for mov [reg + 0], imm
1635 const payload = try self.addExtra(Mir.ImmPair{
1636 .dest_off = 0,
1637 .operand = @bitCast(i32, @intCast(u32, imm)),
1638 });
1639 _ = try self.addInst(.{
1640 .tag = .mov_mem_imm,
1641 .ops = (Mir.Ops{
1642 .reg1 = reg.to64(),
1643 .flags = switch (abi_size) {
1644 1 => 0b00,
1645 2 => 0b01,
1646 4 => 0b10,
1647 else => unreachable,
1648 },
1649 }).encode(),
1650 .data = .{ .payload = payload },
1651 });
1652 },
1653 else => {
1654 return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size});
1655 },
1656 }
1657 },
1658 else => |other| {
1659 return self.fail("TODO implement set pointee with {}", .{other});
1660 },
1661 }
1554 },1662 },
1555 .memory => {1663 .memory => {
1556 return self.fail("TODO implement storing to MCValue.memory", .{});1664 return self.fail("TODO implement storing to MCValue.memory", .{});
...@@ -1559,6 +1667,15 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {...@@ -1559,6 +1667,15 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1559 return self.fail("TODO implement storing to MCValue.stack_offset", .{});1667 return self.fail("TODO implement storing to MCValue.stack_offset", .{});
1560 },1668 },
1561 }1669 }
1670}
1671
1672fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1673 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1674 const ptr = try self.resolveInst(bin_op.lhs);
1675 const ptr_ty = self.air.typeOf(bin_op.lhs);
1676 const value = try self.resolveInst(bin_op.rhs);
1677 const value_ty = self.air.typeOf(bin_op.rhs);
1678 try self.store(ptr, value, ptr_ty, value_ty);
1562 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });1679 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1563}1680}
15641681
...@@ -1586,9 +1703,8 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -1586,9 +1703,8 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
15861703
1587 switch (mcv) {1704 switch (mcv) {
1588 .ptr_stack_offset => |off| {1705 .ptr_stack_offset => |off| {
1589 break :result MCValue{1706 const ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size;
1590 .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size,1707 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
1591 };
1592 },1708 },
1593 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),1709 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
1594 }1710 }
...@@ -1610,9 +1726,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1610,9 +1726,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
16101726
1611 switch (mcv) {1727 switch (mcv) {
1612 .stack_offset => |off| {1728 .stack_offset => |off| {
1613 break :result MCValue{1729 const stack_offset = off + struct_size - struct_field_offset - struct_field_size;
1614 .stack_offset = off + struct_size - struct_field_offset - struct_field_size,1730 break :result MCValue{ .stack_offset = stack_offset };
1615 };
1616 },1731 },
1617 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),1732 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
1618 }1733 }
...@@ -1785,6 +1900,15 @@ fn genBinMathOpMir(...@@ -1785,6 +1900,15 @@ fn genBinMathOpMir(
1785 }1900 }
1786 },1901 },
1787 .stack_offset => |off| {1902 .stack_offset => |off| {
1903 if (off > math.maxInt(i32)) {
1904 return self.fail("stack offset too large", .{});
1905 }
1906 const abi_size = dst_ty.abiSize(self.target.*);
1907 if (abi_size > 8) {
1908 return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{});
1909 }
1910 const adj_off = off + abi_size;
1911
1788 switch (src_mcv) {1912 switch (src_mcv) {
1789 .none => unreachable,1913 .none => unreachable,
1790 .undef => return self.genSetStack(dst_ty, off, .undef),1914 .undef => return self.genSetStack(dst_ty, off, .undef),
...@@ -1792,11 +1916,6 @@ fn genBinMathOpMir(...@@ -1792,11 +1916,6 @@ fn genBinMathOpMir(
1792 .ptr_stack_offset => unreachable,1916 .ptr_stack_offset => unreachable,
1793 .ptr_embedded_in_code => unreachable,1917 .ptr_embedded_in_code => unreachable,
1794 .register => |src_reg| {1918 .register => |src_reg| {
1795 if (off > math.maxInt(i32)) {
1796 return self.fail("stack offset too large", .{});
1797 }
1798 const abi_size = dst_ty.abiSize(self.target.*);
1799 const adj_off = off + abi_size;
1800 _ = try self.addInst(.{1919 _ = try self.addInst(.{
1801 .tag = mir_tag,1920 .tag = mir_tag,
1802 .ops = (Mir.Ops{1921 .ops = (Mir.Ops{
...@@ -1808,8 +1927,34 @@ fn genBinMathOpMir(...@@ -1808,8 +1927,34 @@ fn genBinMathOpMir(
1808 });1927 });
1809 },1928 },
1810 .immediate => |imm| {1929 .immediate => |imm| {
1811 _ = imm;1930 const tag: Mir.Inst.Tag = switch (mir_tag) {
1812 return self.fail("TODO implement x86 ADD/SUB/CMP source immediate", .{});1931 .add => .add_mem_imm,
1932 .@"or" => .or_mem_imm,
1933 .@"and" => .and_mem_imm,
1934 .sub => .sub_mem_imm,
1935 .xor => .xor_mem_imm,
1936 .cmp => .cmp_mem_imm,
1937 else => unreachable,
1938 };
1939 const flags: u2 = switch (abi_size) {
1940 1 => 0b00,
1941 2 => 0b01,
1942 4 => 0b10,
1943 8 => 0b11,
1944 else => unreachable,
1945 };
1946 const payload = try self.addExtra(Mir.ImmPair{
1947 .dest_off = -@intCast(i32, adj_off),
1948 .operand = @bitCast(i32, @intCast(u32, imm)),
1949 });
1950 _ = try self.addInst(.{
1951 .tag = tag,
1952 .ops = (Mir.Ops{
1953 .reg1 = .rbp,
1954 .flags = flags,
1955 }).encode(),
1956 .data = .{ .payload = payload },
1957 });
1813 },1958 },
1814 .embedded_in_code, .memory, .stack_offset => {1959 .embedded_in_code, .memory, .stack_offset => {
1815 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});1960 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
...@@ -1859,7 +2004,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !...@@ -1859,7 +2004,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
1859 .immediate => |imm| {2004 .immediate => |imm| {
1860 // TODO take into account the type's ABI size when selecting the register alias2005 // TODO take into account the type's ABI size when selecting the register alias
1861 // register, immediate2006 // register, immediate
1862 if (imm <= math.maxInt(i32)) {2007 if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {
1863 _ = try self.addInst(.{2008 _ = try self.addInst(.{
1864 .tag = .imul_complex,2009 .tag = .imul_complex,
1865 .ops = (Mir.Ops{2010 .ops = (Mir.Ops{
...@@ -2059,6 +2204,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2059,6 +2204,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2059 assert(ty.zigTypeTag() == .Pointer);2204 assert(ty.zigTypeTag() == .Pointer);
2060 const mcv = try self.resolveInst(callee);2205 const mcv = try self.resolveInst(callee);
2061 try self.genSetReg(Type.initTag(.usize), .rax, mcv);2206 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
2207 _ = try self.addInst(.{
2208 .tag = .call,
2209 .ops = (Mir.Ops{
2210 .reg1 = .rax,
2211 .flags = 0b01,
2212 }).encode(),
2213 .data = undefined,
2214 });
2062 }2215 }
2063 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {2216 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
2064 for (info.args) |mc_arg, arg_i| {2217 for (info.args) |mc_arg, arg_i| {
...@@ -2128,6 +2281,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2128,6 +2281,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2128 assert(ty.zigTypeTag() == .Pointer);2281 assert(ty.zigTypeTag() == .Pointer);
2129 const mcv = try self.resolveInst(callee);2282 const mcv = try self.resolveInst(callee);
2130 try self.genSetReg(Type.initTag(.usize), .rax, mcv);2283 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
2284 _ = try self.addInst(.{
2285 .tag = .call,
2286 .ops = (Mir.Ops{
2287 .reg1 = .rax,
2288 .flags = 0b01,
2289 }).encode(),
2290 .data = undefined,
2291 });
2131 }2292 }
2132 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {2293 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2133 for (info.args) |mc_arg, arg_i| {2294 for (info.args) |mc_arg, arg_i| {
...@@ -2180,7 +2341,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2180,7 +2341,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2180 });2341 });
2181 } else return self.fail("TODO implement calling extern fn on plan9", .{});2342 } else return self.fail("TODO implement calling extern fn on plan9", .{});
2182 } else {2343 } else {
2183 return self.fail("TODO implement calling runtime known function pointer", .{});2344 assert(ty.zigTypeTag() == .Pointer);
2345 const mcv = try self.resolveInst(callee);
2346 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
2347 _ = try self.addInst(.{
2348 .tag = .call,
2349 .ops = (Mir.Ops{
2350 .reg1 = .rax,
2351 .flags = 0b01,
2352 }).encode(),
2353 .data = undefined,
2354 });
2184 }2355 }
2185 } else unreachable;2356 } else unreachable;
21862357
...@@ -3029,8 +3200,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3029,8 +3200,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3029 }3200 }
3030 return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});3201 return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});
3031 },3202 },
3032 .stack_offset => |unadjusted_off| {3203 .stack_offset => |off| {
3033 if (stack_offset == unadjusted_off) {3204 if (stack_offset == off) {
3034 // Copy stack variable to itself; nothing to do.3205 // Copy stack variable to itself; nothing to do.
3035 return;3206 return;
3036 }3207 }
...@@ -3041,33 +3212,43 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3041,33 +3212,43 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3041 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });3212 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3042 }3213 }
30433214
3044 const regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{});3215 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx });
3045 const addr_reg = regs[0];3216 const addr_reg = regs[0];
3046 const len_reg = regs[1];3217 const count_reg = regs[1];
3218 const tmp_reg = regs[2];
3219
3220 try self.register_manager.getReg(.rax, null);
3221 try self.register_manager.getReg(.rcx, null);
30473222
3048 const off = unadjusted_off + abi_size;
3049 _ = try self.addInst(.{3223 _ = try self.addInst(.{
3050 .tag = .lea,3224 .tag = .lea,
3051 .ops = (Mir.Ops{3225 .ops = (Mir.Ops{
3052 .reg1 = addr_reg.to64(),3226 .reg1 = addr_reg.to64(),
3053 .reg2 = .rbp,3227 .reg2 = .rbp,
3054 }).encode(),3228 }).encode(),
3055 .data = .{ .imm = -@intCast(i32, off) },3229 .data = .{ .imm = -@intCast(i32, off + abi_size) },
3056 });3230 });
30573231
3058 // TODO allow for abi_size to be u643232 // TODO allow for abi_size to be u64
3059 try self.genSetReg(Type.initTag(.u32), len_reg, .{ .immediate = @intCast(u32, abi_size) });3233 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
30603234
3061 return self.genInlineMemcpy(-@intCast(i32, off), addr_reg.to64(), len_reg.to64());3235 return self.genInlineMemcpy(
3236 -@intCast(i32, stack_offset + abi_size),
3237 addr_reg.to64(),
3238 count_reg.to64(),
3239 tmp_reg.to8(),
3240 );
3062 },3241 },
3063 }3242 }
3064}3243}
30653244
3066fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: Register) InnerError!void {3245fn genInlineMemcpy(
3067 try self.register_manager.getReg(.rax, null);3246 self: *Self,
3068 try self.register_manager.getReg(.rcx, null);3247 stack_offset: i32,
3069 const tmp_reg = try self.register_manager.allocReg(null, &.{ addr_reg, len_reg, .rax, .rcx });3248 addr_reg: Register,
30703249 count_reg: Register,
3250 tmp_reg: Register,
3251) InnerError!void {
3071 // mov rcx, 03252 // mov rcx, 0
3072 _ = try self.addInst(.{3253 _ = try self.addInst(.{
3073 .tag = .mov,3254 .tag = .mov,
...@@ -3087,20 +3268,19 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg:...@@ -3087,20 +3268,19 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg:
3087 });3268 });
30883269
3089 // loop:3270 // loop:
3090 // cmp rcx, len3271 // cmp count, 0
3091 const loop_start = try self.addInst(.{3272 const loop_start = try self.addInst(.{
3092 .tag = .cmp,3273 .tag = .cmp,
3093 .ops = (Mir.Ops{3274 .ops = (Mir.Ops{
3094 .reg1 = .rcx,3275 .reg1 = count_reg,
3095 .reg2 = len_reg,
3096 }).encode(),3276 }).encode(),
3097 .data = undefined,3277 .data = .{ .imm = 0 },
3098 });3278 });
30993279
3100 // jge end3280 // je end
3101 const loop_reloc = try self.addInst(.{3281 const loop_reloc = try self.addInst(.{
3102 .tag = .cond_jmp_above_below,3282 .tag = .cond_jmp_eq_ne,
3103 .ops = (Mir.Ops{ .flags = 0b00 }).encode(),3283 .ops = (Mir.Ops{ .flags = 0b01 }).encode(),
3104 .data = .{ .inst = undefined },3284 .data = .{ .inst = undefined },
3105 });3285 });
31063286
...@@ -3142,6 +3322,15 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg:...@@ -3142,6 +3322,15 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg:
3142 .data = .{ .imm = 1 },3322 .data = .{ .imm = 1 },
3143 });3323 });
31443324
3325 // sub count, 1
3326 _ = try self.addInst(.{
3327 .tag = .sub,
3328 .ops = (Mir.Ops{
3329 .reg1 = count_reg,
3330 }).encode(),
3331 .data = .{ .imm = 1 },
3332 });
3333
3145 // jmp loop3334 // jmp loop
3146 _ = try self.addInst(.{3335 _ = try self.addInst(.{
3147 .tag = .jmp,3336 .tag = .jmp,
...@@ -3153,47 +3342,6 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg:...@@ -3153,47 +3342,6 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg:
3153 try self.performReloc(loop_reloc);3342 try self.performReloc(loop_reloc);
3154}3343}
31553344
3156/// Set pointee via pointer stored in a register.
3157/// mov [reg], value
3158fn genSetPtrReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
3159 switch (mcv) {
3160 .dead => unreachable,
3161 .unreach, .none => return, // Nothing to do.
3162 .immediate => |imm| {
3163 const abi_size = ty.abiSize(self.target.*);
3164 switch (abi_size) {
3165 1, 2, 4 => {
3166 // TODO this is wasteful!
3167 // introduce new MIR tag specifically for mov [reg + 0], imm
3168 const payload = try self.addExtra(Mir.ImmPair{
3169 .dest_off = 0,
3170 .operand = @bitCast(i32, @intCast(u32, imm)),
3171 });
3172 _ = try self.addInst(.{
3173 .tag = .mov_mem_imm,
3174 .ops = (Mir.Ops{
3175 .reg1 = reg.to64(),
3176 .flags = switch (abi_size) {
3177 1 => 0b00,
3178 2 => 0b01,
3179 4 => 0b10,
3180 else => unreachable,
3181 },
3182 }).encode(),
3183 .data = .{ .payload = payload },
3184 });
3185 },
3186 else => {
3187 return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size});
3188 },
3189 }
3190 },
3191 else => |other| {
3192 return self.fail("TODO implement set pointee with {}", .{other});
3193 },
3194 }
3195}
3196
3197fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {3345fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
3198 switch (mcv) {3346 switch (mcv) {
3199 .dead => unreachable,3347 .dead => unreachable,
...@@ -3616,7 +3764,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3616,7 +3764,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3616 if (typed_value.val.tag() == .int_u64) {3764 if (typed_value.val.tag() == .int_u64) {
3617 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };3765 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
3618 }3766 }
3619 return self.fail("TODO codegen more kinds of const pointers", .{});3767 return self.fail("TODO codegen more kinds of const pointers: {}", .{typed_value.val.tag()});
3620 },3768 },
3621 },3769 },
3622 .Int => {3770 .Int => {
src/arch/x86_64/Isel.zig+76-46
...@@ -265,32 +265,43 @@ fn mirPushPopRegsFromCalleePreservedRegs(isel: *Isel, tag: Tag, inst: Mir.Inst.I...@@ -265,32 +265,43 @@ fn mirPushPopRegsFromCalleePreservedRegs(isel: *Isel, tag: Tag, inst: Mir.Inst.I
265265
266fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {266fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
267 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);267 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
268 const flag = @truncate(u1, ops.flags);268 switch (ops.flags) {
269 if (flag == 0) {269 0b00 => {
270 const target = isel.mir.instructions.items(.data)[inst].inst;270 const target = isel.mir.instructions.items(.data)[inst].inst;
271 const source = isel.code.items.len;271 const source = isel.code.items.len;
272 lowerToDEnc(tag, 0, isel.code) catch |err|272 lowerToDEnc(tag, 0, isel.code) catch |err|
273 return isel.failWithLoweringError(err);273 return isel.failWithLoweringError(err);
274 try isel.relocs.append(isel.bin_file.allocator, .{274 try isel.relocs.append(isel.bin_file.allocator, .{
275 .source = source,275 .source = source,
276 .target = target,276 .target = target,
277 .offset = isel.code.items.len - 4,277 .offset = isel.code.items.len - 4,
278 .length = 5,278 .length = 5,
279 });279 });
280 return;280 },
281 }281 0b01 => {
282 if (ops.reg1 == .none) {282 if (ops.reg1 == .none) {
283 // JMP/CALL [imm]283 // JMP/CALL [imm]
284 const imm = isel.mir.instructions.items(.data)[inst].imm;284 const imm = isel.mir.instructions.items(.data)[inst].imm;
285 const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) {285 const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) {
286 16 => .word_ptr,286 16 => .word_ptr,
287 else => .qword_ptr,287 else => .qword_ptr,
288 };288 };
289 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err|289 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err|
290 isel.failWithLoweringError(err);290 isel.failWithLoweringError(err);
291 }
292 // JMP/CALL reg
293 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), isel.code) catch |err| isel.failWithLoweringError(err);
294 },
295 0b10 => {
296 // JMP/CALL r/m64
297 const imm = isel.mir.instructions.items(.data)[inst].imm;
298 return lowerToMEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
299 .disp = imm,
300 .base = ops.reg1,
301 }), isel.code) catch |err| isel.failWithLoweringError(err);
302 },
303 0b11 => return isel.fail("TODO unused JMP/CALL variant 0b11", .{}),
291 }304 }
292 // JMP/CALL reg
293 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), isel.code) catch |err| isel.failWithLoweringError(err);
294}305}
295306
296fn mirCondJmp(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {307fn mirCondJmp(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
...@@ -493,13 +504,14 @@ fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -493,13 +504,14 @@ fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void
493 const scale = ops.flags;504 const scale = ops.flags;
494 const imm = isel.mir.instructions.items(.data)[inst].imm;505 const imm = isel.mir.instructions.items(.data)[inst].imm;
495 // OP reg1, [reg2 + scale*rcx + imm32]506 // OP reg1, [reg2 + scale*rcx + imm32]
507 const scale_index = ScaleIndex{
508 .scale = scale,
509 .index = .rcx,
510 };
496 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{511 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
497 .disp = imm,512 .disp = imm,
498 .base = ops.reg2,513 .base = ops.reg2,
499 .scale_index = .{514 .scale_index = scale_index,
500 .scale = scale,
501 .index = .rcx,
502 },
503 }), isel.code) catch |err| isel.failWithLoweringError(err);515 }), isel.code) catch |err| isel.failWithLoweringError(err);
504}516}
505517
...@@ -507,25 +519,23 @@ fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -507,25 +519,23 @@ fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void
507 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);519 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
508 const scale = ops.flags;520 const scale = ops.flags;
509 const imm = isel.mir.instructions.items(.data)[inst].imm;521 const imm = isel.mir.instructions.items(.data)[inst].imm;
522 const scale_index = ScaleIndex{
523 .scale = scale,
524 .index = .rax,
525 };
510 if (ops.reg2 == .none) {526 if (ops.reg2 == .none) {
511 // OP qword ptr [reg1 + scale*rax + 0], imm32527 // OP qword ptr [reg1 + scale*rax + 0], imm32
512 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{528 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{
513 .disp = 0,529 .disp = 0,
514 .base = ops.reg1,530 .base = ops.reg1,
515 .scale_index = .{531 .scale_index = scale_index,
516 .scale = scale,
517 .index = .rax,
518 },
519 }), imm, isel.code) catch |err| isel.failWithLoweringError(err);532 }), imm, isel.code) catch |err| isel.failWithLoweringError(err);
520 }533 }
521 // OP [reg1 + scale*rax + imm32], reg2534 // OP [reg1 + scale*rax + imm32], reg2
522 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{535 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
523 .disp = imm,536 .disp = imm,
524 .base = ops.reg1,537 .base = ops.reg1,
525 .scale_index = .{538 .scale_index = scale_index,
526 .scale = scale,
527 .index = .rax,
528 },
529 }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);539 }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
530}540}
531541
...@@ -534,14 +544,15 @@ fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -534,14 +544,15 @@ fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void
534 const scale = ops.flags;544 const scale = ops.flags;
535 const payload = isel.mir.instructions.items(.data)[inst].payload;545 const payload = isel.mir.instructions.items(.data)[inst].payload;
536 const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data;546 const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data;
547 const scale_index = ScaleIndex{
548 .scale = scale,
549 .index = .rax,
550 };
537 // OP qword ptr [reg1 + scale*rax + imm32], imm32551 // OP qword ptr [reg1 + scale*rax + imm32], imm32
538 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{552 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{
539 .disp = imm_pair.dest_off,553 .disp = imm_pair.dest_off,
540 .base = ops.reg1,554 .base = ops.reg1,
541 .scale_index = .{555 .scale_index = scale_index,
542 .scale = scale,
543 .index = .rax,
544 },
545 }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);556 }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);
546}557}
547558
...@@ -658,16 +669,17 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {...@@ -658,16 +669,17 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
658 // lea reg, [rbp + rcx + imm32]669 // lea reg, [rbp + rcx + imm32]
659 const imm = isel.mir.instructions.items(.data)[inst].imm;670 const imm = isel.mir.instructions.items(.data)[inst].imm;
660 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;671 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
672 const scale_index = ScaleIndex{
673 .scale = 0,
674 .index = .rcx,
675 };
661 return lowerToRmEnc(676 return lowerToRmEnc(
662 .lea,677 .lea,
663 ops.reg1,678 ops.reg1,
664 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{679 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
665 .disp = imm,680 .disp = imm,
666 .base = src_reg,681 .base = src_reg,
667 .scale_index = .{682 .scale_index = scale_index,
668 .scale = 0,
669 .index = .rcx,
670 },
671 }),683 }),
672 isel.code,684 isel.code,
673 ) catch |err| isel.failWithLoweringError(err);685 ) catch |err| isel.failWithLoweringError(err);
...@@ -1248,7 +1260,7 @@ const Memory = struct {...@@ -1248,7 +1260,7 @@ const Memory = struct {
1248 const dst = base.lowId();1260 const dst = base.lowId();
1249 const src = operand;1261 const src = operand;
1250 if (dst == 4 or mem_op.scale_index != null) {1262 if (dst == 4 or mem_op.scale_index != null) {
1251 if (mem_op.disp == 0) {1263 if (mem_op.disp == 0 and dst != 5) {
1252 encoder.modRm_SIBDisp0(src);1264 encoder.modRm_SIBDisp0(src);
1253 if (mem_op.scale_index) |si| {1265 if (mem_op.scale_index) |si| {
1254 encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst);1266 encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst);
...@@ -1907,6 +1919,24 @@ test "lower RM encoding" {...@@ -1907,6 +1919,24 @@ test "lower RM encoding" {
1907 },1919 },
1908 }), isel.code());1920 }), isel.code());
1909 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");1921 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");
1922 try lowerToRmEnc(.mov, .r8b, RegisterOrMemory.mem(.byte_ptr, .{
1923 .disp = -24,
1924 .base = .rsi,
1925 .scale_index = .{
1926 .scale = 0,
1927 .index = .rcx,
1928 },
1929 }), isel.code());
1930 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", isel.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]");
1931 try lowerToRmEnc(.lea, .rsi, RegisterOrMemory.mem(.qword_ptr, .{
1932 .disp = 0,
1933 .base = .rbp,
1934 .scale_index = .{
1935 .scale = 0,
1936 .index = .rcx,
1937 },
1938 }), isel.code());
1939 try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", isel.lowered(), "lea rsi, qword ptr [rbp + rcx*1 + 0]");
1910}1940}
19111941
1912test "lower MR encoding" {1942test "lower MR encoding" {
src/arch/x86_64/Mir.zig+5-6
...@@ -199,12 +199,11 @@ pub const Inst = struct {...@@ -199,12 +199,11 @@ pub const Inst = struct {
199 /// TODO handle scaling199 /// TODO handle scaling
200 movabs,200 movabs,
201201
202 /// ops flags: 0bX0:202 /// ops flags: form:
203 /// - Uses the `inst` Data tag as the jump target.203 /// 0b00 inst
204 /// - reg1 and reg2 are ignored.204 /// 0b01 reg1
205 /// ops flags: 0bX1:205 /// 0b01 [imm32] if reg1 is none
206 /// - reg1 is the jump target, reg2 and data are ignored.206 /// 0b10 [reg1 + imm32]
207 /// - if reg1 is none, [imm]
208 jmp,207 jmp,
209 call,208 call,
210209
test/behavior.zig+195-199
...@@ -4,211 +4,207 @@ test {...@@ -4,211 +4,207 @@ test {
4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.
5 _ = @import("behavior/bugs/1111.zig");5 _ = @import("behavior/bugs/1111.zig");
6 _ = @import("behavior/bugs/2346.zig");6 _ = @import("behavior/bugs/2346.zig");
7 _ = @import("behavior/bugs/3586.zig");
8 _ = @import("behavior/slice_sentinel_comptime.zig");7 _ = @import("behavior/slice_sentinel_comptime.zig");
8 _ = @import("behavior/bugs/679.zig");
9 _ = @import("behavior/bugs/6850.zig");
10 _ = @import("behavior/fn_in_struct_in_comptime.zig");
11 _ = @import("behavior/hasfield.zig");
12 _ = @import("behavior/hasdecl.zig");
13 _ = @import("behavior/pub_enum.zig");
14 _ = @import("behavior/type_info.zig");
15 _ = @import("behavior/type.zig");
916
10 if (builtin.zig_backend != .stage2_x86_64) {17 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
11 // Tests that pass for stage1, llvm backend, C backend, wasm backend, and arm backend.18 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
12 _ = @import("behavior/bugs/679.zig");19 _ = @import("behavior/bugs/3586.zig");
13 _ = @import("behavior/bugs/6850.zig");20 _ = @import("behavior/basic.zig");
14 _ = @import("behavior/fn_in_struct_in_comptime.zig");21 _ = @import("behavior/bitcast.zig");
15 _ = @import("behavior/hasfield.zig");22 _ = @import("behavior/bool.zig");
16 _ = @import("behavior/hasdecl.zig");23 _ = @import("behavior/bugs/624.zig");
17 _ = @import("behavior/pub_enum.zig");24 _ = @import("behavior/bugs/655.zig");
18 _ = @import("behavior/type_info.zig");25 _ = @import("behavior/bugs/704.zig");
19 _ = @import("behavior/type.zig");26 _ = @import("behavior/bugs/1486.zig");
27 _ = @import("behavior/bugs/2692.zig");
28 _ = @import("behavior/bugs/2889.zig");
29 _ = @import("behavior/bugs/3046.zig");
30 _ = @import("behavior/bugs/4769_a.zig");
31 _ = @import("behavior/bugs/4769_b.zig");
32 _ = @import("behavior/bugs/4954.zig");
33 _ = @import("behavior/byval_arg_var.zig");
34 _ = @import("behavior/call.zig");
35 _ = @import("behavior/defer.zig");
36 _ = @import("behavior/enum.zig");
37 _ = @import("behavior/error.zig");
38 _ = @import("behavior/generics.zig");
39 _ = @import("behavior/if.zig");
40 _ = @import("behavior/import.zig");
41 _ = @import("behavior/incomplete_struct_param_tld.zig");
42 _ = @import("behavior/inttoptr.zig");
43 _ = @import("behavior/member_func.zig");
44 _ = @import("behavior/null.zig");
45 _ = @import("behavior/pointers.zig");
46 _ = @import("behavior/ptrcast.zig");
47 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
48 _ = @import("behavior/struct.zig");
49 _ = @import("behavior/this.zig");
50 _ = @import("behavior/truncate.zig");
51 _ = @import("behavior/underscore.zig");
52 _ = @import("behavior/usingnamespace.zig");
53 _ = @import("behavior/void.zig");
54 _ = @import("behavior/while.zig");
2055
21 if (builtin.zig_backend != .stage2_arm) {56 if (builtin.zig_backend != .stage2_wasm) {
22 // Tests that pass for stage1, llvm backend, C backend, wasm backend.57 // Tests that pass for stage1, llvm backend, C backend
23 _ = @import("behavior/basic.zig");58 _ = @import("behavior/align.zig");
24 _ = @import("behavior/bitcast.zig");59 _ = @import("behavior/array.zig");
25 _ = @import("behavior/bool.zig");60 _ = @import("behavior/bugs/4560.zig");
26 _ = @import("behavior/bugs/624.zig");61 _ = @import("behavior/cast.zig");
27 _ = @import("behavior/bugs/655.zig");62 _ = @import("behavior/for.zig");
28 _ = @import("behavior/bugs/704.zig");63 _ = @import("behavior/int128.zig");
29 _ = @import("behavior/bugs/1486.zig");64 _ = @import("behavior/optional.zig");
30 _ = @import("behavior/bugs/2692.zig");65 _ = @import("behavior/translate_c_macros.zig");
31 _ = @import("behavior/bugs/2889.zig");
32 _ = @import("behavior/bugs/3046.zig");
33 _ = @import("behavior/bugs/4769_a.zig");
34 _ = @import("behavior/bugs/4769_b.zig");
35 _ = @import("behavior/bugs/4954.zig");
36 _ = @import("behavior/byval_arg_var.zig");
37 _ = @import("behavior/call.zig");
38 _ = @import("behavior/defer.zig");
39 _ = @import("behavior/enum.zig");
40 _ = @import("behavior/error.zig");
41 _ = @import("behavior/generics.zig");
42 _ = @import("behavior/if.zig");
43 _ = @import("behavior/import.zig");
44 _ = @import("behavior/incomplete_struct_param_tld.zig");
45 _ = @import("behavior/inttoptr.zig");
46 _ = @import("behavior/member_func.zig");
47 _ = @import("behavior/null.zig");
48 _ = @import("behavior/pointers.zig");
49 _ = @import("behavior/ptrcast.zig");
50 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
51 _ = @import("behavior/struct.zig");
52 _ = @import("behavior/this.zig");
53 _ = @import("behavior/truncate.zig");
54 _ = @import("behavior/underscore.zig");
55 _ = @import("behavior/usingnamespace.zig");
56 _ = @import("behavior/void.zig");
57 _ = @import("behavior/while.zig");
5866
59 if (builtin.zig_backend != .stage2_wasm) {67 if (builtin.zig_backend != .stage2_c) {
60 // Tests that pass for stage1, llvm backend, C backend68 // Tests that pass for stage1 and the llvm backend.
61 _ = @import("behavior/align.zig");69 _ = @import("behavior/align_llvm.zig");
62 _ = @import("behavior/array.zig");70 _ = @import("behavior/alignof.zig");
63 _ = @import("behavior/bugs/4560.zig");71 _ = @import("behavior/array_llvm.zig");
64 _ = @import("behavior/cast.zig");72 _ = @import("behavior/atomics.zig");
65 _ = @import("behavior/for.zig");73 _ = @import("behavior/basic_llvm.zig");
66 _ = @import("behavior/int128.zig");74 _ = @import("behavior/bugs/394.zig");
67 _ = @import("behavior/optional.zig");75 _ = @import("behavior/bugs/656.zig");
68 _ = @import("behavior/translate_c_macros.zig");76 _ = @import("behavior/bugs/1277.zig");
77 _ = @import("behavior/bugs/1310.zig");
78 _ = @import("behavior/bugs/1381.zig");
79 _ = @import("behavior/bugs/1500.zig");
80 _ = @import("behavior/bugs/1741.zig");
81 _ = @import("behavior/bugs/2006.zig");
82 _ = @import("behavior/bugs/2578.zig");
83 _ = @import("behavior/bugs/3007.zig");
84 _ = @import("behavior/bugs/3112.zig");
85 _ = @import("behavior/bugs/3367.zig");
86 _ = @import("behavior/bugs/7250.zig");
87 _ = @import("behavior/bugs/9584.zig");
88 _ = @import("behavior/cast_llvm.zig");
89 _ = @import("behavior/enum_llvm.zig");
90 _ = @import("behavior/eval.zig");
91 _ = @import("behavior/floatop.zig");
92 _ = @import("behavior/fn.zig");
93 _ = @import("behavior/generics_llvm.zig");
94 _ = @import("behavior/math.zig");
95 _ = @import("behavior/maximum_minimum.zig");
96 _ = @import("behavior/namespace_depends_on_compile_var.zig");
97 _ = @import("behavior/null_llvm.zig");
98 _ = @import("behavior/optional_llvm.zig");
99 _ = @import("behavior/popcount.zig");
100 _ = @import("behavior/saturating_arithmetic.zig");
101 _ = @import("behavior/sizeof_and_typeof.zig");
102 _ = @import("behavior/slice.zig");
103 _ = @import("behavior/struct_llvm.zig");
104 _ = @import("behavior/switch.zig");
105 _ = @import("behavior/undefined.zig");
106 _ = @import("behavior/union.zig");
107 _ = @import("behavior/widening.zig");
69108
70 if (builtin.zig_backend != .stage2_c) {109 if (builtin.zig_backend != .stage1) {
71 // Tests that pass for stage1 and the llvm backend.110 // When all comptime_memory.zig tests pass, #9646 can be closed.
72 _ = @import("behavior/align_llvm.zig");111 // _ = @import("behavior/comptime_memory.zig");
73 _ = @import("behavior/alignof.zig");112 _ = @import("behavior/slice_stage2.zig");
74 _ = @import("behavior/array_llvm.zig");113 } else {
75 _ = @import("behavior/atomics.zig");114 // Tests that only pass for the stage1 backend.
76 _ = @import("behavior/basic_llvm.zig");115 _ = @import("behavior/align_stage1.zig");
77 _ = @import("behavior/bugs/394.zig");116 _ = @import("behavior/array_stage1.zig");
78 _ = @import("behavior/bugs/656.zig");117 if (builtin.os.tag != .wasi) {
79 _ = @import("behavior/bugs/1277.zig");118 _ = @import("behavior/asm.zig");
80 _ = @import("behavior/bugs/1310.zig");119 _ = @import("behavior/async_fn.zig");
81 _ = @import("behavior/bugs/1381.zig");120 }
82 _ = @import("behavior/bugs/1500.zig");121 _ = @import("behavior/await_struct.zig");
83 _ = @import("behavior/bugs/1741.zig");122 _ = @import("behavior/bit_shifting.zig");
84 _ = @import("behavior/bugs/2006.zig");123 _ = @import("behavior/bitcast_stage1.zig");
85 _ = @import("behavior/bugs/2578.zig");124 _ = @import("behavior/bitreverse.zig");
86 _ = @import("behavior/bugs/3007.zig");125 _ = @import("behavior/bugs/421.zig");
87 _ = @import("behavior/bugs/3112.zig");126 _ = @import("behavior/bugs/529.zig");
88 _ = @import("behavior/bugs/3367.zig");127 _ = @import("behavior/bugs/718.zig");
89 _ = @import("behavior/bugs/7250.zig");128 _ = @import("behavior/bugs/726.zig");
90 _ = @import("behavior/bugs/9584.zig");129 _ = @import("behavior/bugs/828.zig");
91 _ = @import("behavior/cast_llvm.zig");130 _ = @import("behavior/bugs/920.zig");
92 _ = @import("behavior/enum_llvm.zig");131 _ = @import("behavior/bugs/1025.zig");
93 _ = @import("behavior/eval.zig");132 _ = @import("behavior/bugs/1076.zig");
94 _ = @import("behavior/floatop.zig");133 _ = @import("behavior/bugs/1120.zig");
95 _ = @import("behavior/fn.zig");134 _ = @import("behavior/bugs/1421.zig");
96 _ = @import("behavior/generics_llvm.zig");135 _ = @import("behavior/bugs/1442.zig");
97 _ = @import("behavior/math.zig");136 _ = @import("behavior/bugs/1607.zig");
98 _ = @import("behavior/maximum_minimum.zig");137 _ = @import("behavior/bugs/1735.zig");
99 _ = @import("behavior/namespace_depends_on_compile_var.zig");138 _ = @import("behavior/bugs/1851.zig");
100 _ = @import("behavior/null_llvm.zig");139 _ = @import("behavior/bugs/1914.zig");
101 _ = @import("behavior/optional_llvm.zig");140 _ = @import("behavior/bugs/2114.zig");
102 _ = @import("behavior/popcount.zig");141 _ = @import("behavior/bugs/3384.zig");
103 _ = @import("behavior/saturating_arithmetic.zig");142 _ = @import("behavior/bugs/3742.zig");
104 _ = @import("behavior/sizeof_and_typeof.zig");143 _ = @import("behavior/bugs/3779.zig");
105 _ = @import("behavior/slice.zig");144 _ = @import("behavior/bugs/4328.zig");
106 _ = @import("behavior/struct_llvm.zig");145 _ = @import("behavior/bugs/5398.zig");
107 _ = @import("behavior/switch.zig");146 _ = @import("behavior/bugs/5413.zig");
108 _ = @import("behavior/undefined.zig");147 _ = @import("behavior/bugs/5474.zig");
109 _ = @import("behavior/union.zig");148 _ = @import("behavior/bugs/5487.zig");
110 _ = @import("behavior/widening.zig");149 _ = @import("behavior/bugs/6456.zig");
111150 _ = @import("behavior/bugs/6781.zig");
112 if (builtin.zig_backend != .stage1) {151 _ = @import("behavior/bugs/7003.zig");
113 // When all comptime_memory.zig tests pass, #9646 can be closed.152 _ = @import("behavior/bugs/7027.zig");
114 // _ = @import("behavior/comptime_memory.zig");153 _ = @import("behavior/bugs/7047.zig");
115 _ = @import("behavior/slice_stage2.zig");154 _ = @import("behavior/bugs/10147.zig");
116 } else {155 _ = @import("behavior/byteswap.zig");
117 // Tests that only pass for the stage1 backend.156 _ = @import("behavior/call_stage1.zig");
118 _ = @import("behavior/align_stage1.zig");157 _ = @import("behavior/cast_stage1.zig");
119 _ = @import("behavior/array_stage1.zig");158 _ = @import("behavior/const_slice_child.zig");
120 if (builtin.os.tag != .wasi) {159 _ = @import("behavior/defer_stage1.zig");
121 _ = @import("behavior/asm.zig");160 _ = @import("behavior/enum_stage1.zig");
122 _ = @import("behavior/async_fn.zig");161 _ = @import("behavior/error_stage1.zig");
123 }162 _ = @import("behavior/eval_stage1.zig");
124 _ = @import("behavior/await_struct.zig");163 _ = @import("behavior/field_parent_ptr.zig");
125 _ = @import("behavior/bit_shifting.zig");164 _ = @import("behavior/floatop_stage1.zig");
126 _ = @import("behavior/bitcast_stage1.zig");165 _ = @import("behavior/fn_stage1.zig");
127 _ = @import("behavior/bitreverse.zig");166 _ = @import("behavior/fn_delegation.zig");
128 _ = @import("behavior/bugs/421.zig");167 _ = @import("behavior/for_stage1.zig");
129 _ = @import("behavior/bugs/529.zig");168 _ = @import("behavior/if_stage1.zig");
130 _ = @import("behavior/bugs/718.zig");169 _ = @import("behavior/ir_block_deps.zig");
131 _ = @import("behavior/bugs/726.zig");170 _ = @import("behavior/math_stage1.zig");
132 _ = @import("behavior/bugs/828.zig");171 _ = @import("behavior/merge_error_sets.zig");
133 _ = @import("behavior/bugs/920.zig");172 _ = @import("behavior/misc.zig");
134 _ = @import("behavior/bugs/1025.zig");173 _ = @import("behavior/muladd.zig");
135 _ = @import("behavior/bugs/1076.zig");174 _ = @import("behavior/null_stage1.zig");
136 _ = @import("behavior/bugs/1120.zig");175 _ = @import("behavior/optional_stage1.zig");
137 _ = @import("behavior/bugs/1421.zig");176 _ = @import("behavior/pointers_stage1.zig");
138 _ = @import("behavior/bugs/1442.zig");177 _ = @import("behavior/popcount_stage1.zig");
139 _ = @import("behavior/bugs/1607.zig");178 _ = @import("behavior/prefetch.zig");
140 _ = @import("behavior/bugs/1735.zig");179 _ = @import("behavior/ptrcast_stage1.zig");
141 _ = @import("behavior/bugs/1851.zig");180 _ = @import("behavior/reflection.zig");
142 _ = @import("behavior/bugs/1914.zig");181 _ = @import("behavior/saturating_arithmetic_stage1.zig");
143 _ = @import("behavior/bugs/2114.zig");182 _ = @import("behavior/select.zig");
144 _ = @import("behavior/bugs/3384.zig");183 _ = @import("behavior/shuffle.zig");
145 _ = @import("behavior/bugs/3742.zig");184 _ = @import("behavior/sizeof_and_typeof_stage1.zig");
146 _ = @import("behavior/bugs/3779.zig");185 _ = @import("behavior/slice_stage1.zig");
147 _ = @import("behavior/bugs/4328.zig");186 _ = @import("behavior/struct_contains_null_ptr_itself.zig");
148 _ = @import("behavior/bugs/5398.zig");187 _ = @import("behavior/struct_contains_slice_of_itself.zig");
149 _ = @import("behavior/bugs/5413.zig");188 _ = @import("behavior/struct_stage1.zig");
150 _ = @import("behavior/bugs/5474.zig");189 _ = @import("behavior/switch_prong_err_enum.zig");
151 _ = @import("behavior/bugs/5487.zig");190 _ = @import("behavior/switch_prong_implicit_cast.zig");
152 _ = @import("behavior/bugs/6456.zig");191 _ = @import("behavior/switch_stage1.zig");
153 _ = @import("behavior/bugs/6781.zig");192 _ = @import("behavior/truncate_stage1.zig");
154 _ = @import("behavior/bugs/7003.zig");193 _ = @import("behavior/try.zig");
155 _ = @import("behavior/bugs/7027.zig");194 _ = @import("behavior/tuple.zig");
156 _ = @import("behavior/bugs/7047.zig");195 _ = @import("behavior/type_stage1.zig");
157 _ = @import("behavior/bugs/10147.zig");196 _ = @import("behavior/type_info_stage1.zig");
158 _ = @import("behavior/byteswap.zig");197 _ = @import("behavior/typename.zig");
159 _ = @import("behavior/call_stage1.zig");198 _ = @import("behavior/union_stage1.zig");
160 _ = @import("behavior/cast_stage1.zig");199 _ = @import("behavior/union_with_members.zig");
161 _ = @import("behavior/const_slice_child.zig");200 _ = @import("behavior/var_args.zig");
162 _ = @import("behavior/defer_stage1.zig");201 _ = @import("behavior/vector.zig");
163 _ = @import("behavior/enum_stage1.zig");202 if (builtin.target.cpu.arch == .wasm32) {
164 _ = @import("behavior/error_stage1.zig");203 _ = @import("behavior/wasm.zig");
165 _ = @import("behavior/eval_stage1.zig");
166 _ = @import("behavior/field_parent_ptr.zig");
167 _ = @import("behavior/floatop_stage1.zig");
168 _ = @import("behavior/fn_stage1.zig");
169 _ = @import("behavior/fn_delegation.zig");
170 _ = @import("behavior/for_stage1.zig");
171 _ = @import("behavior/if_stage1.zig");
172 _ = @import("behavior/ir_block_deps.zig");
173 _ = @import("behavior/math_stage1.zig");
174 _ = @import("behavior/merge_error_sets.zig");
175 _ = @import("behavior/misc.zig");
176 _ = @import("behavior/muladd.zig");
177 _ = @import("behavior/null_stage1.zig");
178 _ = @import("behavior/optional_stage1.zig");
179 _ = @import("behavior/pointers_stage1.zig");
180 _ = @import("behavior/popcount_stage1.zig");
181 _ = @import("behavior/prefetch.zig");
182 _ = @import("behavior/ptrcast_stage1.zig");
183 _ = @import("behavior/reflection.zig");
184 _ = @import("behavior/saturating_arithmetic_stage1.zig");
185 _ = @import("behavior/select.zig");
186 _ = @import("behavior/shuffle.zig");
187 _ = @import("behavior/sizeof_and_typeof_stage1.zig");
188 _ = @import("behavior/slice_stage1.zig");
189 _ = @import("behavior/struct_contains_null_ptr_itself.zig");
190 _ = @import("behavior/struct_contains_slice_of_itself.zig");
191 _ = @import("behavior/struct_stage1.zig");
192 _ = @import("behavior/switch_prong_err_enum.zig");
193 _ = @import("behavior/switch_prong_implicit_cast.zig");
194 _ = @import("behavior/switch_stage1.zig");
195 _ = @import("behavior/truncate_stage1.zig");
196 _ = @import("behavior/try.zig");
197 _ = @import("behavior/tuple.zig");
198 _ = @import("behavior/type_stage1.zig");
199 _ = @import("behavior/type_info_stage1.zig");
200 _ = @import("behavior/typename.zig");
201 _ = @import("behavior/union_stage1.zig");
202 _ = @import("behavior/union_with_members.zig");
203 _ = @import("behavior/var_args.zig");
204 _ = @import("behavior/vector.zig");
205 if (builtin.target.cpu.arch == .wasm32) {
206 _ = @import("behavior/wasm.zig");
207 }
208 _ = @import("behavior/while_stage1.zig");
209 _ = @import("behavior/src.zig");
210 _ = @import("behavior/translate_c_macros_stage1.zig");
211 }204 }
205 _ = @import("behavior/while_stage1.zig");
206 _ = @import("behavior/src.zig");
207 _ = @import("behavior/translate_c_macros_stage1.zig");
212 }208 }
213 }209 }
214 }210 }
test/stage2/x86_64.zig+20
...@@ -2014,6 +2014,26 @@ fn addLinuxTestCases(ctx: *TestContext) !void {...@@ -2014,6 +2014,26 @@ fn addLinuxTestCases(ctx: *TestContext) !void {
2014 \\}2014 \\}
2015 , "");2015 , "");
2016 }2016 }
2017
2018 {
2019 // TODO fixing this will enable zig test on macOS
2020 var case = ctx.exe("access slice element by index - slice_elem_val", linux_x64);
2021 case.addCompareOutput(
2022 \\var array = [_]usize{ 0, 42, 123, 34 };
2023 \\var slice: []const usize = &array;
2024 \\
2025 \\pub fn main() void {
2026 \\ assert(slice[0] == 0);
2027 \\ assert(slice[1] == 42);
2028 \\ assert(slice[2] == 123);
2029 \\ assert(slice[3] == 34);
2030 \\}
2031 \\
2032 \\fn assert(ok: bool) void {
2033 \\ if (!ok) unreachable;
2034 \\}
2035 , "");
2036 }
2017}2037}
20182038
2019fn addMacOsTestCases(ctx: *TestContext) !void {2039fn addMacOsTestCases(ctx: *TestContext) !void {