| author | |
| committer | |
| log | e80ebc6740d6bbe4b9b1958180a337804ff98450 |
| tree | 7a4be1449a4fe3a69953d8319b82f33f376e75cc |
| parent | 305a7def136580e7a05652a95c1d2ff338541607 |
| parent | 8201939d7f57d5332d209dd7fb728eafe5a8b882 |
| signature |
stage2: add inline memset, partial intcast and more array goodness for x86_647 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 { | ... | @@ -876,10 +876,26 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 876 | if (info_a.signedness != info_b.signedness) | 876 | if (info_a.signedness != info_b.signedness) |
| 877 | return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); | 877 | return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); |
| 878 | 878 | ||
| 879 | if (info_a.bits == info_b.bits) | 879 | const operand_abi_size = operand_ty.abiSize(self.target.*); |
| 880 | return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); | 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 | }; | ||
| 881 | 897 | ||
| 882 | return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch}); | 898 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 883 | } | 899 | } |
| 884 | 900 | ||
| 885 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 901 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1312,59 +1328,49 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1312,59 +1328,49 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1312 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1328 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1313 | } | 1329 | } |
| 1314 | 1330 | ||
| 1331 | fn 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 | |||
| 1315 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 1338 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1316 | const is_volatile = false; // TODO | 1339 | const is_volatile = false; // TODO |
| 1317 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1340 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1318 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { | 1341 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { |
| 1319 | const slice_mcv = try self.resolveInst(bin_op.lhs); | 1342 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 1320 | const slice_ty = self.air.typeOf(bin_op.lhs); | 1343 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 1321 | |||
| 1322 | const elem_ty = slice_ty.childType(); | 1344 | const elem_ty = slice_ty.childType(); |
| 1323 | const elem_size = elem_ty.abiSize(self.target.*); | 1345 | const elem_size = elem_ty.abiSize(self.target.*); |
| 1324 | |||
| 1325 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1346 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1326 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | 1347 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| 1327 | 1348 | const index_ty = self.air.typeOf(bin_op.rhs); | |
| 1328 | const offset_reg = blk: { | 1349 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 1329 | const index_ty = self.air.typeOf(bin_op.rhs); | 1350 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); |
| 1330 | const index_mcv = try self.resolveInst(bin_op.rhs); | 1351 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); |
| 1331 | const offset_reg = try self.register_manager.allocReg(null, &.{}); | 1352 | switch (slice_mcv) { |
| 1332 | try self.genSetReg(index_ty, offset_reg, index_mcv); | 1353 | .stack_offset => |off| { |
| 1333 | try self.genIMulOpMir(index_ty, .{ .register = offset_reg }, .{ .immediate = elem_size }); | 1354 | // mov reg, [rbp - 8] |
| 1334 | break :blk offset_reg; | 1355 | _ = try self.addInst(.{ |
| 1335 | }; | 1356 | .tag = .mov, |
| 1336 | 1357 | .ops = (Mir.Ops{ | |
| 1337 | const dst_mcv = blk: { | 1358 | .reg1 = addr_reg.to64(), |
| 1338 | switch (slice_mcv) { | 1359 | .reg2 = .rbp, |
| 1339 | .stack_offset => |off| { | 1360 | .flags = 0b01, |
| 1340 | const dst_mcv = try self.allocRegOrMem(inst, false); | 1361 | }).encode(), |
| 1341 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); | 1362 | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) }, |
| 1342 | // mov reg, [rbp - 8] | 1363 | }); |
| 1343 | _ = try self.addInst(.{ | 1364 | }, |
| 1344 | .tag = .mov, | 1365 | else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}), |
| 1345 | .ops = (Mir.Ops{ | 1366 | } |
| 1346 | .reg1 = addr_reg.to64(), | 1367 | // TODO we could allocate register here, but need to except addr register and potentially |
| 1347 | .reg2 = .rbp, | 1368 | // offset register. |
| 1348 | .flags = 0b01, | 1369 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1349 | }).encode(), | 1370 | try self.genBinMathOpMir(.add, slice_ptr_field_type, .unsigned, .{ .register = addr_reg.to64() }, .{ |
| 1350 | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) }, | 1371 | .register = offset_reg.to64(), |
| 1351 | }); | 1372 | }); |
| 1352 | // add addr, offset | 1373 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, slice_ptr_field_type); |
| 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 | |||
| 1368 | break :result dst_mcv; | 1374 | break :result dst_mcv; |
| 1369 | }; | 1375 | }; |
| 1370 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1376 | 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 { | ... | @@ -1382,10 +1388,43 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1382 | 1388 | ||
| 1383 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | 1389 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1384 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1390 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1385 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1391 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1386 | .dead | 1392 | const array_ty = self.air.typeOf(bin_op.lhs); |
| 1387 | else | 1393 | const array = try self.resolveInst(bin_op.lhs); |
| 1388 | return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch}); | 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 | }; | ||
| 1389 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1428 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1390 | } | 1429 | } |
| 1391 | 1430 | ||
| ... | @@ -1402,10 +1441,27 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1402,10 +1441,27 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1402 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | 1441 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1403 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1442 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1404 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1443 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1405 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1444 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1406 | .dead | 1445 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 1407 | else | 1446 | const ptr = try self.resolveInst(extra.lhs); |
| 1408 | return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch}); | 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 | }; | ||
| 1409 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); | 1465 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1410 | } | 1466 | } |
| 1411 | 1467 | ||
| ... | @@ -3147,7 +3203,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3147,7 +3203,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3147 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), | 3203 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 3148 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 3204 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 3149 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), | 3205 | 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 }), |
| 3151 | } | 3207 | } |
| 3152 | }, | 3208 | }, |
| 3153 | .compare_flags_unsigned => |op| { | 3209 | .compare_flags_unsigned => |op| { |
| ... | @@ -3397,6 +3453,97 @@ fn genInlineMemcpy( | ... | @@ -3397,6 +3453,97 @@ fn genInlineMemcpy( |
| 3397 | try self.performReloc(loop_reloc); | 3453 | try self.performReloc(loop_reloc); |
| 3398 | } | 3454 | } |
| 3399 | 3455 | ||
| 3456 | fn 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 | |||
| 3400 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { | 3547 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 3401 | switch (mcv) { | 3548 | switch (mcv) { |
| 3402 | .dead => unreachable, | 3549 | .dead => unreachable, |
| ... | @@ -3634,12 +3781,12 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3634,12 +3781,12 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 3634 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3781 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3635 | const ptr_ty = self.air.typeOf(ty_op.operand); | 3782 | const ptr_ty = self.air.typeOf(ty_op.operand); |
| 3636 | const ptr = try self.resolveInst(ty_op.operand); | 3783 | const ptr = try self.resolveInst(ty_op.operand); |
| 3784 | const array_ty = ptr_ty.childType(); | ||
| 3785 | const array_len = array_ty.arrayLenIncludingSentinel(); | ||
| 3637 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { | 3786 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 3638 | const stack_offset = try self.allocMem(inst, 16, 16); | 3787 | const stack_offset = try self.allocMem(inst, 16, 16); |
| 3639 | const array_ty = ptr_ty.childType(); | 3788 | try self.genSetStack(ptr_ty, stack_offset + 8, ptr); |
| 3640 | const array_len = array_ty.arrayLenIncludingSentinel(); | 3789 | try self.genSetStack(Type.initTag(.u64), stack_offset, .{ .immediate = array_len }); |
| 3641 | try self.genSetStack(Type.initTag(.usize), stack_offset + 8, ptr); | ||
| 3642 | try self.genSetStack(Type.initTag(.u64), stack_offset + 16, .{ .immediate = array_len }); | ||
| 3643 | break :blk .{ .stack_offset = stack_offset }; | 3790 | break :blk .{ .stack_offset = stack_offset }; |
| 3644 | }; | 3791 | }; |
| 3645 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3792 | 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 { | ... | @@ -115,6 +115,16 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 115 | .cmp_scale_imm => try emit.mirArithScaleImm(.cmp, inst), | 115 | .cmp_scale_imm => try emit.mirArithScaleImm(.cmp, inst), |
| 116 | .mov_scale_imm => try emit.mirArithScaleImm(.mov, inst), | 116 | .mov_scale_imm => try emit.mirArithScaleImm(.mov, inst), |
| 117 | 117 | ||
| 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 | |||
| 118 | .movabs => try emit.mirMovabs(inst), | 128 | .movabs => try emit.mirMovabs(inst), |
| 119 | 129 | ||
| 120 | .lea => try emit.mirLea(inst), | 130 | .lea => try emit.mirLea(inst), |
| ... | @@ -549,6 +559,29 @@ fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void | ... | @@ -549,6 +559,29 @@ fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 549 | }), imm_pair.operand, emit.code) catch |err| emit.failWithLoweringError(err); | 559 | }), imm_pair.operand, emit.code) catch |err| emit.failWithLoweringError(err); |
| 550 | } | 560 | } |
| 551 | 561 | ||
| 562 | fn 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 | |||
| 552 | fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 585 | fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 553 | const tag = emit.mir.instructions.items(.tag)[inst]; | 586 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 554 | assert(tag == .movabs); | 587 | assert(tag == .movabs); |
| ... | @@ -1287,7 +1320,7 @@ const Memory = struct { | ... | @@ -1287,7 +1320,7 @@ const Memory = struct { |
| 1287 | encoder.disp32(@bitCast(i32, mem_op.disp)); | 1320 | encoder.disp32(@bitCast(i32, mem_op.disp)); |
| 1288 | } | 1321 | } |
| 1289 | } else { | 1322 | } else { |
| 1290 | if (mem_op.disp == 0) { | 1323 | if (mem_op.disp == 0 and dst != 5) { |
| 1291 | encoder.modRm_indirectDisp0(src, dst); | 1324 | encoder.modRm_indirectDisp0(src, dst); |
| 1292 | } else if (immOpSize(mem_op.disp) == 8) { | 1325 | } else if (immOpSize(mem_op.disp) == 8) { |
| 1293 | encoder.modRm_indirectDisp8(src, dst); | 1326 | encoder.modRm_indirectDisp8(src, dst); |
src/arch/x86_64/Mir.zig+23| ... | @@ -79,6 +79,13 @@ pub const Inst = struct { | ... | @@ -79,6 +79,13 @@ pub const Inst = struct { |
| 79 | /// * Data field `payload` points at `ImmPair`. | 79 | /// * Data field `payload` points at `ImmPair`. |
| 80 | adc_scale_imm, | 80 | adc_scale_imm, |
| 81 | 81 | ||
| 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 | |||
| 82 | // The following instructions all have the same encoding as `adc`. | 89 | // The following instructions all have the same encoding as `adc`. |
| 83 | 90 | ||
| 84 | add, | 91 | add, |
| ... | @@ -86,81 +93,97 @@ pub const Inst = struct { | ... | @@ -86,81 +93,97 @@ pub const Inst = struct { |
| 86 | add_scale_src, | 93 | add_scale_src, |
| 87 | add_scale_dst, | 94 | add_scale_dst, |
| 88 | add_scale_imm, | 95 | add_scale_imm, |
| 96 | add_mem_index_imm, | ||
| 89 | sub, | 97 | sub, |
| 90 | sub_mem_imm, | 98 | sub_mem_imm, |
| 91 | sub_scale_src, | 99 | sub_scale_src, |
| 92 | sub_scale_dst, | 100 | sub_scale_dst, |
| 93 | sub_scale_imm, | 101 | sub_scale_imm, |
| 102 | sub_mem_index_imm, | ||
| 94 | xor, | 103 | xor, |
| 95 | xor_mem_imm, | 104 | xor_mem_imm, |
| 96 | xor_scale_src, | 105 | xor_scale_src, |
| 97 | xor_scale_dst, | 106 | xor_scale_dst, |
| 98 | xor_scale_imm, | 107 | xor_scale_imm, |
| 108 | xor_mem_index_imm, | ||
| 99 | @"and", | 109 | @"and", |
| 100 | and_mem_imm, | 110 | and_mem_imm, |
| 101 | and_scale_src, | 111 | and_scale_src, |
| 102 | and_scale_dst, | 112 | and_scale_dst, |
| 103 | and_scale_imm, | 113 | and_scale_imm, |
| 114 | and_mem_index_imm, | ||
| 104 | @"or", | 115 | @"or", |
| 105 | or_mem_imm, | 116 | or_mem_imm, |
| 106 | or_scale_src, | 117 | or_scale_src, |
| 107 | or_scale_dst, | 118 | or_scale_dst, |
| 108 | or_scale_imm, | 119 | or_scale_imm, |
| 120 | or_mem_index_imm, | ||
| 109 | rol, | 121 | rol, |
| 110 | rol_mem_imm, | 122 | rol_mem_imm, |
| 111 | rol_scale_src, | 123 | rol_scale_src, |
| 112 | rol_scale_dst, | 124 | rol_scale_dst, |
| 113 | rol_scale_imm, | 125 | rol_scale_imm, |
| 126 | rol_mem_index_imm, | ||
| 114 | ror, | 127 | ror, |
| 115 | ror_mem_imm, | 128 | ror_mem_imm, |
| 116 | ror_scale_src, | 129 | ror_scale_src, |
| 117 | ror_scale_dst, | 130 | ror_scale_dst, |
| 118 | ror_scale_imm, | 131 | ror_scale_imm, |
| 132 | ror_mem_index_imm, | ||
| 119 | rcl, | 133 | rcl, |
| 120 | rcl_mem_imm, | 134 | rcl_mem_imm, |
| 121 | rcl_scale_src, | 135 | rcl_scale_src, |
| 122 | rcl_scale_dst, | 136 | rcl_scale_dst, |
| 123 | rcl_scale_imm, | 137 | rcl_scale_imm, |
| 138 | rcl_mem_index_imm, | ||
| 124 | rcr, | 139 | rcr, |
| 125 | rcr_mem_imm, | 140 | rcr_mem_imm, |
| 126 | rcr_scale_src, | 141 | rcr_scale_src, |
| 127 | rcr_scale_dst, | 142 | rcr_scale_dst, |
| 128 | rcr_scale_imm, | 143 | rcr_scale_imm, |
| 144 | rcr_mem_index_imm, | ||
| 129 | shl, | 145 | shl, |
| 130 | shl_mem_imm, | 146 | shl_mem_imm, |
| 131 | shl_scale_src, | 147 | shl_scale_src, |
| 132 | shl_scale_dst, | 148 | shl_scale_dst, |
| 133 | shl_scale_imm, | 149 | shl_scale_imm, |
| 150 | shl_mem_index_imm, | ||
| 134 | sal, | 151 | sal, |
| 135 | sal_mem_imm, | 152 | sal_mem_imm, |
| 136 | sal_scale_src, | 153 | sal_scale_src, |
| 137 | sal_scale_dst, | 154 | sal_scale_dst, |
| 138 | sal_scale_imm, | 155 | sal_scale_imm, |
| 156 | sal_mem_index_imm, | ||
| 139 | shr, | 157 | shr, |
| 140 | shr_mem_imm, | 158 | shr_mem_imm, |
| 141 | shr_scale_src, | 159 | shr_scale_src, |
| 142 | shr_scale_dst, | 160 | shr_scale_dst, |
| 143 | shr_scale_imm, | 161 | shr_scale_imm, |
| 162 | shr_mem_index_imm, | ||
| 144 | sar, | 163 | sar, |
| 145 | sar_mem_imm, | 164 | sar_mem_imm, |
| 146 | sar_scale_src, | 165 | sar_scale_src, |
| 147 | sar_scale_dst, | 166 | sar_scale_dst, |
| 148 | sar_scale_imm, | 167 | sar_scale_imm, |
| 168 | sar_mem_index_imm, | ||
| 149 | sbb, | 169 | sbb, |
| 150 | sbb_mem_imm, | 170 | sbb_mem_imm, |
| 151 | sbb_scale_src, | 171 | sbb_scale_src, |
| 152 | sbb_scale_dst, | 172 | sbb_scale_dst, |
| 153 | sbb_scale_imm, | 173 | sbb_scale_imm, |
| 174 | sbb_mem_index_imm, | ||
| 154 | cmp, | 175 | cmp, |
| 155 | cmp_mem_imm, | 176 | cmp_mem_imm, |
| 156 | cmp_scale_src, | 177 | cmp_scale_src, |
| 157 | cmp_scale_dst, | 178 | cmp_scale_dst, |
| 158 | cmp_scale_imm, | 179 | cmp_scale_imm, |
| 180 | cmp_mem_index_imm, | ||
| 159 | mov, | 181 | mov, |
| 160 | mov_mem_imm, | 182 | mov_mem_imm, |
| 161 | mov_scale_src, | 183 | mov_scale_src, |
| 162 | mov_scale_dst, | 184 | mov_scale_dst, |
| 163 | mov_scale_imm, | 185 | mov_scale_imm, |
| 186 | mov_mem_index_imm, | ||
| 164 | 187 | ||
| 165 | /// ops flags: form: | 188 | /// ops flags: form: |
| 166 | /// 0b00 reg1, [reg2 + imm32] | 189 | /// 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 | ... | @@ -64,6 +64,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap |
| 64 | .@"or" => try print.mirArith(.@"or", inst, w), | 64 | .@"or" => try print.mirArith(.@"or", inst, w), |
| 65 | .sbb => try print.mirArith(.sbb, inst, w), | 65 | .sbb => try print.mirArith(.sbb, inst, w), |
| 66 | .cmp => try print.mirArith(.cmp, inst, w), | 66 | .cmp => try print.mirArith(.cmp, inst, w), |
| 67 | .mov => try print.mirArith(.mov, inst, w), | ||
| 67 | 68 | ||
| 68 | .adc_mem_imm => try print.mirArithMemImm(.adc, inst, w), | 69 | .adc_mem_imm => try print.mirArithMemImm(.adc, inst, w), |
| 69 | .add_mem_imm => try print.mirArithMemImm(.add, inst, w), | 70 | .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 | ... | @@ -73,6 +74,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap |
| 73 | .or_mem_imm => try print.mirArithMemImm(.@"or", inst, w), | 74 | .or_mem_imm => try print.mirArithMemImm(.@"or", inst, w), |
| 74 | .sbb_mem_imm => try print.mirArithMemImm(.sbb, inst, w), | 75 | .sbb_mem_imm => try print.mirArithMemImm(.sbb, inst, w), |
| 75 | .cmp_mem_imm => try print.mirArithMemImm(.cmp, inst, w), | 76 | .cmp_mem_imm => try print.mirArithMemImm(.cmp, inst, w), |
| 77 | .mov_mem_imm => try print.mirArithMemImm(.mov, inst, w), | ||
| 76 | 78 | ||
| 77 | .adc_scale_src => try print.mirArithScaleSrc(.adc, inst, w), | 79 | .adc_scale_src => try print.mirArithScaleSrc(.adc, inst, w), |
| 78 | .add_scale_src => try print.mirArithScaleSrc(.add, inst, w), | 80 | .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 | ... | @@ -82,6 +84,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap |
| 82 | .or_scale_src => try print.mirArithScaleSrc(.@"or", inst, w), | 84 | .or_scale_src => try print.mirArithScaleSrc(.@"or", inst, w), |
| 83 | .sbb_scale_src => try print.mirArithScaleSrc(.sbb, inst, w), | 85 | .sbb_scale_src => try print.mirArithScaleSrc(.sbb, inst, w), |
| 84 | .cmp_scale_src => try print.mirArithScaleSrc(.cmp, inst, w), | 86 | .cmp_scale_src => try print.mirArithScaleSrc(.cmp, inst, w), |
| 87 | .mov_scale_src => try print.mirArithScaleSrc(.mov, inst, w), | ||
| 85 | 88 | ||
| 86 | .adc_scale_dst => try print.mirArithScaleDst(.adc, inst, w), | 89 | .adc_scale_dst => try print.mirArithScaleDst(.adc, inst, w), |
| 87 | .add_scale_dst => try print.mirArithScaleDst(.add, inst, w), | 90 | .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 | ... | @@ -91,6 +94,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap |
| 91 | .or_scale_dst => try print.mirArithScaleDst(.@"or", inst, w), | 94 | .or_scale_dst => try print.mirArithScaleDst(.@"or", inst, w), |
| 92 | .sbb_scale_dst => try print.mirArithScaleDst(.sbb, inst, w), | 95 | .sbb_scale_dst => try print.mirArithScaleDst(.sbb, inst, w), |
| 93 | .cmp_scale_dst => try print.mirArithScaleDst(.cmp, inst, w), | 96 | .cmp_scale_dst => try print.mirArithScaleDst(.cmp, inst, w), |
| 97 | .mov_scale_dst => try print.mirArithScaleDst(.mov, inst, w), | ||
| 94 | 98 | ||
| 95 | .adc_scale_imm => try print.mirArithScaleImm(.adc, inst, w), | 99 | .adc_scale_imm => try print.mirArithScaleImm(.adc, inst, w), |
| 96 | .add_scale_imm => try print.mirArithScaleImm(.add, inst, w), | 100 | .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 | ... | @@ -100,11 +104,18 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap |
| 100 | .or_scale_imm => try print.mirArithScaleImm(.@"or", inst, w), | 104 | .or_scale_imm => try print.mirArithScaleImm(.@"or", inst, w), |
| 101 | .sbb_scale_imm => try print.mirArithScaleImm(.sbb, inst, w), | 105 | .sbb_scale_imm => try print.mirArithScaleImm(.sbb, inst, w), |
| 102 | .cmp_scale_imm => try print.mirArithScaleImm(.cmp, inst, w), | 106 | .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), | ||
| 107 | .mov_scale_imm => try print.mirArithScaleImm(.mov, inst, w), | 107 | .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 | |||
| 108 | .movabs => try print.mirMovabs(inst, w), | 119 | .movabs => try print.mirMovabs(inst, w), |
| 109 | 120 | ||
| 110 | .lea => try print.mirLea(inst, w), | 121 | .lea => try print.mirLea(inst, w), |
| ... | @@ -316,11 +327,11 @@ fn mirArithScaleDst(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index | ... | @@ -316,11 +327,11 @@ fn mirArithScaleDst(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index |
| 316 | 327 | ||
| 317 | if (ops.reg2 == .none) { | 328 | if (ops.reg2 == .none) { |
| 318 | // OP [reg1 + scale*rax + 0], imm32 | 329 | // 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 }); |
| 320 | } | 331 | } |
| 321 | 332 | ||
| 322 | // OP [reg1 + scale*rax + imm32], reg2 | 333 | // 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) }); |
| 324 | } | 335 | } |
| 325 | 336 | ||
| 326 | fn mirArithScaleImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void { | 337 | fn 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 | ... | @@ -328,7 +339,21 @@ fn mirArithScaleImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index |
| 328 | const scale = ops.flags; | 339 | const scale = ops.flags; |
| 329 | const payload = print.mir.instructions.items(.data)[inst].payload; | 340 | const payload = print.mir.instructions.items(.data)[inst].payload; |
| 330 | const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data; | 341 | 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 | |||
| 345 | fn 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 }); | ||
| 332 | } | 357 | } |
| 333 | 358 | ||
| 334 | fn mirMovabs(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { | 359 | fn mirMovabs(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { |
test/behavior.zig+1-1| ... | @@ -17,6 +17,7 @@ test { | ... | @@ -17,6 +17,7 @@ test { |
| 17 | _ = @import("behavior/bool.zig"); | 17 | _ = @import("behavior/bool.zig"); |
| 18 | _ = @import("behavior/align.zig"); | 18 | _ = @import("behavior/align.zig"); |
| 19 | _ = @import("behavior/array.zig"); | 19 | _ = @import("behavior/array.zig"); |
| 20 | _ = @import("behavior/cast.zig"); | ||
| 20 | 21 | ||
| 21 | if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) { | 22 | if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) { |
| 22 | // Tests that pass for stage1, llvm backend, C backend, wasm backend. | 23 | // Tests that pass for stage1, llvm backend, C backend, wasm backend. |
| ... | @@ -35,7 +36,6 @@ test { | ... | @@ -35,7 +36,6 @@ test { |
| 35 | _ = @import("behavior/bugs/4954.zig"); | 36 | _ = @import("behavior/bugs/4954.zig"); |
| 36 | _ = @import("behavior/byval_arg_var.zig"); | 37 | _ = @import("behavior/byval_arg_var.zig"); |
| 37 | _ = @import("behavior/call.zig"); | 38 | _ = @import("behavior/call.zig"); |
| 38 | _ = @import("behavior/cast.zig"); | ||
| 39 | _ = @import("behavior/defer.zig"); | 39 | _ = @import("behavior/defer.zig"); |
| 40 | _ = @import("behavior/enum.zig"); | 40 | _ = @import("behavior/enum.zig"); |
| 41 | _ = @import("behavior/error.zig"); | 41 | _ = @import("behavior/error.zig"); |
test/behavior/array.zig+1-3| ... | @@ -75,8 +75,6 @@ test "array literal with inferred length" { | ... | @@ -75,8 +75,6 @@ test "array literal with inferred length" { |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | test "array dot len const expr" { | 77 | test "array dot len const expr" { |
| 78 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 79 | |||
| 80 | try expect(comptime x: { | 78 | try expect(comptime x: { |
| 81 | break :x some_array.len == 4; | 79 | break :x some_array.len == 4; |
| 82 | }); | 80 | }); |
| ... | @@ -166,7 +164,7 @@ test "nested arrays" { | ... | @@ -166,7 +164,7 @@ test "nested arrays" { |
| 166 | } | 164 | } |
| 167 | 165 | ||
| 168 | test "implicit comptime in array type size" { | 166 | test "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; |
| 170 | 168 | ||
| 171 | var arr: [plusOne(10)]bool = undefined; | 169 | var arr: [plusOne(10)]bool = undefined; |
| 172 | try expect(arr.len == 11); | 170 | try expect(arr.len == 11); |
test/behavior/cast.zig+30| ... | @@ -5,6 +5,8 @@ const maxInt = std.math.maxInt; | ... | @@ -5,6 +5,8 @@ const maxInt = std.math.maxInt; |
| 5 | const builtin = @import("builtin"); | 5 | const builtin = @import("builtin"); |
| 6 | 6 | ||
| 7 | test "int to ptr cast" { | 7 | test "int to ptr cast" { |
| 8 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 9 | |||
| 8 | const x = @as(usize, 13); | 10 | const x = @as(usize, 13); |
| 9 | const y = @intToPtr(*u8, x); | 11 | const y = @intToPtr(*u8, x); |
| 10 | const z = @ptrToInt(y); | 12 | const z = @ptrToInt(y); |
| ... | @@ -12,11 +14,15 @@ test "int to ptr cast" { | ... | @@ -12,11 +14,15 @@ test "int to ptr cast" { |
| 12 | } | 14 | } |
| 13 | 15 | ||
| 14 | test "integer literal to pointer cast" { | 16 | test "integer literal to pointer cast" { |
| 17 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 18 | |||
| 15 | const vga_mem = @intToPtr(*u16, 0xB8000); | 19 | const vga_mem = @intToPtr(*u16, 0xB8000); |
| 16 | try expect(@ptrToInt(vga_mem) == 0xB8000); | 20 | try expect(@ptrToInt(vga_mem) == 0xB8000); |
| 17 | } | 21 | } |
| 18 | 22 | ||
| 19 | test "peer type resolution: ?T and T" { | 23 | test "peer type resolution: ?T and T" { |
| 24 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 25 | |||
| 20 | try expect(peerTypeTAndOptionalT(true, false).? == 0); | 26 | try expect(peerTypeTAndOptionalT(true, false).? == 0); |
| 21 | try expect(peerTypeTAndOptionalT(false, false).? == 3); | 27 | try expect(peerTypeTAndOptionalT(false, false).? == 3); |
| 22 | comptime { | 28 | comptime { |
| ... | @@ -33,6 +39,8 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { | ... | @@ -33,6 +39,8 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { |
| 33 | } | 39 | } |
| 34 | 40 | ||
| 35 | test "resolve undefined with integer" { | 41 | test "resolve undefined with integer" { |
| 42 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 43 | |||
| 36 | try testResolveUndefWithInt(true, 1234); | 44 | try testResolveUndefWithInt(true, 1234); |
| 37 | comptime try testResolveUndefWithInt(true, 1234); | 45 | comptime try testResolveUndefWithInt(true, 1234); |
| 38 | } | 46 | } |
| ... | @@ -88,6 +96,8 @@ test "comptime_int @intToFloat" { | ... | @@ -88,6 +96,8 @@ test "comptime_int @intToFloat" { |
| 88 | } | 96 | } |
| 89 | 97 | ||
| 90 | test "@floatToInt" { | 98 | test "@floatToInt" { |
| 99 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 100 | |||
| 91 | try testFloatToInts(); | 101 | try testFloatToInts(); |
| 92 | comptime try testFloatToInts(); | 102 | comptime try testFloatToInts(); |
| 93 | } | 103 | } |
| ... | @@ -107,6 +117,8 @@ fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void { | ... | @@ -107,6 +117,8 @@ fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void { |
| 107 | } | 117 | } |
| 108 | 118 | ||
| 109 | test "implicitly cast indirect pointer to maybe-indirect pointer" { | 119 | test "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 | |||
| 110 | const S = struct { | 122 | const S = struct { |
| 111 | const Self = @This(); | 123 | const Self = @This(); |
| 112 | x: u8, | 124 | x: u8, |
| ... | @@ -163,6 +175,8 @@ test "@floatCast comptime_int and comptime_float" { | ... | @@ -163,6 +175,8 @@ test "@floatCast comptime_int and comptime_float" { |
| 163 | } | 175 | } |
| 164 | 176 | ||
| 165 | test "coerce undefined to optional" { | 177 | test "coerce undefined to optional" { |
| 178 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 179 | |||
| 166 | try expect(MakeType(void).getNull() == null); | 180 | try expect(MakeType(void).getNull() == null); |
| 167 | try expect(MakeType(void).getNonNull() != null); | 181 | try expect(MakeType(void).getNonNull() != null); |
| 168 | } | 182 | } |
| ... | @@ -180,6 +194,8 @@ fn MakeType(comptime T: type) type { | ... | @@ -180,6 +194,8 @@ fn MakeType(comptime T: type) type { |
| 180 | } | 194 | } |
| 181 | 195 | ||
| 182 | test "implicit cast from *[N]T to [*c]T" { | 196 | test "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 | |||
| 183 | var x: [4]u16 = [4]u16{ 0, 1, 2, 3 }; | 199 | var x: [4]u16 = [4]u16{ 0, 1, 2, 3 }; |
| 184 | var y: [*c]u16 = &x; | 200 | var y: [*c]u16 = &x; |
| 185 | 201 | ||
| ... | @@ -190,6 +206,8 @@ test "implicit cast from *[N]T to [*c]T" { | ... | @@ -190,6 +206,8 @@ test "implicit cast from *[N]T to [*c]T" { |
| 190 | } | 206 | } |
| 191 | 207 | ||
| 192 | test "*usize to *void" { | 208 | test "*usize to *void" { |
| 209 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 210 | |||
| 193 | var i = @as(usize, 0); | 211 | var i = @as(usize, 0); |
| 194 | var v = @ptrCast(*void, &i); | 212 | var v = @ptrCast(*void, &i); |
| 195 | v.* = {}; | 213 | v.* = {}; |
| ... | @@ -202,6 +220,8 @@ test "@intToEnum passed a comptime_int to an enum with one item" { | ... | @@ -202,6 +220,8 @@ test "@intToEnum passed a comptime_int to an enum with one item" { |
| 202 | } | 220 | } |
| 203 | 221 | ||
| 204 | test "@intCast to u0 and use the result" { | 222 | test "@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 | |||
| 205 | const S = struct { | 225 | const S = struct { |
| 206 | fn doTheTest(zero: u1, one: u1, bigzero: i32) !void { | 226 | fn doTheTest(zero: u1, one: u1, bigzero: i32) !void { |
| 207 | try expect((one << @intCast(u0, bigzero)) == 1); | 227 | try expect((one << @intCast(u0, bigzero)) == 1); |
| ... | @@ -213,6 +233,8 @@ test "@intCast to u0 and use the result" { | ... | @@ -213,6 +233,8 @@ test "@intCast to u0 and use the result" { |
| 213 | } | 233 | } |
| 214 | 234 | ||
| 215 | test "peer result null and comptime_int" { | 235 | test "peer result null and comptime_int" { |
| 236 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 237 | |||
| 216 | const S = struct { | 238 | const S = struct { |
| 217 | fn blah(n: i32) ?i32 { | 239 | fn blah(n: i32) ?i32 { |
| 218 | if (n == 0) { | 240 | if (n == 0) { |
| ... | @@ -234,6 +256,8 @@ test "peer result null and comptime_int" { | ... | @@ -234,6 +256,8 @@ test "peer result null and comptime_int" { |
| 234 | } | 256 | } |
| 235 | 257 | ||
| 236 | test "*const ?[*]const T to [*c]const [*c]const T" { | 258 | test "*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 | |||
| 237 | var array = [_]u8{ 'o', 'k' }; | 261 | var array = [_]u8{ 'o', 'k' }; |
| 238 | const opt_array_ptr: ?[*]const u8 = &array; | 262 | const opt_array_ptr: ?[*]const u8 = &array; |
| 239 | const a: *const ?[*]const u8 = &opt_array_ptr; | 263 | const a: *const ?[*]const u8 = &opt_array_ptr; |
| ... | @@ -243,6 +267,8 @@ test "*const ?[*]const T to [*c]const [*c]const T" { | ... | @@ -243,6 +267,8 @@ test "*const ?[*]const T to [*c]const [*c]const T" { |
| 243 | } | 267 | } |
| 244 | 268 | ||
| 245 | test "array coersion to undefined at runtime" { | 269 | test "array coersion to undefined at runtime" { |
| 270 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 271 | |||
| 246 | @setRuntimeSafety(true); | 272 | @setRuntimeSafety(true); |
| 247 | 273 | ||
| 248 | // TODO implement @setRuntimeSafety in stage2 | 274 | // TODO implement @setRuntimeSafety in stage2 |
| ... | @@ -270,6 +296,8 @@ fn implicitIntLitToOptional() void { | ... | @@ -270,6 +296,8 @@ fn implicitIntLitToOptional() void { |
| 270 | } | 296 | } |
| 271 | 297 | ||
| 272 | test "return u8 coercing into ?u32 return type" { | 298 | test "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 | |||
| 273 | const S = struct { | 301 | const S = struct { |
| 274 | fn doTheTest() !void { | 302 | fn doTheTest() !void { |
| 275 | try expect(foo(123).? == 123); | 303 | try expect(foo(123).? == 123); |
| ... | @@ -288,6 +316,8 @@ test "cast from ?[*]T to ??[*]T" { | ... | @@ -288,6 +316,8 @@ test "cast from ?[*]T to ??[*]T" { |
| 288 | } | 316 | } |
| 289 | 317 | ||
| 290 | test "peer type unsigned int to signed" { | 318 | test "peer type unsigned int to signed" { |
| 319 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 320 | |||
| 291 | var w: u31 = 5; | 321 | var w: u31 = 5; |
| 292 | var x: u8 = 7; | 322 | var x: u8 = 7; |
| 293 | var y: i32 = -5; | 323 | var y: i32 = -5; |