| ... | @@ -813,6 +813,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -813,6 +813,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 813 | | 813 | |
| 814 | switch (air_tags[inst]) { | 814 | switch (air_tags[inst]) { |
| 815 | // zig fmt: off | 815 | // zig fmt: off |
| | 816 | .not, |
| | 817 | => |tag| try self.airUnOp(inst, tag), |
| | 818 | |
| 816 | .add, | 819 | .add, |
| 817 | .addwrap, | 820 | .addwrap, |
| 818 | .sub, | 821 | .sub, |
| ... | @@ -905,7 +908,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -905,7 +908,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 905 | .is_err_ptr => try self.airIsErrPtr(inst), | 908 | .is_err_ptr => try self.airIsErrPtr(inst), |
| 906 | .load => try self.airLoad(inst), | 909 | .load => try self.airLoad(inst), |
| 907 | .loop => try self.airLoop(inst), | 910 | .loop => try self.airLoop(inst), |
| 908 | .not => try self.airNot(inst), | | |
| 909 | .ptrtoint => try self.airPtrToInt(inst), | 911 | .ptrtoint => try self.airPtrToInt(inst), |
| 910 | .ret => try self.airRet(inst), | 912 | .ret => try self.airRet(inst), |
| 911 | .ret_load => try self.airRetLoad(inst), | 913 | .ret_load => try self.airRetLoad(inst), |
| ... | @@ -1419,8 +1421,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1419,8 +1421,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1419 | | 1421 | |
| 1420 | // when truncating a `u16` to `u5`, for example, those top 3 bits in the result | 1422 | // when truncating a `u16` to `u5`, for example, those top 3 bits in the result |
| 1421 | // have to be removed. this only happens if the dst if not a power-of-two size. | 1423 | // have to be removed. this only happens if the dst if not a power-of-two size. |
| 1422 | const dst_bit_size = dst_ty.bitSize(self.target.*); | 1424 | if (self.regExtraBits(dst_ty) > 0) { |
| 1423 | if (!math.isPowerOfTwo(dst_bit_size) or dst_bit_size < 8) { | | |
| 1424 | try self.truncateRegister(dst_ty, reg); | 1425 | try self.truncateRegister(dst_ty, reg); |
| 1425 | } | 1426 | } |
| 1426 | | 1427 | |
| ... | @@ -1434,58 +1435,6 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1434,58 +1435,6 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 1434 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 1435 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 1435 | } | 1436 | } |
| 1436 | | 1437 | |
| 1437 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1438 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | | |
| 1439 | | | |
| 1440 | if (self.liveness.isUnused(inst)) { | | |
| 1441 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | | |
| 1442 | } | | |
| 1443 | | | |
| 1444 | const operand_ty = self.air.typeOf(ty_op.operand); | | |
| 1445 | const operand = try self.resolveInst(ty_op.operand); | | |
| 1446 | | | |
| 1447 | const result: MCValue = result: { | | |
| 1448 | switch (operand) { | | |
| 1449 | .dead => unreachable, | | |
| 1450 | .unreach => unreachable, | | |
| 1451 | .eflags => |cc| { | | |
| 1452 | break :result MCValue{ .eflags = cc.negate() }; | | |
| 1453 | }, | | |
| 1454 | else => {}, | | |
| 1455 | } | | |
| 1456 | | | |
| 1457 | const operand_lock: ?RegisterLock = switch (operand) { | | |
| 1458 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1459 | else => null, | | |
| 1460 | }; | | |
| 1461 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1462 | | | |
| 1463 | const dst_mcv: MCValue = blk: { | | |
| 1464 | if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand.isRegister()) { | | |
| 1465 | break :blk operand; | | |
| 1466 | } | | |
| 1467 | break :blk try self.copyToRegisterWithInstTracking(inst, operand_ty, operand); | | |
| 1468 | }; | | |
| 1469 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { | | |
| 1470 | .register => |reg| self.register_manager.lockReg(reg), | | |
| 1471 | else => null, | | |
| 1472 | }; | | |
| 1473 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1474 | | | |
| 1475 | const mask = switch (operand_ty.abiSize(self.target.*)) { | | |
| 1476 | 1 => ~@as(u8, 0), | | |
| 1477 | 2 => ~@as(u16, 0), | | |
| 1478 | 4 => ~@as(u32, 0), | | |
| 1479 | 8 => ~@as(u64, 0), | | |
| 1480 | else => unreachable, | | |
| 1481 | }; | | |
| 1482 | try self.genBinOpMir(.xor, operand_ty, dst_mcv, .{ .immediate = mask }); | | |
| 1483 | | | |
| 1484 | break :result dst_mcv; | | |
| 1485 | }; | | |
| 1486 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 1487 | } | | |
| 1488 | | | |
| 1489 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | 1438 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1490 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1439 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1491 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1440 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | @@ -1507,6 +1456,16 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1507,6 +1456,16 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1507 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1456 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1508 | } | 1457 | } |
| 1509 | | 1458 | |
| | 1459 | fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| | 1460 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1461 | |
| | 1462 | const result = if (self.liveness.isUnused(inst)) |
| | 1463 | .dead |
| | 1464 | else |
| | 1465 | try self.genUnOp(inst, tag, ty_op.operand); |
| | 1466 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 1467 | } |
| | 1468 | |
| 1510 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 1469 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1511 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1470 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1512 | | 1471 | |
| ... | @@ -2602,7 +2561,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2602,7 +2561,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 2602 | | 2561 | |
| 2603 | const dst_ty = self.air.typeOfIndex(inst); | 2562 | const dst_ty = self.air.typeOfIndex(inst); |
| 2604 | const src_ty = self.air.typeOf(ty_op.operand); | 2563 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2605 | const src_bits = src_ty.bitSize(self.target.*); | | |
| 2606 | | 2564 | |
| 2607 | const src_mcv = try self.resolveInst(ty_op.operand); | 2565 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2608 | const mat_src_mcv = switch (src_mcv) { | 2566 | const mat_src_mcv = switch (src_mcv) { |
| ... | @@ -2622,14 +2580,14 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2622,14 +2580,14 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 2622 | | 2580 | |
| 2623 | if (Target.x86.featureSetHas(self.target.cpu.features, .lzcnt)) { | 2581 | if (Target.x86.featureSetHas(self.target.cpu.features, .lzcnt)) { |
| 2624 | try self.genBinOpMir(.lzcnt, src_ty, dst_mcv, mat_src_mcv); | 2582 | try self.genBinOpMir(.lzcnt, src_ty, dst_mcv, mat_src_mcv); |
| 2625 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | 2583 | const extra_bits = self.regExtraBits(src_ty); |
| 2626 | const extra_bits = registerAlias(dst_reg, src_abi_size).bitSize() - src_bits; | | |
| 2627 | if (extra_bits > 0) { | 2584 | if (extra_bits > 0) { |
| 2628 | try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .immediate = extra_bits }); | 2585 | try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .immediate = extra_bits }); |
| 2629 | } | 2586 | } |
| 2630 | break :result dst_mcv; | 2587 | break :result dst_mcv; |
| 2631 | } | 2588 | } |
| 2632 | | 2589 | |
| | 2590 | const src_bits = src_ty.bitSize(self.target.*); |
| 2633 | const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits }); | 2591 | const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits }); |
| 2634 | const width_mcv = MCValue{ .register = width_reg }; | 2592 | const width_mcv = MCValue{ .register = width_reg }; |
| 2635 | try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv); | 2593 | try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv); |
| ... | @@ -2673,8 +2631,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2673,8 +2631,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 2673 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 2631 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2674 | | 2632 | |
| 2675 | if (Target.x86.featureSetHas(self.target.cpu.features, .bmi)) { | 2633 | if (Target.x86.featureSetHas(self.target.cpu.features, .bmi)) { |
| 2676 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | 2634 | const extra_bits = self.regExtraBits(src_ty); |
| 2677 | const extra_bits = registerAlias(dst_reg, src_abi_size).bitSize() - src_bits; | | |
| 2678 | const masked_mcv = if (extra_bits > 0) masked: { | 2635 | const masked_mcv = if (extra_bits > 0) masked: { |
| 2679 | const mask_mcv = MCValue{ | 2636 | const mask_mcv = MCValue{ |
| 2680 | .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) << @intCast(u6, src_bits), | 2637 | .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) << @intCast(u6, src_bits), |
| ... | @@ -3293,6 +3250,106 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3293,6 +3250,106 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3293 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3250 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3294 | } | 3251 | } |
| 3295 | | 3252 | |
| | 3253 | fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { |
| | 3254 | const src_ty = self.air.typeOf(src_air); |
| | 3255 | const src_mcv = try self.resolveInst(src_air); |
| | 3256 | if (src_ty.zigTypeTag() == .Vector) { |
| | 3257 | return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); |
| | 3258 | } |
| | 3259 | if (src_ty.abiSize(self.target.*) > 8) { |
| | 3260 | return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); |
| | 3261 | } |
| | 3262 | |
| | 3263 | switch (src_mcv) { |
| | 3264 | .eflags => |cc| switch (tag) { |
| | 3265 | .not => return .{ .eflags = cc.negate() }, |
| | 3266 | else => {}, |
| | 3267 | }, |
| | 3268 | else => {}, |
| | 3269 | } |
| | 3270 | |
| | 3271 | const src_lock = switch (src_mcv) { |
| | 3272 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 3273 | else => null, |
| | 3274 | }; |
| | 3275 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3276 | |
| | 3277 | const dst_mcv: MCValue = if (maybe_inst) |inst| |
| | 3278 | if (self.reuseOperand(inst, src_air, 0, src_mcv)) |
| | 3279 | src_mcv |
| | 3280 | else |
| | 3281 | try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv) |
| | 3282 | else |
| | 3283 | .{ .register = try self.copyToTmpRegister(src_ty, src_mcv) }; |
| | 3284 | const dst_lock = switch (dst_mcv) { |
| | 3285 | .register => |reg| self.register_manager.lockReg(reg), |
| | 3286 | else => null, |
| | 3287 | }; |
| | 3288 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3289 | |
| | 3290 | switch (tag) { |
| | 3291 | .not => { |
| | 3292 | const int_info = if (src_ty.tag() == .bool) |
| | 3293 | std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 } |
| | 3294 | else |
| | 3295 | src_ty.intInfo(self.target.*); |
| | 3296 | const extra_bits = self.regExtraBits(src_ty); |
| | 3297 | if (int_info.signedness == .unsigned and extra_bits > 0) { |
| | 3298 | const mask = (@as(u64, 1) << @intCast(u6, src_ty.bitSize(self.target.*))) - 1; |
| | 3299 | try self.genBinOpMir(.xor, src_ty, dst_mcv, .{ .immediate = mask }); |
| | 3300 | } else try self.genUnOpMir(.not, src_ty, dst_mcv); |
| | 3301 | }, |
| | 3302 | |
| | 3303 | .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv), |
| | 3304 | |
| | 3305 | else => unreachable, |
| | 3306 | } |
| | 3307 | return dst_mcv; |
| | 3308 | } |
| | 3309 | |
| | 3310 | fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue) !void { |
| | 3311 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| | 3312 | switch (dst_mcv) { |
| | 3313 | .none => unreachable, |
| | 3314 | .undef => unreachable, |
| | 3315 | .dead, .unreach, .immediate => unreachable, |
| | 3316 | .eflags => unreachable, |
| | 3317 | .register_overflow => unreachable, |
| | 3318 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), |
| | 3319 | .ptr_stack_offset, .stack_offset => |off| { |
| | 3320 | if (off > math.maxInt(i32)) { |
| | 3321 | return self.fail("stack offset too large", .{}); |
| | 3322 | } |
| | 3323 | if (abi_size > 8) { |
| | 3324 | return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag}); |
| | 3325 | } |
| | 3326 | |
| | 3327 | try self.asmMemory(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| | 3328 | .base = .rbp, |
| | 3329 | .disp = -off, |
| | 3330 | })); |
| | 3331 | }, |
| | 3332 | .memory, .linker_load => { |
| | 3333 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); |
| | 3334 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| | 3335 | defer self.register_manager.unlockReg(addr_reg_lock); |
| | 3336 | |
| | 3337 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv); |
| | 3338 | |
| | 3339 | // To get the actual address of the value we want to modify we have to go through the GOT |
| | 3340 | try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ |
| | 3341 | .base = addr_reg, |
| | 3342 | .disp = 0, |
| | 3343 | })); |
| | 3344 | |
| | 3345 | try self.asmMemory(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| | 3346 | .base = addr_reg, |
| | 3347 | .disp = 0, |
| | 3348 | })); |
| | 3349 | }, |
| | 3350 | } |
| | 3351 | } |
| | 3352 | |
| 3296 | /// Clobbers .rcx for non-immediate shift value. | 3353 | /// Clobbers .rcx for non-immediate shift value. |
| 3297 | fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void { | 3354 | fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void { |
| 3298 | assert(reg.to64() != .rcx); | 3355 | assert(reg.to64() != .rcx); |
| ... | @@ -3573,6 +3630,17 @@ fn genBinOp( | ... | @@ -3573,6 +3630,17 @@ fn genBinOp( |
| 3573 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)}); | 3630 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)}); |
| 3574 | } | 3631 | } |
| 3575 | | 3632 | |
| | 3633 | switch (lhs) { |
| | 3634 | .immediate => |imm| switch (imm) { |
| | 3635 | 0 => switch (tag) { |
| | 3636 | .sub, .subwrap => return self.genUnOp(maybe_inst, .neg, rhs_air), |
| | 3637 | else => {}, |
| | 3638 | }, |
| | 3639 | else => {}, |
| | 3640 | }, |
| | 3641 | else => {}, |
| | 3642 | } |
| | 3643 | |
| 3576 | const is_commutative: bool = switch (tag) { | 3644 | const is_commutative: bool = switch (tag) { |
| 3577 | .add, | 3645 | .add, |
| 3578 | .addwrap, | 3646 | .addwrap, |
| ... | @@ -3595,7 +3663,7 @@ fn genBinOp( | ... | @@ -3595,7 +3663,7 @@ fn genBinOp( |
| 3595 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 3663 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3596 | | 3664 | |
| 3597 | const rhs_lock: ?RegisterLock = switch (rhs) { | 3665 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 3598 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 3666 | .register => |reg| self.register_manager.lockReg(reg), |
| 3599 | else => null, | 3667 | else => null, |
| 3600 | }; | 3668 | }; |
| 3601 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 3669 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -3740,7 +3808,28 @@ fn genBinOp( | ... | @@ -3740,7 +3808,28 @@ fn genBinOp( |
| 3740 | | 3808 | |
| 3741 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); | 3809 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); |
| 3742 | switch (dst_mcv) { | 3810 | switch (dst_mcv) { |
| | 3811 | .none, |
| | 3812 | .undef, |
| | 3813 | .dead, |
| | 3814 | .unreach, |
| | 3815 | .immediate, |
| | 3816 | .eflags, |
| | 3817 | .register_overflow, |
| | 3818 | .stack_offset, |
| | 3819 | .ptr_stack_offset, |
| | 3820 | .memory, |
| | 3821 | .linker_load, |
| | 3822 | => unreachable, |
| 3743 | .register => |dst_reg| switch (mat_src_mcv) { | 3823 | .register => |dst_reg| switch (mat_src_mcv) { |
| | 3824 | .none, |
| | 3825 | .undef, |
| | 3826 | .dead, |
| | 3827 | .unreach, |
| | 3828 | .immediate, |
| | 3829 | .eflags, |
| | 3830 | .register_overflow, |
| | 3831 | .ptr_stack_offset, |
| | 3832 | => unreachable, |
| 3744 | .register => |src_reg| try self.asmCmovccRegisterRegister( | 3833 | .register => |src_reg| try self.asmCmovccRegisterRegister( |
| 3745 | registerAlias(dst_reg, abi_size), | 3834 | registerAlias(dst_reg, abi_size), |
| 3746 | registerAlias(src_reg, abi_size), | 3835 | registerAlias(src_reg, abi_size), |
| ... | @@ -3748,12 +3837,36 @@ fn genBinOp( | ... | @@ -3748,12 +3837,36 @@ fn genBinOp( |
| 3748 | ), | 3837 | ), |
| 3749 | .stack_offset => |off| try self.asmCmovccRegisterMemory( | 3838 | .stack_offset => |off| try self.asmCmovccRegisterMemory( |
| 3750 | registerAlias(dst_reg, abi_size), | 3839 | registerAlias(dst_reg, abi_size), |
| 3751 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }), | 3840 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| | 3841 | .base = .rbp, |
| | 3842 | .disp = -off, |
| | 3843 | }), |
| 3752 | cc, | 3844 | cc, |
| 3753 | ), | 3845 | ), |
| 3754 | else => unreachable, | 3846 | .memory, .linker_load => { |
| | 3847 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); |
| | 3848 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| | 3849 | defer self.register_manager.unlockReg(addr_reg_lock); |
| | 3850 | |
| | 3851 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv); |
| | 3852 | |
| | 3853 | // To get the actual address of the value we want to modify we |
| | 3854 | // we have to go through the GOT |
| | 3855 | try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ |
| | 3856 | .base = addr_reg, |
| | 3857 | .disp = 0, |
| | 3858 | })); |
| | 3859 | |
| | 3860 | try self.asmCmovccRegisterMemory( |
| | 3861 | registerAlias(dst_reg, abi_size), |
| | 3862 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| | 3863 | .base = addr_reg, |
| | 3864 | .disp = 0, |
| | 3865 | }), |
| | 3866 | cc, |
| | 3867 | ); |
| | 3868 | }, |
| 3755 | }, | 3869 | }, |
| 3756 | else => unreachable, | | |
| 3757 | } | 3870 | } |
| 3758 | }, | 3871 | }, |
| 3759 | .Float => try self.genBinOpMir(switch (lhs_ty.tag()) { | 3872 | .Float => try self.genBinOpMir(switch (lhs_ty.tag()) { |
| ... | @@ -3813,16 +3926,15 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu | ... | @@ -3813,16 +3926,15 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu |
| 3813 | ), | 3926 | ), |
| 3814 | }, | 3927 | }, |
| 3815 | .immediate => |imm| { | 3928 | .immediate => |imm| { |
| 3816 | switch (abi_size) { | 3929 | switch (self.regBitSize(dst_ty)) { |
| 3817 | 0 => unreachable, | 3930 | 8, 16, 32 => { |
| 3818 | 1...4 => { | | |
| 3819 | try self.asmRegisterImmediate( | 3931 | try self.asmRegisterImmediate( |
| 3820 | mir_tag, | 3932 | mir_tag, |
| 3821 | registerAlias(dst_reg, abi_size), | 3933 | registerAlias(dst_reg, abi_size), |
| 3822 | Immediate.u(@intCast(u32, imm)), | 3934 | Immediate.u(@intCast(u32, imm)), |
| 3823 | ); | 3935 | ); |
| 3824 | }, | 3936 | }, |
| 3825 | 5...8 => { | 3937 | 64 => { |
| 3826 | if (math.cast(i32, @bitCast(i64, imm))) |small| { | 3938 | if (math.cast(i32, @bitCast(i64, imm))) |small| { |
| 3827 | try self.asmRegisterImmediate( | 3939 | try self.asmRegisterImmediate( |
| 3828 | mir_tag, | 3940 | mir_tag, |
| ... | @@ -3883,11 +3995,40 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu | ... | @@ -3883,11 +3995,40 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu |
| 3883 | }), registerAlias(src_reg, abi_size)); | 3995 | }), registerAlias(src_reg, abi_size)); |
| 3884 | }, | 3996 | }, |
| 3885 | .immediate => |imm| { | 3997 | .immediate => |imm| { |
| 3886 | // TODO | 3998 | switch (self.regBitSize(dst_ty)) { |
| 3887 | try self.asmMemoryImmediate(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | 3999 | 8, 16, 32 => { |
| 3888 | .base = .rbp, | 4000 | try self.asmMemoryImmediate( |
| 3889 | .disp = -off, | 4001 | mir_tag, |
| 3890 | }), Immediate.u(@intCast(u32, imm))); | 4002 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| | 4003 | .base = .rbp, |
| | 4004 | .disp = -off, |
| | 4005 | }), |
| | 4006 | Immediate.u(@intCast(u32, imm)), |
| | 4007 | ); |
| | 4008 | }, |
| | 4009 | 64 => { |
| | 4010 | if (math.cast(i32, @bitCast(i64, imm))) |small| { |
| | 4011 | try self.asmMemoryImmediate( |
| | 4012 | mir_tag, |
| | 4013 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| | 4014 | .base = .rbp, |
| | 4015 | .disp = -off, |
| | 4016 | }), |
| | 4017 | Immediate.s(small), |
| | 4018 | ); |
| | 4019 | } else { |
| | 4020 | try self.asmMemoryRegister( |
| | 4021 | mir_tag, |
| | 4022 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| | 4023 | .base = .rbp, |
| | 4024 | .disp = -off, |
| | 4025 | }), |
| | 4026 | registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size), |
| | 4027 | ); |
| | 4028 | } |
| | 4029 | }, |
| | 4030 | else => return self.fail("TODO getBinOpMir implement large immediate ABI", .{}), |
| | 4031 | } |
| 3891 | }, | 4032 | }, |
| 3892 | .memory, | 4033 | .memory, |
| 3893 | .stack_offset, | 4034 | .stack_offset, |
| ... | @@ -4119,17 +4260,20 @@ fn airBreakpoint(self: *Self) !void { | ... | @@ -4119,17 +4260,20 @@ fn airBreakpoint(self: *Self) !void { |
| 4119 | } | 4260 | } |
| 4120 | | 4261 | |
| 4121 | fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void { | 4262 | fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void { |
| 4122 | const result: MCValue = if (self.liveness.isUnused(inst)) | 4263 | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4123 | .dead | 4264 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 4124 | else | 4265 | try self.setRegOrMem(Type.usize, dst_mcv, .{ |
| 4125 | .{ .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)) }; | 4266 | .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)), |
| | 4267 | }); |
| | 4268 | break :result dst_mcv; |
| | 4269 | }; |
| 4126 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 4270 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 4127 | } | 4271 | } |
| 4128 | | 4272 | |
| 4129 | fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void { | 4273 | fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void { |
| 4130 | const result = if (self.liveness.isUnused(inst)) .dead else result: { | 4274 | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4131 | const dst_mcv = try self.allocRegOrMem(inst, true); | 4275 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 4132 | try self.genBinOpMir(.mov, Type.usize, dst_mcv, .{ .register = .rbp }); | 4276 | try self.setRegOrMem(Type.usize, dst_mcv, .{ .register = .rbp }); |
| 4133 | break :result dst_mcv; | 4277 | break :result dst_mcv; |
| 4134 | }; | 4278 | }; |
| 4135 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 4279 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| ... | @@ -5864,7 +6008,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5864,7 +6008,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5864 | .undef => { | 6008 | .undef => { |
| 5865 | if (!self.wantSafety()) return; // The already existing value will do just fine. | 6009 | if (!self.wantSafety()) return; // The already existing value will do just fine. |
| 5866 | // Write the debug undefined value. | 6010 | // Write the debug undefined value. |
| 5867 | switch (registerAlias(reg, abi_size).bitSize()) { | 6011 | switch (self.regBitSize(ty)) { |
| 5868 | 8 => return self.genSetReg(ty, reg, .{ .immediate = 0xaa }), | 6012 | 8 => return self.genSetReg(ty, reg, .{ .immediate = 0xaa }), |
| 5869 | 16 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaa }), | 6013 | 16 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaa }), |
| 5870 | 32 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa }), | 6014 | 32 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa }), |
| ... | @@ -6763,6 +6907,27 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | ... | @@ -6763,6 +6907,27 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 6763 | } | 6907 | } |
| 6764 | } | 6908 | } |
| 6765 | | 6909 | |
| | 6910 | fn regBitSize(self: *Self, ty: Type) u64 { |
| | 6911 | return switch (ty.zigTypeTag()) { |
| | 6912 | else => switch (ty.abiSize(self.target.*)) { |
| | 6913 | 1 => 8, |
| | 6914 | 2 => 16, |
| | 6915 | 3...4 => 32, |
| | 6916 | 5...8 => 64, |
| | 6917 | else => unreachable, |
| | 6918 | }, |
| | 6919 | .Float => switch (ty.abiSize(self.target.*)) { |
| | 6920 | 1...16 => 128, |
| | 6921 | 17...32 => 256, |
| | 6922 | else => unreachable, |
| | 6923 | }, |
| | 6924 | }; |
| | 6925 | } |
| | 6926 | |
| | 6927 | fn regExtraBits(self: *Self, ty: Type) u64 { |
| | 6928 | return self.regBitSize(ty) - ty.bitSize(self.target.*); |
| | 6929 | } |
| | 6930 | |
| 6766 | fn intrinsicsAllowed(target: Target, ty: Type) bool { | 6931 | fn intrinsicsAllowed(target: Target, ty: Type) bool { |
| 6767 | return switch (ty.tag()) { | 6932 | return switch (ty.tag()) { |
| 6768 | .f32, | 6933 | .f32, |