authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-04 01:53:02-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-04 01:53:02-05:00
log76fd6fc36505a203fba77e2103db12be59514532
tree43e1ee8b8f5d933fabc06fa32c846dd9c26a4983
parent4e38b3ed9ba6969e5b6c9e65125a5dbd49726a0b
parenta8ff51b0920fdc7edcaca332dd2c9fab6f497ca9
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

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

stage2: enable "zig test" on x86_64

5 files changed, 850 insertions(+), 663 deletions(-)

src/arch/x86_64/CodeGen.zig+333-91
...@@ -415,9 +415,14 @@ fn gen(self: *Self) InnerError!void {...@@ -415,9 +415,14 @@ fn gen(self: *Self) InnerError!void {
415415
416 try self.genBody(self.air.getMainBody());416 try self.genBody(self.air.getMainBody());
417417
418 if (self.exitlude_jump_relocs.items.len == 1) {418 // TODO can single exitlude jump reloc be elided? What if it is not at the end of the code?
419 self.mir_instructions.len -= 1;419 // Example:
420 } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {420 // pub fn main() void {
421 // maybeErr() catch return;
422 // unreachable;
423 // }
424 // Eliding the reloc will cause a miscompilation in this case.
425 for (self.exitlude_jump_relocs.items) |jmp_reloc| {
421 self.mir_instructions.items(.data)[jmp_reloc].inst = @intCast(u32, self.mir_instructions.len);426 self.mir_instructions.items(.data)[jmp_reloc].inst = @intCast(u32, self.mir_instructions.len);
422 }427 }
423428
...@@ -1180,19 +1185,24 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -1180,19 +1185,24 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
11801185
1181fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {1186fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1182 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1187 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1183 const result: MCValue = if (self.liveness.isUnused(inst))1188 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1184 .dead1189 const err_union_ty = self.air.typeOf(ty_op.operand);
1185 else1190 const payload_ty = err_union_ty.errorUnionPayload();
1186 return self.fail("TODO implement unwrap error union error for {}", .{self.target.cpu.arch});1191 const mcv = try self.resolveInst(ty_op.operand);
1192 if (!payload_ty.hasCodeGenBits()) break :result mcv;
1193 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1194 };
1187 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1195 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1188}1196}
11891197
1190fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {1198fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1191 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1199 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1192 const result: MCValue = if (self.liveness.isUnused(inst))1200 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1193 .dead1201 const err_union_ty = self.air.typeOf(ty_op.operand);
1194 else1202 const payload_ty = err_union_ty.errorUnionPayload();
1195 return self.fail("TODO implement unwrap error union payload for {}", .{self.target.cpu.arch});1203 if (!payload_ty.hasCodeGenBits()) break :result MCValue.none;
1204 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1205 };
1196 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1206 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1197}1207}
11981208
...@@ -1261,10 +1271,14 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1261,10 +1271,14 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
12611271
1262fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {1272fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1263 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1273 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1264 const result: MCValue = if (self.liveness.isUnused(inst))1274 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1265 .dead1275 const operand = try self.resolveInst(ty_op.operand);
1266 else1276 const dst_mcv: MCValue = switch (operand) {
1267 return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch});1277 .stack_offset => |off| MCValue{ .stack_offset = off + 8 },
1278 else => return self.fail("TODO implement slice_len for {}", .{operand}),
1279 };
1280 break :result dst_mcv;
1281 };
1268 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1282 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1269}1283}
12701284
...@@ -1289,10 +1303,57 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1289,10 +1303,57 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
1289fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {1303fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1290 const is_volatile = false; // TODO1304 const is_volatile = false; // TODO
1291 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1305 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1292 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst))1306 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: {
1293 .dead1307 const slice_mcv = try self.resolveInst(bin_op.lhs);
1294 else1308 const slice_ty = self.air.typeOf(bin_op.lhs);
1295 return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch});1309
1310 const elem_ty = slice_ty.childType();
1311 const elem_size = elem_ty.abiSize(self.target.*);
1312
1313 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1314 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
1315
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 }
1327 };
1328
1329 try self.genIMulOpMir(index_ty, index_mcv, .{ .immediate = elem_size });
1330
1331 const dst_mcv = blk: {
1332 switch (slice_mcv) {
1333 .stack_offset => |unadjusted_off| {
1334 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]
1339 _ = try self.addInst(.{
1340 .tag = .lea,
1341 .ops = (Mir.Ops{
1342 .reg1 = registerAlias(addr_reg, slice_ptr_abi_size),
1343 .reg2 = .rbp,
1344 .flags = 0b11,
1345 }).encode(),
1346 .data = .{ .imm = -@intCast(i32, off) },
1347 });
1348 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1349 break :blk dst_mcv;
1350 },
1351 else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}),
1352 }
1353 };
1354
1355 break :result dst_mcv;
1356 };
1296 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1357 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1297}1358}
12981359
...@@ -1427,10 +1488,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1427,10 +1488,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1427 .embedded_in_code => {1488 .embedded_in_code => {
1428 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});1489 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
1429 },1490 },
1430 .register => |reg| try self.setRegOrMem(elem_ty, dst_mcv, .{ .register = reg }),1491 .register => |reg| try self.setRegOrMem(ptr_ty, dst_mcv, .{ .register = reg }),
1431 .memory => |addr| {1492 .memory => |addr| {
1432 const reg = try self.register_manager.allocReg(null, &.{});1493 const reg = try self.copyToTmpRegister(ptr_ty, .{ .memory = addr });
1433 try self.genSetReg(ptr_ty, reg, .{ .memory = addr });
1434 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);1494 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
1435 },1495 },
1436 .stack_offset => {1496 .stack_offset => {
...@@ -1505,28 +1565,60 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {...@@ -1505,28 +1565,60 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1505fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {1565fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
1506 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1566 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1507 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;1567 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
1508 return self.structFieldPtr(extra.struct_operand, ty_pl.ty, extra.field_index);1568 const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index);
1569 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
1509}1570}
15101571
1511fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {1572fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
1512 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1573 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1513 return self.structFieldPtr(ty_op.operand, ty_op.ty, index);1574 const result = try self.structFieldPtr(inst, ty_op.operand, index);
1575 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1514}1576}
1515fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void {1577
1516 _ = self;1578fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
1517 _ = operand;1579 return if (self.liveness.isUnused(inst)) .dead else result: {
1518 _ = ty;1580 const mcv = try self.resolveInst(operand);
1519 _ = index;1581 const struct_ty = self.air.typeOf(operand).childType();
1520 return self.fail("TODO implement codegen struct_field_ptr", .{});1582 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
1521 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });1583 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
1584 const struct_field_ty = struct_ty.structFieldType(index);
1585 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
1586
1587 switch (mcv) {
1588 .ptr_stack_offset => |off| {
1589 break :result MCValue{
1590 .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size,
1591 };
1592 },
1593 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
1594 }
1595 };
1522}1596}
15231597
1524fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {1598fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
1525 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1599 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1526 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;1600 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
1527 _ = extra;1601 const operand = extra.struct_operand;
1528 return self.fail("TODO implement codegen struct_field_val", .{});1602 const index = extra.field_index;
1529 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });1603 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1604 const mcv = try self.resolveInst(operand);
1605 const struct_ty = self.air.typeOf(operand);
1606 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
1607 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
1608 const struct_field_ty = struct_ty.structFieldType(index);
1609 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
1610
1611 switch (mcv) {
1612 .stack_offset => |off| {
1613 break :result MCValue{
1614 .stack_offset = off + struct_size - struct_field_offset - struct_field_size,
1615 };
1616 },
1617 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
1618 }
1619 };
1620
1621 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
1530}1622}
15311623
1532/// Perform "binary" operators, excluding comparisons.1624/// Perform "binary" operators, excluding comparisons.
...@@ -1778,6 +1870,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !...@@ -1778,6 +1870,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
1778 .data = .{ .imm = @intCast(i32, imm) },1870 .data = .{ .imm = @intCast(i32, imm) },
1779 });1871 });
1780 } else {1872 } else {
1873 // TODO verify we don't spill and assign to the same register as dst_mcv
1781 const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);1874 const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);
1782 return self.genIMulOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });1875 return self.genIMulOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });
1783 }1876 }
...@@ -1887,10 +1980,16 @@ fn airFence(self: *Self) !void {...@@ -1887,10 +1980,16 @@ fn airFence(self: *Self) !void {
18871980
1888fn airCall(self: *Self, inst: Air.Inst.Index) !void {1981fn airCall(self: *Self, inst: Air.Inst.Index) !void {
1889 const pl_op = self.air.instructions.items(.data)[inst].pl_op;1982 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1890 const fn_ty = self.air.typeOf(pl_op.operand);
1891 const callee = pl_op.operand;1983 const callee = pl_op.operand;
1892 const extra = self.air.extraData(Air.Call, pl_op.payload);1984 const extra = self.air.extraData(Air.Call, pl_op.payload);
1893 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);1985 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
1986 const ty = self.air.typeOf(callee);
1987
1988 const fn_ty = switch (ty.zigTypeTag()) {
1989 .Fn => ty,
1990 .Pointer => ty.childType(),
1991 else => unreachable,
1992 };
18941993
1895 var info = try self.resolveCallingConventionValues(fn_ty);1994 var info = try self.resolveCallingConventionValues(fn_ty);
1896 defer info.deinit(self);1995 defer info.deinit(self);
...@@ -1957,7 +2056,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -1957,7 +2056,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
1957 return self.fail("TODO implement calling bitcasted functions", .{});2056 return self.fail("TODO implement calling bitcasted functions", .{});
1958 }2057 }
1959 } else {2058 } else {
1960 return self.fail("TODO implement calling runtime known function pointer", .{});2059 assert(ty.zigTypeTag() == .Pointer);
2060 const mcv = try self.resolveInst(callee);
2061 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
1961 }2062 }
1962 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {2063 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
1963 for (info.args) |mc_arg, arg_i| {2064 for (info.args) |mc_arg, arg_i| {
...@@ -2000,7 +2101,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2000,7 +2101,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2000 const func = func_payload.data;2101 const func = func_payload.data;
2001 // TODO I'm hacking my way through here by repurposing .memory for storing2102 // TODO I'm hacking my way through here by repurposing .memory for storing
2002 // index to the GOT target symbol index.2103 // index to the GOT target symbol index.
2003 try self.genSetReg(Type.initTag(.u64), .rax, .{2104 try self.genSetReg(Type.initTag(.usize), .rax, .{
2004 .memory = func.owner_decl.link.macho.local_sym_index,2105 .memory = func.owner_decl.link.macho.local_sym_index,
2005 });2106 });
2006 // callq *%rax2107 // callq *%rax
...@@ -2024,7 +2125,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2024,7 +2125,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2024 return self.fail("TODO implement calling bitcasted functions", .{});2125 return self.fail("TODO implement calling bitcasted functions", .{});
2025 }2126 }
2026 } else {2127 } else {
2027 return self.fail("TODO implement calling runtime known function pointer", .{});2128 assert(ty.zigTypeTag() == .Pointer);
2129 const mcv = try self.resolveInst(callee);
2130 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
2028 }2131 }
2029 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {2132 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2030 for (info.args) |mc_arg, arg_i| {2133 for (info.args) |mc_arg, arg_i| {
...@@ -2142,12 +2245,19 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -2142,12 +2245,19 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
21422245
2143fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {2246fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2144 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2247 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2145 if (self.liveness.isUnused(inst))2248
2249 if (self.liveness.isUnused(inst)) {
2146 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });2250 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2251 }
2252
2147 const ty = self.air.typeOf(bin_op.lhs);2253 const ty = self.air.typeOf(bin_op.lhs);
2148 assert(ty.eql(self.air.typeOf(bin_op.rhs)));2254 const signedness: std.builtin.Signedness = blk: {
2149 if (ty.zigTypeTag() == .ErrorSet)2255 // For non-int types, we treat the values as unsigned
2150 return self.fail("TODO implement cmp for errors", .{});2256 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
2257
2258 // Otherwise, we take the signedness of the actual int
2259 break :blk ty.intInfo(self.target.*).signedness;
2260 };
21512261
2152 const lhs = try self.resolveInst(bin_op.lhs);2262 const lhs = try self.resolveInst(bin_op.lhs);
2153 const rhs = try self.resolveInst(bin_op.rhs);2263 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -2163,9 +2273,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2163,9 +2273,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2163 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);2273 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);
21642274
2165 try self.genBinMathOpMir(.cmp, ty, dst_mcv, src_mcv);2275 try self.genBinMathOpMir(.cmp, ty, dst_mcv, src_mcv);
2166 break :result switch (ty.isSignedInt()) {2276 break :result switch (signedness) {
2167 true => MCValue{ .compare_flags_signed = op },2277 .signed => MCValue{ .compare_flags_signed = op },
2168 false => MCValue{ .compare_flags_unsigned = op },2278 .unsigned => MCValue{ .compare_flags_unsigned = op },
2169 };2279 };
2170 };2280 };
2171 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2281 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
...@@ -2274,6 +2384,9 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2274,6 +2384,9 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
2274 const parent_registers = self.register_manager.registers;2384 const parent_registers = self.register_manager.registers;
22752385
2276 try self.branch_stack.append(.{});2386 try self.branch_stack.append(.{});
2387 errdefer {
2388 _ = self.branch_stack.pop();
2389 }
22772390
2278 try self.ensureProcessDeathCapacity(liveness_condbr.then_deaths.len);2391 try self.ensureProcessDeathCapacity(liveness_condbr.then_deaths.len);
2279 for (liveness_condbr.then_deaths) |operand| {2392 for (liveness_condbr.then_deaths) |operand| {
...@@ -2393,19 +2506,35 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -2393,19 +2506,35 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
2393}2506}
23942507
2395fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {2508fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2396 _ = ty;2509 const err_type = ty.errorUnionSet();
2397 _ = operand;2510 const payload_type = ty.errorUnionPayload();
2398 // Here you can specialize this instruction if it makes sense to, otherwise the default2511 if (!err_type.hasCodeGenBits()) {
2399 // will call isNonErr and invert the result.2512 return MCValue{ .immediate = 0 }; // always false
2400 return self.fail("TODO call isNonErr and invert the result", .{});2513 } else if (!payload_type.hasCodeGenBits()) {
2514 if (err_type.abiSize(self.target.*) <= 8) {
2515 try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
2516 return MCValue{ .compare_flags_unsigned = .gt };
2517 } else {
2518 return self.fail("TODO isErr for errors with size larger than register size", .{});
2519 }
2520 } else {
2521 return self.fail("TODO isErr for non-empty payloads", .{});
2522 }
2401}2523}
24022524
2403fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {2525fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2404 _ = ty;2526 const is_err_res = try self.isErr(ty, operand);
2405 _ = operand;2527 switch (is_err_res) {
2406 // Here you can specialize this instruction if it makes sense to, otherwise the default2528 .compare_flags_unsigned => |op| {
2407 // will call isErr and invert the result.2529 assert(op == .gt);
2408 return self.fail("TODO call isErr and invert the result", .{});2530 return MCValue{ .compare_flags_unsigned = .lte };
2531 },
2532 .immediate => |imm| {
2533 assert(imm == 0);
2534 return MCValue{ .immediate = 1 };
2535 },
2536 else => unreachable,
2537 }
2409}2538}
24102539
2411fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {2540fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
...@@ -2877,12 +3006,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2877,12 +3006,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2877 },3006 },
2878 }3007 }
2879 },3008 },
2880 .embedded_in_code => {
2881 // TODO this and `.stack_offset` below need to get improved to support types greater than
2882 // register size, and do general memcpy
2883 const reg = try self.copyToTmpRegister(ty, mcv);
2884 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2885 },
2886 .register => |reg| {3009 .register => |reg| {
2887 if (stack_offset > math.maxInt(i32)) {3010 if (stack_offset > math.maxInt(i32)) {
2888 return self.fail("stack offset too large", .{});3011 return self.fail("stack offset too large", .{});
...@@ -2899,23 +3022,137 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2899,23 +3022,137 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2899 .data = .{ .imm = -@intCast(i32, adj_off) },3022 .data = .{ .imm = -@intCast(i32, adj_off) },
2900 });3023 });
2901 },3024 },
2902 .memory => |vaddr| {3025 .memory, .embedded_in_code => {
2903 _ = vaddr;3026 if (ty.abiSize(self.target.*) <= 8) {
2904 return self.fail("TODO implement set stack variable from memory vaddr", .{});3027 const reg = try self.copyToTmpRegister(ty, mcv);
3028 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3029 }
3030 return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});
2905 },3031 },
2906 .stack_offset => |off| {3032 .stack_offset => |unadjusted_off| {
2907 // TODO this and `.embedded_in_code` above need to get improved to support types greater than3033 if (stack_offset == unadjusted_off) {
2908 // register size, and do general memcpy3034 // Copy stack variable to itself; nothing to do.
3035 return;
3036 }
3037
3038 const abi_size = ty.abiSize(self.target.*);
3039 if (abi_size <= 8) {
3040 const reg = try self.copyToTmpRegister(ty, mcv);
3041 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3042 }
3043
3044 const regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{});
3045 const addr_reg = regs[0];
3046 const len_reg = regs[1];
3047
3048 const off = unadjusted_off + abi_size;
3049 _ = try self.addInst(.{
3050 .tag = .lea,
3051 .ops = (Mir.Ops{
3052 .reg1 = addr_reg.to64(),
3053 .reg2 = .rbp,
3054 }).encode(),
3055 .data = .{ .imm = -@intCast(i32, off) },
3056 });
29093057
2910 if (stack_offset == off)3058 // TODO allow for abi_size to be u64
2911 return; // Copy stack variable to itself; nothing to do.3059 try self.genSetReg(Type.initTag(.u32), len_reg, .{ .immediate = @intCast(u32, abi_size) });
29123060
2913 const reg = try self.copyToTmpRegister(ty, mcv);3061 return self.genInlineMemcpy(-@intCast(i32, off), addr_reg.to64(), len_reg.to64());
2914 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2915 },3062 },
2916 }3063 }
2917}3064}
29183065
3066fn 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
3071 // mov rcx, 0
3072 _ = try self.addInst(.{
3073 .tag = .mov,
3074 .ops = (Mir.Ops{
3075 .reg1 = .rcx,
3076 }).encode(),
3077 .data = .{ .imm = 0 },
3078 });
3079
3080 // mov rax, 0
3081 _ = try self.addInst(.{
3082 .tag = .mov,
3083 .ops = (Mir.Ops{
3084 .reg1 = .rax,
3085 }).encode(),
3086 .data = .{ .imm = 0 },
3087 });
3088
3089 // loop:
3090 // cmp rcx, len
3091 const loop_start = try self.addInst(.{
3092 .tag = .cmp,
3093 .ops = (Mir.Ops{
3094 .reg1 = .rcx,
3095 .reg2 = len_reg,
3096 }).encode(),
3097 .data = undefined,
3098 });
3099
3100 // jge end
3101 const loop_reloc = try self.addInst(.{
3102 .tag = .cond_jmp_above_below,
3103 .ops = (Mir.Ops{ .flags = 0b00 }).encode(),
3104 .data = .{ .inst = undefined },
3105 });
3106
3107 // mov tmp, [addr + rcx]
3108 _ = try self.addInst(.{
3109 .tag = .mov_scale_src,
3110 .ops = (Mir.Ops{
3111 .reg1 = tmp_reg.to8(),
3112 .reg2 = addr_reg,
3113 }).encode(),
3114 .data = .{ .imm = 0 },
3115 });
3116
3117 // mov [stack_offset + rax], tmp
3118 _ = try self.addInst(.{
3119 .tag = .mov_scale_dst,
3120 .ops = (Mir.Ops{
3121 .reg1 = .rbp,
3122 .reg2 = tmp_reg.to8(),
3123 }).encode(),
3124 .data = .{ .imm = stack_offset },
3125 });
3126
3127 // add rcx, 1
3128 _ = try self.addInst(.{
3129 .tag = .add,
3130 .ops = (Mir.Ops{
3131 .reg1 = .rcx,
3132 }).encode(),
3133 .data = .{ .imm = 1 },
3134 });
3135
3136 // add rax, 1
3137 _ = try self.addInst(.{
3138 .tag = .add,
3139 .ops = (Mir.Ops{
3140 .reg1 = .rax,
3141 }).encode(),
3142 .data = .{ .imm = 1 },
3143 });
3144
3145 // jmp loop
3146 _ = try self.addInst(.{
3147 .tag = .jmp,
3148 .ops = (Mir.Ops{ .flags = 0b00 }).encode(),
3149 .data = .{ .inst = loop_start },
3150 });
3151
3152 // end:
3153 try self.performReloc(loop_reloc);
3154}
3155
2919/// Set pointee via pointer stored in a register.3156/// Set pointee via pointer stored in a register.
2920/// mov [reg], value3157/// mov [reg], value
2921fn genSetPtrReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {3158fn genSetPtrReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
...@@ -3436,31 +3673,32 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3436,31 +3673,32 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3436 }3673 }
3437 },3674 },
3438 .ErrorSet => {3675 .ErrorSet => {
3439 switch (typed_value.val.tag()) {3676 const err_name = typed_value.val.castTag(.@"error").?.data.name;
3440 .@"error" => {3677 const module = self.bin_file.options.module.?;
3441 const err_name = typed_value.val.castTag(.@"error").?.data.name;3678 const global_error_set = module.global_error_set;
3442 const module = self.bin_file.options.module.?;3679 const error_index = global_error_set.get(err_name).?;
3443 const global_error_set = module.global_error_set;3680 return MCValue{ .immediate = error_index };
3444 const error_index = global_error_set.get(err_name).?;
3445 return MCValue{ .immediate = error_index };
3446 },
3447 else => {
3448 // In this case we are rendering an error union which has a 0 bits payload.
3449 return MCValue{ .immediate = 0 };
3450 },
3451 }
3452 },3681 },
3453 .ErrorUnion => {3682 .ErrorUnion => {
3454 const error_type = typed_value.ty.errorUnionSet();3683 const error_type = typed_value.ty.errorUnionSet();
3455 const payload_type = typed_value.ty.errorUnionPayload();3684 const payload_type = typed_value.ty.errorUnionPayload();
3456 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
34573685
3458 if (!payload_type.hasCodeGenBits()) {3686 if (typed_value.val.castTag(.eu_payload)) |pl| {
3459 // We use the error type directly as the type.3687 if (!payload_type.hasCodeGenBits()) {
3460 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });3688 // We use the error type directly as the type.
3689 return MCValue{ .immediate = 0 };
3690 }
3691
3692 _ = pl;
3693 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
3694 } else {
3695 if (!payload_type.hasCodeGenBits()) {
3696 // We use the error type directly as the type.
3697 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
3698 }
3461 }3699 }
34623700
3463 return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty});3701 return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty});
3464 },3702 },
3465 else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}),3703 else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}),
3466 }3704 }
...@@ -3557,8 +3795,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -3557,8 +3795,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
3557 .Naked => unreachable,3795 .Naked => unreachable,
3558 .Unspecified, .C => {3796 .Unspecified, .C => {
3559 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));3797 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
3560 const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size);3798 if (ret_ty_size <= 8) {
3561 result.return_value = .{ .register = aliased_reg };3799 const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size);
3800 result.return_value = .{ .register = aliased_reg };
3801 } else {
3802 return self.fail("TODO support more return types for x86_64 backend", .{});
3803 }
3562 },3804 },
3563 else => return self.fail("TODO implement function return values for {}", .{cc}),3805 else => return self.fail("TODO implement function return values for {}", .{cc}),
3564 }3806 }
src/arch/x86_64/Isel.zig+294-377
...@@ -227,8 +227,10 @@ fn mirPushPop(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -227,8 +227,10 @@ fn mirPushPop(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
227 16 => .word_ptr,227 16 => .word_ptr,
228 else => .qword_ptr,228 else => .qword_ptr,
229 };229 };
230 return lowerToMEnc(tag, RegisterOrMemory.mem(ops.reg1, imm, ptr_size), isel.code) catch |err|230 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{
231 isel.failWithLoweringError(err);231 .disp = imm,
232 .base = ops.reg1,
233 }), isel.code) catch |err| isel.failWithLoweringError(err);
232 },234 },
233 0b10 => {235 0b10 => {
234 // PUSH imm32236 // PUSH imm32
...@@ -284,7 +286,7 @@ fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -284,7 +286,7 @@ fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
284 16 => .word_ptr,286 16 => .word_ptr,
285 else => .qword_ptr,287 else => .qword_ptr,
286 };288 };
287 return lowerToMEnc(tag, RegisterOrMemory.mem(null, imm, ptr_size), isel.code) catch |err|289 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err|
288 isel.failWithLoweringError(err);290 isel.failWithLoweringError(err);
289 }291 }
290 // JMP/CALL reg292 // JMP/CALL reg
...@@ -422,12 +424,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -422,12 +424,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
422 // RM424 // RM
423 const imm = isel.mir.instructions.items(.data)[inst].imm;425 const imm = isel.mir.instructions.items(.data)[inst].imm;
424 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;426 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
425 return lowerToRmEnc(427 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
426 tag,428 .disp = imm,
427 ops.reg1,429 .base = src_reg,
428 RegisterOrMemory.mem(src_reg, imm, Memory.PtrSize.fromBits(ops.reg1.size())),430 }), isel.code) catch |err| isel.failWithLoweringError(err);
429 isel.code,
430 ) catch |err| isel.failWithLoweringError(err);
431 },431 },
432 0b10 => {432 0b10 => {
433 if (ops.reg2 == .none) {433 if (ops.reg2 == .none) {
...@@ -436,12 +436,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -436,12 +436,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
436 // mov [reg1 + imm32], reg2436 // mov [reg1 + imm32], reg2
437 // MR437 // MR
438 const imm = isel.mir.instructions.items(.data)[inst].imm;438 const imm = isel.mir.instructions.items(.data)[inst].imm;
439 return lowerToMrEnc(439 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
440 tag,440 .disp = imm,
441 RegisterOrMemory.mem(ops.reg1, imm, Memory.PtrSize.fromBits(ops.reg2.size())),441 .base = ops.reg1,
442 ops.reg2,442 }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
443 isel.code,
444 ) catch |err| isel.failWithLoweringError(err);
445 },443 },
446 0b11 => {444 0b11 => {
447 return isel.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});445 return isel.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});
...@@ -460,12 +458,10 @@ fn mirArithMemImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -460,12 +458,10 @@ fn mirArithMemImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
460 0b10 => .dword_ptr,458 0b10 => .dword_ptr,
461 0b11 => .qword_ptr,459 0b11 => .qword_ptr,
462 };460 };
463 return lowerToMiEnc(461 return lowerToMiEnc(tag, RegisterOrMemory.mem(ptr_size, .{
464 tag,462 .disp = imm_pair.dest_off,
465 RegisterOrMemory.mem(ops.reg1, imm_pair.dest_off, ptr_size),463 .base = ops.reg1,
466 imm_pair.operand,464 }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);
467 isel.code,
468 ) catch |err| isel.failWithLoweringError(err);
469}465}
470466
471inline fn setRexWRegister(reg: Register) bool {467inline fn setRexWRegister(reg: Register) bool {
...@@ -492,103 +488,61 @@ inline fn immOpSize(imm: i64) u8 {...@@ -492,103 +488,61 @@ inline fn immOpSize(imm: i64) u8 {
492 return 64;488 return 64;
493}489}
494490
495// TODO
496fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {491fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
497 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);492 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
498 const scale = ops.flags;493 const scale = ops.flags;
499 // OP reg1, [reg2 + scale*rcx + imm32]
500 const opc = getOpCode(tag, .rm, ops.reg1.size() == 8).?;
501 const imm = isel.mir.instructions.items(.data)[inst].imm;494 const imm = isel.mir.instructions.items(.data)[inst].imm;
502 const encoder = try Encoder.init(isel.code, 8);495 // OP reg1, [reg2 + scale*rcx + imm32]
503 encoder.rex(.{496 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
504 .w = ops.reg1.size() == 64,497 .disp = imm,
505 .r = ops.reg1.isExtended(),498 .base = ops.reg2,
506 .b = ops.reg2.isExtended(),499 .scale_index = .{
507 });500 .scale = scale,
508 opc.encode(encoder);501 .index = .rcx,
509 if (imm <= math.maxInt(i8)) {502 },
510 encoder.modRm_SIBDisp8(ops.reg1.lowId());503 }), isel.code) catch |err| isel.failWithLoweringError(err);
511 encoder.sib_scaleIndexBaseDisp8(scale, Register.rcx.lowId(), ops.reg2.lowId());
512 encoder.disp8(@intCast(i8, imm));
513 } else {
514 encoder.modRm_SIBDisp32(ops.reg1.lowId());
515 encoder.sib_scaleIndexBaseDisp32(scale, Register.rcx.lowId(), ops.reg2.lowId());
516 encoder.disp32(imm);
517 }
518}504}
519505
520// TODO
521fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {506fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
522 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);507 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
523 const scale = ops.flags;508 const scale = ops.flags;
524 const imm = isel.mir.instructions.items(.data)[inst].imm;509 const imm = isel.mir.instructions.items(.data)[inst].imm;
525
526 if (ops.reg2 == .none) {510 if (ops.reg2 == .none) {
527 // OP [reg1 + scale*rax + 0], imm32511 // OP qword ptr [reg1 + scale*rax + 0], imm32
528 const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?;512 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{
529 const modrm_ext = getModRmExt(tag).?;513 .disp = 0,
530 const encoder = try Encoder.init(isel.code, 8);514 .base = ops.reg1,
531 encoder.rex(.{515 .scale_index = .{
532 .w = ops.reg1.size() == 64,516 .scale = scale,
533 .b = ops.reg1.isExtended(),517 .index = .rax,
534 });518 },
535 opc.encode(encoder);519 }), imm, isel.code) catch |err| isel.failWithLoweringError(err);
536 encoder.modRm_SIBDisp0(modrm_ext);
537 encoder.sib_scaleIndexBase(scale, Register.rax.lowId(), ops.reg1.lowId());
538 if (imm <= math.maxInt(i8)) {
539 encoder.imm8(@intCast(i8, imm));
540 } else if (imm <= math.maxInt(i16)) {
541 encoder.imm16(@intCast(i16, imm));
542 } else {
543 encoder.imm32(imm);
544 }
545 return;
546 }520 }
547
548 // OP [reg1 + scale*rax + imm32], reg2521 // OP [reg1 + scale*rax + imm32], reg2
549 const opc = getOpCode(tag, .mr, ops.reg1.size() == 8).?;522 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
550 const encoder = try Encoder.init(isel.code, 8);523 .disp = imm,
551 encoder.rex(.{524 .base = ops.reg1,
552 .w = ops.reg1.size() == 64,525 .scale_index = .{
553 .r = ops.reg2.isExtended(),526 .scale = scale,
554 .b = ops.reg1.isExtended(),527 .index = .rax,
555 });528 },
556 opc.encode(encoder);529 }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
557 if (imm <= math.maxInt(i8)) {
558 encoder.modRm_SIBDisp8(ops.reg2.lowId());
559 encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId());
560 encoder.disp8(@intCast(i8, imm));
561 } else {
562 encoder.modRm_SIBDisp32(ops.reg2.lowId());
563 encoder.sib_scaleIndexBaseDisp32(scale, Register.rax.lowId(), ops.reg1.lowId());
564 encoder.disp32(imm);
565 }
566}530}
567531
568// TODO
569fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {532fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
570 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);533 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
571 const scale = ops.flags;534 const scale = ops.flags;
572 const payload = isel.mir.instructions.items(.data)[inst].payload;535 const payload = isel.mir.instructions.items(.data)[inst].payload;
573 const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data;536 const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data;
574 const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?;537 // OP qword ptr [reg1 + scale*rax + imm32], imm32
575 const modrm_ext = getModRmExt(tag).?;538 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{
576 const encoder = try Encoder.init(isel.code, 2);539 .disp = imm_pair.dest_off,
577 encoder.rex(.{540 .base = ops.reg1,
578 .w = ops.reg1.size() == 64,541 .scale_index = .{
579 .b = ops.reg1.isExtended(),542 .scale = scale,
580 });543 .index = .rax,
581 opc.encode(encoder);544 },
582 if (imm_pair.dest_off <= math.maxInt(i8)) {545 }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);
583 encoder.modRm_SIBDisp8(modrm_ext);
584 encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId());
585 encoder.disp8(@intCast(i8, imm_pair.dest_off));
586 } else {
587 encoder.modRm_SIBDisp32(modrm_ext);
588 encoder.sib_scaleIndexBaseDisp32(scale, Register.rax.lowId(), ops.reg1.lowId());
589 encoder.disp32(imm_pair.dest_off);
590 }
591 encoder.imm32(imm_pair.operand);
592}546}
593547
594fn mirMovabs(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {548fn mirMovabs(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
...@@ -646,7 +600,10 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {...@@ -646,7 +600,10 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
646 return lowerToRmEnc(600 return lowerToRmEnc(
647 .lea,601 .lea,
648 ops.reg1,602 ops.reg1,
649 RegisterOrMemory.mem(src_reg, imm, Memory.PtrSize.fromBits(ops.reg1.size())),603 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
604 .disp = imm,
605 .base = src_reg,
606 }),
650 isel.code,607 isel.code,
651 ) catch |err| isel.failWithLoweringError(err);608 ) catch |err| isel.failWithLoweringError(err);
652 },609 },
...@@ -657,7 +614,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {...@@ -657,7 +614,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
657 lowerToRmEnc(614 lowerToRmEnc(
658 .lea,615 .lea,
659 ops.reg1,616 ops.reg1,
660 RegisterOrMemory.rip(0, Memory.PtrSize.fromBits(ops.reg1.size())),617 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
661 isel.code,618 isel.code,
662 ) catch |err| return isel.failWithLoweringError(err);619 ) catch |err| return isel.failWithLoweringError(err);
663 const end_offset = isel.code.items.len;620 const end_offset = isel.code.items.len;
...@@ -673,7 +630,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {...@@ -673,7 +630,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
673 lowerToRmEnc(630 lowerToRmEnc(
674 .lea,631 .lea,
675 ops.reg1,632 ops.reg1,
676 RegisterOrMemory.rip(0, Memory.PtrSize.fromBits(ops.reg1.size())),633 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
677 isel.code,634 isel.code,
678 ) catch |err| return isel.failWithLoweringError(err);635 ) catch |err| return isel.failWithLoweringError(err);
679 const end_offset = isel.code.items.len;636 const end_offset = isel.code.items.len;
...@@ -697,7 +654,24 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {...@@ -697,7 +654,24 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
697 );654 );
698 }655 }
699 },656 },
700 0b11 => return isel.fail("TODO unused variant lea reg1, reg2, 0b11", .{}),657 0b11 => {
658 // lea reg, [rbp + rcx + imm32]
659 const imm = isel.mir.instructions.items(.data)[inst].imm;
660 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
661 return lowerToRmEnc(
662 .lea,
663 ops.reg1,
664 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
665 .disp = imm,
666 .base = src_reg,
667 .scale_index = .{
668 .scale = 0,
669 .index = .rcx,
670 },
671 }),
672 isel.code,
673 ) catch |err| isel.failWithLoweringError(err);
674 },
701 }675 }
702}676}
703677
...@@ -1230,18 +1204,17 @@ inline fn getModRmExt(tag: Tag) ?u3 {...@@ -1230,18 +1204,17 @@ inline fn getModRmExt(tag: Tag) ?u3 {
1230 };1204 };
1231}1205}
12321206
1233const ScaleIndexBase = struct {1207const ScaleIndex = struct {
1234 scale: u2,1208 scale: u2,
1235 index_reg: ?Register,1209 index: Register,
1236 base_reg: ?Register,
1237};1210};
12381211
1239const Memory = struct {1212const Memory = struct {
1240 reg: ?Register,1213 base: ?Register,
1241 rip: bool = false,1214 rip: bool = false,
1242 disp: i32,1215 disp: i32,
1243 ptr_size: PtrSize,1216 ptr_size: PtrSize,
1244 sib: ?ScaleIndexBase = null,1217 scale_index: ?ScaleIndex = null,
12451218
1246 const PtrSize = enum {1219 const PtrSize = enum {
1247 byte_ptr,1220 byte_ptr,
...@@ -1269,8 +1242,72 @@ const Memory = struct {...@@ -1269,8 +1242,72 @@ const Memory = struct {
1269 };1242 };
1270 }1243 }
1271 };1244 };
1245
1246 fn encode(mem_op: Memory, encoder: Encoder, operand: u3) void {
1247 if (mem_op.base) |base| {
1248 const dst = base.lowId();
1249 const src = operand;
1250 if (dst == 4 or mem_op.scale_index != null) {
1251 if (mem_op.disp == 0) {
1252 encoder.modRm_SIBDisp0(src);
1253 if (mem_op.scale_index) |si| {
1254 encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst);
1255 } else {
1256 encoder.sib_base(dst);
1257 }
1258 } else if (immOpSize(mem_op.disp) == 8) {
1259 encoder.modRm_SIBDisp8(src);
1260 if (mem_op.scale_index) |si| {
1261 encoder.sib_scaleIndexBaseDisp8(si.scale, si.index.lowId(), dst);
1262 } else {
1263 encoder.sib_baseDisp8(dst);
1264 }
1265 encoder.disp8(@intCast(i8, mem_op.disp));
1266 } else {
1267 encoder.modRm_SIBDisp32(src);
1268 if (mem_op.scale_index) |si| {
1269 encoder.sib_scaleIndexBaseDisp32(si.scale, si.index.lowId(), dst);
1270 } else {
1271 encoder.sib_baseDisp32(dst);
1272 }
1273 encoder.disp32(mem_op.disp);
1274 }
1275 } else {
1276 if (mem_op.disp == 0) {
1277 encoder.modRm_indirectDisp0(src, dst);
1278 } else if (immOpSize(mem_op.disp) == 8) {
1279 encoder.modRm_indirectDisp8(src, dst);
1280 encoder.disp8(@intCast(i8, mem_op.disp));
1281 } else {
1282 encoder.modRm_indirectDisp32(src, dst);
1283 encoder.disp32(mem_op.disp);
1284 }
1285 }
1286 } else {
1287 if (mem_op.rip) {
1288 encoder.modRm_RIPDisp32(operand);
1289 } else {
1290 encoder.modRm_SIBDisp0(operand);
1291 if (mem_op.scale_index) |si| {
1292 encoder.sib_scaleIndexDisp32(si.scale, si.index.lowId());
1293 } else {
1294 encoder.sib_disp32();
1295 }
1296 }
1297 encoder.disp32(mem_op.disp);
1298 }
1299 }
1272};1300};
12731301
1302fn encodeImm(encoder: Encoder, imm: i32, size: u64) void {
1303 switch (size) {
1304 8 => encoder.imm8(@intCast(i8, imm)),
1305 16 => encoder.imm16(@intCast(i16, imm)),
1306 32, 64 => encoder.imm32(imm),
1307 else => unreachable,
1308 }
1309}
1310
1274const RegisterOrMemory = union(enum) {1311const RegisterOrMemory = union(enum) {
1275 register: Register,1312 register: Register,
1276 memory: Memory,1313 memory: Memory,
...@@ -1279,20 +1316,25 @@ const RegisterOrMemory = union(enum) {...@@ -1279,20 +1316,25 @@ const RegisterOrMemory = union(enum) {
1279 return .{ .register = register };1316 return .{ .register = register };
1280 }1317 }
12811318
1282 fn mem(register: ?Register, disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory {1319 fn mem(ptr_size: Memory.PtrSize, args: struct {
1320 disp: i32,
1321 base: ?Register = null,
1322 scale_index: ?ScaleIndex = null,
1323 }) RegisterOrMemory {
1283 return .{1324 return .{
1284 .memory = .{1325 .memory = .{
1285 .reg = register,1326 .base = args.base,
1286 .disp = disp,1327 .disp = args.disp,
1287 .ptr_size = ptr_size,1328 .ptr_size = ptr_size,
1329 .scale_index = args.scale_index,
1288 },1330 },
1289 };1331 };
1290 }1332 }
12911333
1292 fn rip(disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory {1334 fn rip(ptr_size: Memory.PtrSize, disp: i32) RegisterOrMemory {
1293 return .{1335 return .{
1294 .memory = .{1336 .memory = .{
1295 .reg = null,1337 .base = null,
1296 .rip = true,1338 .rip = true,
1297 .disp = disp,1339 .disp = disp,
1298 .ptr_size = ptr_size,1340 .ptr_size = ptr_size,
...@@ -1325,16 +1367,10 @@ fn lowerToIEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) LoweringError!void...@@ -1325,16 +1367,10 @@ fn lowerToIEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) LoweringError!void
1325 const opc = getOpCode(tag, .i, immOpSize(imm) == 8).?;1367 const opc = getOpCode(tag, .i, immOpSize(imm) == 8).?;
1326 const encoder = try Encoder.init(code, 5);1368 const encoder = try Encoder.init(code, 5);
1327 if (immOpSize(imm) == 16) {1369 if (immOpSize(imm) == 16) {
1328 encoder.opcode_1byte(0x66);1370 encoder.prefix16BitMode();
1329 }1371 }
1330 opc.encode(encoder);1372 opc.encode(encoder);
1331 if (immOpSize(imm) == 8) {1373 encodeImm(encoder, imm, immOpSize(imm));
1332 encoder.imm8(@intCast(i8, imm));
1333 } else if (immOpSize(imm) == 16) {
1334 encoder.imm16(@intCast(i16, imm));
1335 } else {
1336 encoder.imm32(imm);
1337 }
1338}1374}
13391375
1340fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) LoweringError!void {1376fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) LoweringError!void {
...@@ -1344,7 +1380,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) LoweringError!...@@ -1344,7 +1380,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) LoweringError!
1344 const opc = getOpCode(tag, .o, false).?;1380 const opc = getOpCode(tag, .o, false).?;
1345 const encoder = try Encoder.init(code, 3);1381 const encoder = try Encoder.init(code, 3);
1346 if (reg.size() == 16) {1382 if (reg.size() == 16) {
1347 encoder.opcode_1byte(0x66);1383 encoder.prefix16BitMode();
1348 }1384 }
1349 encoder.rex(.{1385 encoder.rex(.{
1350 .w = false,1386 .w = false,
...@@ -1375,7 +1411,7 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))...@@ -1375,7 +1411,7 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
1375 }1411 }
1376 const encoder = try Encoder.init(code, 4);1412 const encoder = try Encoder.init(code, 4);
1377 if (reg.size() == 16) {1413 if (reg.size() == 16) {
1378 encoder.opcode_1byte(0x66);1414 encoder.prefix16BitMode();
1379 }1415 }
1380 encoder.rex(.{1416 encoder.rex(.{
1381 .w = switch (reg) {1417 .w = switch (reg) {
...@@ -1393,51 +1429,19 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))...@@ -1393,51 +1429,19 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
1393 }1429 }
1394 const encoder = try Encoder.init(code, 8);1430 const encoder = try Encoder.init(code, 8);
1395 if (mem_op.ptr_size == .word_ptr) {1431 if (mem_op.ptr_size == .word_ptr) {
1396 encoder.opcode_1byte(0x66);1432 encoder.prefix16BitMode();
1397 }1433 }
1398 if (mem_op.reg) |reg| {1434 if (mem_op.base) |base| {
1399 if (reg.size() != 64) {1435 if (base.size() != 64) {
1400 return error.OperandSizeMismatch;1436 return error.OperandSizeMismatch;
1401 }1437 }
1402 encoder.rex(.{1438 encoder.rex(.{
1403 .w = false,1439 .w = false,
1404 .b = reg.isExtended(),1440 .b = base.isExtended(),
1405 });1441 });
1406 opc.encode(encoder);
1407 if (reg.lowId() == 4) {
1408 if (mem_op.disp == 0) {
1409 encoder.modRm_SIBDisp0(modrm_ext);
1410 encoder.sib_base(reg.lowId());
1411 } else if (immOpSize(mem_op.disp) == 8) {
1412 encoder.modRm_SIBDisp8(modrm_ext);
1413 encoder.sib_baseDisp8(reg.lowId());
1414 encoder.disp8(@intCast(i8, mem_op.disp));
1415 } else {
1416 encoder.modRm_SIBDisp32(modrm_ext);
1417 encoder.sib_baseDisp32(reg.lowId());
1418 encoder.disp32(mem_op.disp);
1419 }
1420 } else {
1421 if (mem_op.disp == 0) {
1422 encoder.modRm_indirectDisp0(modrm_ext, reg.lowId());
1423 } else if (immOpSize(mem_op.disp) == 8) {
1424 encoder.modRm_indirectDisp8(modrm_ext, reg.lowId());
1425 encoder.disp8(@intCast(i8, mem_op.disp));
1426 } else {
1427 encoder.modRm_indirectDisp32(modrm_ext, reg.lowId());
1428 encoder.disp32(mem_op.disp);
1429 }
1430 }
1431 } else {
1432 opc.encode(encoder);
1433 if (mem_op.rip) {
1434 encoder.modRm_RIPDisp32(modrm_ext);
1435 } else {
1436 encoder.modRm_SIBDisp0(modrm_ext);
1437 encoder.sib_disp32();
1438 }
1439 encoder.disp32(mem_op.disp);
1440 }1442 }
1443 opc.encode(encoder);
1444 mem_op.encode(encoder, modrm_ext);
1441 },1445 },
1442 }1446 }
1443}1447}
...@@ -1463,7 +1467,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8),...@@ -1463,7 +1467,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8),
1463 getOpCode(tag, .fd, reg.size() == 8).?;1467 getOpCode(tag, .fd, reg.size() == 8).?;
1464 const encoder = try Encoder.init(code, 10);1468 const encoder = try Encoder.init(code, 10);
1465 if (reg.size() == 16) {1469 if (reg.size() == 16) {
1466 encoder.opcode_1byte(0x66);1470 encoder.prefix16BitMode();
1467 }1471 }
1468 encoder.rex(.{1472 encoder.rex(.{
1469 .w = setRexWRegister(reg),1473 .w = setRexWRegister(reg),
...@@ -1496,7 +1500,7 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) Low...@@ -1496,7 +1500,7 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) Low
1496 const opc = getOpCode(tag, .oi, reg.size() == 8).?;1500 const opc = getOpCode(tag, .oi, reg.size() == 8).?;
1497 const encoder = try Encoder.init(code, 10);1501 const encoder = try Encoder.init(code, 10);
1498 if (reg.size() == 16) {1502 if (reg.size() == 16) {
1499 encoder.opcode_1byte(0x66);1503 encoder.prefix16BitMode();
1500 }1504 }
1501 encoder.rex(.{1505 encoder.rex(.{
1502 .w = setRexWRegister(reg),1506 .w = setRexWRegister(reg),
...@@ -1533,7 +1537,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr...@@ -1533,7 +1537,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr
1533 // 0x66 prefix switches to the non-default size; here we assume a switch from1537 // 0x66 prefix switches to the non-default size; here we assume a switch from
1534 // the default 32bits to 16bits operand-size.1538 // the default 32bits to 16bits operand-size.
1535 // More info: https://www.cs.uni-potsdam.de/desn/lehre/ss15/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf#page=32&zoom=auto,-159,7731539 // More info: https://www.cs.uni-potsdam.de/desn/lehre/ss15/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf#page=32&zoom=auto,-159,773
1536 encoder.opcode_1byte(0x66);1540 encoder.prefix16BitMode();
1537 }1541 }
1538 encoder.rex(.{1542 encoder.rex(.{
1539 .w = setRexWRegister(dst_reg),1543 .w = setRexWRegister(dst_reg),
...@@ -1541,81 +1545,30 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr...@@ -1541,81 +1545,30 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr
1541 });1545 });
1542 opc.encode(encoder);1546 opc.encode(encoder);
1543 encoder.modRm_direct(modrm_ext, dst_reg.lowId());1547 encoder.modRm_direct(modrm_ext, dst_reg.lowId());
1544 switch (dst_reg.size()) {1548 encodeImm(encoder, imm, dst_reg.size());
1545 8 => {
1546 const imm8 = try math.cast(i8, imm);
1547 encoder.imm8(imm8);
1548 },
1549 16 => {
1550 const imm16 = try math.cast(i16, imm);
1551 encoder.imm16(imm16);
1552 },
1553 32, 64 => encoder.imm32(imm),
1554 else => unreachable,
1555 }
1556 },1549 },
1557 .memory => |dst_mem| {1550 .memory => |dst_mem| {
1558 const opc = getOpCode(tag, .mi, dst_mem.ptr_size == .byte_ptr).?;1551 const opc = getOpCode(tag, .mi, dst_mem.ptr_size == .byte_ptr).?;
1559 const encoder = try Encoder.init(code, 12);1552 const encoder = try Encoder.init(code, 12);
1560 if (dst_mem.ptr_size == .word_ptr) {1553 if (dst_mem.ptr_size == .word_ptr) {
1561 encoder.opcode_1byte(0x66);1554 encoder.prefix16BitMode();
1562 }1555 }
1563 if (dst_mem.reg) |dst_reg| {1556 if (dst_mem.base) |base| {
1564 if (dst_reg.size() != 64) {1557 if (base.size() != 64) {
1565 return error.OperandSizeMismatch;1558 return error.OperandSizeMismatch;
1566 }1559 }
1567 encoder.rex(.{1560 encoder.rex(.{
1568 .w = dst_mem.ptr_size == .qword_ptr,1561 .w = dst_mem.ptr_size == .qword_ptr,
1569 .b = dst_reg.isExtended(),1562 .b = base.isExtended(),
1570 });1563 });
1571 opc.encode(encoder);
1572 if (dst_reg.lowId() == 4) {
1573 if (dst_mem.disp == 0) {
1574 encoder.modRm_SIBDisp0(modrm_ext);
1575 encoder.sib_base(dst_reg.lowId());
1576 } else if (immOpSize(dst_mem.disp) == 8) {
1577 encoder.modRm_SIBDisp8(modrm_ext);
1578 encoder.sib_baseDisp8(dst_reg.lowId());
1579 encoder.disp8(@intCast(i8, dst_mem.disp));
1580 } else {
1581 encoder.modRm_SIBDisp32(modrm_ext);
1582 encoder.sib_baseDisp32(dst_reg.lowId());
1583 encoder.disp32(dst_mem.disp);
1584 }
1585 } else {
1586 if (dst_mem.disp == 0) {
1587 encoder.modRm_indirectDisp0(modrm_ext, dst_reg.lowId());
1588 } else if (immOpSize(dst_mem.disp) == 8) {
1589 encoder.modRm_indirectDisp8(modrm_ext, dst_reg.lowId());
1590 encoder.disp8(@intCast(i8, dst_mem.disp));
1591 } else {
1592 encoder.modRm_indirectDisp32(modrm_ext, dst_reg.lowId());
1593 encoder.disp32(dst_mem.disp);
1594 }
1595 }
1596 } else {1564 } else {
1597 opc.encode(encoder);1565 encoder.rex(.{
1598 if (dst_mem.rip) {1566 .w = dst_mem.ptr_size == .qword_ptr,
1599 encoder.modRm_RIPDisp32(modrm_ext);1567 });
1600 } else {
1601 encoder.modRm_SIBDisp0(modrm_ext);
1602 encoder.sib_disp32();
1603 }
1604 encoder.disp32(dst_mem.disp);
1605 }
1606 switch (dst_mem.ptr_size) {
1607 .byte_ptr => {
1608 const imm8 = try math.cast(i8, imm);
1609 encoder.imm8(imm8);
1610 },
1611 .word_ptr => {
1612 const imm16 = try math.cast(i16, imm);
1613 encoder.imm16(imm16);
1614 },
1615 .dword_ptr, .qword_ptr => {
1616 encoder.imm32(imm);
1617 },
1618 }1568 }
1569 opc.encode(encoder);
1570 dst_mem.encode(encoder, modrm_ext);
1571 encodeImm(encoder, imm, dst_mem.ptr_size.size());
1619 },1572 },
1620 }1573 }
1621}1574}
...@@ -1647,58 +1600,27 @@ fn lowerToRmEnc(...@@ -1647,58 +1600,27 @@ fn lowerToRmEnc(
1647 }1600 }
1648 const encoder = try Encoder.init(code, 9);1601 const encoder = try Encoder.init(code, 9);
1649 if (reg.size() == 16) {1602 if (reg.size() == 16) {
1650 encoder.opcode_1byte(0x66);1603 encoder.prefix16BitMode();
1651 }1604 }
1652 if (src_mem.reg) |src_reg| {1605 if (src_mem.base) |base| {
1653 // TODO handle 32-bit base register - requires prefix 0x671606 // TODO handle 32-bit base register - requires prefix 0x67
1654 // Intel Manual, Vol 1, chapter 3.6 and 3.6.11607 // Intel Manual, Vol 1, chapter 3.6 and 3.6.1
1655 if (src_reg.size() != 64) {1608 if (base.size() != 64) {
1656 return error.OperandSizeMismatch;1609 return error.OperandSizeMismatch;
1657 }1610 }
1658 encoder.rex(.{1611 encoder.rex(.{
1659 .w = setRexWRegister(reg),1612 .w = setRexWRegister(reg),
1660 .r = reg.isExtended(),1613 .r = reg.isExtended(),
1661 .b = src_reg.isExtended(),1614 .b = base.isExtended(),
1662 });1615 });
1663 opc.encode(encoder);
1664 if (src_reg.lowId() == 4) {
1665 if (src_mem.disp == 0) {
1666 encoder.modRm_SIBDisp0(reg.lowId());
1667 encoder.sib_base(src_reg.lowId());
1668 } else if (immOpSize(src_mem.disp) == 8) {
1669 encoder.modRm_SIBDisp8(reg.lowId());
1670 encoder.sib_baseDisp8(src_reg.lowId());
1671 encoder.disp8(@intCast(i8, src_mem.disp));
1672 } else {
1673 encoder.modRm_SIBDisp32(reg.lowId());
1674 encoder.sib_baseDisp32(src_reg.lowId());
1675 encoder.disp32(src_mem.disp);
1676 }
1677 } else {
1678 if (src_mem.disp == 0) {
1679 encoder.modRm_indirectDisp0(reg.lowId(), src_reg.lowId());
1680 } else if (immOpSize(src_mem.disp) == 8) {
1681 encoder.modRm_indirectDisp8(reg.lowId(), src_reg.lowId());
1682 encoder.disp8(@intCast(i8, src_mem.disp));
1683 } else {
1684 encoder.modRm_indirectDisp32(reg.lowId(), src_reg.lowId());
1685 encoder.disp32(src_mem.disp);
1686 }
1687 }
1688 } else {1616 } else {
1689 encoder.rex(.{1617 encoder.rex(.{
1690 .w = setRexWRegister(reg),1618 .w = setRexWRegister(reg),
1691 .r = reg.isExtended(),1619 .r = reg.isExtended(),
1692 });1620 });
1693 opc.encode(encoder);
1694 if (src_mem.rip) {
1695 encoder.modRm_RIPDisp32(reg.lowId());
1696 } else {
1697 encoder.modRm_SIBDisp0(reg.lowId());
1698 encoder.sib_disp32();
1699 }
1700 encoder.disp32(src_mem.disp);
1701 }1621 }
1622 opc.encode(encoder);
1623 src_mem.encode(encoder, reg.lowId());
1702 },1624 },
1703 }1625 }
1704}1626}
...@@ -1730,56 +1652,25 @@ fn lowerToMrEnc(...@@ -1730,56 +1652,25 @@ fn lowerToMrEnc(
1730 }1652 }
1731 const encoder = try Encoder.init(code, 9);1653 const encoder = try Encoder.init(code, 9);
1732 if (reg.size() == 16) {1654 if (reg.size() == 16) {
1733 encoder.opcode_1byte(0x66);1655 encoder.prefix16BitMode();
1734 }1656 }
1735 if (dst_mem.reg) |dst_reg| {1657 if (dst_mem.base) |base| {
1736 if (dst_reg.size() != 64) {1658 if (base.size() != 64) {
1737 return error.OperandSizeMismatch;1659 return error.OperandSizeMismatch;
1738 }1660 }
1739 encoder.rex(.{1661 encoder.rex(.{
1740 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),1662 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),
1741 .r = reg.isExtended(),1663 .r = reg.isExtended(),
1742 .b = dst_reg.isExtended(),1664 .b = base.isExtended(),
1743 });1665 });
1744 opc.encode(encoder);
1745 if (dst_reg.lowId() == 4) {
1746 if (dst_mem.disp == 0) {
1747 encoder.modRm_SIBDisp0(reg.lowId());
1748 encoder.sib_base(dst_reg.lowId());
1749 } else if (immOpSize(dst_mem.disp) == 8) {
1750 encoder.modRm_SIBDisp8(reg.lowId());
1751 encoder.sib_baseDisp8(dst_reg.lowId());
1752 encoder.disp8(@intCast(i8, dst_mem.disp));
1753 } else {
1754 encoder.modRm_SIBDisp32(reg.lowId());
1755 encoder.sib_baseDisp32(dst_reg.lowId());
1756 encoder.disp32(dst_mem.disp);
1757 }
1758 } else {
1759 if (dst_mem.disp == 0) {
1760 encoder.modRm_indirectDisp0(reg.lowId(), dst_reg.lowId());
1761 } else if (immOpSize(dst_mem.disp) == 8) {
1762 encoder.modRm_indirectDisp8(reg.lowId(), dst_reg.lowId());
1763 encoder.disp8(@intCast(i8, dst_mem.disp));
1764 } else {
1765 encoder.modRm_indirectDisp32(reg.lowId(), dst_reg.lowId());
1766 encoder.disp32(dst_mem.disp);
1767 }
1768 }
1769 } else {1666 } else {
1770 encoder.rex(.{1667 encoder.rex(.{
1771 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),1668 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),
1772 .r = reg.isExtended(),1669 .r = reg.isExtended(),
1773 });1670 });
1774 opc.encode(encoder);
1775 if (dst_mem.rip) {
1776 encoder.modRm_RIPDisp32(reg.lowId());
1777 } else {
1778 encoder.modRm_SIBDisp0(reg.lowId());
1779 encoder.sib_disp32();
1780 }
1781 encoder.disp32(dst_mem.disp);
1782 }1671 }
1672 opc.encode(encoder);
1673 dst_mem.encode(encoder, reg.lowId());
1783 },1674 },
1784 }1675 }
1785}1676}
...@@ -1797,7 +1688,7 @@ fn lowerToRmiEnc(...@@ -1797,7 +1688,7 @@ fn lowerToRmiEnc(
1797 const opc = getOpCode(tag, .rmi, false).?;1688 const opc = getOpCode(tag, .rmi, false).?;
1798 const encoder = try Encoder.init(code, 13);1689 const encoder = try Encoder.init(code, 13);
1799 if (reg.size() == 16) {1690 if (reg.size() == 16) {
1800 encoder.opcode_1byte(0x66);1691 encoder.prefix16BitMode();
1801 }1692 }
1802 switch (reg_or_mem) {1693 switch (reg_or_mem) {
1803 .register => |src_reg| {1694 .register => |src_reg| {
...@@ -1813,10 +1704,10 @@ fn lowerToRmiEnc(...@@ -1813,10 +1704,10 @@ fn lowerToRmiEnc(
1813 encoder.modRm_direct(reg.lowId(), src_reg.lowId());1704 encoder.modRm_direct(reg.lowId(), src_reg.lowId());
1814 },1705 },
1815 .memory => |src_mem| {1706 .memory => |src_mem| {
1816 if (src_mem.reg) |src_reg| {1707 if (src_mem.base) |base| {
1817 // TODO handle 32-bit base register - requires prefix 0x671708 // TODO handle 32-bit base register - requires prefix 0x67
1818 // Intel Manual, Vol 1, chapter 3.6 and 3.6.11709 // Intel Manual, Vol 1, chapter 3.6 and 3.6.1
1819 if (src_reg.size() != 64) {1710 if (base.size() != 64) {
1820 return error.OperandSizeMismatch;1711 return error.OperandSizeMismatch;
1821 }1712 }
1822 if (src_mem.ptr_size == .byte_ptr) {1713 if (src_mem.ptr_size == .byte_ptr) {
...@@ -1825,59 +1716,19 @@ fn lowerToRmiEnc(...@@ -1825,59 +1716,19 @@ fn lowerToRmiEnc(
1825 encoder.rex(.{1716 encoder.rex(.{
1826 .w = setRexWRegister(reg),1717 .w = setRexWRegister(reg),
1827 .r = reg.isExtended(),1718 .r = reg.isExtended(),
1828 .b = src_reg.isExtended(),1719 .b = base.isExtended(),
1829 });1720 });
1830 opc.encode(encoder);
1831 if (src_reg.lowId() == 4) {
1832 if (src_mem.disp == 0) {
1833 encoder.modRm_SIBDisp0(reg.lowId());
1834 encoder.sib_base(src_reg.lowId());
1835 } else if (immOpSize(src_mem.disp) == 8) {
1836 encoder.modRm_SIBDisp8(reg.lowId());
1837 encoder.sib_baseDisp8(src_reg.lowId());
1838 encoder.disp8(@intCast(i8, src_mem.disp));
1839 } else {
1840 encoder.modRm_SIBDisp32(reg.lowId());
1841 encoder.sib_baseDisp32(src_reg.lowId());
1842 encoder.disp32(src_mem.disp);
1843 }
1844 } else {
1845 if (src_mem.disp == 0) {
1846 encoder.modRm_indirectDisp0(reg.lowId(), src_reg.lowId());
1847 } else if (immOpSize(src_mem.disp) == 8) {
1848 encoder.modRm_indirectDisp8(reg.lowId(), src_reg.lowId());
1849 encoder.disp8(@intCast(i8, src_mem.disp));
1850 } else {
1851 encoder.modRm_indirectDisp32(reg.lowId(), src_reg.lowId());
1852 encoder.disp32(src_mem.disp);
1853 }
1854 }
1855 } else {1721 } else {
1856 encoder.rex(.{1722 encoder.rex(.{
1857 .w = setRexWRegister(reg),1723 .w = setRexWRegister(reg),
1858 .r = reg.isExtended(),1724 .r = reg.isExtended(),
1859 });1725 });
1860 opc.encode(encoder);
1861 if (src_mem.rip) {
1862 encoder.modRm_RIPDisp32(reg.lowId());
1863 } else {
1864 encoder.modRm_SIBDisp0(reg.lowId());
1865 encoder.sib_disp32();
1866 }
1867 encoder.disp32(src_mem.disp);
1868 }1726 }
1727 opc.encode(encoder);
1728 src_mem.encode(encoder, reg.lowId());
1869 },1729 },
1870 }1730 }
1871 switch (reg.size()) {1731 encodeImm(encoder, imm, reg.size());
1872 // TODO 8bit immediate
1873 8 => unreachable,
1874 16 => {
1875 const imm16 = try math.cast(i16, imm);
1876 encoder.imm16(imm16);
1877 },
1878 32, 64 => encoder.imm32(imm),
1879 else => unreachable,
1880 }
1881}1732}
18821733
1883fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []const u8) !void {1734fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []const u8) !void {
...@@ -1930,44 +1781,62 @@ test "lower MI encoding" {...@@ -1930,44 +1781,62 @@ test "lower MI encoding" {
1930 defer isel.deinit();1781 defer isel.deinit();
1931 try lowerToMiEnc(.mov, RegisterOrMemory.reg(.rax), 0x10, isel.code());1782 try lowerToMiEnc(.mov, RegisterOrMemory.reg(.rax), 0x10, isel.code());
1932 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", isel.lowered(), "mov rax, 0x10");1783 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", isel.lowered(), "mov rax, 0x10");
1933 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.r11, 0, .dword_ptr), 0x10, isel.code());1784 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0, .base = .r11 }), 0x10, isel.code());
1934 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", isel.lowered(), "mov dword ptr [r11 + 0], 0x10");1785 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", isel.lowered(), "mov dword ptr [r11 + 0], 0x10");
1935 try lowerToMiEnc(.add, RegisterOrMemory.mem(.rdx, -8, .dword_ptr), 0x10, isel.code());1786 try lowerToMiEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = -8, .base = .rdx }), 0x10, isel.code());
1936 try expectEqualHexStrings("\x81\x42\xF8\x10\x00\x00\x00", isel.lowered(), "add dword ptr [rdx - 8], 0x10");1787 try expectEqualHexStrings("\x81\x42\xF8\x10\x00\x00\x00", isel.lowered(), "add dword ptr [rdx - 8], 0x10");
1937 try lowerToMiEnc(.sub, RegisterOrMemory.mem(.r11, 0x10000000, .dword_ptr), 0x10, isel.code());1788 try lowerToMiEnc(.sub, RegisterOrMemory.mem(.dword_ptr, .{
1789 .disp = 0x10000000,
1790 .base = .r11,
1791 }), 0x10, isel.code());
1938 try expectEqualHexStrings(1792 try expectEqualHexStrings(
1939 "\x41\x81\xab\x00\x00\x00\x10\x10\x00\x00\x00",1793 "\x41\x81\xab\x00\x00\x00\x10\x10\x00\x00\x00",
1940 isel.lowered(),1794 isel.lowered(),
1941 "sub dword ptr [r11 + 0x10000000], 0x10",1795 "sub dword ptr [r11 + 0x10000000], 0x10",
1942 );1796 );
1943 try lowerToMiEnc(.@"and", RegisterOrMemory.mem(null, 0x10000000, .dword_ptr), 0x10, isel.code());1797 try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), 0x10, isel.code());
1944 try expectEqualHexStrings(1798 try expectEqualHexStrings(
1945 "\x81\x24\x25\x00\x00\x00\x10\x10\x00\x00\x00",1799 "\x81\x24\x25\x00\x00\x00\x10\x10\x00\x00\x00",
1946 isel.lowered(),1800 isel.lowered(),
1947 "and dword ptr [ds:0x10000000], 0x10",1801 "and dword ptr [ds:0x10000000], 0x10",
1948 );1802 );
1949 try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.r12, 0x10000000, .dword_ptr), 0x10, isel.code());1803 try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.dword_ptr, .{
1804 .disp = 0x10000000,
1805 .base = .r12,
1806 }), 0x10, isel.code());
1950 try expectEqualHexStrings(1807 try expectEqualHexStrings(
1951 "\x41\x81\xA4\x24\x00\x00\x00\x10\x10\x00\x00\x00",1808 "\x41\x81\xA4\x24\x00\x00\x00\x10\x10\x00\x00\x00",
1952 isel.lowered(),1809 isel.lowered(),
1953 "and dword ptr [r12 + 0x10000000], 0x10",1810 "and dword ptr [r12 + 0x10000000], 0x10",
1954 );1811 );
1955 try lowerToMiEnc(.mov, RegisterOrMemory.rip(0x10, .qword_ptr), 0x10, isel.code());1812 try lowerToMiEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), 0x10, isel.code());
1956 try expectEqualHexStrings(1813 try expectEqualHexStrings(
1957 "\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",1814 "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
1958 isel.lowered(),1815 isel.lowered(),
1959 "mov qword ptr [rip + 0x10], 0x10",1816 "mov qword ptr [rip + 0x10], 0x10",
1960 );1817 );
1961 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.rbp, -8, .qword_ptr), 0x10, isel.code());1818 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -8, .base = .rbp }), 0x10, isel.code());
1962 try expectEqualHexStrings(1819 try expectEqualHexStrings(
1963 "\x48\xc7\x45\xf8\x10\x00\x00\x00",1820 "\x48\xc7\x45\xf8\x10\x00\x00\x00",
1964 isel.lowered(),1821 isel.lowered(),
1965 "mov qword ptr [rbp - 8], 0x10",1822 "mov qword ptr [rbp - 8], 0x10",
1966 );1823 );
1967 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.rbp, -2, .word_ptr), 0x10, isel.code());1824 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.word_ptr, .{ .disp = -2, .base = .rbp }), 0x10, isel.code());
1968 try expectEqualHexStrings("\x66\xC7\x45\xFE\x10\x00", isel.lowered(), "mov word ptr [rbp - 2], 0x10");1825 try expectEqualHexStrings("\x66\xC7\x45\xFE\x10\x00", isel.lowered(), "mov word ptr [rbp - 2], 0x10");
1969 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.rbp, -1, .byte_ptr), 0x10, isel.code());1826 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.byte_ptr, .{ .disp = -1, .base = .rbp }), 0x10, isel.code());
1970 try expectEqualHexStrings("\xC6\x45\xFF\x10", isel.lowered(), "mov byte ptr [rbp - 1], 0x10");1827 try expectEqualHexStrings("\xC6\x45\xFF\x10", isel.lowered(), "mov byte ptr [rbp - 1], 0x10");
1828 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
1829 .disp = 0x10000000,
1830 .scale_index = .{
1831 .scale = 1,
1832 .index = .rcx,
1833 },
1834 }), 0x10, isel.code());
1835 try expectEqualHexStrings(
1836 "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
1837 isel.lowered(),
1838 "mov qword ptr [rcx*2 + 0x10000000], 0x10",
1839 );
1971}1840}
19721841
1973test "lower RM encoding" {1842test "lower RM encoding" {
...@@ -1975,36 +1844,69 @@ test "lower RM encoding" {...@@ -1975,36 +1844,69 @@ test "lower RM encoding" {
1975 defer isel.deinit();1844 defer isel.deinit();
1976 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), isel.code());1845 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), isel.code());
1977 try expectEqualHexStrings("\x48\x8b\xc3", isel.lowered(), "mov rax, rbx");1846 try expectEqualHexStrings("\x48\x8b\xc3", isel.lowered(), "mov rax, rbx");
1978 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.r11, 0, .qword_ptr), isel.code());1847 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r11 }), isel.code());
1979 try expectEqualHexStrings("\x49\x8b\x03", isel.lowered(), "mov rax, qword ptr [r11 + 0]");1848 try expectEqualHexStrings("\x49\x8b\x03", isel.lowered(), "mov rax, qword ptr [r11 + 0]");
1980 try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(null, 0x10000000, .qword_ptr), isel.code());1849 try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10000000 }), isel.code());
1981 try expectEqualHexStrings(1850 try expectEqualHexStrings(
1982 "\x4C\x03\x1C\x25\x00\x00\x00\x10",1851 "\x4C\x03\x1C\x25\x00\x00\x00\x10",
1983 isel.lowered(),1852 isel.lowered(),
1984 "add r11, qword ptr [ds:0x10000000]",1853 "add r11, qword ptr [ds:0x10000000]",
1985 );1854 );
1986 try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(null, 0x10000000, .byte_ptr), isel.code());1855 try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), isel.code());
1987 try expectEqualHexStrings(1856 try expectEqualHexStrings(
1988 "\x44\x02\x24\x25\x00\x00\x00\x10",1857 "\x44\x02\x24\x25\x00\x00\x00\x10",
1989 isel.lowered(),1858 isel.lowered(),
1990 "add r11b, byte ptr [ds:0x10000000]",1859 "add r11b, byte ptr [ds:0x10000000]",
1991 );1860 );
1992 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.r13, 0x10000000, .qword_ptr), isel.code());1861 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{
1862 .disp = 0x10000000,
1863 .base = .r13,
1864 }), isel.code());
1993 try expectEqualHexStrings(1865 try expectEqualHexStrings(
1994 "\x4D\x2B\x9D\x00\x00\x00\x10",1866 "\x4D\x2B\x9D\x00\x00\x00\x10",
1995 isel.lowered(),1867 isel.lowered(),
1996 "sub r11, qword ptr [r13 + 0x10000000]",1868 "sub r11, qword ptr [r13 + 0x10000000]",
1997 );1869 );
1998 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.r12, 0x10000000, .qword_ptr), isel.code());1870 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{
1871 .disp = 0x10000000,
1872 .base = .r12,
1873 }), isel.code());
1999 try expectEqualHexStrings(1874 try expectEqualHexStrings(
2000 "\x4D\x2B\x9C\x24\x00\x00\x00\x10",1875 "\x4D\x2B\x9C\x24\x00\x00\x00\x10",
2001 isel.lowered(),1876 isel.lowered(),
2002 "sub r11, qword ptr [r12 + 0x10000000]",1877 "sub r11, qword ptr [r12 + 0x10000000]",
2003 );1878 );
2004 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.rbp, -4, .qword_ptr), isel.code());1879 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -4, .base = .rbp }), isel.code());
2005 try expectEqualHexStrings("\x48\x8B\x45\xFC", isel.lowered(), "mov rax, qword ptr [rbp - 4]");1880 try expectEqualHexStrings("\x48\x8B\x45\xFC", isel.lowered(), "mov rax, qword ptr [rbp - 4]");
2006 try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(0x10, .qword_ptr), isel.code());1881 try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code());
2007 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", isel.lowered(), "lea rax, [rip + 0x10]");1882 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", isel.lowered(), "lea rax, [rip + 0x10]");
1883 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
1884 .disp = -8,
1885 .base = .rbp,
1886 .scale_index = .{
1887 .scale = 0,
1888 .index = .rcx,
1889 },
1890 }), isel.code());
1891 try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");
1892 try lowerToRmEnc(.mov, .eax, RegisterOrMemory.mem(.dword_ptr, .{
1893 .disp = -4,
1894 .base = .rbp,
1895 .scale_index = .{
1896 .scale = 2,
1897 .index = .rdx,
1898 },
1899 }), isel.code());
1900 try expectEqualHexStrings("\x8B\x44\x95\xFC", isel.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");
1901 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
1902 .disp = -8,
1903 .base = .rbp,
1904 .scale_index = .{
1905 .scale = 3,
1906 .index = .rcx,
1907 },
1908 }), isel.code());
1909 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");
2008}1910}
20091911
2010test "lower MR encoding" {1912test "lower MR encoding" {
...@@ -2012,27 +1914,30 @@ test "lower MR encoding" {...@@ -2012,27 +1914,30 @@ test "lower MR encoding" {
2012 defer isel.deinit();1914 defer isel.deinit();
2013 try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, isel.code());1915 try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, isel.code());
2014 try expectEqualHexStrings("\x48\x89\xd8", isel.lowered(), "mov rax, rbx");1916 try expectEqualHexStrings("\x48\x89\xd8", isel.lowered(), "mov rax, rbx");
2015 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.rbp, -4, .qword_ptr), .r11, isel.code());1917 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -4, .base = .rbp }), .r11, isel.code());
2016 try expectEqualHexStrings("\x4c\x89\x5d\xfc", isel.lowered(), "mov qword ptr [rbp - 4], r11");1918 try expectEqualHexStrings("\x4c\x89\x5d\xfc", isel.lowered(), "mov qword ptr [rbp - 4], r11");
2017 try lowerToMrEnc(.add, RegisterOrMemory.mem(null, 0x10000000, .byte_ptr), .r12b, isel.code());1919 try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), .r12b, isel.code());
2018 try expectEqualHexStrings(1920 try expectEqualHexStrings(
2019 "\x44\x00\x24\x25\x00\x00\x00\x10",1921 "\x44\x00\x24\x25\x00\x00\x00\x10",
2020 isel.lowered(),1922 isel.lowered(),
2021 "add byte ptr [ds:0x10000000], r12b",1923 "add byte ptr [ds:0x10000000], r12b",
2022 );1924 );
2023 try lowerToMrEnc(.add, RegisterOrMemory.mem(null, 0x10000000, .dword_ptr), .r12d, isel.code());1925 try lowerToMrEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), .r12d, isel.code());
2024 try expectEqualHexStrings(1926 try expectEqualHexStrings(
2025 "\x44\x01\x24\x25\x00\x00\x00\x10",1927 "\x44\x01\x24\x25\x00\x00\x00\x10",
2026 isel.lowered(),1928 isel.lowered(),
2027 "add dword ptr [ds:0x10000000], r12d",1929 "add dword ptr [ds:0x10000000], r12d",
2028 );1930 );
2029 try lowerToMrEnc(.sub, RegisterOrMemory.mem(.r11, 0x10000000, .qword_ptr), .r12, isel.code());1931 try lowerToMrEnc(.sub, RegisterOrMemory.mem(.qword_ptr, .{
1932 .disp = 0x10000000,
1933 .base = .r11,
1934 }), .r12, isel.code());
2030 try expectEqualHexStrings(1935 try expectEqualHexStrings(
2031 "\x4D\x29\xA3\x00\x00\x00\x10",1936 "\x4D\x29\xA3\x00\x00\x00\x10",
2032 isel.lowered(),1937 isel.lowered(),
2033 "sub qword ptr [r11 + 0x10000000], r12",1938 "sub qword ptr [r11 + 0x10000000], r12",
2034 );1939 );
2035 try lowerToMrEnc(.mov, RegisterOrMemory.rip(0x10, .qword_ptr), .r12, isel.code());1940 try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), .r12, isel.code());
2036 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", isel.lowered(), "mov qword ptr [rip + 0x10], r12");1941 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", isel.lowered(), "mov qword ptr [rip + 0x10], r12");
2037}1942}
20381943
...@@ -2083,21 +1988,24 @@ test "lower M encoding" {...@@ -2083,21 +1988,24 @@ test "lower M encoding" {
2083 try expectEqualHexStrings("\x41\xFF\xE4", isel.lowered(), "jmp r12");1988 try expectEqualHexStrings("\x41\xFF\xE4", isel.lowered(), "jmp r12");
2084 try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12w), isel.code());1989 try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12w), isel.code());
2085 try expectEqualHexStrings("\x66\x41\xFF\xE4", isel.lowered(), "jmp r12w");1990 try expectEqualHexStrings("\x66\x41\xFF\xE4", isel.lowered(), "jmp r12w");
2086 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0, .qword_ptr), isel.code());1991 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r12 }), isel.code());
2087 try expectEqualHexStrings("\x41\xFF\x24\x24", isel.lowered(), "jmp qword ptr [r12]");1992 try expectEqualHexStrings("\x41\xFF\x24\x24", isel.lowered(), "jmp qword ptr [r12]");
2088 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0, .word_ptr), isel.code());1993 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.word_ptr, .{ .disp = 0, .base = .r12 }), isel.code());
2089 try expectEqualHexStrings("\x66\x41\xFF\x24\x24", isel.lowered(), "jmp word ptr [r12]");1994 try expectEqualHexStrings("\x66\x41\xFF\x24\x24", isel.lowered(), "jmp word ptr [r12]");
2090 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0x10, .qword_ptr), isel.code());1995 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10, .base = .r12 }), isel.code());
2091 try expectEqualHexStrings("\x41\xFF\x64\x24\x10", isel.lowered(), "jmp qword ptr [r12 + 0x10]");1996 try expectEqualHexStrings("\x41\xFF\x64\x24\x10", isel.lowered(), "jmp qword ptr [r12 + 0x10]");
2092 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0x1000, .qword_ptr), isel.code());1997 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{
1998 .disp = 0x1000,
1999 .base = .r12,
2000 }), isel.code());
2093 try expectEqualHexStrings(2001 try expectEqualHexStrings(
2094 "\x41\xFF\xA4\x24\x00\x10\x00\x00",2002 "\x41\xFF\xA4\x24\x00\x10\x00\x00",
2095 isel.lowered(),2003 isel.lowered(),
2096 "jmp qword ptr [r12 + 0x1000]",2004 "jmp qword ptr [r12 + 0x1000]",
2097 );2005 );
2098 try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(0x10, .qword_ptr), isel.code());2006 try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code());
2099 try expectEqualHexStrings("\xFF\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [rip + 0x10]");2007 try expectEqualHexStrings("\xFF\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [rip + 0x10]");
2100 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(null, 0x10, .qword_ptr), isel.code());2008 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10 }), isel.code());
2101 try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [ds:0x10]");2009 try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [ds:0x10]");
2102 try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), isel.code());2010 try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), isel.code());
2103 try expectEqualHexStrings("\x41\x0F\x97\xC3", isel.lowered(), "seta r11b");2011 try expectEqualHexStrings("\x41\x0F\x97\xC3", isel.lowered(), "seta r11b");
...@@ -2115,15 +2023,24 @@ test "lower O encoding" {...@@ -2115,15 +2023,24 @@ test "lower O encoding" {
2115test "lower RMI encoding" {2023test "lower RMI encoding" {
2116 var isel = TestIsel.init();2024 var isel = TestIsel.init();
2117 defer isel.deinit();2025 defer isel.deinit();
2118 try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.rbp, -8, .qword_ptr), 0x10, isel.code());2026 try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.qword_ptr, .{
2027 .disp = -8,
2028 .base = .rbp,
2029 }), 0x10, isel.code());
2119 try expectEqualHexStrings(2030 try expectEqualHexStrings(
2120 "\x48\x69\x45\xF8\x10\x00\x00\x00",2031 "\x48\x69\x45\xF8\x10\x00\x00\x00",
2121 isel.lowered(),2032 isel.lowered(),
2122 "imul rax, qword ptr [rbp - 8], 0x10",2033 "imul rax, qword ptr [rbp - 8], 0x10",
2123 );2034 );
2124 try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.rbp, -4, .dword_ptr), 0x10, isel.code());2035 try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.dword_ptr, .{
2036 .disp = -4,
2037 .base = .rbp,
2038 }), 0x10, isel.code());
2125 try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", isel.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");2039 try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", isel.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");
2126 try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.rbp, -2, .word_ptr), 0x10, isel.code());2040 try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.word_ptr, .{
2041 .disp = -2,
2042 .base = .rbp,
2043 }), 0x10, isel.code());
2127 try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", isel.lowered(), "imul ax, word ptr [rbp - 2], 0x10");2044 try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", isel.lowered(), "imul ax, word ptr [rbp - 2], 0x10");
2128 try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, isel.code());2045 try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, isel.code());
2129 try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", isel.lowered(), "imul r12, r12, 0x10");2046 try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", isel.lowered(), "imul r12, r12, 0x10");
src/arch/x86_64/Mir.zig+1
...@@ -167,6 +167,7 @@ pub const Inst = struct {...@@ -167,6 +167,7 @@ pub const Inst = struct {
167 /// 0b00 reg1, [ds:imm32]167 /// 0b00 reg1, [ds:imm32]
168 /// 0b01 reg1, [rip + imm32]168 /// 0b01 reg1, [rip + imm32]
169 /// 0b10 reg1, [rip + reloc]169 /// 0b10 reg1, [rip + reloc]
170 /// 0b11 reg1, [reg2 + rcx + imm32]
170 /// Notes:171 /// Notes:
171 /// * if flags are 0b10, `Data` contains `got_entry` for the linker to generate172 /// * if flags are 0b10, `Data` contains `got_entry` for the linker to generate
172 /// a valid relocation for.173 /// a valid relocation for.
test/behavior.zig+199-195
...@@ -1,210 +1,214 @@...@@ -1,210 +1,214 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
22
3test {3test {
4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, and arm backend.4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.
5 _ = @import("behavior/bugs/679.zig");
6 _ = @import("behavior/bugs/1111.zig");5 _ = @import("behavior/bugs/1111.zig");
7 _ = @import("behavior/bugs/2346.zig");6 _ = @import("behavior/bugs/2346.zig");
8 _ = @import("behavior/bugs/3586.zig");7 _ = @import("behavior/bugs/3586.zig");
9 _ = @import("behavior/bugs/4560.zig");
10 _ = @import("behavior/bugs/6850.zig");
11 _ = @import("behavior/slice_sentinel_comptime.zig");8 _ = @import("behavior/slice_sentinel_comptime.zig");
12 _ = @import("behavior/fn_in_struct_in_comptime.zig");
13 _ = @import("behavior/hasfield.zig");
14 _ = @import("behavior/hasdecl.zig");
15 _ = @import("behavior/pub_enum.zig");
16 _ = @import("behavior/type_info.zig");
17 _ = @import("behavior/type.zig");
189
19 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .arm) {10 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .x86_64) {
20 // Tests that pass for stage1, llvm backend, C backend, wasm backend.11 // Tests that pass for stage1, llvm backend, C backend, wasm backend, and arm backend.
21 _ = @import("behavior/basic.zig");12 _ = @import("behavior/bugs/679.zig");
22 _ = @import("behavior/bitcast.zig");13 _ = @import("behavior/bugs/4560.zig");
23 _ = @import("behavior/bool.zig");14 _ = @import("behavior/bugs/6850.zig");
24 _ = @import("behavior/bugs/624.zig");15 _ = @import("behavior/fn_in_struct_in_comptime.zig");
25 _ = @import("behavior/bugs/655.zig");16 _ = @import("behavior/hasfield.zig");
26 _ = @import("behavior/bugs/704.zig");17 _ = @import("behavior/hasdecl.zig");
27 _ = @import("behavior/bugs/1486.zig");18 _ = @import("behavior/pub_enum.zig");
28 _ = @import("behavior/bugs/2692.zig");19 _ = @import("behavior/type_info.zig");
29 _ = @import("behavior/bugs/2889.zig");20 _ = @import("behavior/type.zig");
30 _ = @import("behavior/bugs/3046.zig");
31 _ = @import("behavior/bugs/4769_a.zig");
32 _ = @import("behavior/bugs/4769_b.zig");
33 _ = @import("behavior/bugs/4954.zig");
34 _ = @import("behavior/byval_arg_var.zig");
35 _ = @import("behavior/call.zig");
36 _ = @import("behavior/defer.zig");
37 _ = @import("behavior/enum.zig");
38 _ = @import("behavior/error.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/pointers.zig");
44 _ = @import("behavior/ptrcast.zig");
45 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
46 _ = @import("behavior/truncate.zig");
47 _ = @import("behavior/usingnamespace.zig");
48 _ = @import("behavior/underscore.zig");
4921
50 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .wasm32) {22 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .arm) {
51 // Tests that pass for stage1, llvm backend, C backend23 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
52 _ = @import("behavior/align.zig");24 _ = @import("behavior/basic.zig");
53 _ = @import("behavior/array.zig");25 _ = @import("behavior/bitcast.zig");
54 _ = @import("behavior/cast.zig");26 _ = @import("behavior/bool.zig");
55 _ = @import("behavior/for.zig");27 _ = @import("behavior/bugs/624.zig");
56 _ = @import("behavior/generics.zig");28 _ = @import("behavior/bugs/655.zig");
57 _ = @import("behavior/int128.zig");29 _ = @import("behavior/bugs/704.zig");
58 _ = @import("behavior/member_func.zig");30 _ = @import("behavior/bugs/1486.zig");
59 _ = @import("behavior/null.zig");31 _ = @import("behavior/bugs/2692.zig");
60 _ = @import("behavior/optional.zig");32 _ = @import("behavior/bugs/2889.zig");
61 _ = @import("behavior/struct.zig");33 _ = @import("behavior/bugs/3046.zig");
62 _ = @import("behavior/this.zig");34 _ = @import("behavior/bugs/4769_a.zig");
63 _ = @import("behavior/translate_c_macros.zig");35 _ = @import("behavior/bugs/4769_b.zig");
64 _ = @import("behavior/while.zig");36 _ = @import("behavior/bugs/4954.zig");
65 _ = @import("behavior/void.zig");37 _ = @import("behavior/byval_arg_var.zig");
38 _ = @import("behavior/call.zig");
39 _ = @import("behavior/defer.zig");
40 _ = @import("behavior/enum.zig");
41 _ = @import("behavior/error.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/pointers.zig");
47 _ = @import("behavior/ptrcast.zig");
48 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
49 _ = @import("behavior/truncate.zig");
50 _ = @import("behavior/usingnamespace.zig");
51 _ = @import("behavior/underscore.zig");
6652
67 if (builtin.object_format != .c) {53 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .wasm32) {
68 // Tests that pass for stage1 and the llvm backend.54 // Tests that pass for stage1, llvm backend, C backend
69 _ = @import("behavior/align_llvm.zig");55 _ = @import("behavior/align.zig");
70 _ = @import("behavior/alignof.zig");56 _ = @import("behavior/array.zig");
71 _ = @import("behavior/array_llvm.zig");57 _ = @import("behavior/cast.zig");
72 _ = @import("behavior/atomics.zig");58 _ = @import("behavior/for.zig");
73 _ = @import("behavior/basic_llvm.zig");59 _ = @import("behavior/generics.zig");
74 _ = @import("behavior/bugs/394.zig");60 _ = @import("behavior/int128.zig");
75 _ = @import("behavior/bugs/656.zig");61 _ = @import("behavior/member_func.zig");
76 _ = @import("behavior/bugs/1277.zig");62 _ = @import("behavior/null.zig");
77 _ = @import("behavior/bugs/1310.zig");63 _ = @import("behavior/optional.zig");
78 _ = @import("behavior/bugs/1381.zig");64 _ = @import("behavior/struct.zig");
79 _ = @import("behavior/bugs/1500.zig");65 _ = @import("behavior/this.zig");
80 _ = @import("behavior/bugs/1741.zig");66 _ = @import("behavior/translate_c_macros.zig");
81 _ = @import("behavior/bugs/2006.zig");67 _ = @import("behavior/while.zig");
82 _ = @import("behavior/bugs/2578.zig");68 _ = @import("behavior/void.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");
10869
109 if (builtin.zig_is_stage2) {70 if (builtin.object_format != .c) {
110 // When all comptime_memory.zig tests pass, #9646 can be closed.71 // Tests that pass for stage1 and the llvm backend.
111 // _ = @import("behavior/comptime_memory.zig");72 _ = @import("behavior/align_llvm.zig");
112 _ = @import("behavior/slice_stage2.zig");73 _ = @import("behavior/alignof.zig");
113 } else {74 _ = @import("behavior/array_llvm.zig");
114 // Tests that only pass for the stage1 backend.75 _ = @import("behavior/atomics.zig");
115 _ = @import("behavior/align_stage1.zig");76 _ = @import("behavior/basic_llvm.zig");
116 _ = @import("behavior/array_stage1.zig");77 _ = @import("behavior/bugs/394.zig");
117 if (builtin.os.tag != .wasi) {78 _ = @import("behavior/bugs/656.zig");
118 _ = @import("behavior/asm.zig");79 _ = @import("behavior/bugs/1277.zig");
119 _ = @import("behavior/async_fn.zig");80 _ = @import("behavior/bugs/1310.zig");
120 }81 _ = @import("behavior/bugs/1381.zig");
121 _ = @import("behavior/await_struct.zig");82 _ = @import("behavior/bugs/1500.zig");
122 _ = @import("behavior/bit_shifting.zig");83 _ = @import("behavior/bugs/1741.zig");
123 _ = @import("behavior/bitcast_stage1.zig");84 _ = @import("behavior/bugs/2006.zig");
124 _ = @import("behavior/bitreverse.zig");85 _ = @import("behavior/bugs/2578.zig");
125 _ = @import("behavior/bugs/421.zig");86 _ = @import("behavior/bugs/3007.zig");
126 _ = @import("behavior/bugs/529.zig");87 _ = @import("behavior/bugs/3112.zig");
127 _ = @import("behavior/bugs/718.zig");88 _ = @import("behavior/bugs/3367.zig");
128 _ = @import("behavior/bugs/726.zig");89 _ = @import("behavior/bugs/7250.zig");
129 _ = @import("behavior/bugs/828.zig");90 _ = @import("behavior/bugs/9584.zig");
130 _ = @import("behavior/bugs/920.zig");91 _ = @import("behavior/cast_llvm.zig");
131 _ = @import("behavior/bugs/1025.zig");92 _ = @import("behavior/enum_llvm.zig");
132 _ = @import("behavior/bugs/1076.zig");93 _ = @import("behavior/eval.zig");
133 _ = @import("behavior/bugs/1120.zig");94 _ = @import("behavior/floatop.zig");
134 _ = @import("behavior/bugs/1421.zig");95 _ = @import("behavior/fn.zig");
135 _ = @import("behavior/bugs/1442.zig");96 _ = @import("behavior/generics_llvm.zig");
136 _ = @import("behavior/bugs/1607.zig");97 _ = @import("behavior/math.zig");
137 _ = @import("behavior/bugs/1735.zig");98 _ = @import("behavior/maximum_minimum.zig");
138 _ = @import("behavior/bugs/1851.zig");99 _ = @import("behavior/namespace_depends_on_compile_var.zig");
139 _ = @import("behavior/bugs/1914.zig");100 _ = @import("behavior/null_llvm.zig");
140 _ = @import("behavior/bugs/2114.zig");101 _ = @import("behavior/optional_llvm.zig");
141 _ = @import("behavior/bugs/3384.zig");102 _ = @import("behavior/popcount.zig");
142 _ = @import("behavior/bugs/3742.zig");103 _ = @import("behavior/saturating_arithmetic.zig");
143 _ = @import("behavior/bugs/3779.zig");104 _ = @import("behavior/sizeof_and_typeof.zig");
144 _ = @import("behavior/bugs/4328.zig");105 _ = @import("behavior/slice.zig");
145 _ = @import("behavior/bugs/5398.zig");106 _ = @import("behavior/struct_llvm.zig");
146 _ = @import("behavior/bugs/5413.zig");107 _ = @import("behavior/switch.zig");
147 _ = @import("behavior/bugs/5474.zig");108 _ = @import("behavior/undefined.zig");
148 _ = @import("behavior/bugs/5487.zig");109 _ = @import("behavior/union.zig");
149 _ = @import("behavior/bugs/6456.zig");110 _ = @import("behavior/widening.zig");
150 _ = @import("behavior/bugs/6781.zig");111
151 _ = @import("behavior/bugs/7003.zig");112 if (builtin.zig_is_stage2) {
152 _ = @import("behavior/bugs/7027.zig");113 // When all comptime_memory.zig tests pass, #9646 can be closed.
153 _ = @import("behavior/bugs/7047.zig");114 // _ = @import("behavior/comptime_memory.zig");
154 _ = @import("behavior/bugs/10147.zig");115 _ = @import("behavior/slice_stage2.zig");
155 _ = @import("behavior/byteswap.zig");116 } else {
156 _ = @import("behavior/call_stage1.zig");117 // Tests that only pass for the stage1 backend.
157 _ = @import("behavior/cast_stage1.zig");118 _ = @import("behavior/align_stage1.zig");
158 _ = @import("behavior/const_slice_child.zig");119 _ = @import("behavior/array_stage1.zig");
159 _ = @import("behavior/defer_stage1.zig");120 if (builtin.os.tag != .wasi) {
160 _ = @import("behavior/enum_stage1.zig");121 _ = @import("behavior/asm.zig");
161 _ = @import("behavior/error_stage1.zig");122 _ = @import("behavior/async_fn.zig");
162 _ = @import("behavior/eval_stage1.zig");123 }
163 _ = @import("behavior/field_parent_ptr.zig");124 _ = @import("behavior/await_struct.zig");
164 _ = @import("behavior/floatop_stage1.zig");125 _ = @import("behavior/bit_shifting.zig");
165 _ = @import("behavior/fn_stage1.zig");126 _ = @import("behavior/bitcast_stage1.zig");
166 _ = @import("behavior/fn_delegation.zig");127 _ = @import("behavior/bitreverse.zig");
167 _ = @import("behavior/for_stage1.zig");128 _ = @import("behavior/bugs/421.zig");
168 _ = @import("behavior/if_stage1.zig");129 _ = @import("behavior/bugs/529.zig");
169 _ = @import("behavior/ir_block_deps.zig");130 _ = @import("behavior/bugs/718.zig");
170 _ = @import("behavior/math_stage1.zig");131 _ = @import("behavior/bugs/726.zig");
171 _ = @import("behavior/merge_error_sets.zig");132 _ = @import("behavior/bugs/828.zig");
172 _ = @import("behavior/misc.zig");133 _ = @import("behavior/bugs/920.zig");
173 _ = @import("behavior/muladd.zig");134 _ = @import("behavior/bugs/1025.zig");
174 _ = @import("behavior/null_stage1.zig");135 _ = @import("behavior/bugs/1076.zig");
175 _ = @import("behavior/optional_stage1.zig");136 _ = @import("behavior/bugs/1120.zig");
176 _ = @import("behavior/pointers_stage1.zig");137 _ = @import("behavior/bugs/1421.zig");
177 _ = @import("behavior/popcount_stage1.zig");138 _ = @import("behavior/bugs/1442.zig");
178 _ = @import("behavior/prefetch.zig");139 _ = @import("behavior/bugs/1607.zig");
179 _ = @import("behavior/ptrcast_stage1.zig");140 _ = @import("behavior/bugs/1735.zig");
180 _ = @import("behavior/reflection.zig");141 _ = @import("behavior/bugs/1851.zig");
181 _ = @import("behavior/saturating_arithmetic_stage1.zig");142 _ = @import("behavior/bugs/1914.zig");
182 _ = @import("behavior/select.zig");143 _ = @import("behavior/bugs/2114.zig");
183 _ = @import("behavior/shuffle.zig");144 _ = @import("behavior/bugs/3384.zig");
184 _ = @import("behavior/sizeof_and_typeof_stage1.zig");145 _ = @import("behavior/bugs/3742.zig");
185 _ = @import("behavior/slice_stage1.zig");146 _ = @import("behavior/bugs/3779.zig");
186 _ = @import("behavior/struct_contains_null_ptr_itself.zig");147 _ = @import("behavior/bugs/4328.zig");
187 _ = @import("behavior/struct_contains_slice_of_itself.zig");148 _ = @import("behavior/bugs/5398.zig");
188 _ = @import("behavior/struct_stage1.zig");149 _ = @import("behavior/bugs/5413.zig");
189 _ = @import("behavior/switch_prong_err_enum.zig");150 _ = @import("behavior/bugs/5474.zig");
190 _ = @import("behavior/switch_prong_implicit_cast.zig");151 _ = @import("behavior/bugs/5487.zig");
191 _ = @import("behavior/switch_stage1.zig");152 _ = @import("behavior/bugs/6456.zig");
192 _ = @import("behavior/truncate_stage1.zig");153 _ = @import("behavior/bugs/6781.zig");
193 _ = @import("behavior/try.zig");154 _ = @import("behavior/bugs/7003.zig");
194 _ = @import("behavior/tuple.zig");155 _ = @import("behavior/bugs/7027.zig");
195 _ = @import("behavior/type_stage1.zig");156 _ = @import("behavior/bugs/7047.zig");
196 _ = @import("behavior/type_info_stage1.zig");157 _ = @import("behavior/bugs/10147.zig");
197 _ = @import("behavior/typename.zig");158 _ = @import("behavior/byteswap.zig");
198 _ = @import("behavior/union_stage1.zig");159 _ = @import("behavior/call_stage1.zig");
199 _ = @import("behavior/union_with_members.zig");160 _ = @import("behavior/cast_stage1.zig");
200 _ = @import("behavior/var_args.zig");161 _ = @import("behavior/const_slice_child.zig");
201 _ = @import("behavior/vector.zig");162 _ = @import("behavior/defer_stage1.zig");
202 if (builtin.target.cpu.arch == .wasm32) {163 _ = @import("behavior/enum_stage1.zig");
203 _ = @import("behavior/wasm.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");
204 }211 }
205 _ = @import("behavior/while_stage1.zig");
206 _ = @import("behavior/src.zig");
207 _ = @import("behavior/translate_c_macros_stage1.zig");
208 }212 }
209 }213 }
210 }214 }
test/stage2/x86_64.zig+23
...@@ -1738,6 +1738,29 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1738,6 +1738,29 @@ pub fn addCases(ctx: *TestContext) !void {
1738 \\}1738 \\}
1739 , "");1739 , "");
1740 }1740 }
1741
1742 {
1743 var case = ctx.exe("unwrap error union - simple errors", target);
1744 case.addCompareOutput(
1745 \\pub fn main() void {
1746 \\ maybeErr() catch unreachable;
1747 \\}
1748 \\
1749 \\fn maybeErr() !void {
1750 \\ return;
1751 \\}
1752 , "");
1753 case.addCompareOutput(
1754 \\pub fn main() void {
1755 \\ maybeErr() catch return;
1756 \\ unreachable;
1757 \\}
1758 \\
1759 \\fn maybeErr() !void {
1760 \\ return error.NoWay;
1761 \\}
1762 , "");
1763 }
1741 }1764 }
1742}1765}
17431766