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 {
415415
416416 try self.genBody(self.air.getMainBody());
417417
418 if (self.exitlude_jump_relocs.items.len == 1) {
419 self.mir_instructions.len -= 1;
420 } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {
418 // TODO can single exitlude jump reloc be elided? What if it is not at the end of the code?
419 // Example:
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| {
421426 self.mir_instructions.items(.data)[jmp_reloc].inst = @intCast(u32, self.mir_instructions.len);
422427 }
423428
......@@ -1180,19 +1185,24 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
11801185
11811186fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
11821187 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1183 const result: MCValue = if (self.liveness.isUnused(inst))
1184 .dead
1185 else
1186 return self.fail("TODO implement unwrap error union error for {}", .{self.target.cpu.arch});
1188 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1189 const err_union_ty = self.air.typeOf(ty_op.operand);
1190 const payload_ty = err_union_ty.errorUnionPayload();
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 };
11871195 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11881196}
11891197
11901198fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
11911199 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1192 const result: MCValue = if (self.liveness.isUnused(inst))
1193 .dead
1194 else
1195 return self.fail("TODO implement unwrap error union payload for {}", .{self.target.cpu.arch});
1200 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1201 const err_union_ty = self.air.typeOf(ty_op.operand);
1202 const payload_ty = err_union_ty.errorUnionPayload();
1203 if (!payload_ty.hasCodeGenBits()) break :result MCValue.none;
1204 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1205 };
11961206 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11971207}
11981208
......@@ -1261,10 +1271,14 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
12611271
12621272fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
12631273 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1264 const result: MCValue = if (self.liveness.isUnused(inst))
1265 .dead
1266 else
1267 return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch});
1274 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1275 const operand = try self.resolveInst(ty_op.operand);
1276 const dst_mcv: MCValue = switch (operand) {
1277 .stack_offset => |off| MCValue{ .stack_offset = off + 8 },
1278 else => return self.fail("TODO implement slice_len for {}", .{operand}),
1279 };
1280 break :result dst_mcv;
1281 };
12681282 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12691283}
12701284
......@@ -1289,10 +1303,57 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
12891303fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
12901304 const is_volatile = false; // TODO
12911305 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1292 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst))
1293 .dead
1294 else
1295 return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch});
1306 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: {
1307 const slice_mcv = try self.resolveInst(bin_op.lhs);
1308 const slice_ty = self.air.typeOf(bin_op.lhs);
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 };
12961357 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12971358}
12981359
......@@ -1427,10 +1488,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
14271488 .embedded_in_code => {
14281489 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
14291490 },
1430 .register => |reg| try self.setRegOrMem(elem_ty, dst_mcv, .{ .register = reg }),
1491 .register => |reg| try self.setRegOrMem(ptr_ty, dst_mcv, .{ .register = reg }),
14311492 .memory => |addr| {
1432 const reg = try self.register_manager.allocReg(null, &.{});
1433 try self.genSetReg(ptr_ty, reg, .{ .memory = addr });
1493 const reg = try self.copyToTmpRegister(ptr_ty, .{ .memory = addr });
14341494 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
14351495 },
14361496 .stack_offset => {
......@@ -1505,28 +1565,60 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
15051565fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
15061566 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
15071567 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 });
15091570}
15101571
15111572fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
15121573 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 });
15141576}
1515fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void {
1516 _ = self;
1517 _ = operand;
1518 _ = ty;
1519 _ = index;
1520 return self.fail("TODO implement codegen struct_field_ptr", .{});
1521 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
1577
1578fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
1579 return if (self.liveness.isUnused(inst)) .dead else result: {
1580 const mcv = try self.resolveInst(operand);
1581 const struct_ty = self.air.typeOf(operand).childType();
1582 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
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 };
15221596}
15231597
15241598fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
15251599 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
15261600 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
1527 _ = extra;
1528 return self.fail("TODO implement codegen struct_field_val", .{});
1529 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
1601 const operand = extra.struct_operand;
1602 const index = extra.field_index;
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 });
15301622}
15311623
15321624/// Perform "binary" operators, excluding comparisons.
......@@ -1778,6 +1870,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
17781870 .data = .{ .imm = @intCast(i32, imm) },
17791871 });
17801872 } else {
1873 // TODO verify we don't spill and assign to the same register as dst_mcv
17811874 const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);
17821875 return self.genIMulOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });
17831876 }
......@@ -1887,10 +1980,16 @@ fn airFence(self: *Self) !void {
18871980
18881981fn airCall(self: *Self, inst: Air.Inst.Index) !void {
18891982 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1890 const fn_ty = self.air.typeOf(pl_op.operand);
18911983 const callee = pl_op.operand;
18921984 const extra = self.air.extraData(Air.Call, pl_op.payload);
18931985 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
18951994 var info = try self.resolveCallingConventionValues(fn_ty);
18961995 defer info.deinit(self);
......@@ -1957,7 +2056,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
19572056 return self.fail("TODO implement calling bitcasted functions", .{});
19582057 }
19592058 } 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);
19612062 }
19622063 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
19632064 for (info.args) |mc_arg, arg_i| {
......@@ -2000,7 +2101,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
20002101 const func = func_payload.data;
20012102 // TODO I'm hacking my way through here by repurposing .memory for storing
20022103 // index to the GOT target symbol index.
2003 try self.genSetReg(Type.initTag(.u64), .rax, .{
2104 try self.genSetReg(Type.initTag(.usize), .rax, .{
20042105 .memory = func.owner_decl.link.macho.local_sym_index,
20052106 });
20062107 // callq *%rax
......@@ -2024,7 +2125,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
20242125 return self.fail("TODO implement calling bitcasted functions", .{});
20252126 }
20262127 } 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);
20282131 }
20292132 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
20302133 for (info.args) |mc_arg, arg_i| {
......@@ -2142,12 +2245,19 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
21422245
21432246fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
21442247 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2145 if (self.liveness.isUnused(inst))
2248
2249 if (self.liveness.isUnused(inst)) {
21462250 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2251 }
2252
21472253 const ty = self.air.typeOf(bin_op.lhs);
2148 assert(ty.eql(self.air.typeOf(bin_op.rhs)));
2149 if (ty.zigTypeTag() == .ErrorSet)
2150 return self.fail("TODO implement cmp for errors", .{});
2254 const signedness: std.builtin.Signedness = blk: {
2255 // For non-int types, we treat the values as unsigned
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
21522262 const lhs = try self.resolveInst(bin_op.lhs);
21532263 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -2163,9 +2273,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
21632273 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);
21642274
21652275 try self.genBinMathOpMir(.cmp, ty, dst_mcv, src_mcv);
2166 break :result switch (ty.isSignedInt()) {
2167 true => MCValue{ .compare_flags_signed = op },
2168 false => MCValue{ .compare_flags_unsigned = op },
2276 break :result switch (signedness) {
2277 .signed => MCValue{ .compare_flags_signed = op },
2278 .unsigned => MCValue{ .compare_flags_unsigned = op },
21692279 };
21702280 };
21712281 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 {
22742384 const parent_registers = self.register_manager.registers;
22752385
22762386 try self.branch_stack.append(.{});
2387 errdefer {
2388 _ = self.branch_stack.pop();
2389 }
22772390
22782391 try self.ensureProcessDeathCapacity(liveness_condbr.then_deaths.len);
22792392 for (liveness_condbr.then_deaths) |operand| {
......@@ -2393,19 +2506,35 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
23932506}
23942507
23952508fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2396 _ = ty;
2397 _ = operand;
2398 // Here you can specialize this instruction if it makes sense to, otherwise the default
2399 // will call isNonErr and invert the result.
2400 return self.fail("TODO call isNonErr and invert the result", .{});
2509 const err_type = ty.errorUnionSet();
2510 const payload_type = ty.errorUnionPayload();
2511 if (!err_type.hasCodeGenBits()) {
2512 return MCValue{ .immediate = 0 }; // always false
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 }
24012523}
24022524
24032525fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2404 _ = ty;
2405 _ = operand;
2406 // Here you can specialize this instruction if it makes sense to, otherwise the default
2407 // will call isErr and invert the result.
2408 return self.fail("TODO call isErr and invert the result", .{});
2526 const is_err_res = try self.isErr(ty, operand);
2527 switch (is_err_res) {
2528 .compare_flags_unsigned => |op| {
2529 assert(op == .gt);
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 }
24092538}
24102539
24112540fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2877,12 +3006,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
28773006 },
28783007 }
28793008 },
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 },
28863009 .register => |reg| {
28873010 if (stack_offset > math.maxInt(i32)) {
28883011 return self.fail("stack offset too large", .{});
......@@ -2899,23 +3022,137 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
28993022 .data = .{ .imm = -@intCast(i32, adj_off) },
29003023 });
29013024 },
2902 .memory => |vaddr| {
2903 _ = vaddr;
2904 return self.fail("TODO implement set stack variable from memory vaddr", .{});
3025 .memory, .embedded_in_code => {
3026 if (ty.abiSize(self.target.*) <= 8) {
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});
29053031 },
2906 .stack_offset => |off| {
2907 // TODO this and `.embedded_in_code` above need to get improved to support types greater than
2908 // register size, and do general memcpy
3032 .stack_offset => |unadjusted_off| {
3033 if (stack_offset == unadjusted_off) {
3034 // 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)
2911 return; // Copy stack variable to itself; nothing to do.
3058 // TODO allow for abi_size to be u64
3059 try self.genSetReg(Type.initTag(.u32), len_reg, .{ .immediate = @intCast(u32, abi_size) });
29123060
2913 const reg = try self.copyToTmpRegister(ty, mcv);
2914 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3061 return self.genInlineMemcpy(-@intCast(i32, off), addr_reg.to64(), len_reg.to64());
29153062 },
29163063 }
29173064}
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
29193156/// Set pointee via pointer stored in a register.
29203157/// mov [reg], value
29213158fn genSetPtrReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
......@@ -3436,31 +3673,32 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
34363673 }
34373674 },
34383675 .ErrorSet => {
3439 switch (typed_value.val.tag()) {
3440 .@"error" => {
3441 const err_name = typed_value.val.castTag(.@"error").?.data.name;
3442 const module = self.bin_file.options.module.?;
3443 const global_error_set = module.global_error_set;
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 }
3676 const err_name = typed_value.val.castTag(.@"error").?.data.name;
3677 const module = self.bin_file.options.module.?;
3678 const global_error_set = module.global_error_set;
3679 const error_index = global_error_set.get(err_name).?;
3680 return MCValue{ .immediate = error_index };
34523681 },
34533682 .ErrorUnion => {
34543683 const error_type = typed_value.ty.errorUnionSet();
34553684 const payload_type = typed_value.ty.errorUnionPayload();
3456 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
34573685
3458 if (!payload_type.hasCodeGenBits()) {
3459 // We use the error type directly as the type.
3460 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
3686 if (typed_value.val.castTag(.eu_payload)) |pl| {
3687 if (!payload_type.hasCodeGenBits()) {
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 }
34613699 }
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});
34643702 },
34653703 else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}),
34663704 }
......@@ -3557,8 +3795,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
35573795 .Naked => unreachable,
35583796 .Unspecified, .C => {
35593797 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);
3561 result.return_value = .{ .register = aliased_reg };
3798 if (ret_ty_size <= 8) {
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 }
35623804 },
35633805 else => return self.fail("TODO implement function return values for {}", .{cc}),
35643806 }
src/arch/x86_64/Isel.zig+294-377
......@@ -227,8 +227,10 @@ fn mirPushPop(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
227227 16 => .word_ptr,
228228 else => .qword_ptr,
229229 };
230 return lowerToMEnc(tag, RegisterOrMemory.mem(ops.reg1, imm, ptr_size), isel.code) catch |err|
231 isel.failWithLoweringError(err);
230 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{
231 .disp = imm,
232 .base = ops.reg1,
233 }), isel.code) catch |err| isel.failWithLoweringError(err);
232234 },
233235 0b10 => {
234236 // PUSH imm32
......@@ -284,7 +286,7 @@ fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
284286 16 => .word_ptr,
285287 else => .qword_ptr,
286288 };
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|
288290 isel.failWithLoweringError(err);
289291 }
290292 // JMP/CALL reg
......@@ -422,12 +424,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
422424 // RM
423425 const imm = isel.mir.instructions.items(.data)[inst].imm;
424426 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
425 return lowerToRmEnc(
426 tag,
427 ops.reg1,
428 RegisterOrMemory.mem(src_reg, imm, Memory.PtrSize.fromBits(ops.reg1.size())),
429 isel.code,
430 ) catch |err| isel.failWithLoweringError(err);
427 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
428 .disp = imm,
429 .base = src_reg,
430 }), isel.code) catch |err| isel.failWithLoweringError(err);
431431 },
432432 0b10 => {
433433 if (ops.reg2 == .none) {
......@@ -436,12 +436,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
436436 // mov [reg1 + imm32], reg2
437437 // MR
438438 const imm = isel.mir.instructions.items(.data)[inst].imm;
439 return lowerToMrEnc(
440 tag,
441 RegisterOrMemory.mem(ops.reg1, imm, Memory.PtrSize.fromBits(ops.reg2.size())),
442 ops.reg2,
443 isel.code,
444 ) catch |err| isel.failWithLoweringError(err);
439 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
440 .disp = imm,
441 .base = ops.reg1,
442 }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
445443 },
446444 0b11 => {
447445 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 {
460458 0b10 => .dword_ptr,
461459 0b11 => .qword_ptr,
462460 };
463 return lowerToMiEnc(
464 tag,
465 RegisterOrMemory.mem(ops.reg1, imm_pair.dest_off, ptr_size),
466 imm_pair.operand,
467 isel.code,
468 ) catch |err| isel.failWithLoweringError(err);
461 return lowerToMiEnc(tag, RegisterOrMemory.mem(ptr_size, .{
462 .disp = imm_pair.dest_off,
463 .base = ops.reg1,
464 }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);
469465}
470466
471467inline fn setRexWRegister(reg: Register) bool {
......@@ -492,103 +488,61 @@ inline fn immOpSize(imm: i64) u8 {
492488 return 64;
493489}
494490
495// TODO
496491fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
497492 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
498493 const scale = ops.flags;
499 // OP reg1, [reg2 + scale*rcx + imm32]
500 const opc = getOpCode(tag, .rm, ops.reg1.size() == 8).?;
501494 const imm = isel.mir.instructions.items(.data)[inst].imm;
502 const encoder = try Encoder.init(isel.code, 8);
503 encoder.rex(.{
504 .w = ops.reg1.size() == 64,
505 .r = ops.reg1.isExtended(),
506 .b = ops.reg2.isExtended(),
507 });
508 opc.encode(encoder);
509 if (imm <= math.maxInt(i8)) {
510 encoder.modRm_SIBDisp8(ops.reg1.lowId());
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 }
495 // OP reg1, [reg2 + scale*rcx + imm32]
496 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
497 .disp = imm,
498 .base = ops.reg2,
499 .scale_index = .{
500 .scale = scale,
501 .index = .rcx,
502 },
503 }), isel.code) catch |err| isel.failWithLoweringError(err);
518504}
519505
520// TODO
521506fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
522507 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
523508 const scale = ops.flags;
524509 const imm = isel.mir.instructions.items(.data)[inst].imm;
525
526510 if (ops.reg2 == .none) {
527 // OP [reg1 + scale*rax + 0], imm32
528 const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?;
529 const modrm_ext = getModRmExt(tag).?;
530 const encoder = try Encoder.init(isel.code, 8);
531 encoder.rex(.{
532 .w = ops.reg1.size() == 64,
533 .b = ops.reg1.isExtended(),
534 });
535 opc.encode(encoder);
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;
511 // OP qword ptr [reg1 + scale*rax + 0], imm32
512 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{
513 .disp = 0,
514 .base = ops.reg1,
515 .scale_index = .{
516 .scale = scale,
517 .index = .rax,
518 },
519 }), imm, isel.code) catch |err| isel.failWithLoweringError(err);
546520 }
547
548521 // OP [reg1 + scale*rax + imm32], reg2
549 const opc = getOpCode(tag, .mr, ops.reg1.size() == 8).?;
550 const encoder = try Encoder.init(isel.code, 8);
551 encoder.rex(.{
552 .w = ops.reg1.size() == 64,
553 .r = ops.reg2.isExtended(),
554 .b = ops.reg1.isExtended(),
555 });
556 opc.encode(encoder);
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 }
522 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
523 .disp = imm,
524 .base = ops.reg1,
525 .scale_index = .{
526 .scale = scale,
527 .index = .rax,
528 },
529 }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
566530}
567531
568// TODO
569532fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
570533 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
571534 const scale = ops.flags;
572535 const payload = isel.mir.instructions.items(.data)[inst].payload;
573536 const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data;
574 const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?;
575 const modrm_ext = getModRmExt(tag).?;
576 const encoder = try Encoder.init(isel.code, 2);
577 encoder.rex(.{
578 .w = ops.reg1.size() == 64,
579 .b = ops.reg1.isExtended(),
580 });
581 opc.encode(encoder);
582 if (imm_pair.dest_off <= math.maxInt(i8)) {
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);
537 // OP qword ptr [reg1 + scale*rax + imm32], imm32
538 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{
539 .disp = imm_pair.dest_off,
540 .base = ops.reg1,
541 .scale_index = .{
542 .scale = scale,
543 .index = .rax,
544 },
545 }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);
592546}
593547
594548fn mirMovabs(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
......@@ -646,7 +600,10 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
646600 return lowerToRmEnc(
647601 .lea,
648602 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 }),
650607 isel.code,
651608 ) catch |err| isel.failWithLoweringError(err);
652609 },
......@@ -657,7 +614,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
657614 lowerToRmEnc(
658615 .lea,
659616 ops.reg1,
660 RegisterOrMemory.rip(0, Memory.PtrSize.fromBits(ops.reg1.size())),
617 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
661618 isel.code,
662619 ) catch |err| return isel.failWithLoweringError(err);
663620 const end_offset = isel.code.items.len;
......@@ -673,7 +630,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
673630 lowerToRmEnc(
674631 .lea,
675632 ops.reg1,
676 RegisterOrMemory.rip(0, Memory.PtrSize.fromBits(ops.reg1.size())),
633 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
677634 isel.code,
678635 ) catch |err| return isel.failWithLoweringError(err);
679636 const end_offset = isel.code.items.len;
......@@ -697,7 +654,24 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
697654 );
698655 }
699656 },
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 },
701675 }
702676}
703677
......@@ -1230,18 +1204,17 @@ inline fn getModRmExt(tag: Tag) ?u3 {
12301204 };
12311205}
12321206
1233const ScaleIndexBase = struct {
1207const ScaleIndex = struct {
12341208 scale: u2,
1235 index_reg: ?Register,
1236 base_reg: ?Register,
1209 index: Register,
12371210};
12381211
12391212const Memory = struct {
1240 reg: ?Register,
1213 base: ?Register,
12411214 rip: bool = false,
12421215 disp: i32,
12431216 ptr_size: PtrSize,
1244 sib: ?ScaleIndexBase = null,
1217 scale_index: ?ScaleIndex = null,
12451218
12461219 const PtrSize = enum {
12471220 byte_ptr,
......@@ -1269,8 +1242,72 @@ const Memory = struct {
12691242 };
12701243 }
12711244 };
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 }
12721300};
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
12741311const RegisterOrMemory = union(enum) {
12751312 register: Register,
12761313 memory: Memory,
......@@ -1279,20 +1316,25 @@ const RegisterOrMemory = union(enum) {
12791316 return .{ .register = register };
12801317 }
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 {
12831324 return .{
12841325 .memory = .{
1285 .reg = register,
1286 .disp = disp,
1326 .base = args.base,
1327 .disp = args.disp,
12871328 .ptr_size = ptr_size,
1329 .scale_index = args.scale_index,
12881330 },
12891331 };
12901332 }
12911333
1292 fn rip(disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory {
1334 fn rip(ptr_size: Memory.PtrSize, disp: i32) RegisterOrMemory {
12931335 return .{
12941336 .memory = .{
1295 .reg = null,
1337 .base = null,
12961338 .rip = true,
12971339 .disp = disp,
12981340 .ptr_size = ptr_size,
......@@ -1325,16 +1367,10 @@ fn lowerToIEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) LoweringError!void
13251367 const opc = getOpCode(tag, .i, immOpSize(imm) == 8).?;
13261368 const encoder = try Encoder.init(code, 5);
13271369 if (immOpSize(imm) == 16) {
1328 encoder.opcode_1byte(0x66);
1370 encoder.prefix16BitMode();
13291371 }
13301372 opc.encode(encoder);
1331 if (immOpSize(imm) == 8) {
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 }
1373 encodeImm(encoder, imm, immOpSize(imm));
13381374}
13391375
13401376fn 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!
13441380 const opc = getOpCode(tag, .o, false).?;
13451381 const encoder = try Encoder.init(code, 3);
13461382 if (reg.size() == 16) {
1347 encoder.opcode_1byte(0x66);
1383 encoder.prefix16BitMode();
13481384 }
13491385 encoder.rex(.{
13501386 .w = false,
......@@ -1375,7 +1411,7 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
13751411 }
13761412 const encoder = try Encoder.init(code, 4);
13771413 if (reg.size() == 16) {
1378 encoder.opcode_1byte(0x66);
1414 encoder.prefix16BitMode();
13791415 }
13801416 encoder.rex(.{
13811417 .w = switch (reg) {
......@@ -1393,51 +1429,19 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
13931429 }
13941430 const encoder = try Encoder.init(code, 8);
13951431 if (mem_op.ptr_size == .word_ptr) {
1396 encoder.opcode_1byte(0x66);
1432 encoder.prefix16BitMode();
13971433 }
1398 if (mem_op.reg) |reg| {
1399 if (reg.size() != 64) {
1434 if (mem_op.base) |base| {
1435 if (base.size() != 64) {
14001436 return error.OperandSizeMismatch;
14011437 }
14021438 encoder.rex(.{
14031439 .w = false,
1404 .b = reg.isExtended(),
1440 .b = base.isExtended(),
14051441 });
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);
14401442 }
1443 opc.encode(encoder);
1444 mem_op.encode(encoder, modrm_ext);
14411445 },
14421446 }
14431447}
......@@ -1463,7 +1467,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8),
14631467 getOpCode(tag, .fd, reg.size() == 8).?;
14641468 const encoder = try Encoder.init(code, 10);
14651469 if (reg.size() == 16) {
1466 encoder.opcode_1byte(0x66);
1470 encoder.prefix16BitMode();
14671471 }
14681472 encoder.rex(.{
14691473 .w = setRexWRegister(reg),
......@@ -1496,7 +1500,7 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) Low
14961500 const opc = getOpCode(tag, .oi, reg.size() == 8).?;
14971501 const encoder = try Encoder.init(code, 10);
14981502 if (reg.size() == 16) {
1499 encoder.opcode_1byte(0x66);
1503 encoder.prefix16BitMode();
15001504 }
15011505 encoder.rex(.{
15021506 .w = setRexWRegister(reg),
......@@ -1533,7 +1537,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr
15331537 // 0x66 prefix switches to the non-default size; here we assume a switch from
15341538 // the default 32bits to 16bits operand-size.
15351539 // 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();
15371541 }
15381542 encoder.rex(.{
15391543 .w = setRexWRegister(dst_reg),
......@@ -1541,81 +1545,30 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr
15411545 });
15421546 opc.encode(encoder);
15431547 encoder.modRm_direct(modrm_ext, dst_reg.lowId());
1544 switch (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 }
1548 encodeImm(encoder, imm, dst_reg.size());
15561549 },
15571550 .memory => |dst_mem| {
15581551 const opc = getOpCode(tag, .mi, dst_mem.ptr_size == .byte_ptr).?;
15591552 const encoder = try Encoder.init(code, 12);
15601553 if (dst_mem.ptr_size == .word_ptr) {
1561 encoder.opcode_1byte(0x66);
1554 encoder.prefix16BitMode();
15621555 }
1563 if (dst_mem.reg) |dst_reg| {
1564 if (dst_reg.size() != 64) {
1556 if (dst_mem.base) |base| {
1557 if (base.size() != 64) {
15651558 return error.OperandSizeMismatch;
15661559 }
15671560 encoder.rex(.{
15681561 .w = dst_mem.ptr_size == .qword_ptr,
1569 .b = dst_reg.isExtended(),
1562 .b = base.isExtended(),
15701563 });
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 }
15961564 } else {
1597 opc.encode(encoder);
1598 if (dst_mem.rip) {
1599 encoder.modRm_RIPDisp32(modrm_ext);
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 },
1565 encoder.rex(.{
1566 .w = dst_mem.ptr_size == .qword_ptr,
1567 });
16181568 }
1569 opc.encode(encoder);
1570 dst_mem.encode(encoder, modrm_ext);
1571 encodeImm(encoder, imm, dst_mem.ptr_size.size());
16191572 },
16201573 }
16211574}
......@@ -1647,58 +1600,27 @@ fn lowerToRmEnc(
16471600 }
16481601 const encoder = try Encoder.init(code, 9);
16491602 if (reg.size() == 16) {
1650 encoder.opcode_1byte(0x66);
1603 encoder.prefix16BitMode();
16511604 }
1652 if (src_mem.reg) |src_reg| {
1605 if (src_mem.base) |base| {
16531606 // TODO handle 32-bit base register - requires prefix 0x67
16541607 // Intel Manual, Vol 1, chapter 3.6 and 3.6.1
1655 if (src_reg.size() != 64) {
1608 if (base.size() != 64) {
16561609 return error.OperandSizeMismatch;
16571610 }
16581611 encoder.rex(.{
16591612 .w = setRexWRegister(reg),
16601613 .r = reg.isExtended(),
1661 .b = src_reg.isExtended(),
1614 .b = base.isExtended(),
16621615 });
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 }
16881616 } else {
16891617 encoder.rex(.{
16901618 .w = setRexWRegister(reg),
16911619 .r = reg.isExtended(),
16921620 });
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);
17011621 }
1622 opc.encode(encoder);
1623 src_mem.encode(encoder, reg.lowId());
17021624 },
17031625 }
17041626}
......@@ -1730,56 +1652,25 @@ fn lowerToMrEnc(
17301652 }
17311653 const encoder = try Encoder.init(code, 9);
17321654 if (reg.size() == 16) {
1733 encoder.opcode_1byte(0x66);
1655 encoder.prefix16BitMode();
17341656 }
1735 if (dst_mem.reg) |dst_reg| {
1736 if (dst_reg.size() != 64) {
1657 if (dst_mem.base) |base| {
1658 if (base.size() != 64) {
17371659 return error.OperandSizeMismatch;
17381660 }
17391661 encoder.rex(.{
17401662 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),
17411663 .r = reg.isExtended(),
1742 .b = dst_reg.isExtended(),
1664 .b = base.isExtended(),
17431665 });
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 }
17691666 } else {
17701667 encoder.rex(.{
17711668 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),
17721669 .r = reg.isExtended(),
17731670 });
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);
17821671 }
1672 opc.encode(encoder);
1673 dst_mem.encode(encoder, reg.lowId());
17831674 },
17841675 }
17851676}
......@@ -1797,7 +1688,7 @@ fn lowerToRmiEnc(
17971688 const opc = getOpCode(tag, .rmi, false).?;
17981689 const encoder = try Encoder.init(code, 13);
17991690 if (reg.size() == 16) {
1800 encoder.opcode_1byte(0x66);
1691 encoder.prefix16BitMode();
18011692 }
18021693 switch (reg_or_mem) {
18031694 .register => |src_reg| {
......@@ -1813,10 +1704,10 @@ fn lowerToRmiEnc(
18131704 encoder.modRm_direct(reg.lowId(), src_reg.lowId());
18141705 },
18151706 .memory => |src_mem| {
1816 if (src_mem.reg) |src_reg| {
1707 if (src_mem.base) |base| {
18171708 // TODO handle 32-bit base register - requires prefix 0x67
18181709 // Intel Manual, Vol 1, chapter 3.6 and 3.6.1
1819 if (src_reg.size() != 64) {
1710 if (base.size() != 64) {
18201711 return error.OperandSizeMismatch;
18211712 }
18221713 if (src_mem.ptr_size == .byte_ptr) {
......@@ -1825,59 +1716,19 @@ fn lowerToRmiEnc(
18251716 encoder.rex(.{
18261717 .w = setRexWRegister(reg),
18271718 .r = reg.isExtended(),
1828 .b = src_reg.isExtended(),
1719 .b = base.isExtended(),
18291720 });
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 }
18551721 } else {
18561722 encoder.rex(.{
18571723 .w = setRexWRegister(reg),
18581724 .r = reg.isExtended(),
18591725 });
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);
18681726 }
1727 opc.encode(encoder);
1728 src_mem.encode(encoder, reg.lowId());
18691729 },
18701730 }
1871 switch (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 }
1731 encodeImm(encoder, imm, reg.size());
18811732}
18821733
18831734fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []const u8) !void {
......@@ -1930,44 +1781,62 @@ test "lower MI encoding" {
19301781 defer isel.deinit();
19311782 try lowerToMiEnc(.mov, RegisterOrMemory.reg(.rax), 0x10, isel.code());
19321783 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());
19341785 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());
19361787 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());
19381792 try expectEqualHexStrings(
19391793 "\x41\x81\xab\x00\x00\x00\x10\x10\x00\x00\x00",
19401794 isel.lowered(),
19411795 "sub dword ptr [r11 + 0x10000000], 0x10",
19421796 );
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());
19441798 try expectEqualHexStrings(
19451799 "\x81\x24\x25\x00\x00\x00\x10\x10\x00\x00\x00",
19461800 isel.lowered(),
19471801 "and dword ptr [ds:0x10000000], 0x10",
19481802 );
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());
19501807 try expectEqualHexStrings(
19511808 "\x41\x81\xA4\x24\x00\x00\x00\x10\x10\x00\x00\x00",
19521809 isel.lowered(),
19531810 "and dword ptr [r12 + 0x10000000], 0x10",
19541811 );
1955 try lowerToMiEnc(.mov, RegisterOrMemory.rip(0x10, .qword_ptr), 0x10, isel.code());
1812 try lowerToMiEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), 0x10, isel.code());
19561813 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",
19581815 isel.lowered(),
19591816 "mov qword ptr [rip + 0x10], 0x10",
19601817 );
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());
19621819 try expectEqualHexStrings(
19631820 "\x48\xc7\x45\xf8\x10\x00\x00\x00",
19641821 isel.lowered(),
19651822 "mov qword ptr [rbp - 8], 0x10",
19661823 );
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());
19681825 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());
19701827 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 );
19711840}
19721841
19731842test "lower RM encoding" {
......@@ -1975,36 +1844,69 @@ test "lower RM encoding" {
19751844 defer isel.deinit();
19761845 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), isel.code());
19771846 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());
19791848 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());
19811850 try expectEqualHexStrings(
19821851 "\x4C\x03\x1C\x25\x00\x00\x00\x10",
19831852 isel.lowered(),
19841853 "add r11, qword ptr [ds:0x10000000]",
19851854 );
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());
19871856 try expectEqualHexStrings(
19881857 "\x44\x02\x24\x25\x00\x00\x00\x10",
19891858 isel.lowered(),
19901859 "add r11b, byte ptr [ds:0x10000000]",
19911860 );
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());
19931865 try expectEqualHexStrings(
19941866 "\x4D\x2B\x9D\x00\x00\x00\x10",
19951867 isel.lowered(),
19961868 "sub r11, qword ptr [r13 + 0x10000000]",
19971869 );
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());
19991874 try expectEqualHexStrings(
20001875 "\x4D\x2B\x9C\x24\x00\x00\x00\x10",
20011876 isel.lowered(),
20021877 "sub r11, qword ptr [r12 + 0x10000000]",
20031878 );
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());
20051880 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());
20071882 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]");
20081910}
20091911
20101912test "lower MR encoding" {
......@@ -2012,27 +1914,30 @@ test "lower MR encoding" {
20121914 defer isel.deinit();
20131915 try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, isel.code());
20141916 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());
20161918 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());
20181920 try expectEqualHexStrings(
20191921 "\x44\x00\x24\x25\x00\x00\x00\x10",
20201922 isel.lowered(),
20211923 "add byte ptr [ds:0x10000000], r12b",
20221924 );
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());
20241926 try expectEqualHexStrings(
20251927 "\x44\x01\x24\x25\x00\x00\x00\x10",
20261928 isel.lowered(),
20271929 "add dword ptr [ds:0x10000000], r12d",
20281930 );
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());
20301935 try expectEqualHexStrings(
20311936 "\x4D\x29\xA3\x00\x00\x00\x10",
20321937 isel.lowered(),
20331938 "sub qword ptr [r11 + 0x10000000], r12",
20341939 );
2035 try lowerToMrEnc(.mov, RegisterOrMemory.rip(0x10, .qword_ptr), .r12, isel.code());
1940 try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), .r12, isel.code());
20361941 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", isel.lowered(), "mov qword ptr [rip + 0x10], r12");
20371942}
20381943
......@@ -2083,21 +1988,24 @@ test "lower M encoding" {
20831988 try expectEqualHexStrings("\x41\xFF\xE4", isel.lowered(), "jmp r12");
20841989 try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12w), isel.code());
20851990 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());
20871992 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());
20891994 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());
20911996 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());
20932001 try expectEqualHexStrings(
20942002 "\x41\xFF\xA4\x24\x00\x10\x00\x00",
20952003 isel.lowered(),
20962004 "jmp qword ptr [r12 + 0x1000]",
20972005 );
2098 try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(0x10, .qword_ptr), isel.code());
2006 try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code());
20992007 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());
21012009 try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [ds:0x10]");
21022010 try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), isel.code());
21032011 try expectEqualHexStrings("\x41\x0F\x97\xC3", isel.lowered(), "seta r11b");
......@@ -2115,15 +2023,24 @@ test "lower O encoding" {
21152023test "lower RMI encoding" {
21162024 var isel = TestIsel.init();
21172025 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());
21192030 try expectEqualHexStrings(
21202031 "\x48\x69\x45\xF8\x10\x00\x00\x00",
21212032 isel.lowered(),
21222033 "imul rax, qword ptr [rbp - 8], 0x10",
21232034 );
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());
21252039 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());
21272044 try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", isel.lowered(), "imul ax, word ptr [rbp - 2], 0x10");
21282045 try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, isel.code());
21292046 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 {
167167 /// 0b00 reg1, [ds:imm32]
168168 /// 0b01 reg1, [rip + imm32]
169169 /// 0b10 reg1, [rip + reloc]
170 /// 0b11 reg1, [reg2 + rcx + imm32]
170171 /// Notes:
171172 /// * if flags are 0b10, `Data` contains `got_entry` for the linker to generate
172173 /// a valid relocation for.
test/behavior.zig+199-195
......@@ -1,210 +1,214 @@
11const builtin = @import("builtin");
22
33test {
4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, and arm backend.
5 _ = @import("behavior/bugs/679.zig");
4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.
65 _ = @import("behavior/bugs/1111.zig");
76 _ = @import("behavior/bugs/2346.zig");
87 _ = @import("behavior/bugs/3586.zig");
9 _ = @import("behavior/bugs/4560.zig");
10 _ = @import("behavior/bugs/6850.zig");
118 _ = @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) {
20 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
21 _ = @import("behavior/basic.zig");
22 _ = @import("behavior/bitcast.zig");
23 _ = @import("behavior/bool.zig");
24 _ = @import("behavior/bugs/624.zig");
25 _ = @import("behavior/bugs/655.zig");
26 _ = @import("behavior/bugs/704.zig");
27 _ = @import("behavior/bugs/1486.zig");
28 _ = @import("behavior/bugs/2692.zig");
29 _ = @import("behavior/bugs/2889.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");
10 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .x86_64) {
11 // Tests that pass for stage1, llvm backend, C backend, wasm backend, and arm backend.
12 _ = @import("behavior/bugs/679.zig");
13 _ = @import("behavior/bugs/4560.zig");
14 _ = @import("behavior/bugs/6850.zig");
15 _ = @import("behavior/fn_in_struct_in_comptime.zig");
16 _ = @import("behavior/hasfield.zig");
17 _ = @import("behavior/hasdecl.zig");
18 _ = @import("behavior/pub_enum.zig");
19 _ = @import("behavior/type_info.zig");
20 _ = @import("behavior/type.zig");
4921
50 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .wasm32) {
51 // Tests that pass for stage1, llvm backend, C backend
52 _ = @import("behavior/align.zig");
53 _ = @import("behavior/array.zig");
54 _ = @import("behavior/cast.zig");
55 _ = @import("behavior/for.zig");
56 _ = @import("behavior/generics.zig");
57 _ = @import("behavior/int128.zig");
58 _ = @import("behavior/member_func.zig");
59 _ = @import("behavior/null.zig");
60 _ = @import("behavior/optional.zig");
61 _ = @import("behavior/struct.zig");
62 _ = @import("behavior/this.zig");
63 _ = @import("behavior/translate_c_macros.zig");
64 _ = @import("behavior/while.zig");
65 _ = @import("behavior/void.zig");
22 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .arm) {
23 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
24 _ = @import("behavior/basic.zig");
25 _ = @import("behavior/bitcast.zig");
26 _ = @import("behavior/bool.zig");
27 _ = @import("behavior/bugs/624.zig");
28 _ = @import("behavior/bugs/655.zig");
29 _ = @import("behavior/bugs/704.zig");
30 _ = @import("behavior/bugs/1486.zig");
31 _ = @import("behavior/bugs/2692.zig");
32 _ = @import("behavior/bugs/2889.zig");
33 _ = @import("behavior/bugs/3046.zig");
34 _ = @import("behavior/bugs/4769_a.zig");
35 _ = @import("behavior/bugs/4769_b.zig");
36 _ = @import("behavior/bugs/4954.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) {
68 // Tests that pass for stage1 and the llvm backend.
69 _ = @import("behavior/align_llvm.zig");
70 _ = @import("behavior/alignof.zig");
71 _ = @import("behavior/array_llvm.zig");
72 _ = @import("behavior/atomics.zig");
73 _ = @import("behavior/basic_llvm.zig");
74 _ = @import("behavior/bugs/394.zig");
75 _ = @import("behavior/bugs/656.zig");
76 _ = @import("behavior/bugs/1277.zig");
77 _ = @import("behavior/bugs/1310.zig");
78 _ = @import("behavior/bugs/1381.zig");
79 _ = @import("behavior/bugs/1500.zig");
80 _ = @import("behavior/bugs/1741.zig");
81 _ = @import("behavior/bugs/2006.zig");
82 _ = @import("behavior/bugs/2578.zig");
83 _ = @import("behavior/bugs/3007.zig");
84 _ = @import("behavior/bugs/3112.zig");
85 _ = @import("behavior/bugs/3367.zig");
86 _ = @import("behavior/bugs/7250.zig");
87 _ = @import("behavior/bugs/9584.zig");
88 _ = @import("behavior/cast_llvm.zig");
89 _ = @import("behavior/enum_llvm.zig");
90 _ = @import("behavior/eval.zig");
91 _ = @import("behavior/floatop.zig");
92 _ = @import("behavior/fn.zig");
93 _ = @import("behavior/generics_llvm.zig");
94 _ = @import("behavior/math.zig");
95 _ = @import("behavior/maximum_minimum.zig");
96 _ = @import("behavior/namespace_depends_on_compile_var.zig");
97 _ = @import("behavior/null_llvm.zig");
98 _ = @import("behavior/optional_llvm.zig");
99 _ = @import("behavior/popcount.zig");
100 _ = @import("behavior/saturating_arithmetic.zig");
101 _ = @import("behavior/sizeof_and_typeof.zig");
102 _ = @import("behavior/slice.zig");
103 _ = @import("behavior/struct_llvm.zig");
104 _ = @import("behavior/switch.zig");
105 _ = @import("behavior/undefined.zig");
106 _ = @import("behavior/union.zig");
107 _ = @import("behavior/widening.zig");
53 if (!builtin.zig_is_stage2 or builtin.stage2_arch != .wasm32) {
54 // Tests that pass for stage1, llvm backend, C backend
55 _ = @import("behavior/align.zig");
56 _ = @import("behavior/array.zig");
57 _ = @import("behavior/cast.zig");
58 _ = @import("behavior/for.zig");
59 _ = @import("behavior/generics.zig");
60 _ = @import("behavior/int128.zig");
61 _ = @import("behavior/member_func.zig");
62 _ = @import("behavior/null.zig");
63 _ = @import("behavior/optional.zig");
64 _ = @import("behavior/struct.zig");
65 _ = @import("behavior/this.zig");
66 _ = @import("behavior/translate_c_macros.zig");
67 _ = @import("behavior/while.zig");
68 _ = @import("behavior/void.zig");
10869
109 if (builtin.zig_is_stage2) {
110 // When all comptime_memory.zig tests pass, #9646 can be closed.
111 // _ = @import("behavior/comptime_memory.zig");
112 _ = @import("behavior/slice_stage2.zig");
113 } else {
114 // Tests that only pass for the stage1 backend.
115 _ = @import("behavior/align_stage1.zig");
116 _ = @import("behavior/array_stage1.zig");
117 if (builtin.os.tag != .wasi) {
118 _ = @import("behavior/asm.zig");
119 _ = @import("behavior/async_fn.zig");
120 }
121 _ = @import("behavior/await_struct.zig");
122 _ = @import("behavior/bit_shifting.zig");
123 _ = @import("behavior/bitcast_stage1.zig");
124 _ = @import("behavior/bitreverse.zig");
125 _ = @import("behavior/bugs/421.zig");
126 _ = @import("behavior/bugs/529.zig");
127 _ = @import("behavior/bugs/718.zig");
128 _ = @import("behavior/bugs/726.zig");
129 _ = @import("behavior/bugs/828.zig");
130 _ = @import("behavior/bugs/920.zig");
131 _ = @import("behavior/bugs/1025.zig");
132 _ = @import("behavior/bugs/1076.zig");
133 _ = @import("behavior/bugs/1120.zig");
134 _ = @import("behavior/bugs/1421.zig");
135 _ = @import("behavior/bugs/1442.zig");
136 _ = @import("behavior/bugs/1607.zig");
137 _ = @import("behavior/bugs/1735.zig");
138 _ = @import("behavior/bugs/1851.zig");
139 _ = @import("behavior/bugs/1914.zig");
140 _ = @import("behavior/bugs/2114.zig");
141 _ = @import("behavior/bugs/3384.zig");
142 _ = @import("behavior/bugs/3742.zig");
143 _ = @import("behavior/bugs/3779.zig");
144 _ = @import("behavior/bugs/4328.zig");
145 _ = @import("behavior/bugs/5398.zig");
146 _ = @import("behavior/bugs/5413.zig");
147 _ = @import("behavior/bugs/5474.zig");
148 _ = @import("behavior/bugs/5487.zig");
149 _ = @import("behavior/bugs/6456.zig");
150 _ = @import("behavior/bugs/6781.zig");
151 _ = @import("behavior/bugs/7003.zig");
152 _ = @import("behavior/bugs/7027.zig");
153 _ = @import("behavior/bugs/7047.zig");
154 _ = @import("behavior/bugs/10147.zig");
155 _ = @import("behavior/byteswap.zig");
156 _ = @import("behavior/call_stage1.zig");
157 _ = @import("behavior/cast_stage1.zig");
158 _ = @import("behavior/const_slice_child.zig");
159 _ = @import("behavior/defer_stage1.zig");
160 _ = @import("behavior/enum_stage1.zig");
161 _ = @import("behavior/error_stage1.zig");
162 _ = @import("behavior/eval_stage1.zig");
163 _ = @import("behavior/field_parent_ptr.zig");
164 _ = @import("behavior/floatop_stage1.zig");
165 _ = @import("behavior/fn_stage1.zig");
166 _ = @import("behavior/fn_delegation.zig");
167 _ = @import("behavior/for_stage1.zig");
168 _ = @import("behavior/if_stage1.zig");
169 _ = @import("behavior/ir_block_deps.zig");
170 _ = @import("behavior/math_stage1.zig");
171 _ = @import("behavior/merge_error_sets.zig");
172 _ = @import("behavior/misc.zig");
173 _ = @import("behavior/muladd.zig");
174 _ = @import("behavior/null_stage1.zig");
175 _ = @import("behavior/optional_stage1.zig");
176 _ = @import("behavior/pointers_stage1.zig");
177 _ = @import("behavior/popcount_stage1.zig");
178 _ = @import("behavior/prefetch.zig");
179 _ = @import("behavior/ptrcast_stage1.zig");
180 _ = @import("behavior/reflection.zig");
181 _ = @import("behavior/saturating_arithmetic_stage1.zig");
182 _ = @import("behavior/select.zig");
183 _ = @import("behavior/shuffle.zig");
184 _ = @import("behavior/sizeof_and_typeof_stage1.zig");
185 _ = @import("behavior/slice_stage1.zig");
186 _ = @import("behavior/struct_contains_null_ptr_itself.zig");
187 _ = @import("behavior/struct_contains_slice_of_itself.zig");
188 _ = @import("behavior/struct_stage1.zig");
189 _ = @import("behavior/switch_prong_err_enum.zig");
190 _ = @import("behavior/switch_prong_implicit_cast.zig");
191 _ = @import("behavior/switch_stage1.zig");
192 _ = @import("behavior/truncate_stage1.zig");
193 _ = @import("behavior/try.zig");
194 _ = @import("behavior/tuple.zig");
195 _ = @import("behavior/type_stage1.zig");
196 _ = @import("behavior/type_info_stage1.zig");
197 _ = @import("behavior/typename.zig");
198 _ = @import("behavior/union_stage1.zig");
199 _ = @import("behavior/union_with_members.zig");
200 _ = @import("behavior/var_args.zig");
201 _ = @import("behavior/vector.zig");
202 if (builtin.target.cpu.arch == .wasm32) {
203 _ = @import("behavior/wasm.zig");
70 if (builtin.object_format != .c) {
71 // Tests that pass for stage1 and the llvm backend.
72 _ = @import("behavior/align_llvm.zig");
73 _ = @import("behavior/alignof.zig");
74 _ = @import("behavior/array_llvm.zig");
75 _ = @import("behavior/atomics.zig");
76 _ = @import("behavior/basic_llvm.zig");
77 _ = @import("behavior/bugs/394.zig");
78 _ = @import("behavior/bugs/656.zig");
79 _ = @import("behavior/bugs/1277.zig");
80 _ = @import("behavior/bugs/1310.zig");
81 _ = @import("behavior/bugs/1381.zig");
82 _ = @import("behavior/bugs/1500.zig");
83 _ = @import("behavior/bugs/1741.zig");
84 _ = @import("behavior/bugs/2006.zig");
85 _ = @import("behavior/bugs/2578.zig");
86 _ = @import("behavior/bugs/3007.zig");
87 _ = @import("behavior/bugs/3112.zig");
88 _ = @import("behavior/bugs/3367.zig");
89 _ = @import("behavior/bugs/7250.zig");
90 _ = @import("behavior/bugs/9584.zig");
91 _ = @import("behavior/cast_llvm.zig");
92 _ = @import("behavior/enum_llvm.zig");
93 _ = @import("behavior/eval.zig");
94 _ = @import("behavior/floatop.zig");
95 _ = @import("behavior/fn.zig");
96 _ = @import("behavior/generics_llvm.zig");
97 _ = @import("behavior/math.zig");
98 _ = @import("behavior/maximum_minimum.zig");
99 _ = @import("behavior/namespace_depends_on_compile_var.zig");
100 _ = @import("behavior/null_llvm.zig");
101 _ = @import("behavior/optional_llvm.zig");
102 _ = @import("behavior/popcount.zig");
103 _ = @import("behavior/saturating_arithmetic.zig");
104 _ = @import("behavior/sizeof_and_typeof.zig");
105 _ = @import("behavior/slice.zig");
106 _ = @import("behavior/struct_llvm.zig");
107 _ = @import("behavior/switch.zig");
108 _ = @import("behavior/undefined.zig");
109 _ = @import("behavior/union.zig");
110 _ = @import("behavior/widening.zig");
111
112 if (builtin.zig_is_stage2) {
113 // When all comptime_memory.zig tests pass, #9646 can be closed.
114 // _ = @import("behavior/comptime_memory.zig");
115 _ = @import("behavior/slice_stage2.zig");
116 } else {
117 // Tests that only pass for the stage1 backend.
118 _ = @import("behavior/align_stage1.zig");
119 _ = @import("behavior/array_stage1.zig");
120 if (builtin.os.tag != .wasi) {
121 _ = @import("behavior/asm.zig");
122 _ = @import("behavior/async_fn.zig");
123 }
124 _ = @import("behavior/await_struct.zig");
125 _ = @import("behavior/bit_shifting.zig");
126 _ = @import("behavior/bitcast_stage1.zig");
127 _ = @import("behavior/bitreverse.zig");
128 _ = @import("behavior/bugs/421.zig");
129 _ = @import("behavior/bugs/529.zig");
130 _ = @import("behavior/bugs/718.zig");
131 _ = @import("behavior/bugs/726.zig");
132 _ = @import("behavior/bugs/828.zig");
133 _ = @import("behavior/bugs/920.zig");
134 _ = @import("behavior/bugs/1025.zig");
135 _ = @import("behavior/bugs/1076.zig");
136 _ = @import("behavior/bugs/1120.zig");
137 _ = @import("behavior/bugs/1421.zig");
138 _ = @import("behavior/bugs/1442.zig");
139 _ = @import("behavior/bugs/1607.zig");
140 _ = @import("behavior/bugs/1735.zig");
141 _ = @import("behavior/bugs/1851.zig");
142 _ = @import("behavior/bugs/1914.zig");
143 _ = @import("behavior/bugs/2114.zig");
144 _ = @import("behavior/bugs/3384.zig");
145 _ = @import("behavior/bugs/3742.zig");
146 _ = @import("behavior/bugs/3779.zig");
147 _ = @import("behavior/bugs/4328.zig");
148 _ = @import("behavior/bugs/5398.zig");
149 _ = @import("behavior/bugs/5413.zig");
150 _ = @import("behavior/bugs/5474.zig");
151 _ = @import("behavior/bugs/5487.zig");
152 _ = @import("behavior/bugs/6456.zig");
153 _ = @import("behavior/bugs/6781.zig");
154 _ = @import("behavior/bugs/7003.zig");
155 _ = @import("behavior/bugs/7027.zig");
156 _ = @import("behavior/bugs/7047.zig");
157 _ = @import("behavior/bugs/10147.zig");
158 _ = @import("behavior/byteswap.zig");
159 _ = @import("behavior/call_stage1.zig");
160 _ = @import("behavior/cast_stage1.zig");
161 _ = @import("behavior/const_slice_child.zig");
162 _ = @import("behavior/defer_stage1.zig");
163 _ = @import("behavior/enum_stage1.zig");
164 _ = @import("behavior/error_stage1.zig");
165 _ = @import("behavior/eval_stage1.zig");
166 _ = @import("behavior/field_parent_ptr.zig");
167 _ = @import("behavior/floatop_stage1.zig");
168 _ = @import("behavior/fn_stage1.zig");
169 _ = @import("behavior/fn_delegation.zig");
170 _ = @import("behavior/for_stage1.zig");
171 _ = @import("behavior/if_stage1.zig");
172 _ = @import("behavior/ir_block_deps.zig");
173 _ = @import("behavior/math_stage1.zig");
174 _ = @import("behavior/merge_error_sets.zig");
175 _ = @import("behavior/misc.zig");
176 _ = @import("behavior/muladd.zig");
177 _ = @import("behavior/null_stage1.zig");
178 _ = @import("behavior/optional_stage1.zig");
179 _ = @import("behavior/pointers_stage1.zig");
180 _ = @import("behavior/popcount_stage1.zig");
181 _ = @import("behavior/prefetch.zig");
182 _ = @import("behavior/ptrcast_stage1.zig");
183 _ = @import("behavior/reflection.zig");
184 _ = @import("behavior/saturating_arithmetic_stage1.zig");
185 _ = @import("behavior/select.zig");
186 _ = @import("behavior/shuffle.zig");
187 _ = @import("behavior/sizeof_and_typeof_stage1.zig");
188 _ = @import("behavior/slice_stage1.zig");
189 _ = @import("behavior/struct_contains_null_ptr_itself.zig");
190 _ = @import("behavior/struct_contains_slice_of_itself.zig");
191 _ = @import("behavior/struct_stage1.zig");
192 _ = @import("behavior/switch_prong_err_enum.zig");
193 _ = @import("behavior/switch_prong_implicit_cast.zig");
194 _ = @import("behavior/switch_stage1.zig");
195 _ = @import("behavior/truncate_stage1.zig");
196 _ = @import("behavior/try.zig");
197 _ = @import("behavior/tuple.zig");
198 _ = @import("behavior/type_stage1.zig");
199 _ = @import("behavior/type_info_stage1.zig");
200 _ = @import("behavior/typename.zig");
201 _ = @import("behavior/union_stage1.zig");
202 _ = @import("behavior/union_with_members.zig");
203 _ = @import("behavior/var_args.zig");
204 _ = @import("behavior/vector.zig");
205 if (builtin.target.cpu.arch == .wasm32) {
206 _ = @import("behavior/wasm.zig");
207 }
208 _ = @import("behavior/while_stage1.zig");
209 _ = @import("behavior/src.zig");
210 _ = @import("behavior/translate_c_macros_stage1.zig");
204211 }
205 _ = @import("behavior/while_stage1.zig");
206 _ = @import("behavior/src.zig");
207 _ = @import("behavior/translate_c_macros_stage1.zig");
208212 }
209213 }
210214 }
test/stage2/x86_64.zig+23
......@@ -1738,6 +1738,29 @@ pub fn addCases(ctx: *TestContext) !void {
17381738 \\}
17391739 , "");
17401740 }
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 }
17411764 }
17421765}
17431766