| author | |
| committer | |
| log | 0772fb0518902e06d1217b24fd11fe9ce40d295d |
| tree | 59bbc278ae29e790a9d2b36f60f2bb1e17198a43 |
| parent | b47530b9fef28d32747b0f6978ad4b71e5fc5df9 |
| parent | 97e76bf36c7130a6d43032ab7d6f4e7451b075f4 |
| signature |
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 | 1150 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1151 | 1151 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1152 | 1152 | const operand = try self.resolveInst(ty_op.operand); |
| 1153 | const dst_mcv: MCValue = blk: { | |
| 1154 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) { | |
| 1155 | break :blk operand; | |
| 1156 | } else { | |
| 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; | |
| 1153 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) { | |
| 1154 | break :result operand; | |
| 1155 | } | |
| 1156 | break :result try self.copyToNewRegister(inst, operand); | |
| 1164 | 1157 | }; |
| 1165 | 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 | 1246 | /// E to E!T |
| 1254 | 1247 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1255 | 1248 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1256 | const result: MCValue = if (self.liveness.isUnused(inst)) | |
| 1257 | .dead | |
| 1258 | else | |
| 1259 | return self.fail("TODO implement wrap errunion error for {}", .{self.target.cpu.arch}); | |
| 1249 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 1250 | const error_union_ty = self.air.getRefType(ty_op.ty); | |
| 1251 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 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 | 1257 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1261 | 1258 | } |
| 1262 | 1259 | |
| 1263 | 1260 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1264 | 1261 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1265 | const result: MCValue = if (self.liveness.isUnused(inst)) | |
| 1266 | .dead | |
| 1267 | else | |
| 1268 | return self.fail("TODO implement slice_ptr for {}", .{self.target.cpu.arch}); | |
| 1262 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 1263 | const operand = try self.resolveInst(ty_op.operand); | |
| 1264 | const dst_mcv: MCValue = blk: { | |
| 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 | 1274 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1270 | 1275 | } |
| 1271 | 1276 | |
| ... | ... | @@ -1273,9 +1278,13 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1273 | 1278 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1274 | 1279 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1275 | 1280 | const operand = try self.resolveInst(ty_op.operand); |
| 1276 | const dst_mcv: MCValue = switch (operand) { | |
| 1277 | .stack_offset => |off| MCValue{ .stack_offset = off + 8 }, | |
| 1278 | else => return self.fail("TODO implement slice_len for {}", .{operand}), | |
| 1281 | const dst_mcv: MCValue = blk: { | |
| 1282 | switch (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 | 1289 | break :result dst_mcv; |
| 1281 | 1290 | }; |
| ... | ... | @@ -1313,37 +1322,38 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1313 | 1322 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1314 | 1323 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| 1315 | 1324 | |
| 1316 | const index_ty = self.air.typeOf(bin_op.rhs); | |
| 1317 | const index_mcv: MCValue = blk: { | |
| 1318 | switch (try self.resolveInst(bin_op.rhs)) { | |
| 1319 | .register => |reg| { | |
| 1320 | if (reg.to64() != .rcx) { | |
| 1321 | try self.register_manager.getReg(.rcx, inst); | |
| 1322 | } | |
| 1323 | break :blk MCValue{ .register = .rcx }; | |
| 1324 | }, | |
| 1325 | else => return self.fail("TODO move index mcv into a register", .{}), | |
| 1326 | } | |
| 1325 | const offset_reg = blk: { | |
| 1326 | const index_ty = self.air.typeOf(bin_op.rhs); | |
| 1327 | const index_mcv = try self.resolveInst(bin_op.rhs); | |
| 1328 | const offset_reg = try self.register_manager.allocReg(null, &.{}); | |
| 1329 | try self.genSetReg(index_ty, offset_reg, index_mcv); | |
| 1330 | try self.genIMulOpMir(index_ty, .{ .register = offset_reg }, .{ .immediate = elem_size }); | |
| 1331 | break :blk offset_reg; | |
| 1327 | 1332 | }; |
| 1328 | 1333 | |
| 1329 | try self.genIMulOpMir(index_ty, index_mcv, .{ .immediate = elem_size }); | |
| 1330 | ||
| 1331 | 1334 | const dst_mcv = blk: { |
| 1332 | 1335 | switch (slice_mcv) { |
| 1333 | .stack_offset => |unadjusted_off| { | |
| 1336 | .stack_offset => |off| { | |
| 1334 | 1337 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1335 | const addr_reg = try self.register_manager.allocReg(null, &.{index_mcv.register}); | |
| 1336 | const slice_ptr_abi_size = @intCast(u32, slice_ptr_field_type.abiSize(self.target.*)); | |
| 1337 | const off = unadjusted_off + elem_size; | |
| 1338 | // lea reg, [rbp - 8 + rcx*1] | |
| 1338 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); | |
| 1339 | // mov reg, [rbp - 8] | |
| 1339 | 1340 | _ = try self.addInst(.{ |
| 1340 | .tag = .lea, | |
| 1341 | .tag = .mov, | |
| 1341 | 1342 | .ops = (Mir.Ops{ |
| 1342 | .reg1 = registerAlias(addr_reg, slice_ptr_abi_size), | |
| 1343 | .reg1 = addr_reg.to64(), | |
| 1343 | 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 | 1355 | }).encode(), |
| 1346 | .data = .{ .imm = -@intCast(i32, off) }, | |
| 1356 | .data = undefined, | |
| 1347 | 1357 | }); |
| 1348 | 1358 | try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type); |
| 1349 | 1359 | break :blk dst_mcv; |
| ... | ... | @@ -1471,6 +1481,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind |
| 1471 | 1481 | |
| 1472 | 1482 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 1473 | 1483 | const elem_ty = ptr_ty.elemType(); |
| 1484 | const abi_size = elem_ty.abiSize(self.target.*); | |
| 1474 | 1485 | switch (ptr) { |
| 1475 | 1486 | .none => unreachable, |
| 1476 | 1487 | .undef => unreachable, |
| ... | ... | @@ -1478,7 +1489,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1478 | 1489 | .dead => unreachable, |
| 1479 | 1490 | .compare_flags_unsigned => unreachable, |
| 1480 | 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 | 1495 | .ptr_stack_offset => |off| { |
| 1483 | 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 | 1501 | .embedded_in_code => { |
| 1489 | 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 | 1564 | .memory => |addr| { |
| 1493 | 1565 | const reg = try self.copyToTmpRegister(ptr_ty, .{ .memory = addr }); |
| 1494 | 1566 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| ... | ... | @@ -1525,11 +1597,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1525 | 1597 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1526 | 1598 | } |
| 1527 | 1599 | |
| 1528 | fn airStore(self: *Self, inst: Air.Inst.Index) !void { | |
| 1529 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 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); | |
| 1600 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { | |
| 1601 | _ = ptr_ty; | |
| 1533 | 1602 | switch (ptr) { |
| 1534 | 1603 | .none => unreachable, |
| 1535 | 1604 | .undef => unreachable, |
| ... | ... | @@ -1538,19 +1607,58 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1538 | 1607 | .compare_flags_unsigned => unreachable, |
| 1539 | 1608 | .compare_flags_signed => unreachable, |
| 1540 | 1609 | .immediate => |imm| { |
| 1541 | try self.setRegOrMem(elem_ty, .{ .memory = imm }, value); | |
| 1610 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); | |
| 1542 | 1611 | }, |
| 1543 | 1612 | .ptr_stack_offset => |off| { |
| 1544 | try self.genSetStack(elem_ty, off, value); | |
| 1613 | try self.genSetStack(value_ty, off, value); | |
| 1545 | 1614 | }, |
| 1546 | 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 | 1618 | .embedded_in_code => { |
| 1550 | 1619 | return self.fail("TODO implement storing to MCValue.embedded_in_code", .{}); |
| 1551 | 1620 | }, |
| 1552 | 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 | 1663 | .memory => { |
| 1556 | 1664 | return self.fail("TODO implement storing to MCValue.memory", .{}); |
| ... | ... | @@ -1559,6 +1667,15 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1559 | 1667 | return self.fail("TODO implement storing to MCValue.stack_offset", .{}); |
| 1560 | 1668 | }, |
| 1561 | 1669 | } |
| 1670 | } | |
| 1671 | ||
| 1672 | fn 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 | 1679 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1563 | 1680 | } |
| 1564 | 1681 | |
| ... | ... | @@ -1586,9 +1703,8 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 1586 | 1703 | |
| 1587 | 1704 | switch (mcv) { |
| 1588 | 1705 | .ptr_stack_offset => |off| { |
| 1589 | break :result MCValue{ | |
| 1590 | .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size, | |
| 1591 | }; | |
| 1706 | const ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size; | |
| 1707 | break :result MCValue{ .ptr_stack_offset = ptr_stack_offset }; | |
| 1592 | 1708 | }, |
| 1593 | 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 | 1726 | |
| 1611 | 1727 | switch (mcv) { |
| 1612 | 1728 | .stack_offset => |off| { |
| 1613 | break :result MCValue{ | |
| 1614 | .stack_offset = off + struct_size - struct_field_offset - struct_field_size, | |
| 1615 | }; | |
| 1729 | const stack_offset = off + struct_size - struct_field_offset - struct_field_size; | |
| 1730 | break :result MCValue{ .stack_offset = stack_offset }; | |
| 1616 | 1731 | }, |
| 1617 | 1732 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), |
| 1618 | 1733 | } |
| ... | ... | @@ -1785,6 +1900,15 @@ fn genBinMathOpMir( |
| 1785 | 1900 | } |
| 1786 | 1901 | }, |
| 1787 | 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 | 1912 | switch (src_mcv) { |
| 1789 | 1913 | .none => unreachable, |
| 1790 | 1914 | .undef => return self.genSetStack(dst_ty, off, .undef), |
| ... | ... | @@ -1792,11 +1916,6 @@ fn genBinMathOpMir( |
| 1792 | 1916 | .ptr_stack_offset => unreachable, |
| 1793 | 1917 | .ptr_embedded_in_code => unreachable, |
| 1794 | 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 | 1919 | _ = try self.addInst(.{ |
| 1801 | 1920 | .tag = mir_tag, |
| 1802 | 1921 | .ops = (Mir.Ops{ |
| ... | ... | @@ -1808,8 +1927,34 @@ fn genBinMathOpMir( |
| 1808 | 1927 | }); |
| 1809 | 1928 | }, |
| 1810 | 1929 | .immediate => |imm| { |
| 1811 | _ = imm; | |
| 1812 | return self.fail("TODO implement x86 ADD/SUB/CMP source immediate", .{}); | |
| 1930 | const tag: Mir.Inst.Tag = switch (mir_tag) { | |
| 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 | 1959 | .embedded_in_code, .memory, .stack_offset => { |
| 1815 | 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 | 2004 | .immediate => |imm| { |
| 1860 | 2005 | // TODO take into account the type's ABI size when selecting the register alias |
| 1861 | 2006 | // register, immediate |
| 1862 | if (imm <= math.maxInt(i32)) { | |
| 2007 | if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) { | |
| 1863 | 2008 | _ = try self.addInst(.{ |
| 1864 | 2009 | .tag = .imul_complex, |
| 1865 | 2010 | .ops = (Mir.Ops{ |
| ... | ... | @@ -2059,6 +2204,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2059 | 2204 | assert(ty.zigTypeTag() == .Pointer); |
| 2060 | 2205 | const mcv = try self.resolveInst(callee); |
| 2061 | 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 | 2216 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 2064 | 2217 | for (info.args) |mc_arg, arg_i| { |
| ... | ... | @@ -2128,6 +2281,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2128 | 2281 | assert(ty.zigTypeTag() == .Pointer); |
| 2129 | 2282 | const mcv = try self.resolveInst(callee); |
| 2130 | 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 | 2293 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { |
| 2133 | 2294 | for (info.args) |mc_arg, arg_i| { |
| ... | ... | @@ -2180,7 +2341,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2180 | 2341 | }); |
| 2181 | 2342 | } else return self.fail("TODO implement calling extern fn on plan9", .{}); |
| 2182 | 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 | 2356 | } else unreachable; |
| 2186 | 2357 | |
| ... | ... | @@ -3029,8 +3200,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3029 | 3200 | } |
| 3030 | 3201 | return self.fail("TODO implement memcpy for setting stack from {}", .{mcv}); |
| 3031 | 3202 | }, |
| 3032 | .stack_offset => |unadjusted_off| { | |
| 3033 | if (stack_offset == unadjusted_off) { | |
| 3203 | .stack_offset => |off| { | |
| 3204 | if (stack_offset == off) { | |
| 3034 | 3205 | // Copy stack variable to itself; nothing to do. |
| 3035 | 3206 | return; |
| 3036 | 3207 | } |
| ... | ... | @@ -3041,33 +3212,43 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3041 | 3212 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3042 | 3213 | } |
| 3043 | 3214 | |
| 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 | 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); | |
| 3047 | 3222 | |
| 3048 | const off = unadjusted_off + abi_size; | |
| 3049 | 3223 | _ = try self.addInst(.{ |
| 3050 | 3224 | .tag = .lea, |
| 3051 | 3225 | .ops = (Mir.Ops{ |
| 3052 | 3226 | .reg1 = addr_reg.to64(), |
| 3053 | 3227 | .reg2 = .rbp, |
| 3054 | 3228 | }).encode(), |
| 3055 | .data = .{ .imm = -@intCast(i32, off) }, | |
| 3229 | .data = .{ .imm = -@intCast(i32, off + abi_size) }, | |
| 3056 | 3230 | }); |
| 3057 | 3231 | |
| 3058 | 3232 | // TODO allow for abi_size to be u64 |
| 3059 | try self.genSetReg(Type.initTag(.u32), len_reg, .{ .immediate = @intCast(u32, abi_size) }); | |
| 3060 | ||
| 3061 | return self.genInlineMemcpy(-@intCast(i32, off), addr_reg.to64(), len_reg.to64()); | |
| 3233 | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); | |
| 3234 | ||
| 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 | } |
| 3065 | 3244 | |
| 3066 | fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: Register) InnerError!void { | |
| 3067 | try self.register_manager.getReg(.rax, null); | |
| 3068 | try self.register_manager.getReg(.rcx, null); | |
| 3069 | const tmp_reg = try self.register_manager.allocReg(null, &.{ addr_reg, len_reg, .rax, .rcx }); | |
| 3070 | ||
| 3245 | fn genInlineMemcpy( | |
| 3246 | self: *Self, | |
| 3247 | stack_offset: i32, | |
| 3248 | addr_reg: Register, | |
| 3249 | count_reg: Register, | |
| 3250 | tmp_reg: Register, | |
| 3251 | ) InnerError!void { | |
| 3071 | 3252 | // mov rcx, 0 |
| 3072 | 3253 | _ = try self.addInst(.{ |
| 3073 | 3254 | .tag = .mov, |
| ... | ... | @@ -3087,20 +3268,19 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: |
| 3087 | 3268 | }); |
| 3088 | 3269 | |
| 3089 | 3270 | // loop: |
| 3090 | // cmp rcx, len | |
| 3271 | // cmp count, 0 | |
| 3091 | 3272 | const loop_start = try self.addInst(.{ |
| 3092 | 3273 | .tag = .cmp, |
| 3093 | 3274 | .ops = (Mir.Ops{ |
| 3094 | .reg1 = .rcx, | |
| 3095 | .reg2 = len_reg, | |
| 3275 | .reg1 = count_reg, | |
| 3096 | 3276 | }).encode(), |
| 3097 | .data = undefined, | |
| 3277 | .data = .{ .imm = 0 }, | |
| 3098 | 3278 | }); |
| 3099 | 3279 | |
| 3100 | // jge end | |
| 3280 | // je end | |
| 3101 | 3281 | const loop_reloc = try self.addInst(.{ |
| 3102 | .tag = .cond_jmp_above_below, | |
| 3103 | .ops = (Mir.Ops{ .flags = 0b00 }).encode(), | |
| 3282 | .tag = .cond_jmp_eq_ne, | |
| 3283 | .ops = (Mir.Ops{ .flags = 0b01 }).encode(), | |
| 3104 | 3284 | .data = .{ .inst = undefined }, |
| 3105 | 3285 | }); |
| 3106 | 3286 | |
| ... | ... | @@ -3142,6 +3322,15 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: |
| 3142 | 3322 | .data = .{ .imm = 1 }, |
| 3143 | 3323 | }); |
| 3144 | 3324 | |
| 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 | 3334 | // jmp loop |
| 3146 | 3335 | _ = try self.addInst(.{ |
| 3147 | 3336 | .tag = .jmp, |
| ... | ... | @@ -3153,47 +3342,6 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: |
| 3153 | 3342 | try self.performReloc(loop_reloc); |
| 3154 | 3343 | } |
| 3155 | 3344 | |
| 3156 | /// Set pointee via pointer stored in a register. | |
| 3157 | /// mov [reg], value | |
| 3158 | fn 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 | ||
| 3197 | 3345 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 3198 | 3346 | switch (mcv) { |
| 3199 | 3347 | .dead => unreachable, |
| ... | ... | @@ -3616,7 +3764,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3616 | 3764 | if (typed_value.val.tag() == .int_u64) { |
| 3617 | 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 | 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 | 265 | |
| 266 | 266 | fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 267 | 267 | const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]); |
| 268 | const flag = @truncate(u1, ops.flags); | |
| 269 | if (flag == 0) { | |
| 270 | const target = isel.mir.instructions.items(.data)[inst].inst; | |
| 271 | const source = isel.code.items.len; | |
| 272 | lowerToDEnc(tag, 0, isel.code) catch |err| | |
| 273 | return isel.failWithLoweringError(err); | |
| 274 | try isel.relocs.append(isel.bin_file.allocator, .{ | |
| 275 | .source = source, | |
| 276 | .target = target, | |
| 277 | .offset = isel.code.items.len - 4, | |
| 278 | .length = 5, | |
| 279 | }); | |
| 280 | return; | |
| 281 | } | |
| 282 | if (ops.reg1 == .none) { | |
| 283 | // JMP/CALL [imm] | |
| 284 | const imm = isel.mir.instructions.items(.data)[inst].imm; | |
| 285 | const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) { | |
| 286 | 16 => .word_ptr, | |
| 287 | else => .qword_ptr, | |
| 288 | }; | |
| 289 | return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err| | |
| 290 | isel.failWithLoweringError(err); | |
| 268 | switch (ops.flags) { | |
| 269 | 0b00 => { | |
| 270 | const target = isel.mir.instructions.items(.data)[inst].inst; | |
| 271 | const source = isel.code.items.len; | |
| 272 | lowerToDEnc(tag, 0, isel.code) catch |err| | |
| 273 | return isel.failWithLoweringError(err); | |
| 274 | try isel.relocs.append(isel.bin_file.allocator, .{ | |
| 275 | .source = source, | |
| 276 | .target = target, | |
| 277 | .offset = isel.code.items.len - 4, | |
| 278 | .length = 5, | |
| 279 | }); | |
| 280 | }, | |
| 281 | 0b01 => { | |
| 282 | if (ops.reg1 == .none) { | |
| 283 | // JMP/CALL [imm] | |
| 284 | const imm = isel.mir.instructions.items(.data)[inst].imm; | |
| 285 | const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) { | |
| 286 | 16 => .word_ptr, | |
| 287 | else => .qword_ptr, | |
| 288 | }; | |
| 289 | return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |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 | } |
| 295 | 306 | |
| 296 | 307 | fn 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 | 504 | const scale = ops.flags; |
| 494 | 505 | const imm = isel.mir.instructions.items(.data)[inst].imm; |
| 495 | 506 | // OP reg1, [reg2 + scale*rcx + imm32] |
| 507 | const scale_index = ScaleIndex{ | |
| 508 | .scale = scale, | |
| 509 | .index = .rcx, | |
| 510 | }; | |
| 496 | 511 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ |
| 497 | 512 | .disp = imm, |
| 498 | 513 | .base = ops.reg2, |
| 499 | .scale_index = .{ | |
| 500 | .scale = scale, | |
| 501 | .index = .rcx, | |
| 502 | }, | |
| 514 | .scale_index = scale_index, | |
| 503 | 515 | }), isel.code) catch |err| isel.failWithLoweringError(err); |
| 504 | 516 | } |
| 505 | 517 | |
| ... | ... | @@ -507,25 +519,23 @@ fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 507 | 519 | const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]); |
| 508 | 520 | const scale = ops.flags; |
| 509 | 521 | const imm = isel.mir.instructions.items(.data)[inst].imm; |
| 522 | const scale_index = ScaleIndex{ | |
| 523 | .scale = scale, | |
| 524 | .index = .rax, | |
| 525 | }; | |
| 510 | 526 | if (ops.reg2 == .none) { |
| 511 | 527 | // OP qword ptr [reg1 + scale*rax + 0], imm32 |
| 512 | 528 | return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{ |
| 513 | 529 | .disp = 0, |
| 514 | 530 | .base = ops.reg1, |
| 515 | .scale_index = .{ | |
| 516 | .scale = scale, | |
| 517 | .index = .rax, | |
| 518 | }, | |
| 531 | .scale_index = scale_index, | |
| 519 | 532 | }), imm, isel.code) catch |err| isel.failWithLoweringError(err); |
| 520 | 533 | } |
| 521 | 534 | // OP [reg1 + scale*rax + imm32], reg2 |
| 522 | 535 | return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{ |
| 523 | 536 | .disp = imm, |
| 524 | 537 | .base = ops.reg1, |
| 525 | .scale_index = .{ | |
| 526 | .scale = scale, | |
| 527 | .index = .rax, | |
| 528 | }, | |
| 538 | .scale_index = scale_index, | |
| 529 | 539 | }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err); |
| 530 | 540 | } |
| 531 | 541 | |
| ... | ... | @@ -534,14 +544,15 @@ fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 534 | 544 | const scale = ops.flags; |
| 535 | 545 | const payload = isel.mir.instructions.items(.data)[inst].payload; |
| 536 | 546 | const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data; |
| 547 | const scale_index = ScaleIndex{ | |
| 548 | .scale = scale, | |
| 549 | .index = .rax, | |
| 550 | }; | |
| 537 | 551 | // OP qword ptr [reg1 + scale*rax + imm32], imm32 |
| 538 | 552 | return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{ |
| 539 | 553 | .disp = imm_pair.dest_off, |
| 540 | 554 | .base = ops.reg1, |
| 541 | .scale_index = .{ | |
| 542 | .scale = scale, | |
| 543 | .index = .rax, | |
| 544 | }, | |
| 555 | .scale_index = scale_index, | |
| 545 | 556 | }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err); |
| 546 | 557 | } |
| 547 | 558 | |
| ... | ... | @@ -658,16 +669,17 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void { |
| 658 | 669 | // lea reg, [rbp + rcx + imm32] |
| 659 | 670 | const imm = isel.mir.instructions.items(.data)[inst].imm; |
| 660 | 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 | 676 | return lowerToRmEnc( |
| 662 | 677 | .lea, |
| 663 | 678 | ops.reg1, |
| 664 | 679 | RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ |
| 665 | 680 | .disp = imm, |
| 666 | 681 | .base = src_reg, |
| 667 | .scale_index = .{ | |
| 668 | .scale = 0, | |
| 669 | .index = .rcx, | |
| 670 | }, | |
| 682 | .scale_index = scale_index, | |
| 671 | 683 | }), |
| 672 | 684 | isel.code, |
| 673 | 685 | ) catch |err| isel.failWithLoweringError(err); |
| ... | ... | @@ -1248,7 +1260,7 @@ const Memory = struct { |
| 1248 | 1260 | const dst = base.lowId(); |
| 1249 | 1261 | const src = operand; |
| 1250 | 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 | 1264 | encoder.modRm_SIBDisp0(src); |
| 1253 | 1265 | if (mem_op.scale_index) |si| { |
| 1254 | 1266 | encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst); |
| ... | ... | @@ -1907,6 +1919,24 @@ test "lower RM encoding" { |
| 1907 | 1919 | }, |
| 1908 | 1920 | }), isel.code()); |
| 1909 | 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 | } |
| 1911 | 1941 | |
| 1912 | 1942 | test "lower MR encoding" { |
src/arch/x86_64/Mir.zig+5-6| ... | ... | @@ -199,12 +199,11 @@ pub const Inst = struct { |
| 199 | 199 | /// TODO handle scaling |
| 200 | 200 | movabs, |
| 201 | 201 | |
| 202 | /// ops flags: 0bX0: | |
| 203 | /// - Uses the `inst` Data tag as the jump target. | |
| 204 | /// - reg1 and reg2 are ignored. | |
| 205 | /// ops flags: 0bX1: | |
| 206 | /// - reg1 is the jump target, reg2 and data are ignored. | |
| 207 | /// - if reg1 is none, [imm] | |
| 202 | /// ops flags: form: | |
| 203 | /// 0b00 inst | |
| 204 | /// 0b01 reg1 | |
| 205 | /// 0b01 [imm32] if reg1 is none | |
| 206 | /// 0b10 [reg1 + imm32] | |
| 208 | 207 | jmp, |
| 209 | 208 | call, |
| 210 | 209 |
test/behavior.zig+195-199| ... | ... | @@ -4,211 +4,207 @@ test { |
| 4 | 4 | // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend. |
| 5 | 5 | _ = @import("behavior/bugs/1111.zig"); |
| 6 | 6 | _ = @import("behavior/bugs/2346.zig"); |
| 7 | _ = @import("behavior/bugs/3586.zig"); | |
| 8 | 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"); | |
| 9 | 16 | |
| 10 | if (builtin.zig_backend != .stage2_x86_64) { | |
| 11 | // Tests that pass for stage1, llvm backend, C backend, wasm backend, and arm backend. | |
| 12 | _ = @import("behavior/bugs/679.zig"); | |
| 13 | _ = @import("behavior/bugs/6850.zig"); | |
| 14 | _ = @import("behavior/fn_in_struct_in_comptime.zig"); | |
| 15 | _ = @import("behavior/hasfield.zig"); | |
| 16 | _ = @import("behavior/hasdecl.zig"); | |
| 17 | _ = @import("behavior/pub_enum.zig"); | |
| 18 | _ = @import("behavior/type_info.zig"); | |
| 19 | _ = @import("behavior/type.zig"); | |
| 17 | if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) { | |
| 18 | // Tests that pass for stage1, llvm backend, C backend, wasm backend. | |
| 19 | _ = @import("behavior/bugs/3586.zig"); | |
| 20 | _ = @import("behavior/basic.zig"); | |
| 21 | _ = @import("behavior/bitcast.zig"); | |
| 22 | _ = @import("behavior/bool.zig"); | |
| 23 | _ = @import("behavior/bugs/624.zig"); | |
| 24 | _ = @import("behavior/bugs/655.zig"); | |
| 25 | _ = @import("behavior/bugs/704.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"); | |
| 20 | 55 | |
| 21 | if (builtin.zig_backend != .stage2_arm) { | |
| 22 | // Tests that pass for stage1, llvm backend, C backend, wasm backend. | |
| 23 | _ = @import("behavior/basic.zig"); | |
| 24 | _ = @import("behavior/bitcast.zig"); | |
| 25 | _ = @import("behavior/bool.zig"); | |
| 26 | _ = @import("behavior/bugs/624.zig"); | |
| 27 | _ = @import("behavior/bugs/655.zig"); | |
| 28 | _ = @import("behavior/bugs/704.zig"); | |
| 29 | _ = @import("behavior/bugs/1486.zig"); | |
| 30 | _ = @import("behavior/bugs/2692.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"); | |
| 56 | if (builtin.zig_backend != .stage2_wasm) { | |
| 57 | // Tests that pass for stage1, llvm backend, C backend | |
| 58 | _ = @import("behavior/align.zig"); | |
| 59 | _ = @import("behavior/array.zig"); | |
| 60 | _ = @import("behavior/bugs/4560.zig"); | |
| 61 | _ = @import("behavior/cast.zig"); | |
| 62 | _ = @import("behavior/for.zig"); | |
| 63 | _ = @import("behavior/int128.zig"); | |
| 64 | _ = @import("behavior/optional.zig"); | |
| 65 | _ = @import("behavior/translate_c_macros.zig"); | |
| 58 | 66 | |
| 59 | if (builtin.zig_backend != .stage2_wasm) { | |
| 60 | // Tests that pass for stage1, llvm backend, C backend | |
| 61 | _ = @import("behavior/align.zig"); | |
| 62 | _ = @import("behavior/array.zig"); | |
| 63 | _ = @import("behavior/bugs/4560.zig"); | |
| 64 | _ = @import("behavior/cast.zig"); | |
| 65 | _ = @import("behavior/for.zig"); | |
| 66 | _ = @import("behavior/int128.zig"); | |
| 67 | _ = @import("behavior/optional.zig"); | |
| 68 | _ = @import("behavior/translate_c_macros.zig"); | |
| 67 | if (builtin.zig_backend != .stage2_c) { | |
| 68 | // Tests that pass for stage1 and the llvm backend. | |
| 69 | _ = @import("behavior/align_llvm.zig"); | |
| 70 | _ = @import("behavior/alignof.zig"); | |
| 71 | _ = @import("behavior/array_llvm.zig"); | |
| 72 | _ = @import("behavior/atomics.zig"); | |
| 73 | _ = @import("behavior/basic_llvm.zig"); | |
| 74 | _ = @import("behavior/bugs/394.zig"); | |
| 75 | _ = @import("behavior/bugs/656.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"); | |
| 69 | 108 | |
| 70 | if (builtin.zig_backend != .stage2_c) { | |
| 71 | // Tests that pass for stage1 and the llvm backend. | |
| 72 | _ = @import("behavior/align_llvm.zig"); | |
| 73 | _ = @import("behavior/alignof.zig"); | |
| 74 | _ = @import("behavior/array_llvm.zig"); | |
| 75 | _ = @import("behavior/atomics.zig"); | |
| 76 | _ = @import("behavior/basic_llvm.zig"); | |
| 77 | _ = @import("behavior/bugs/394.zig"); | |
| 78 | _ = @import("behavior/bugs/656.zig"); | |
| 79 | _ = @import("behavior/bugs/1277.zig"); | |
| 80 | _ = @import("behavior/bugs/1310.zig"); | |
| 81 | _ = @import("behavior/bugs/1381.zig"); | |
| 82 | _ = @import("behavior/bugs/1500.zig"); | |
| 83 | _ = @import("behavior/bugs/1741.zig"); | |
| 84 | _ = @import("behavior/bugs/2006.zig"); | |
| 85 | _ = @import("behavior/bugs/2578.zig"); | |
| 86 | _ = @import("behavior/bugs/3007.zig"); | |
| 87 | _ = @import("behavior/bugs/3112.zig"); | |
| 88 | _ = @import("behavior/bugs/3367.zig"); | |
| 89 | _ = @import("behavior/bugs/7250.zig"); | |
| 90 | _ = @import("behavior/bugs/9584.zig"); | |
| 91 | _ = @import("behavior/cast_llvm.zig"); | |
| 92 | _ = @import("behavior/enum_llvm.zig"); | |
| 93 | _ = @import("behavior/eval.zig"); | |
| 94 | _ = @import("behavior/floatop.zig"); | |
| 95 | _ = @import("behavior/fn.zig"); | |
| 96 | _ = @import("behavior/generics_llvm.zig"); | |
| 97 | _ = @import("behavior/math.zig"); | |
| 98 | _ = @import("behavior/maximum_minimum.zig"); | |
| 99 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); | |
| 100 | _ = @import("behavior/null_llvm.zig"); | |
| 101 | _ = @import("behavior/optional_llvm.zig"); | |
| 102 | _ = @import("behavior/popcount.zig"); | |
| 103 | _ = @import("behavior/saturating_arithmetic.zig"); | |
| 104 | _ = @import("behavior/sizeof_and_typeof.zig"); | |
| 105 | _ = @import("behavior/slice.zig"); | |
| 106 | _ = @import("behavior/struct_llvm.zig"); | |
| 107 | _ = @import("behavior/switch.zig"); | |
| 108 | _ = @import("behavior/undefined.zig"); | |
| 109 | _ = @import("behavior/union.zig"); | |
| 110 | _ = @import("behavior/widening.zig"); | |
| 111 | ||
| 112 | if (builtin.zig_backend != .stage1) { | |
| 113 | // When all comptime_memory.zig tests pass, #9646 can be closed. | |
| 114 | // _ = @import("behavior/comptime_memory.zig"); | |
| 115 | _ = @import("behavior/slice_stage2.zig"); | |
| 116 | } else { | |
| 117 | // Tests that only pass for the stage1 backend. | |
| 118 | _ = @import("behavior/align_stage1.zig"); | |
| 119 | _ = @import("behavior/array_stage1.zig"); | |
| 120 | if (builtin.os.tag != .wasi) { | |
| 121 | _ = @import("behavior/asm.zig"); | |
| 122 | _ = @import("behavior/async_fn.zig"); | |
| 123 | } | |
| 124 | _ = @import("behavior/await_struct.zig"); | |
| 125 | _ = @import("behavior/bit_shifting.zig"); | |
| 126 | _ = @import("behavior/bitcast_stage1.zig"); | |
| 127 | _ = @import("behavior/bitreverse.zig"); | |
| 128 | _ = @import("behavior/bugs/421.zig"); | |
| 129 | _ = @import("behavior/bugs/529.zig"); | |
| 130 | _ = @import("behavior/bugs/718.zig"); | |
| 131 | _ = @import("behavior/bugs/726.zig"); | |
| 132 | _ = @import("behavior/bugs/828.zig"); | |
| 133 | _ = @import("behavior/bugs/920.zig"); | |
| 134 | _ = @import("behavior/bugs/1025.zig"); | |
| 135 | _ = @import("behavior/bugs/1076.zig"); | |
| 136 | _ = @import("behavior/bugs/1120.zig"); | |
| 137 | _ = @import("behavior/bugs/1421.zig"); | |
| 138 | _ = @import("behavior/bugs/1442.zig"); | |
| 139 | _ = @import("behavior/bugs/1607.zig"); | |
| 140 | _ = @import("behavior/bugs/1735.zig"); | |
| 141 | _ = @import("behavior/bugs/1851.zig"); | |
| 142 | _ = @import("behavior/bugs/1914.zig"); | |
| 143 | _ = @import("behavior/bugs/2114.zig"); | |
| 144 | _ = @import("behavior/bugs/3384.zig"); | |
| 145 | _ = @import("behavior/bugs/3742.zig"); | |
| 146 | _ = @import("behavior/bugs/3779.zig"); | |
| 147 | _ = @import("behavior/bugs/4328.zig"); | |
| 148 | _ = @import("behavior/bugs/5398.zig"); | |
| 149 | _ = @import("behavior/bugs/5413.zig"); | |
| 150 | _ = @import("behavior/bugs/5474.zig"); | |
| 151 | _ = @import("behavior/bugs/5487.zig"); | |
| 152 | _ = @import("behavior/bugs/6456.zig"); | |
| 153 | _ = @import("behavior/bugs/6781.zig"); | |
| 154 | _ = @import("behavior/bugs/7003.zig"); | |
| 155 | _ = @import("behavior/bugs/7027.zig"); | |
| 156 | _ = @import("behavior/bugs/7047.zig"); | |
| 157 | _ = @import("behavior/bugs/10147.zig"); | |
| 158 | _ = @import("behavior/byteswap.zig"); | |
| 159 | _ = @import("behavior/call_stage1.zig"); | |
| 160 | _ = @import("behavior/cast_stage1.zig"); | |
| 161 | _ = @import("behavior/const_slice_child.zig"); | |
| 162 | _ = @import("behavior/defer_stage1.zig"); | |
| 163 | _ = @import("behavior/enum_stage1.zig"); | |
| 164 | _ = @import("behavior/error_stage1.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"); | |
| 109 | if (builtin.zig_backend != .stage1) { | |
| 110 | // When all comptime_memory.zig tests pass, #9646 can be closed. | |
| 111 | // _ = @import("behavior/comptime_memory.zig"); | |
| 112 | _ = @import("behavior/slice_stage2.zig"); | |
| 113 | } else { | |
| 114 | // Tests that only pass for the stage1 backend. | |
| 115 | _ = @import("behavior/align_stage1.zig"); | |
| 116 | _ = @import("behavior/array_stage1.zig"); | |
| 117 | if (builtin.os.tag != .wasi) { | |
| 118 | _ = @import("behavior/asm.zig"); | |
| 119 | _ = @import("behavior/async_fn.zig"); | |
| 120 | } | |
| 121 | _ = @import("behavior/await_struct.zig"); | |
| 122 | _ = @import("behavior/bit_shifting.zig"); | |
| 123 | _ = @import("behavior/bitcast_stage1.zig"); | |
| 124 | _ = @import("behavior/bitreverse.zig"); | |
| 125 | _ = @import("behavior/bugs/421.zig"); | |
| 126 | _ = @import("behavior/bugs/529.zig"); | |
| 127 | _ = @import("behavior/bugs/718.zig"); | |
| 128 | _ = @import("behavior/bugs/726.zig"); | |
| 129 | _ = @import("behavior/bugs/828.zig"); | |
| 130 | _ = @import("behavior/bugs/920.zig"); | |
| 131 | _ = @import("behavior/bugs/1025.zig"); | |
| 132 | _ = @import("behavior/bugs/1076.zig"); | |
| 133 | _ = @import("behavior/bugs/1120.zig"); | |
| 134 | _ = @import("behavior/bugs/1421.zig"); | |
| 135 | _ = @import("behavior/bugs/1442.zig"); | |
| 136 | _ = @import("behavior/bugs/1607.zig"); | |
| 137 | _ = @import("behavior/bugs/1735.zig"); | |
| 138 | _ = @import("behavior/bugs/1851.zig"); | |
| 139 | _ = @import("behavior/bugs/1914.zig"); | |
| 140 | _ = @import("behavior/bugs/2114.zig"); | |
| 141 | _ = @import("behavior/bugs/3384.zig"); | |
| 142 | _ = @import("behavior/bugs/3742.zig"); | |
| 143 | _ = @import("behavior/bugs/3779.zig"); | |
| 144 | _ = @import("behavior/bugs/4328.zig"); | |
| 145 | _ = @import("behavior/bugs/5398.zig"); | |
| 146 | _ = @import("behavior/bugs/5413.zig"); | |
| 147 | _ = @import("behavior/bugs/5474.zig"); | |
| 148 | _ = @import("behavior/bugs/5487.zig"); | |
| 149 | _ = @import("behavior/bugs/6456.zig"); | |
| 150 | _ = @import("behavior/bugs/6781.zig"); | |
| 151 | _ = @import("behavior/bugs/7003.zig"); | |
| 152 | _ = @import("behavior/bugs/7027.zig"); | |
| 153 | _ = @import("behavior/bugs/7047.zig"); | |
| 154 | _ = @import("behavior/bugs/10147.zig"); | |
| 155 | _ = @import("behavior/byteswap.zig"); | |
| 156 | _ = @import("behavior/call_stage1.zig"); | |
| 157 | _ = @import("behavior/cast_stage1.zig"); | |
| 158 | _ = @import("behavior/const_slice_child.zig"); | |
| 159 | _ = @import("behavior/defer_stage1.zig"); | |
| 160 | _ = @import("behavior/enum_stage1.zig"); | |
| 161 | _ = @import("behavior/error_stage1.zig"); | |
| 162 | _ = @import("behavior/eval_stage1.zig"); | |
| 163 | _ = @import("behavior/field_parent_ptr.zig"); | |
| 164 | _ = @import("behavior/floatop_stage1.zig"); | |
| 165 | _ = @import("behavior/fn_stage1.zig"); | |
| 166 | _ = @import("behavior/fn_delegation.zig"); | |
| 167 | _ = @import("behavior/for_stage1.zig"); | |
| 168 | _ = @import("behavior/if_stage1.zig"); | |
| 169 | _ = @import("behavior/ir_block_deps.zig"); | |
| 170 | _ = @import("behavior/math_stage1.zig"); | |
| 171 | _ = @import("behavior/merge_error_sets.zig"); | |
| 172 | _ = @import("behavior/misc.zig"); | |
| 173 | _ = @import("behavior/muladd.zig"); | |
| 174 | _ = @import("behavior/null_stage1.zig"); | |
| 175 | _ = @import("behavior/optional_stage1.zig"); | |
| 176 | _ = @import("behavior/pointers_stage1.zig"); | |
| 177 | _ = @import("behavior/popcount_stage1.zig"); | |
| 178 | _ = @import("behavior/prefetch.zig"); | |
| 179 | _ = @import("behavior/ptrcast_stage1.zig"); | |
| 180 | _ = @import("behavior/reflection.zig"); | |
| 181 | _ = @import("behavior/saturating_arithmetic_stage1.zig"); | |
| 182 | _ = @import("behavior/select.zig"); | |
| 183 | _ = @import("behavior/shuffle.zig"); | |
| 184 | _ = @import("behavior/sizeof_and_typeof_stage1.zig"); | |
| 185 | _ = @import("behavior/slice_stage1.zig"); | |
| 186 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); | |
| 187 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); | |
| 188 | _ = @import("behavior/struct_stage1.zig"); | |
| 189 | _ = @import("behavior/switch_prong_err_enum.zig"); | |
| 190 | _ = @import("behavior/switch_prong_implicit_cast.zig"); | |
| 191 | _ = @import("behavior/switch_stage1.zig"); | |
| 192 | _ = @import("behavior/truncate_stage1.zig"); | |
| 193 | _ = @import("behavior/try.zig"); | |
| 194 | _ = @import("behavior/tuple.zig"); | |
| 195 | _ = @import("behavior/type_stage1.zig"); | |
| 196 | _ = @import("behavior/type_info_stage1.zig"); | |
| 197 | _ = @import("behavior/typename.zig"); | |
| 198 | _ = @import("behavior/union_stage1.zig"); | |
| 199 | _ = @import("behavior/union_with_members.zig"); | |
| 200 | _ = @import("behavior/var_args.zig"); | |
| 201 | _ = @import("behavior/vector.zig"); | |
| 202 | if (builtin.target.cpu.arch == .wasm32) { | |
| 203 | _ = @import("behavior/wasm.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 | 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 | } |
| 2018 | 2038 | |
| 2019 | 2039 | fn addMacOsTestCases(ctx: *TestContext) !void { |