| 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,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!T | 1246 | /// E to E!T |
| 1254 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | 1247 | fn 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 | .dead | 1250 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 1258 | else | 1251 | 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 | } |
| 1262 | 1259 | ||
| 1263 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | 1260 | fn 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 | .dead | 1263 | const operand = try self.resolveInst(ty_op.operand); |
| 1267 | else | 1264 | 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 | } |
| 1271 | 1276 | ||
| ... | @@ -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); |
| 1315 | 1324 | ||
| 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 | }; |
| 1328 | 1333 | ||
| 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 |
| 1471 | 1481 | ||
| 1472 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { | 1482 | fn 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 | } |
| 1527 | 1599 | ||
| 1528 | fn airStore(self: *Self, inst: Air.Inst.Index) !void { | 1600 | fn 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 | |||
| 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 | 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 | } |
| 1564 | 1681 | ||
| ... | @@ -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 |
| 1586 | 1703 | ||
| 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 { |
| 1610 | 1726 | ||
| 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 alias | 2005 | // TODO take into account the type's ABI size when selecting the register alias |
| 1861 | // register, immediate | 2006 | // 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; |
| 2186 | 2357 | ||
| ... | @@ -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 | } |
| 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 | 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); | ||
| 3047 | 3222 | ||
| 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 | }); |
| 3057 | 3231 | ||
| 3058 | // TODO allow for abi_size to be u64 | 3232 | // 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) }); |
| 3060 | 3234 | ||
| 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 | } |
| 3065 | 3244 | ||
| 3066 | fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: Register) InnerError!void { | 3245 | fn 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, |
| 3070 | 3249 | count_reg: Register, | |
| 3250 | tmp_reg: Register, | ||
| 3251 | ) InnerError!void { | ||
| 3071 | // mov rcx, 0 | 3252 | // 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 | }); |
| 3088 | 3269 | ||
| 3089 | // loop: | 3270 | // loop: |
| 3090 | // cmp rcx, len | 3271 | // 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 | }); |
| 3099 | 3279 | ||
| 3100 | // jge end | 3280 | // 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 | }); |
| 3106 | 3286 | ||
| ... | @@ -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 | }); |
| 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 | // jmp loop | 3334 | // 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 | } |
| 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 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { | 3345 | fn 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 |
| 265 | 265 | ||
| 266 | fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 266 | fn 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 | } |
| 295 | 306 | ||
| 296 | fn mirCondJmp(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { | 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,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 | } |
| 505 | 517 | ||
| ... | @@ -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], imm32 | 527 | // 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], reg2 | 534 | // 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 | } |
| 531 | 541 | ||
| ... | @@ -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], imm32 | 551 | // 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 | } |
| 547 | 558 | ||
| ... | @@ -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 | } |
| 1911 | 1941 | ||
| 1912 | test "lower MR encoding" { | 1942 | test "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 scaling | 199 | /// TODO handle scaling |
| 200 | movabs, | 200 | movabs, |
| 201 | 201 | ||
| 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, |
| 210 | 209 |
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"); | ||
| 9 | 16 | ||
| 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"); | ||
| 20 | 55 | ||
| 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"); | ||
| 58 | 66 | ||
| 59 | if (builtin.zig_backend != .stage2_wasm) { | 67 | if (builtin.zig_backend != .stage2_c) { |
| 60 | // Tests that pass for stage1, llvm backend, C backend | 68 | // 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"); | ||
| 69 | 108 | ||
| 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"); |
| 111 | 150 | _ = @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 | } |
| 2018 | 2038 | ||
| 2019 | fn addMacOsTestCases(ctx: *TestContext) !void { | 2039 | fn addMacOsTestCases(ctx: *TestContext) !void { |