authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-18 22:23:58+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-18 22:23:58+01:00
loge80ebc6740d6bbe4b9b1958180a337804ff98450
tree7a4be1449a4fe3a69953d8319b82f33f376e75cc
parent305a7def136580e7a05652a95c1d2ff338541607
parent8201939d7f57d5332d209dd7fb728eafe5a8b882
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10625 from ziglang/stage2-x86_64-inline-memset

stage2: add inline memset, partial intcast and more array goodness for x86_64

7 files changed, 327 insertions(+), 71 deletions(-)

src/arch/x86_64/CodeGen.zig+206-59
......@@ -876,10 +876,26 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
876876 if (info_a.signedness != info_b.signedness)
877877 return self.fail("TODO gen intcast sign safety in semantic analysis", .{});
878878
879 if (info_a.bits == info_b.bits)
880 return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
879 const operand_abi_size = operand_ty.abiSize(self.target.*);
880 const dest_ty = self.air.typeOfIndex(inst);
881 const dest_abi_size = dest_ty.abiSize(self.target.*);
882 const dst_mcv: MCValue = blk: {
883 if (info_a.bits == info_b.bits) {
884 break :blk operand;
885 }
886 if (operand_abi_size > 8 or dest_abi_size > 8) {
887 return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
888 }
889 const reg = switch (operand) {
890 .register => |src_reg| try self.register_manager.allocReg(inst, &.{src_reg}),
891 else => try self.register_manager.allocReg(inst, &.{}),
892 };
893 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
894 try self.genSetReg(dest_ty, reg, operand);
895 break :blk .{ .register = registerAlias(reg, @intCast(u32, dest_abi_size)) };
896 };
881897
882 return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch});
898 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
883899}
884900
885901fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1312,59 +1328,49 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
13121328 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13131329}
13141330
1331fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {
1332 const reg = try self.register_manager.allocReg(null, &.{});
1333 try self.genSetReg(index_ty, reg, index);
1334 try self.genIMulOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size });
1335 return reg;
1336}
1337
13151338fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
13161339 const is_volatile = false; // TODO
13171340 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
13181341 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: {
13191342 const slice_mcv = try self.resolveInst(bin_op.lhs);
13201343 const slice_ty = self.air.typeOf(bin_op.lhs);
1321
13221344 const elem_ty = slice_ty.childType();
13231345 const elem_size = elem_ty.abiSize(self.target.*);
1324
13251346 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
13261347 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
1327
1328 const offset_reg = blk: {
1329 const index_ty = self.air.typeOf(bin_op.rhs);
1330 const index_mcv = try self.resolveInst(bin_op.rhs);
1331 const offset_reg = try self.register_manager.allocReg(null, &.{});
1332 try self.genSetReg(index_ty, offset_reg, index_mcv);
1333 try self.genIMulOpMir(index_ty, .{ .register = offset_reg }, .{ .immediate = elem_size });
1334 break :blk offset_reg;
1335 };
1336
1337 const dst_mcv = blk: {
1338 switch (slice_mcv) {
1339 .stack_offset => |off| {
1340 const dst_mcv = try self.allocRegOrMem(inst, false);
1341 const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg});
1342 // mov reg, [rbp - 8]
1343 _ = try self.addInst(.{
1344 .tag = .mov,
1345 .ops = (Mir.Ops{
1346 .reg1 = addr_reg.to64(),
1347 .reg2 = .rbp,
1348 .flags = 0b01,
1349 }).encode(),
1350 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) },
1351 });
1352 // add addr, offset
1353 _ = try self.addInst(.{
1354 .tag = .add,
1355 .ops = (Mir.Ops{
1356 .reg1 = addr_reg.to64(),
1357 .reg2 = offset_reg.to64(),
1358 }).encode(),
1359 .data = undefined,
1360 });
1361 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1362 break :blk dst_mcv;
1363 },
1364 else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}),
1365 }
1366 };
1367
1348 const index_ty = self.air.typeOf(bin_op.rhs);
1349 const index_mcv = try self.resolveInst(bin_op.rhs);
1350 const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size);
1351 const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg});
1352 switch (slice_mcv) {
1353 .stack_offset => |off| {
1354 // mov reg, [rbp - 8]
1355 _ = try self.addInst(.{
1356 .tag = .mov,
1357 .ops = (Mir.Ops{
1358 .reg1 = addr_reg.to64(),
1359 .reg2 = .rbp,
1360 .flags = 0b01,
1361 }).encode(),
1362 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) },
1363 });
1364 },
1365 else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}),
1366 }
1367 // TODO we could allocate register here, but need to except addr register and potentially
1368 // offset register.
1369 const dst_mcv = try self.allocRegOrMem(inst, false);
1370 try self.genBinMathOpMir(.add, slice_ptr_field_type, .unsigned, .{ .register = addr_reg.to64() }, .{
1371 .register = offset_reg.to64(),
1372 });
1373 try self.load(dst_mcv, .{ .register = addr_reg.to64() }, slice_ptr_field_type);
13681374 break :result dst_mcv;
13691375 };
13701376 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -1382,10 +1388,43 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
13821388
13831389fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
13841390 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1385 const result: MCValue = if (self.liveness.isUnused(inst))
1386 .dead
1387 else
1388 return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch});
1391 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1392 const array_ty = self.air.typeOf(bin_op.lhs);
1393 const array = try self.resolveInst(bin_op.lhs);
1394 const array_abi_size = array_ty.abiSize(self.target.*);
1395 const elem_ty = array_ty.childType();
1396 const elem_abi_size = elem_ty.abiSize(self.target.*);
1397 const index_ty = self.air.typeOf(bin_op.rhs);
1398 const index = try self.resolveInst(bin_op.rhs);
1399 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
1400 const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg});
1401 switch (array) {
1402 .stack_offset => |off| {
1403 // lea reg, [rbp]
1404 _ = try self.addInst(.{
1405 .tag = .lea,
1406 .ops = (Mir.Ops{
1407 .reg1 = addr_reg.to64(),
1408 .reg2 = .rbp,
1409 }).encode(),
1410 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + array_abi_size)) },
1411 });
1412 },
1413 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
1414 }
1415 // TODO we could allocate register here, but need to except addr register and potentially
1416 // offset register.
1417 const dst_mcv = try self.allocRegOrMem(inst, false);
1418 try self.genBinMathOpMir(
1419 .add,
1420 array_ty,
1421 .unsigned,
1422 .{ .register = addr_reg.to64() },
1423 .{ .register = offset_reg.to64() },
1424 );
1425 try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty);
1426 break :result dst_mcv;
1427 };
13891428 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
13901429}
13911430
......@@ -1402,10 +1441,27 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
14021441fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
14031442 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
14041443 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1405 const result: MCValue = if (self.liveness.isUnused(inst))
1406 .dead
1407 else
1408 return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch});
1444 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1445 const ptr_ty = self.air.typeOf(extra.lhs);
1446 const ptr = try self.resolveInst(extra.lhs);
1447 const elem_ty = ptr_ty.elemType2();
1448 const elem_abi_size = elem_ty.abiSize(self.target.*);
1449 const index_ty = self.air.typeOf(extra.rhs);
1450 const index = try self.resolveInst(extra.rhs);
1451 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
1452 const dst_mcv = blk: {
1453 switch (ptr) {
1454 .ptr_stack_offset => {
1455 const reg = try self.register_manager.allocReg(inst, &.{offset_reg});
1456 try self.genSetReg(ptr_ty, reg, ptr);
1457 break :blk .{ .register = reg };
1458 },
1459 else => return self.fail("TODO implement ptr_elem_ptr when ptr is {}", .{ptr}),
1460 }
1461 };
1462 try self.genBinMathOpMir(.add, ptr_ty, .unsigned, dst_mcv, .{ .register = offset_reg });
1463 break :result dst_mcv;
1464 };
14091465 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
14101466}
14111467
......@@ -3147,7 +3203,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
31473203 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
31483204 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
31493205 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3150 else => return self.fail("TODO implement memset", .{}),
3206 else => return self.genInlineMemset(ty, stack_offset, .{ .immediate = 0xaa }),
31513207 }
31523208 },
31533209 .compare_flags_unsigned => |op| {
......@@ -3397,6 +3453,97 @@ fn genInlineMemcpy(
33973453 try self.performReloc(loop_reloc);
33983454}
33993455
3456fn genInlineMemset(self: *Self, ty: Type, stack_offset: u32, value: MCValue) InnerError!void {
3457 try self.register_manager.getReg(.rax, null);
3458 const abi_size = ty.abiSize(self.target.*);
3459 const adj_off = stack_offset + abi_size;
3460 if (adj_off > 128) {
3461 return self.fail("TODO inline memset with large stack offset", .{});
3462 }
3463 const negative_offset = @bitCast(u32, -@intCast(i32, adj_off));
3464
3465 // We are actually counting `abi_size` bytes; however, we reuse the index register
3466 // as both the counter and offset scaler, hence we need to subtract one from `abi_size`
3467 // and count until -1.
3468 if (abi_size > math.maxInt(i32)) {
3469 // movabs rax, abi_size - 1
3470 const payload = try self.addExtra(Mir.Imm64.encode(abi_size - 1));
3471 _ = try self.addInst(.{
3472 .tag = .movabs,
3473 .ops = (Mir.Ops{
3474 .reg1 = .rax,
3475 }).encode(),
3476 .data = .{ .payload = payload },
3477 });
3478 } else {
3479 // mov rax, abi_size - 1
3480 _ = try self.addInst(.{
3481 .tag = .mov,
3482 .ops = (Mir.Ops{
3483 .reg1 = .rax,
3484 }).encode(),
3485 .data = .{ .imm = @truncate(u32, abi_size - 1) },
3486 });
3487 }
3488
3489 // loop:
3490 // cmp rax, -1
3491 const loop_start = try self.addInst(.{
3492 .tag = .cmp,
3493 .ops = (Mir.Ops{
3494 .reg1 = .rax,
3495 }).encode(),
3496 .data = .{ .imm = @bitCast(u32, @as(i32, -1)) },
3497 });
3498
3499 // je end
3500 const loop_reloc = try self.addInst(.{
3501 .tag = .cond_jmp_eq_ne,
3502 .ops = (Mir.Ops{ .flags = 0b01 }).encode(),
3503 .data = .{ .inst = undefined },
3504 });
3505
3506 switch (value) {
3507 .immediate => |x| {
3508 if (x > math.maxInt(i32)) {
3509 return self.fail("TODO inline memset for value immediate larger than 32bits", .{});
3510 }
3511 // mov byte ptr [rbp + rax + stack_offset], imm
3512 const payload = try self.addExtra(Mir.ImmPair{
3513 .dest_off = negative_offset,
3514 .operand = @truncate(u32, x),
3515 });
3516 _ = try self.addInst(.{
3517 .tag = .mov_mem_index_imm,
3518 .ops = (Mir.Ops{
3519 .reg1 = .rbp,
3520 }).encode(),
3521 .data = .{ .payload = payload },
3522 });
3523 },
3524 else => return self.fail("TODO inline memset for value of type {}", .{value}),
3525 }
3526
3527 // sub rax, 1
3528 _ = try self.addInst(.{
3529 .tag = .sub,
3530 .ops = (Mir.Ops{
3531 .reg1 = .rax,
3532 }).encode(),
3533 .data = .{ .imm = 1 },
3534 });
3535
3536 // jmp loop
3537 _ = try self.addInst(.{
3538 .tag = .jmp,
3539 .ops = (Mir.Ops{ .flags = 0b00 }).encode(),
3540 .data = .{ .inst = loop_start },
3541 });
3542
3543 // end:
3544 try self.performReloc(loop_reloc);
3545}
3546
34003547fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
34013548 switch (mcv) {
34023549 .dead => unreachable,
......@@ -3634,12 +3781,12 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
36343781 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
36353782 const ptr_ty = self.air.typeOf(ty_op.operand);
36363783 const ptr = try self.resolveInst(ty_op.operand);
3784 const array_ty = ptr_ty.childType();
3785 const array_len = array_ty.arrayLenIncludingSentinel();
36373786 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
36383787 const stack_offset = try self.allocMem(inst, 16, 16);
3639 const array_ty = ptr_ty.childType();
3640 const array_len = array_ty.arrayLenIncludingSentinel();
3641 try self.genSetStack(Type.initTag(.usize), stack_offset + 8, ptr);
3642 try self.genSetStack(Type.initTag(.u64), stack_offset + 16, .{ .immediate = array_len });
3788 try self.genSetStack(ptr_ty, stack_offset + 8, ptr);
3789 try self.genSetStack(Type.initTag(.u64), stack_offset, .{ .immediate = array_len });
36433790 break :blk .{ .stack_offset = stack_offset };
36443791 };
36453792 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
src/arch/x86_64/Emit.zig+34-1
......@@ -115,6 +115,16 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
115115 .cmp_scale_imm => try emit.mirArithScaleImm(.cmp, inst),
116116 .mov_scale_imm => try emit.mirArithScaleImm(.mov, inst),
117117
118 .adc_mem_index_imm => try emit.mirArithMemIndexImm(.adc, inst),
119 .add_mem_index_imm => try emit.mirArithMemIndexImm(.add, inst),
120 .sub_mem_index_imm => try emit.mirArithMemIndexImm(.sub, inst),
121 .xor_mem_index_imm => try emit.mirArithMemIndexImm(.xor, inst),
122 .and_mem_index_imm => try emit.mirArithMemIndexImm(.@"and", inst),
123 .or_mem_index_imm => try emit.mirArithMemIndexImm(.@"or", inst),
124 .sbb_mem_index_imm => try emit.mirArithMemIndexImm(.sbb, inst),
125 .cmp_mem_index_imm => try emit.mirArithMemIndexImm(.cmp, inst),
126 .mov_mem_index_imm => try emit.mirArithMemIndexImm(.mov, inst),
127
118128 .movabs => try emit.mirMovabs(inst),
119129
120130 .lea => try emit.mirLea(inst),
......@@ -549,6 +559,29 @@ fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
549559 }), imm_pair.operand, emit.code) catch |err| emit.failWithLoweringError(err);
550560}
551561
562fn mirArithMemIndexImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
563 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
564 assert(ops.reg2 == .none);
565 const payload = emit.mir.instructions.items(.data)[inst].payload;
566 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
567 const ptr_size: Memory.PtrSize = switch (ops.flags) {
568 0b00 => .byte_ptr,
569 0b01 => .word_ptr,
570 0b10 => .dword_ptr,
571 0b11 => .qword_ptr,
572 };
573 const scale_index = ScaleIndex{
574 .scale = 0,
575 .index = .rax,
576 };
577 // OP ptr [reg1 + rax*1 + imm32], imm32
578 return lowerToMiEnc(tag, RegisterOrMemory.mem(ptr_size, .{
579 .disp = imm_pair.dest_off,
580 .base = ops.reg1,
581 .scale_index = scale_index,
582 }), imm_pair.operand, emit.code) catch |err| emit.failWithLoweringError(err);
583}
584
552585fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
553586 const tag = emit.mir.instructions.items(.tag)[inst];
554587 assert(tag == .movabs);
......@@ -1287,7 +1320,7 @@ const Memory = struct {
12871320 encoder.disp32(@bitCast(i32, mem_op.disp));
12881321 }
12891322 } else {
1290 if (mem_op.disp == 0) {
1323 if (mem_op.disp == 0 and dst != 5) {
12911324 encoder.modRm_indirectDisp0(src, dst);
12921325 } else if (immOpSize(mem_op.disp) == 8) {
12931326 encoder.modRm_indirectDisp8(src, dst);
src/arch/x86_64/Mir.zig+23
......@@ -79,6 +79,13 @@ pub const Inst = struct {
7979 /// * Data field `payload` points at `ImmPair`.
8080 adc_scale_imm,
8181
82 /// ops flags: form:
83 /// 0b00 byte ptr [reg1 + rax + imm32], imm8
84 /// 0b01 word ptr [reg1 + rax + imm32], imm16
85 /// 0b10 dword ptr [reg1 + rax + imm32], imm32
86 /// 0b11 qword ptr [reg1 + rax + imm32], imm32 (sign-extended to imm64)
87 adc_mem_index_imm,
88
8289 // The following instructions all have the same encoding as `adc`.
8390
8491 add,
......@@ -86,81 +93,97 @@ pub const Inst = struct {
8693 add_scale_src,
8794 add_scale_dst,
8895 add_scale_imm,
96 add_mem_index_imm,
8997 sub,
9098 sub_mem_imm,
9199 sub_scale_src,
92100 sub_scale_dst,
93101 sub_scale_imm,
102 sub_mem_index_imm,
94103 xor,
95104 xor_mem_imm,
96105 xor_scale_src,
97106 xor_scale_dst,
98107 xor_scale_imm,
108 xor_mem_index_imm,
99109 @"and",
100110 and_mem_imm,
101111 and_scale_src,
102112 and_scale_dst,
103113 and_scale_imm,
114 and_mem_index_imm,
104115 @"or",
105116 or_mem_imm,
106117 or_scale_src,
107118 or_scale_dst,
108119 or_scale_imm,
120 or_mem_index_imm,
109121 rol,
110122 rol_mem_imm,
111123 rol_scale_src,
112124 rol_scale_dst,
113125 rol_scale_imm,
126 rol_mem_index_imm,
114127 ror,
115128 ror_mem_imm,
116129 ror_scale_src,
117130 ror_scale_dst,
118131 ror_scale_imm,
132 ror_mem_index_imm,
119133 rcl,
120134 rcl_mem_imm,
121135 rcl_scale_src,
122136 rcl_scale_dst,
123137 rcl_scale_imm,
138 rcl_mem_index_imm,
124139 rcr,
125140 rcr_mem_imm,
126141 rcr_scale_src,
127142 rcr_scale_dst,
128143 rcr_scale_imm,
144 rcr_mem_index_imm,
129145 shl,
130146 shl_mem_imm,
131147 shl_scale_src,
132148 shl_scale_dst,
133149 shl_scale_imm,
150 shl_mem_index_imm,
134151 sal,
135152 sal_mem_imm,
136153 sal_scale_src,
137154 sal_scale_dst,
138155 sal_scale_imm,
156 sal_mem_index_imm,
139157 shr,
140158 shr_mem_imm,
141159 shr_scale_src,
142160 shr_scale_dst,
143161 shr_scale_imm,
162 shr_mem_index_imm,
144163 sar,
145164 sar_mem_imm,
146165 sar_scale_src,
147166 sar_scale_dst,
148167 sar_scale_imm,
168 sar_mem_index_imm,
149169 sbb,
150170 sbb_mem_imm,
151171 sbb_scale_src,
152172 sbb_scale_dst,
153173 sbb_scale_imm,
174 sbb_mem_index_imm,
154175 cmp,
155176 cmp_mem_imm,
156177 cmp_scale_src,
157178 cmp_scale_dst,
158179 cmp_scale_imm,
180 cmp_mem_index_imm,
159181 mov,
160182 mov_mem_imm,
161183 mov_scale_src,
162184 mov_scale_dst,
163185 mov_scale_imm,
186 mov_mem_index_imm,
164187
165188 /// ops flags: form:
166189 /// 0b00 reg1, [reg2 + imm32]
src/arch/x86_64/PrintMir.zig+32-7
......@@ -64,6 +64,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap
6464 .@"or" => try print.mirArith(.@"or", inst, w),
6565 .sbb => try print.mirArith(.sbb, inst, w),
6666 .cmp => try print.mirArith(.cmp, inst, w),
67 .mov => try print.mirArith(.mov, inst, w),
6768
6869 .adc_mem_imm => try print.mirArithMemImm(.adc, inst, w),
6970 .add_mem_imm => try print.mirArithMemImm(.add, inst, w),
......@@ -73,6 +74,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap
7374 .or_mem_imm => try print.mirArithMemImm(.@"or", inst, w),
7475 .sbb_mem_imm => try print.mirArithMemImm(.sbb, inst, w),
7576 .cmp_mem_imm => try print.mirArithMemImm(.cmp, inst, w),
77 .mov_mem_imm => try print.mirArithMemImm(.mov, inst, w),
7678
7779 .adc_scale_src => try print.mirArithScaleSrc(.adc, inst, w),
7880 .add_scale_src => try print.mirArithScaleSrc(.add, inst, w),
......@@ -82,6 +84,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap
8284 .or_scale_src => try print.mirArithScaleSrc(.@"or", inst, w),
8385 .sbb_scale_src => try print.mirArithScaleSrc(.sbb, inst, w),
8486 .cmp_scale_src => try print.mirArithScaleSrc(.cmp, inst, w),
87 .mov_scale_src => try print.mirArithScaleSrc(.mov, inst, w),
8588
8689 .adc_scale_dst => try print.mirArithScaleDst(.adc, inst, w),
8790 .add_scale_dst => try print.mirArithScaleDst(.add, inst, w),
......@@ -91,6 +94,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap
9194 .or_scale_dst => try print.mirArithScaleDst(.@"or", inst, w),
9295 .sbb_scale_dst => try print.mirArithScaleDst(.sbb, inst, w),
9396 .cmp_scale_dst => try print.mirArithScaleDst(.cmp, inst, w),
97 .mov_scale_dst => try print.mirArithScaleDst(.mov, inst, w),
9498
9599 .adc_scale_imm => try print.mirArithScaleImm(.adc, inst, w),
96100 .add_scale_imm => try print.mirArithScaleImm(.add, inst, w),
......@@ -100,11 +104,18 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap
100104 .or_scale_imm => try print.mirArithScaleImm(.@"or", inst, w),
101105 .sbb_scale_imm => try print.mirArithScaleImm(.sbb, inst, w),
102106 .cmp_scale_imm => try print.mirArithScaleImm(.cmp, inst, w),
103
104 .mov => try print.mirArith(.mov, inst, w),
105 .mov_scale_src => try print.mirArithScaleSrc(.mov, inst, w),
106 .mov_scale_dst => try print.mirArithScaleDst(.mov, inst, w),
107107 .mov_scale_imm => try print.mirArithScaleImm(.mov, inst, w),
108
109 .adc_mem_index_imm => try print.mirArithMemIndexImm(.adc, inst, w),
110 .add_mem_index_imm => try print.mirArithMemIndexImm(.add, inst, w),
111 .sub_mem_index_imm => try print.mirArithMemIndexImm(.sub, inst, w),
112 .xor_mem_index_imm => try print.mirArithMemIndexImm(.xor, inst, w),
113 .and_mem_index_imm => try print.mirArithMemIndexImm(.@"and", inst, w),
114 .or_mem_index_imm => try print.mirArithMemIndexImm(.@"or", inst, w),
115 .sbb_mem_index_imm => try print.mirArithMemIndexImm(.sbb, inst, w),
116 .cmp_mem_index_imm => try print.mirArithMemIndexImm(.cmp, inst, w),
117 .mov_mem_index_imm => try print.mirArithMemIndexImm(.mov, inst, w),
118
108119 .movabs => try print.mirMovabs(inst, w),
109120
110121 .lea => try print.mirLea(inst, w),
......@@ -316,11 +327,11 @@ fn mirArithScaleDst(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index
316327
317328 if (ops.reg2 == .none) {
318329 // OP [reg1 + scale*rax + 0], imm32
319 try w.print("{s} [{s} + {d}*rcx + 0], {d}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm });
330 try w.print("{s} [{s} + {d}*rax + 0], {d}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm });
320331 }
321332
322333 // OP [reg1 + scale*rax + imm32], reg2
323 try w.print("{s} [{s} + {d}*rcx + {d}], {s}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm, @tagName(ops.reg2) });
334 try w.print("{s} [{s} + {d}*rax + {d}], {s}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm, @tagName(ops.reg2) });
324335}
325336
326337fn mirArithScaleImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
......@@ -328,7 +339,21 @@ fn mirArithScaleImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index
328339 const scale = ops.flags;
329340 const payload = print.mir.instructions.items(.data)[inst].payload;
330341 const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data;
331 try w.print("{s} [{s} + {d}*rcx + {d}], {d}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm_pair.dest_off, imm_pair.operand });
342 try w.print("{s} [{s} + {d}*rax + {d}], {d}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm_pair.dest_off, imm_pair.operand });
343}
344
345fn mirArithMemIndexImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
346 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
347 const payload = print.mir.instructions.items(.data)[inst].payload;
348 const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data;
349 try w.print("{s} ", .{@tagName(tag)});
350 switch (ops.flags) {
351 0b00 => try w.print("byte ptr ", .{}),
352 0b01 => try w.print("word ptr ", .{}),
353 0b10 => try w.print("dword ptr ", .{}),
354 0b11 => try w.print("qword ptr ", .{}),
355 }
356 try w.print("[{s} + 1*rax + {d}], {d}\n", .{ @tagName(ops.reg1), imm_pair.dest_off, imm_pair.operand });
332357}
333358
334359fn mirMovabs(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
test/behavior.zig+1-1
......@@ -17,6 +17,7 @@ test {
1717 _ = @import("behavior/bool.zig");
1818 _ = @import("behavior/align.zig");
1919 _ = @import("behavior/array.zig");
20 _ = @import("behavior/cast.zig");
2021
2122 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
2223 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
......@@ -35,7 +36,6 @@ test {
3536 _ = @import("behavior/bugs/4954.zig");
3637 _ = @import("behavior/byval_arg_var.zig");
3738 _ = @import("behavior/call.zig");
38 _ = @import("behavior/cast.zig");
3939 _ = @import("behavior/defer.zig");
4040 _ = @import("behavior/enum.zig");
4141 _ = @import("behavior/error.zig");
test/behavior/array.zig+1-3
......@@ -75,8 +75,6 @@ test "array literal with inferred length" {
7575}
7676
7777test "array dot len const expr" {
78 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
79
8078 try expect(comptime x: {
8179 break :x some_array.len == 4;
8280 });
......@@ -166,7 +164,7 @@ test "nested arrays" {
166164}
167165
168166test "implicit comptime in array type size" {
169 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
170168
171169 var arr: [plusOne(10)]bool = undefined;
172170 try expect(arr.len == 11);
test/behavior/cast.zig+30
......@@ -5,6 +5,8 @@ const maxInt = std.math.maxInt;
55const builtin = @import("builtin");
66
77test "int to ptr cast" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
9
810 const x = @as(usize, 13);
911 const y = @intToPtr(*u8, x);
1012 const z = @ptrToInt(y);
......@@ -12,11 +14,15 @@ test "int to ptr cast" {
1214}
1315
1416test "integer literal to pointer cast" {
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
18
1519 const vga_mem = @intToPtr(*u16, 0xB8000);
1620 try expect(@ptrToInt(vga_mem) == 0xB8000);
1721}
1822
1923test "peer type resolution: ?T and T" {
24 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
25
2026 try expect(peerTypeTAndOptionalT(true, false).? == 0);
2127 try expect(peerTypeTAndOptionalT(false, false).? == 3);
2228 comptime {
......@@ -33,6 +39,8 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
3339}
3440
3541test "resolve undefined with integer" {
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
43
3644 try testResolveUndefWithInt(true, 1234);
3745 comptime try testResolveUndefWithInt(true, 1234);
3846}
......@@ -88,6 +96,8 @@ test "comptime_int @intToFloat" {
8896}
8997
9098test "@floatToInt" {
99 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
100
91101 try testFloatToInts();
92102 comptime try testFloatToInts();
93103}
......@@ -107,6 +117,8 @@ fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void {
107117}
108118
109119test "implicitly cast indirect pointer to maybe-indirect pointer" {
120 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
121
110122 const S = struct {
111123 const Self = @This();
112124 x: u8,
......@@ -163,6 +175,8 @@ test "@floatCast comptime_int and comptime_float" {
163175}
164176
165177test "coerce undefined to optional" {
178 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
179
166180 try expect(MakeType(void).getNull() == null);
167181 try expect(MakeType(void).getNonNull() != null);
168182}
......@@ -180,6 +194,8 @@ fn MakeType(comptime T: type) type {
180194}
181195
182196test "implicit cast from *[N]T to [*c]T" {
197 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
198
183199 var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };
184200 var y: [*c]u16 = &x;
185201
......@@ -190,6 +206,8 @@ test "implicit cast from *[N]T to [*c]T" {
190206}
191207
192208test "*usize to *void" {
209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
210
193211 var i = @as(usize, 0);
194212 var v = @ptrCast(*void, &i);
195213 v.* = {};
......@@ -202,6 +220,8 @@ test "@intToEnum passed a comptime_int to an enum with one item" {
202220}
203221
204222test "@intCast to u0 and use the result" {
223 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
224
205225 const S = struct {
206226 fn doTheTest(zero: u1, one: u1, bigzero: i32) !void {
207227 try expect((one << @intCast(u0, bigzero)) == 1);
......@@ -213,6 +233,8 @@ test "@intCast to u0 and use the result" {
213233}
214234
215235test "peer result null and comptime_int" {
236 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
237
216238 const S = struct {
217239 fn blah(n: i32) ?i32 {
218240 if (n == 0) {
......@@ -234,6 +256,8 @@ test "peer result null and comptime_int" {
234256}
235257
236258test "*const ?[*]const T to [*c]const [*c]const T" {
259 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
260
237261 var array = [_]u8{ 'o', 'k' };
238262 const opt_array_ptr: ?[*]const u8 = &array;
239263 const a: *const ?[*]const u8 = &opt_array_ptr;
......@@ -243,6 +267,8 @@ test "*const ?[*]const T to [*c]const [*c]const T" {
243267}
244268
245269test "array coersion to undefined at runtime" {
270 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
271
246272 @setRuntimeSafety(true);
247273
248274 // TODO implement @setRuntimeSafety in stage2
......@@ -270,6 +296,8 @@ fn implicitIntLitToOptional() void {
270296}
271297
272298test "return u8 coercing into ?u32 return type" {
299 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
300
273301 const S = struct {
274302 fn doTheTest() !void {
275303 try expect(foo(123).? == 123);
......@@ -288,6 +316,8 @@ test "cast from ?[*]T to ??[*]T" {
288316}
289317
290318test "peer type unsigned int to signed" {
319 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
320
291321 var w: u31 = 5;
292322 var x: u8 = 7;
293323 var y: i32 = -5;