authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-18 01:12:19+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-19 14:24:03+01:00
log2c13a4b87e1d9ae5c5c1117bc03b5fb67825ca34
tree40e0280568ffc5bbc557d6087e75a6aeb446882c
parent1f4aa5ef78f4b516530f26aaeedf3794a0a9f585

x64: implement div_exact for ints (signed+unsigned)


3 files changed, 127 insertions(+), 11 deletions(-)

src/arch/x86_64/CodeGen.zig+92-10
...@@ -1254,10 +1254,92 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1254,10 +1254,92 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
12541254
1255fn airDiv(self: *Self, inst: Air.Inst.Index) !void {1255fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
1256 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1256 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1257 const result: MCValue = if (self.liveness.isUnused(inst))1257 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1258 .dead1258 const dst_ty = self.air.typeOfIndex(inst);
1259 else1259 const tag = self.air.instructions.items(.tag)[inst];
1260 return self.fail("TODO implement div for {}", .{self.target.cpu.arch});1260 switch (tag) {
1261 .div_exact => {},
1262 .div_trunc, .div_floor, .div_float => return self.fail("TODO implement {}", .{tag}),
1263 else => unreachable,
1264 }
1265
1266 if (dst_ty.zigTypeTag() != .Int) {
1267 return self.fail("TODO implement {} for operands of type {}", .{ tag, dst_ty.zigTypeTag() });
1268 }
1269
1270 const signedness = dst_ty.intInfo(self.target.*).signedness;
1271 const ty = if (signedness == .signed) Type.isize else dst_ty;
1272 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
1273
1274 const lhs = try self.resolveInst(bin_op.lhs);
1275 blk: {
1276 switch (lhs) {
1277 .register => |reg| {
1278 if (reg.to64() == .rax) break :blk;
1279 },
1280 else => {},
1281 }
1282 try self.register_manager.getReg(.rax, inst); // track inst -> rax in register manager
1283 try self.genSetReg(ty, .rax, lhs);
1284 }
1285 if (signedness == .signed) {
1286 _ = try self.addInst(.{
1287 .tag = .cwd,
1288 .ops = (Mir.Ops{
1289 .flags = 0b11,
1290 }).encode(),
1291 .data = undefined,
1292 });
1293 }
1294 const dst_mcv = MCValue{ .register = registerAlias(.rax, abi_size) };
1295
1296 try self.register_manager.getReg(.rdx, null);
1297 self.register_manager.freezeRegs(&.{ .rax, .rdx });
1298 defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx });
1299
1300 const rhs = try self.resolveInst(bin_op.rhs);
1301 const divisor = blk: {
1302 switch (rhs) {
1303 .register, .stack_offset => break :blk rhs,
1304 else => {
1305 const reg = try self.copyToTmpRegister(ty, rhs);
1306 break :blk MCValue{ .register = reg };
1307 },
1308 }
1309 };
1310
1311 switch (divisor) {
1312 .register => |reg| {
1313 _ = try self.addInst(.{
1314 .tag = .idiv,
1315 .ops = (Mir.Ops{
1316 .reg1 = registerAlias(reg, abi_size),
1317 }).encode(),
1318 .data = undefined,
1319 });
1320 },
1321 .stack_offset => |off| {
1322 const flags: u2 = switch (abi_size) {
1323 1 => 0b00,
1324 2 => 0b01,
1325 4 => 0b10,
1326 8 => 0b11,
1327 else => unreachable,
1328 };
1329 _ = try self.addInst(.{
1330 .tag = .idiv,
1331 .ops = (Mir.Ops{
1332 .reg2 = .rbp,
1333 .flags = flags,
1334 }).encode(),
1335 .data = .{ .imm = @bitCast(u32, -off) },
1336 });
1337 },
1338 else => unreachable,
1339 }
1340
1341 break :result dst_mcv;
1342 };
1261 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1343 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1262}1344}
12631345
...@@ -4126,7 +4208,7 @@ fn genInlineMemset(...@@ -4126,7 +4208,7 @@ fn genInlineMemset(
4126}4208}
41274209
4128fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {4210fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
4129 const abi_size = ty.abiSize(self.target.*);4211 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4130 switch (mcv) {4212 switch (mcv) {
4131 .dead => unreachable,4213 .dead => unreachable,
4132 .ptr_stack_offset => |off| {4214 .ptr_stack_offset => |off| {
...@@ -4136,7 +4218,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4136,7 +4218,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4136 _ = try self.addInst(.{4218 _ = try self.addInst(.{
4137 .tag = .lea,4219 .tag = .lea,
4138 .ops = (Mir.Ops{4220 .ops = (Mir.Ops{
4139 .reg1 = registerAlias(reg, @intCast(u32, abi_size)),4221 .reg1 = registerAlias(reg, abi_size),
4140 .reg2 = .rbp,4222 .reg2 = .rbp,
4141 }).encode(),4223 }).encode(),
4142 .data = .{ .imm = @bitCast(u32, -off) },4224 .data = .{ .imm = @bitCast(u32, -off) },
...@@ -4202,7 +4284,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4202,7 +4284,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4202 _ = try self.addInst(.{4284 _ = try self.addInst(.{
4203 .tag = .mov,4285 .tag = .mov,
4204 .ops = (Mir.Ops{4286 .ops = (Mir.Ops{
4205 .reg1 = registerAlias(reg, @intCast(u32, abi_size)),4287 .reg1 = registerAlias(reg, abi_size),
4206 }).encode(),4288 }).encode(),
4207 .data = .{ .imm = @truncate(u32, x) },4289 .data = .{ .imm = @truncate(u32, x) },
4208 });4290 });
...@@ -4272,8 +4354,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4272,8 +4354,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4272 _ = try self.addInst(.{4354 _ = try self.addInst(.{
4273 .tag = .mov,4355 .tag = .mov,
4274 .ops = (Mir.Ops{4356 .ops = (Mir.Ops{
4275 .reg1 = registerAlias(reg, @divExact(src_reg.size(), 8)),4357 .reg1 = registerAlias(reg, abi_size),
4276 .reg2 = src_reg,4358 .reg2 = registerAlias(src_reg, abi_size),
4277 }).encode(),4359 }).encode(),
4278 .data = undefined,4360 .data = undefined,
4279 });4361 });
...@@ -4399,7 +4481,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4399,7 +4481,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4399 _ = try self.addInst(.{4481 _ = try self.addInst(.{
4400 .tag = .mov,4482 .tag = .mov,
4401 .ops = (Mir.Ops{4483 .ops = (Mir.Ops{
4402 .reg1 = registerAlias(reg, @intCast(u32, abi_size)),4484 .reg1 = registerAlias(reg, abi_size),
4403 .reg2 = .rbp,4485 .reg2 = .rbp,
4404 .flags = 0b01,4486 .flags = 0b01,
4405 }).encode(),4487 }).encode(),
src/arch/x86_64/Emit.zig+28-1
...@@ -142,6 +142,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -142,6 +142,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
142 .idiv => try emit.mirIMulIDiv(.idiv, inst),142 .idiv => try emit.mirIMulIDiv(.idiv, inst),
143 .imul_complex => try emit.mirIMulComplex(inst),143 .imul_complex => try emit.mirIMulComplex(inst),
144144
145 .cwd => try emit.mirCwd(inst),
146
145 .push => try emit.mirPushPop(.push, inst),147 .push => try emit.mirPushPop(.push, inst),
146 .pop => try emit.mirPushPop(.pop, inst),148 .pop => try emit.mirPushPop(.pop, inst),
147149
...@@ -737,6 +739,17 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -737,6 +739,17 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
737 }739 }
738}740}
739741
742fn mirCwd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
743 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
744 const tag: Tag = switch (ops.flags) {
745 0b00 => .cbw,
746 0b01 => .cwd,
747 0b10 => .cdq,
748 0b11 => .cqo,
749 };
750 return lowerToZoEnc(tag, emit.code);
751}
752
740fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {753fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
741 const tag = emit.mir.instructions.items(.tag)[inst];754 const tag = emit.mir.instructions.items(.tag)[inst];
742 assert(tag == .lea);755 assert(tag == .lea);
...@@ -1139,6 +1152,10 @@ const Tag = enum {...@@ -1139,6 +1152,10 @@ const Tag = enum {
1139 sal,1152 sal,
1140 shr,1153 shr,
1141 sar,1154 sar,
1155 cbw,
1156 cwd,
1157 cdq,
1158 cqo,
11421159
1143 fn isSetCC(tag: Tag) bool {1160 fn isSetCC(tag: Tag) bool {
1144 return switch (tag) {1161 return switch (tag) {
...@@ -1258,6 +1275,8 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1258,6 +1275,8 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1258 .brk => OpCode.oneByte(0xcc),1275 .brk => OpCode.oneByte(0xcc),
1259 .nop => OpCode.oneByte(0x90),1276 .nop => OpCode.oneByte(0x90),
1260 .syscall => OpCode.twoByte(0x0f, 0x05),1277 .syscall => OpCode.twoByte(0x0f, 0x05),
1278 .cbw => OpCode.oneByte(0x98),
1279 .cwd, .cdq, .cqo => OpCode.oneByte(0x99),
1261 else => null,1280 else => null,
1262 },1281 },
1263 .d => return switch (tag) {1282 .d => return switch (tag) {
...@@ -1592,7 +1611,15 @@ const RegisterOrMemory = union(enum) {...@@ -1592,7 +1611,15 @@ const RegisterOrMemory = union(enum) {
15921611
1593fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {1612fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {
1594 const opc = getOpCode(tag, .zo, false).?;1613 const opc = getOpCode(tag, .zo, false).?;
1595 const encoder = try Encoder.init(code, 1);1614 const encoder = try Encoder.init(code, 2);
1615 switch (tag) {
1616 .cqo => {
1617 encoder.rex(.{
1618 .w = true,
1619 });
1620 },
1621 else => {},
1622 }
1596 opc.encode(encoder);1623 opc.encode(encoder);
1597}1624}
15981625
src/arch/x86_64/Mir.zig+7
...@@ -228,6 +228,13 @@ pub const Inst = struct {...@@ -228,6 +228,13 @@ pub const Inst = struct {
228 imul,228 imul,
229 idiv,229 idiv,
230230
231 /// ops flags: form:
232 /// 0b00 AX <- AL
233 /// 0b01 DX:AX <- AX
234 /// 0b10 EDX:EAX <- EAX
235 /// 0b11 RDX:RAX <- RAX
236 cwd,
237
231 /// ops flags: form:238 /// ops flags: form:
232 /// 0b00 reg1, reg2239 /// 0b00 reg1, reg2
233 /// 0b01 reg1, [reg2 + imm32]240 /// 0b01 reg1, [reg2 + imm32]