| ... | @@ -125,6 +125,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void { | ... | @@ -125,6 +125,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 125 | .cmp_mem_index_imm => try emit.mirArithMemIndexImm(.cmp, inst), | 125 | .cmp_mem_index_imm => try emit.mirArithMemIndexImm(.cmp, inst), |
| 126 | .mov_mem_index_imm => try emit.mirArithMemIndexImm(.mov, inst), | 126 | .mov_mem_index_imm => try emit.mirArithMemIndexImm(.mov, inst), |
| 127 | | 127 | |
| | 128 | .mov_sign_extend => try emit.mirMovSignExtend(inst), |
| | 129 | .mov_zero_extend => try emit.mirMovZeroExtend(inst), |
| | 130 | |
| 128 | .movabs => try emit.mirMovabs(inst), | 131 | .movabs => try emit.mirMovabs(inst), |
| 129 | | 132 | |
| 130 | .lea => try emit.mirLea(inst), | 133 | .lea => try emit.mirLea(inst), |
| ... | @@ -188,14 +191,6 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { | ... | @@ -188,14 +191,6 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { |
| 188 | return error.EmitFail; | 191 | return error.EmitFail; |
| 189 | } | 192 | } |
| 190 | | 193 | |
| 191 | fn failWithLoweringError(emit: *Emit, err: LoweringError) InnerError { | | |
| 192 | return switch (err) { | | |
| 193 | error.RaxOperandExpected => emit.fail("Register.rax expected as destination operand", .{}), | | |
| 194 | error.OperandSizeMismatch => emit.fail("operand size mismatch", .{}), | | |
| 195 | else => |e| e, | | |
| 196 | }; | | |
| 197 | } | | |
| 198 | | | |
| 199 | fn fixupRelocs(emit: *Emit) InnerError!void { | 194 | fn fixupRelocs(emit: *Emit) InnerError!void { |
| 200 | // TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size. | 195 | // TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size. |
| 201 | // This should be reversed like it is done in aarch64 MIR emit code: start with the smallest | 196 | // This should be reversed like it is done in aarch64 MIR emit code: start with the smallest |
| ... | @@ -210,15 +205,15 @@ fn fixupRelocs(emit: *Emit) InnerError!void { | ... | @@ -210,15 +205,15 @@ fn fixupRelocs(emit: *Emit) InnerError!void { |
| 210 | } | 205 | } |
| 211 | | 206 | |
| 212 | fn mirBrk(emit: *Emit) InnerError!void { | 207 | fn mirBrk(emit: *Emit) InnerError!void { |
| 213 | return lowerToZoEnc(.brk, emit.code) catch |err| emit.failWithLoweringError(err); | 208 | return lowerToZoEnc(.brk, emit.code); |
| 214 | } | 209 | } |
| 215 | | 210 | |
| 216 | fn mirNop(emit: *Emit) InnerError!void { | 211 | fn mirNop(emit: *Emit) InnerError!void { |
| 217 | return lowerToZoEnc(.nop, emit.code) catch |err| emit.failWithLoweringError(err); | 212 | return lowerToZoEnc(.nop, emit.code); |
| 218 | } | 213 | } |
| 219 | | 214 | |
| 220 | fn mirSyscall(emit: *Emit) InnerError!void { | 215 | fn mirSyscall(emit: *Emit) InnerError!void { |
| 221 | return lowerToZoEnc(.syscall, emit.code) catch |err| emit.failWithLoweringError(err); | 216 | return lowerToZoEnc(.syscall, emit.code); |
| 222 | } | 217 | } |
| 223 | | 218 | |
| 224 | fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 219 | fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| ... | @@ -226,7 +221,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -226,7 +221,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 226 | switch (ops.flags) { | 221 | switch (ops.flags) { |
| 227 | 0b00 => { | 222 | 0b00 => { |
| 228 | // PUSH/POP reg | 223 | // PUSH/POP reg |
| 229 | return lowerToOEnc(tag, ops.reg1, emit.code) catch |err| emit.failWithLoweringError(err); | 224 | return lowerToOEnc(tag, ops.reg1, emit.code); |
| 230 | }, | 225 | }, |
| 231 | 0b01 => { | 226 | 0b01 => { |
| 232 | // PUSH/POP r/m64 | 227 | // PUSH/POP r/m64 |
| ... | @@ -238,14 +233,13 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -238,14 +233,13 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 238 | return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ | 233 | return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ |
| 239 | .disp = imm, | 234 | .disp = imm, |
| 240 | .base = ops.reg1, | 235 | .base = ops.reg1, |
| 241 | }), emit.code) catch |err| emit.failWithLoweringError(err); | 236 | }), emit.code); |
| 242 | }, | 237 | }, |
| 243 | 0b10 => { | 238 | 0b10 => { |
| 244 | // PUSH imm32 | 239 | // PUSH imm32 |
| 245 | assert(tag == .push); | 240 | assert(tag == .push); |
| 246 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 241 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 247 | return lowerToIEnc(.push, imm, emit.code) catch |err| | 242 | return lowerToIEnc(.push, imm, emit.code); |
| 248 | emit.failWithLoweringError(err); | | |
| 249 | }, | 243 | }, |
| 250 | 0b11 => unreachable, | 244 | 0b11 => unreachable, |
| 251 | } | 245 | } |
| ... | @@ -259,15 +253,15 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I | ... | @@ -259,15 +253,15 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I |
| 259 | for (bits.callee_preserved_regs) |reg, i| { | 253 | for (bits.callee_preserved_regs) |reg, i| { |
| 260 | if ((regs >> @intCast(u5, i)) & 1 == 0) continue; | 254 | if ((regs >> @intCast(u5, i)) & 1 == 0) continue; |
| 261 | if (tag == .push) { | 255 | if (tag == .push) { |
| 262 | lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ | 256 | try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ |
| 263 | .disp = @bitCast(u32, -@intCast(i32, disp)), | 257 | .disp = @bitCast(u32, -@intCast(i32, disp)), |
| 264 | .base = ops.reg1, | 258 | .base = ops.reg1, |
| 265 | }), reg.to64(), emit.code) catch |err| return emit.failWithLoweringError(err); | 259 | }), reg.to64(), emit.code); |
| 266 | } else { | 260 | } else { |
| 267 | lowerToRmEnc(.mov, reg.to64(), RegisterOrMemory.mem(.qword_ptr, .{ | 261 | try lowerToRmEnc(.mov, reg.to64(), RegisterOrMemory.mem(.qword_ptr, .{ |
| 268 | .disp = @bitCast(u32, -@intCast(i32, disp)), | 262 | .disp = @bitCast(u32, -@intCast(i32, disp)), |
| 269 | .base = ops.reg1, | 263 | .base = ops.reg1, |
| 270 | }), emit.code) catch |err| return emit.failWithLoweringError(err); | 264 | }), emit.code); |
| 271 | } | 265 | } |
| 272 | disp += 8; | 266 | disp += 8; |
| 273 | } | 267 | } |
| ... | @@ -279,8 +273,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -279,8 +273,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 279 | 0b00 => { | 273 | 0b00 => { |
| 280 | const target = emit.mir.instructions.items(.data)[inst].inst; | 274 | const target = emit.mir.instructions.items(.data)[inst].inst; |
| 281 | const source = emit.code.items.len; | 275 | const source = emit.code.items.len; |
| 282 | lowerToDEnc(tag, 0, emit.code) catch |err| | 276 | try lowerToDEnc(tag, 0, emit.code); |
| 283 | return emit.failWithLoweringError(err); | | |
| 284 | try emit.relocs.append(emit.bin_file.allocator, .{ | 277 | try emit.relocs.append(emit.bin_file.allocator, .{ |
| 285 | .source = source, | 278 | .source = source, |
| 286 | .target = target, | 279 | .target = target, |
| ... | @@ -296,11 +289,10 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -296,11 +289,10 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 296 | 16 => .word_ptr, | 289 | 16 => .word_ptr, |
| 297 | else => .qword_ptr, | 290 | else => .qword_ptr, |
| 298 | }; | 291 | }; |
| 299 | return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), emit.code) catch |err| | 292 | return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), emit.code); |
| 300 | emit.failWithLoweringError(err); | | |
| 301 | } | 293 | } |
| 302 | // JMP/CALL reg | 294 | // JMP/CALL reg |
| 303 | return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code) catch |err| emit.failWithLoweringError(err); | 295 | return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code); |
| 304 | }, | 296 | }, |
| 305 | 0b10 => { | 297 | 0b10 => { |
| 306 | // JMP/CALL r/m64 | 298 | // JMP/CALL r/m64 |
| ... | @@ -308,7 +300,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -308,7 +300,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 308 | return lowerToMEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ | 300 | return lowerToMEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ |
| 309 | .disp = imm, | 301 | .disp = imm, |
| 310 | .base = ops.reg1, | 302 | .base = ops.reg1, |
| 311 | }), emit.code) catch |err| emit.failWithLoweringError(err); | 303 | }), emit.code); |
| 312 | }, | 304 | }, |
| 313 | 0b11 => return emit.fail("TODO unused JMP/CALL variant 0b11", .{}), | 305 | 0b11 => return emit.fail("TODO unused JMP/CALL variant 0b11", .{}), |
| 314 | } | 306 | } |
| ... | @@ -337,8 +329,7 @@ fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerErr | ... | @@ -337,8 +329,7 @@ fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerErr |
| 337 | else => unreachable, | 329 | else => unreachable, |
| 338 | }; | 330 | }; |
| 339 | const source = emit.code.items.len; | 331 | const source = emit.code.items.len; |
| 340 | lowerToDEnc(tag, 0, emit.code) catch |err| | 332 | try lowerToDEnc(tag, 0, emit.code); |
| 341 | return emit.failWithLoweringError(err); | | |
| 342 | try emit.relocs.append(emit.bin_file.allocator, .{ | 333 | try emit.relocs.append(emit.bin_file.allocator, .{ |
| 343 | .source = source, | 334 | .source = source, |
| 344 | .target = target, | 335 | .target = target, |
| ... | @@ -368,8 +359,7 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne | ... | @@ -368,8 +359,7 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne |
| 368 | }, | 359 | }, |
| 369 | else => unreachable, | 360 | else => unreachable, |
| 370 | }; | 361 | }; |
| 371 | return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), emit.code) catch |err| | 362 | return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), emit.code); |
| 372 | emit.failWithLoweringError(err); | | |
| 373 | } | 363 | } |
| 374 | | 364 | |
| 375 | fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 365 | fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| ... | @@ -385,11 +375,9 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -385,11 +375,9 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 385 | if (ops.reg1.to64() == .rax) { | 375 | if (ops.reg1.to64() == .rax) { |
| 386 | // TEST rax, imm32 | 376 | // TEST rax, imm32 |
| 387 | // I | 377 | // I |
| 388 | return lowerToIEnc(.@"test", imm, emit.code) catch |err| | 378 | return lowerToIEnc(.@"test", imm, emit.code); |
| 389 | emit.failWithLoweringError(err); | | |
| 390 | } | 379 | } |
| 391 | return lowerToMiEnc(.@"test", RegisterOrMemory.reg(ops.reg1), imm, emit.code) catch |err| | 380 | return lowerToMiEnc(.@"test", RegisterOrMemory.reg(ops.reg1), imm, emit.code); |
| 392 | emit.failWithLoweringError(err); | | |
| 393 | } | 381 | } |
| 394 | // TEST r/m64, r64 | 382 | // TEST r/m64, r64 |
| 395 | return emit.fail("TODO TEST r/m64, r64", .{}); | 383 | return emit.fail("TODO TEST r/m64, r64", .{}); |
| ... | @@ -407,19 +395,19 @@ fn mirRet(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -407,19 +395,19 @@ fn mirRet(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 407 | // RETF imm16 | 395 | // RETF imm16 |
| 408 | // I | 396 | // I |
| 409 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 397 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 410 | return lowerToIEnc(.ret_far, imm, emit.code) catch |err| emit.failWithLoweringError(err); | 398 | return lowerToIEnc(.ret_far, imm, emit.code); |
| 411 | }, | 399 | }, |
| 412 | 0b01 => { | 400 | 0b01 => { |
| 413 | return lowerToZoEnc(.ret_far, emit.code) catch |err| emit.failWithLoweringError(err); | 401 | return lowerToZoEnc(.ret_far, emit.code); |
| 414 | }, | 402 | }, |
| 415 | 0b10 => { | 403 | 0b10 => { |
| 416 | // RET imm16 | 404 | // RET imm16 |
| 417 | // I | 405 | // I |
| 418 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 406 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 419 | return lowerToIEnc(.ret_near, imm, emit.code) catch |err| emit.failWithLoweringError(err); | 407 | return lowerToIEnc(.ret_near, imm, emit.code); |
| 420 | }, | 408 | }, |
| 421 | 0b11 => { | 409 | 0b11 => { |
| 422 | return lowerToZoEnc(.ret_near, emit.code) catch |err| emit.failWithLoweringError(err); | 410 | return lowerToZoEnc(.ret_near, emit.code); |
| 423 | }, | 411 | }, |
| 424 | } | 412 | } |
| 425 | } | 413 | } |
| ... | @@ -432,13 +420,11 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -432,13 +420,11 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 432 | // mov reg1, imm32 | 420 | // mov reg1, imm32 |
| 433 | // MI | 421 | // MI |
| 434 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 422 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 435 | return lowerToMiEnc(tag, RegisterOrMemory.reg(ops.reg1), imm, emit.code) catch |err| | 423 | return lowerToMiEnc(tag, RegisterOrMemory.reg(ops.reg1), imm, emit.code); |
| 436 | emit.failWithLoweringError(err); | | |
| 437 | } | 424 | } |
| 438 | // mov reg1, reg2 | 425 | // mov reg1, reg2 |
| 439 | // RM | 426 | // RM |
| 440 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code) catch |err| | 427 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| 441 | emit.failWithLoweringError(err); | | |
| 442 | }, | 428 | }, |
| 443 | 0b01 => { | 429 | 0b01 => { |
| 444 | // mov reg1, [reg2 + imm32] | 430 | // mov reg1, [reg2 + imm32] |
| ... | @@ -448,7 +434,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -448,7 +434,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 448 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ | 434 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ |
| 449 | .disp = imm, | 435 | .disp = imm, |
| 450 | .base = src_reg, | 436 | .base = src_reg, |
| 451 | }), emit.code) catch |err| emit.failWithLoweringError(err); | 437 | }), emit.code); |
| 452 | }, | 438 | }, |
| 453 | 0b10 => { | 439 | 0b10 => { |
| 454 | if (ops.reg2 == .none) { | 440 | if (ops.reg2 == .none) { |
| ... | @@ -460,7 +446,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -460,7 +446,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 460 | return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{ | 446 | return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{ |
| 461 | .disp = imm, | 447 | .disp = imm, |
| 462 | .base = ops.reg1, | 448 | .base = ops.reg1, |
| 463 | }), ops.reg2, emit.code) catch |err| emit.failWithLoweringError(err); | 449 | }), ops.reg2, emit.code); |
| 464 | }, | 450 | }, |
| 465 | 0b11 => { | 451 | 0b11 => { |
| 466 | return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{}); | 452 | return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{}); |
| ... | @@ -482,7 +468,7 @@ fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -482,7 +468,7 @@ fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 482 | return lowerToMiEnc(tag, RegisterOrMemory.mem(ptr_size, .{ | 468 | return lowerToMiEnc(tag, RegisterOrMemory.mem(ptr_size, .{ |
| 483 | .disp = imm_pair.dest_off, | 469 | .disp = imm_pair.dest_off, |
| 484 | .base = ops.reg1, | 470 | .base = ops.reg1, |
| 485 | }), imm_pair.operand, emit.code) catch |err| emit.failWithLoweringError(err); | 471 | }), imm_pair.operand, emit.code); |
| 486 | } | 472 | } |
| 487 | | 473 | |
| 488 | inline fn setRexWRegister(reg: Register) bool { | 474 | inline fn setRexWRegister(reg: Register) bool { |
| ... | @@ -517,7 +503,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void | ... | @@ -517,7 +503,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 517 | .disp = imm, | 503 | .disp = imm, |
| 518 | .base = ops.reg2, | 504 | .base = ops.reg2, |
| 519 | .scale_index = scale_index, | 505 | .scale_index = scale_index, |
| 520 | }), emit.code) catch |err| emit.failWithLoweringError(err); | 506 | }), emit.code); |
| 521 | } | 507 | } |
| 522 | | 508 | |
| 523 | fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 509 | fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| ... | @@ -534,14 +520,14 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void | ... | @@ -534,14 +520,14 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 534 | .disp = 0, | 520 | .disp = 0, |
| 535 | .base = ops.reg1, | 521 | .base = ops.reg1, |
| 536 | .scale_index = scale_index, | 522 | .scale_index = scale_index, |
| 537 | }), imm, emit.code) catch |err| emit.failWithLoweringError(err); | 523 | }), imm, emit.code); |
| 538 | } | 524 | } |
| 539 | // OP [reg1 + scale*rax + imm32], reg2 | 525 | // OP [reg1 + scale*rax + imm32], reg2 |
| 540 | return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{ | 526 | return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{ |
| 541 | .disp = imm, | 527 | .disp = imm, |
| 542 | .base = ops.reg1, | 528 | .base = ops.reg1, |
| 543 | .scale_index = scale_index, | 529 | .scale_index = scale_index, |
| 544 | }), ops.reg2, emit.code) catch |err| emit.failWithLoweringError(err); | 530 | }), ops.reg2, emit.code); |
| 545 | } | 531 | } |
| 546 | | 532 | |
| 547 | fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 533 | fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| ... | @@ -558,7 +544,7 @@ fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void | ... | @@ -558,7 +544,7 @@ fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 558 | .disp = imm_pair.dest_off, | 544 | .disp = imm_pair.dest_off, |
| 559 | .base = ops.reg1, | 545 | .base = ops.reg1, |
| 560 | .scale_index = scale_index, | 546 | .scale_index = scale_index, |
| 561 | }), imm_pair.operand, emit.code) catch |err| emit.failWithLoweringError(err); | 547 | }), imm_pair.operand, emit.code); |
| 562 | } | 548 | } |
| 563 | | 549 | |
| 564 | fn mirArithMemIndexImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 550 | fn mirArithMemIndexImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| ... | @@ -581,7 +567,65 @@ fn mirArithMemIndexImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!v | ... | @@ -581,7 +567,65 @@ fn mirArithMemIndexImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!v |
| 581 | .disp = imm_pair.dest_off, | 567 | .disp = imm_pair.dest_off, |
| 582 | .base = ops.reg1, | 568 | .base = ops.reg1, |
| 583 | .scale_index = scale_index, | 569 | .scale_index = scale_index, |
| 584 | }), imm_pair.operand, emit.code) catch |err| emit.failWithLoweringError(err); | 570 | }), imm_pair.operand, emit.code); |
| | 571 | } |
| | 572 | |
| | 573 | fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| | 574 | const mir_tag = emit.mir.instructions.items(.tag)[inst]; |
| | 575 | assert(mir_tag == .mov_sign_extend); |
| | 576 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| | 577 | const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined; |
| | 578 | switch (ops.flags) { |
| | 579 | 0b00 => { |
| | 580 | const tag: Tag = if (ops.reg2.size() == 32) .movsxd else .movsx; |
| | 581 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| | 582 | }, |
| | 583 | 0b01 => { |
| | 584 | return lowerToRmEnc(.movsx, ops.reg1, RegisterOrMemory.mem(.byte_ptr, .{ |
| | 585 | .disp = imm, |
| | 586 | .base = ops.reg2, |
| | 587 | }), emit.code); |
| | 588 | }, |
| | 589 | 0b10 => { |
| | 590 | return lowerToRmEnc(.movsx, ops.reg1, RegisterOrMemory.mem(.word_ptr, .{ |
| | 591 | .disp = imm, |
| | 592 | .base = ops.reg2, |
| | 593 | }), emit.code); |
| | 594 | }, |
| | 595 | 0b11 => { |
| | 596 | return lowerToRmEnc(.movsxd, ops.reg1, RegisterOrMemory.mem(.dword_ptr, .{ |
| | 597 | .disp = imm, |
| | 598 | .base = ops.reg2, |
| | 599 | }), emit.code); |
| | 600 | }, |
| | 601 | } |
| | 602 | } |
| | 603 | |
| | 604 | fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| | 605 | const mir_tag = emit.mir.instructions.items(.tag)[inst]; |
| | 606 | assert(mir_tag == .mov_zero_extend); |
| | 607 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| | 608 | const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined; |
| | 609 | switch (ops.flags) { |
| | 610 | 0b00 => { |
| | 611 | return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| | 612 | }, |
| | 613 | 0b01 => { |
| | 614 | return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.mem(.byte_ptr, .{ |
| | 615 | .disp = imm, |
| | 616 | .base = ops.reg2, |
| | 617 | }), emit.code); |
| | 618 | }, |
| | 619 | 0b10 => { |
| | 620 | return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.mem(.word_ptr, .{ |
| | 621 | .disp = imm, |
| | 622 | .base = ops.reg2, |
| | 623 | }), emit.code); |
| | 624 | }, |
| | 625 | 0b11 => { |
| | 626 | return emit.fail("TODO unused variant: movzx 0b11", .{}); |
| | 627 | }, |
| | 628 | } |
| 585 | } | 629 | } |
| 586 | | 630 | |
| 587 | fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 631 | fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| ... | @@ -596,16 +640,16 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -596,16 +640,16 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 596 | if (ops.flags == 0b00) { | 640 | if (ops.flags == 0b00) { |
| 597 | // movabs reg, imm64 | 641 | // movabs reg, imm64 |
| 598 | // OI | 642 | // OI |
| 599 | return lowerToOiEnc(.mov, ops.reg1, imm, emit.code) catch |err| emit.failWithLoweringError(err); | 643 | return lowerToOiEnc(.mov, ops.reg1, imm, emit.code); |
| 600 | } | 644 | } |
| 601 | if (ops.reg1 == .none) { | 645 | if (ops.reg1 == .none) { |
| 602 | // movabs moffs64, rax | 646 | // movabs moffs64, rax |
| 603 | // TD | 647 | // TD |
| 604 | return lowerToTdEnc(.mov, imm, ops.reg2, emit.code) catch |err| emit.failWithLoweringError(err); | 648 | return lowerToTdEnc(.mov, imm, ops.reg2, emit.code); |
| 605 | } | 649 | } |
| 606 | // movabs rax, moffs64 | 650 | // movabs rax, moffs64 |
| 607 | // FD | 651 | // FD |
| 608 | return lowerToFdEnc(.mov, ops.reg1, imm, emit.code) catch |err| emit.failWithLoweringError(err); | 652 | return lowerToFdEnc(.mov, ops.reg1, imm, emit.code); |
| 609 | } | 653 | } |
| 610 | | 654 | |
| 611 | fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 655 | fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| ... | @@ -614,13 +658,11 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -614,13 +658,11 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 614 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 658 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 615 | switch (ops.flags) { | 659 | switch (ops.flags) { |
| 616 | 0b00 => { | 660 | 0b00 => { |
| 617 | return lowerToRmEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code) catch |err| | 661 | return lowerToRmEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code); |
| 618 | emit.failWithLoweringError(err); | | |
| 619 | }, | 662 | }, |
| 620 | 0b10 => { | 663 | 0b10 => { |
| 621 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 664 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 622 | return lowerToRmiEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), imm, emit.code) catch |err| | 665 | return lowerToRmiEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), imm, emit.code); |
| 623 | emit.failWithLoweringError(err); | | |
| 624 | }, | 666 | }, |
| 625 | else => return emit.fail("TODO implement imul", .{}), | 667 | else => return emit.fail("TODO implement imul", .{}), |
| 626 | } | 668 | } |
| ... | @@ -644,18 +686,18 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -644,18 +686,18 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 644 | .base = src_reg, | 686 | .base = src_reg, |
| 645 | }), | 687 | }), |
| 646 | emit.code, | 688 | emit.code, |
| 647 | ) catch |err| emit.failWithLoweringError(err); | 689 | ); |
| 648 | }, | 690 | }, |
| 649 | 0b01 => { | 691 | 0b01 => { |
| 650 | // lea reg1, [rip + imm32] | 692 | // lea reg1, [rip + imm32] |
| 651 | // RM | 693 | // RM |
| 652 | const start_offset = emit.code.items.len; | 694 | const start_offset = emit.code.items.len; |
| 653 | lowerToRmEnc( | 695 | try lowerToRmEnc( |
| 654 | .lea, | 696 | .lea, |
| 655 | ops.reg1, | 697 | ops.reg1, |
| 656 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), | 698 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), |
| 657 | emit.code, | 699 | emit.code, |
| 658 | ) catch |err| return emit.failWithLoweringError(err); | 700 | ); |
| 659 | const end_offset = emit.code.items.len; | 701 | const end_offset = emit.code.items.len; |
| 660 | // Backpatch the displacement | 702 | // Backpatch the displacement |
| 661 | const payload = emit.mir.instructions.items(.data)[inst].payload; | 703 | const payload = emit.mir.instructions.items(.data)[inst].payload; |
| ... | @@ -666,12 +708,12 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -666,12 +708,12 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 666 | 0b10 => { | 708 | 0b10 => { |
| 667 | // lea reg1, [rip + reloc] | 709 | // lea reg1, [rip + reloc] |
| 668 | // RM | 710 | // RM |
| 669 | lowerToRmEnc( | 711 | try lowerToRmEnc( |
| 670 | .lea, | 712 | .lea, |
| 671 | ops.reg1, | 713 | ops.reg1, |
| 672 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), | 714 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), |
| 673 | emit.code, | 715 | emit.code, |
| 674 | ) catch |err| return emit.failWithLoweringError(err); | 716 | ); |
| 675 | const end_offset = emit.code.items.len; | 717 | const end_offset = emit.code.items.len; |
| 676 | const got_entry = emit.mir.instructions.items(.data)[inst].got_entry; | 718 | const got_entry = emit.mir.instructions.items(.data)[inst].got_entry; |
| 677 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { | 719 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| ... | @@ -710,7 +752,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -710,7 +752,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 710 | .scale_index = scale_index, | 752 | .scale_index = scale_index, |
| 711 | }), | 753 | }), |
| 712 | emit.code, | 754 | emit.code, |
| 713 | ) catch |err| emit.failWithLoweringError(err); | 755 | ); |
| 714 | }, | 756 | }, |
| 715 | } | 757 | } |
| 716 | } | 758 | } |
| ... | @@ -721,8 +763,7 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -721,8 +763,7 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 721 | const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn; | 763 | const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn; |
| 722 | const offset = blk: { | 764 | const offset = blk: { |
| 723 | // callq | 765 | // callq |
| 724 | lowerToDEnc(.call_near, 0, emit.code) catch |err| | 766 | try lowerToDEnc(.call_near, 0, emit.code); |
| 725 | return emit.failWithLoweringError(err); | | |
| 726 | break :blk @intCast(u32, emit.code.items.len) - 4; | 767 | break :blk @intCast(u32, emit.code.items.len) - 4; |
| 727 | }; | 768 | }; |
| 728 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { | 769 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| ... | @@ -934,6 +975,9 @@ const Tag = enum { | ... | @@ -934,6 +975,9 @@ const Tag = enum { |
| 934 | sbb, | 975 | sbb, |
| 935 | cmp, | 976 | cmp, |
| 936 | mov, | 977 | mov, |
| | 978 | movsx, |
| | 979 | movsxd, |
| | 980 | movzx, |
| 937 | lea, | 981 | lea, |
| 938 | jmp_near, | 982 | jmp_near, |
| 939 | call_near, | 983 | call_near, |
| ... | @@ -1200,6 +1244,9 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { | ... | @@ -1200,6 +1244,9 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { |
| 1200 | .sbb => OpCode.oneByte(if (is_one_byte) 0x1a else 0x1b), | 1244 | .sbb => OpCode.oneByte(if (is_one_byte) 0x1a else 0x1b), |
| 1201 | .cmp => OpCode.oneByte(if (is_one_byte) 0x3a else 0x3b), | 1245 | .cmp => OpCode.oneByte(if (is_one_byte) 0x3a else 0x3b), |
| 1202 | .mov => OpCode.oneByte(if (is_one_byte) 0x8a else 0x8b), | 1246 | .mov => OpCode.oneByte(if (is_one_byte) 0x8a else 0x8b), |
| | 1247 | .movsx => OpCode.twoByte(0x0f, if (is_one_byte) 0xbe else 0xbf), |
| | 1248 | .movsxd => OpCode.oneByte(0x63), |
| | 1249 | .movzx => OpCode.twoByte(0x0f, if (is_one_byte) 0xb6 else 0xb7), |
| 1203 | .lea => OpCode.oneByte(if (is_one_byte) 0x8c else 0x8d), | 1250 | .lea => OpCode.oneByte(if (is_one_byte) 0x8c else 0x8d), |
| 1204 | .imul => OpCode.twoByte(0x0f, 0xaf), | 1251 | .imul => OpCode.twoByte(0x0f, 0xaf), |
| 1205 | else => null, | 1252 | else => null, |
| ... | @@ -1367,6 +1414,10 @@ const Memory = struct { | ... | @@ -1367,6 +1414,10 @@ const Memory = struct { |
| 1367 | encoder.disp32(@bitCast(i32, mem_op.disp)); | 1414 | encoder.disp32(@bitCast(i32, mem_op.disp)); |
| 1368 | } | 1415 | } |
| 1369 | } | 1416 | } |
| | 1417 | |
| | 1418 | fn size(memory: Memory) u64 { |
| | 1419 | return memory.ptr_size.size(); |
| | 1420 | } |
| 1370 | }; | 1421 | }; |
| 1371 | | 1422 | |
| 1372 | fn encodeImm(encoder: Encoder, imm: u32, size: u64) void { | 1423 | fn encodeImm(encoder: Encoder, imm: u32, size: u64) void { |
| ... | @@ -1411,21 +1462,22 @@ const RegisterOrMemory = union(enum) { | ... | @@ -1411,21 +1462,22 @@ const RegisterOrMemory = union(enum) { |
| 1411 | }, | 1462 | }, |
| 1412 | }; | 1463 | }; |
| 1413 | } | 1464 | } |
| 1414 | }; | | |
| 1415 | | 1465 | |
| 1416 | const LoweringError = error{ | 1466 | fn size(reg_or_mem: RegisterOrMemory) u64 { |
| 1417 | OutOfMemory, | 1467 | return switch (reg_or_mem) { |
| 1418 | OperandSizeMismatch, | 1468 | .register => |reg| reg.size(), |
| 1419 | RaxOperandExpected, | 1469 | .memory => |memory| memory.size(), |
| | 1470 | }; |
| | 1471 | } |
| 1420 | }; | 1472 | }; |
| 1421 | | 1473 | |
| 1422 | fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) LoweringError!void { | 1474 | fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void { |
| 1423 | const opc = getOpCode(tag, .zo, false).?; | 1475 | const opc = getOpCode(tag, .zo, false).?; |
| 1424 | const encoder = try Encoder.init(code, 1); | 1476 | const encoder = try Encoder.init(code, 1); |
| 1425 | opc.encode(encoder); | 1477 | opc.encode(encoder); |
| 1426 | } | 1478 | } |
| 1427 | | 1479 | |
| 1428 | fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) LoweringError!void { | 1480 | fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { |
| 1429 | if (tag == .ret_far or tag == .ret_near) { | 1481 | if (tag == .ret_far or tag == .ret_near) { |
| 1430 | const encoder = try Encoder.init(code, 3); | 1482 | const encoder = try Encoder.init(code, 3); |
| 1431 | const opc = getOpCode(tag, .i, false).?; | 1483 | const opc = getOpCode(tag, .i, false).?; |
| ... | @@ -1442,10 +1494,7 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) LoweringError!void | ... | @@ -1442,10 +1494,7 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) LoweringError!void |
| 1442 | encodeImm(encoder, imm, immOpSize(imm)); | 1494 | encodeImm(encoder, imm, immOpSize(imm)); |
| 1443 | } | 1495 | } |
| 1444 | | 1496 | |
| 1445 | fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) LoweringError!void { | 1497 | fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void { |
| 1446 | if (reg.size() != 16 and reg.size() != 64) { | | |
| 1447 | return error.OperandSizeMismatch; // TODO correct for push/pop, but is it universal? | | |
| 1448 | } | | |
| 1449 | const opc = getOpCode(tag, .o, false).?; | 1498 | const opc = getOpCode(tag, .o, false).?; |
| 1450 | const encoder = try Encoder.init(code, 3); | 1499 | const encoder = try Encoder.init(code, 3); |
| 1451 | if (reg.size() == 16) { | 1500 | if (reg.size() == 16) { |
| ... | @@ -1458,26 +1507,18 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) LoweringError! | ... | @@ -1458,26 +1507,18 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) LoweringError! |
| 1458 | opc.encodeWithReg(encoder, reg); | 1507 | opc.encodeWithReg(encoder, reg); |
| 1459 | } | 1508 | } |
| 1460 | | 1509 | |
| 1461 | fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) LoweringError!void { | 1510 | fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void { |
| 1462 | const opc = getOpCode(tag, .d, false).?; | 1511 | const opc = getOpCode(tag, .d, false).?; |
| 1463 | const encoder = try Encoder.init(code, 6); | 1512 | const encoder = try Encoder.init(code, 6); |
| 1464 | opc.encode(encoder); | 1513 | opc.encode(encoder); |
| 1465 | encoder.imm32(@bitCast(i32, imm)); | 1514 | encoder.imm32(@bitCast(i32, imm)); |
| 1466 | } | 1515 | } |
| 1467 | | 1516 | |
| 1468 | fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) LoweringError!void { | 1517 | fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void { |
| 1469 | const opc = getOpCode(tag, .m, false).?; | 1518 | const opc = getOpCode(tag, .m, false).?; |
| 1470 | const modrm_ext = getModRmExt(tag).?; | 1519 | const modrm_ext = getModRmExt(tag).?; |
| 1471 | switch (reg_or_mem) { | 1520 | switch (reg_or_mem) { |
| 1472 | .register => |reg| { | 1521 | .register => |reg| { |
| 1473 | const op_size_mismatch = blk: { | | |
| 1474 | if (tag.isSetCC() and reg.size() == 8) | | |
| 1475 | break :blk false; | | |
| 1476 | break :blk reg.size() != 64 and reg.size() != 16; | | |
| 1477 | }; | | |
| 1478 | if (op_size_mismatch) { | | |
| 1479 | return error.OperandSizeMismatch; | | |
| 1480 | } | | |
| 1481 | const encoder = try Encoder.init(code, 4); | 1522 | const encoder = try Encoder.init(code, 4); |
| 1482 | if (reg.size() == 16) { | 1523 | if (reg.size() == 16) { |
| 1483 | encoder.prefix16BitMode(); | 1524 | encoder.prefix16BitMode(); |
| ... | @@ -1493,17 +1534,11 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) | ... | @@ -1493,17 +1534,11 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) |
| 1493 | encoder.modRm_direct(modrm_ext, reg.lowId()); | 1534 | encoder.modRm_direct(modrm_ext, reg.lowId()); |
| 1494 | }, | 1535 | }, |
| 1495 | .memory => |mem_op| { | 1536 | .memory => |mem_op| { |
| 1496 | if (mem_op.ptr_size != .qword_ptr and mem_op.ptr_size != .word_ptr) { | | |
| 1497 | return error.OperandSizeMismatch; | | |
| 1498 | } | | |
| 1499 | const encoder = try Encoder.init(code, 8); | 1537 | const encoder = try Encoder.init(code, 8); |
| 1500 | if (mem_op.ptr_size == .word_ptr) { | 1538 | if (mem_op.ptr_size == .word_ptr) { |
| 1501 | encoder.prefix16BitMode(); | 1539 | encoder.prefix16BitMode(); |
| 1502 | } | 1540 | } |
| 1503 | if (mem_op.base) |base| { | 1541 | if (mem_op.base) |base| { |
| 1504 | if (base.size() != 64) { | | |
| 1505 | return error.OperandSizeMismatch; | | |
| 1506 | } | | |
| 1507 | encoder.rex(.{ | 1542 | encoder.rex(.{ |
| 1508 | .w = false, | 1543 | .w = false, |
| 1509 | .b = base.isExtended(), | 1544 | .b = base.isExtended(), |
| ... | @@ -1515,18 +1550,15 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) | ... | @@ -1515,18 +1550,15 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) |
| 1515 | } | 1550 | } |
| 1516 | } | 1551 | } |
| 1517 | | 1552 | |
| 1518 | fn lowerToTdEnc(tag: Tag, moffs: u64, reg: Register, code: *std.ArrayList(u8)) LoweringError!void { | 1553 | fn lowerToTdEnc(tag: Tag, moffs: u64, reg: Register, code: *std.ArrayList(u8)) InnerError!void { |
| 1519 | return lowerToTdFdEnc(tag, reg, moffs, code, true); | 1554 | return lowerToTdFdEnc(tag, reg, moffs, code, true); |
| 1520 | } | 1555 | } |
| 1521 | | 1556 | |
| 1522 | fn lowerToFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8)) LoweringError!void { | 1557 | fn lowerToFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8)) InnerError!void { |
| 1523 | return lowerToTdFdEnc(tag, reg, moffs, code, false); | 1558 | return lowerToTdFdEnc(tag, reg, moffs, code, false); |
| 1524 | } | 1559 | } |
| 1525 | | 1560 | |
| 1526 | fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), td: bool) LoweringError!void { | 1561 | fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), td: bool) InnerError!void { |
| 1527 | if (reg.lowId() != Register.rax.lowId()) { | | |
| 1528 | return error.RaxOperandExpected; | | |
| 1529 | } | | |
| 1530 | const opc = if (td) | 1562 | const opc = if (td) |
| 1531 | getOpCode(tag, .td, reg.size() == 8).? | 1563 | getOpCode(tag, .td, reg.size() == 8).? |
| 1532 | else | 1564 | else |
| ... | @@ -1548,7 +1580,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), | ... | @@ -1548,7 +1580,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), |
| 1548 | } | 1580 | } |
| 1549 | } | 1581 | } |
| 1550 | | 1582 | |
| 1551 | fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) LoweringError!void { | 1583 | fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) InnerError!void { |
| 1552 | const opc = getOpCode(tag, .oi, reg.size() == 8).?; | 1584 | const opc = getOpCode(tag, .oi, reg.size() == 8).?; |
| 1553 | const encoder = try Encoder.init(code, 10); | 1585 | const encoder = try Encoder.init(code, 10); |
| 1554 | if (reg.size() == 16) { | 1586 | if (reg.size() == 16) { |
| ... | @@ -1568,11 +1600,11 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) Low | ... | @@ -1568,11 +1600,11 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) Low |
| 1568 | } | 1600 | } |
| 1569 | } | 1601 | } |
| 1570 | | 1602 | |
| 1571 | fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.ArrayList(u8)) LoweringError!void { | 1603 | fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.ArrayList(u8)) InnerError!void { |
| 1572 | const modrm_ext = getModRmExt(tag).?; | 1604 | const modrm_ext = getModRmExt(tag).?; |
| | 1605 | const opc = getOpCode(tag, .mi, reg_or_mem.size() == 8).?; |
| 1573 | switch (reg_or_mem) { | 1606 | switch (reg_or_mem) { |
| 1574 | .register => |dst_reg| { | 1607 | .register => |dst_reg| { |
| 1575 | const opc = getOpCode(tag, .mi, dst_reg.size() == 8).?; | | |
| 1576 | const encoder = try Encoder.init(code, 7); | 1608 | const encoder = try Encoder.init(code, 7); |
| 1577 | if (dst_reg.size() == 16) { | 1609 | if (dst_reg.size() == 16) { |
| 1578 | // 0x66 prefix switches to the non-default size; here we assume a switch from | 1610 | // 0x66 prefix switches to the non-default size; here we assume a switch from |
| ... | @@ -1589,15 +1621,11 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.Arr | ... | @@ -1589,15 +1621,11 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.Arr |
| 1589 | encodeImm(encoder, imm, dst_reg.size()); | 1621 | encodeImm(encoder, imm, dst_reg.size()); |
| 1590 | }, | 1622 | }, |
| 1591 | .memory => |dst_mem| { | 1623 | .memory => |dst_mem| { |
| 1592 | const opc = getOpCode(tag, .mi, dst_mem.ptr_size == .byte_ptr).?; | | |
| 1593 | const encoder = try Encoder.init(code, 12); | 1624 | const encoder = try Encoder.init(code, 12); |
| 1594 | if (dst_mem.ptr_size == .word_ptr) { | 1625 | if (dst_mem.ptr_size == .word_ptr) { |
| 1595 | encoder.prefix16BitMode(); | 1626 | encoder.prefix16BitMode(); |
| 1596 | } | 1627 | } |
| 1597 | if (dst_mem.base) |base| { | 1628 | if (dst_mem.base) |base| { |
| 1598 | if (base.size() != 64) { | | |
| 1599 | return error.OperandSizeMismatch; | | |
| 1600 | } | | |
| 1601 | encoder.rex(.{ | 1629 | encoder.rex(.{ |
| 1602 | .w = dst_mem.ptr_size == .qword_ptr, | 1630 | .w = dst_mem.ptr_size == .qword_ptr, |
| 1603 | .b = base.isExtended(), | 1631 | .b = base.isExtended(), |
| ... | @@ -1619,13 +1647,10 @@ fn lowerToRmEnc( | ... | @@ -1619,13 +1647,10 @@ fn lowerToRmEnc( |
| 1619 | reg: Register, | 1647 | reg: Register, |
| 1620 | reg_or_mem: RegisterOrMemory, | 1648 | reg_or_mem: RegisterOrMemory, |
| 1621 | code: *std.ArrayList(u8), | 1649 | code: *std.ArrayList(u8), |
| 1622 | ) LoweringError!void { | 1650 | ) InnerError!void { |
| 1623 | const opc = getOpCode(tag, .rm, reg.size() == 8).?; | 1651 | const opc = getOpCode(tag, .rm, reg.size() == 8 or reg_or_mem.size() == 8).?; |
| 1624 | switch (reg_or_mem) { | 1652 | switch (reg_or_mem) { |
| 1625 | .register => |src_reg| { | 1653 | .register => |src_reg| { |
| 1626 | if (reg.size() != src_reg.size()) { | | |
| 1627 | return error.OperandSizeMismatch; | | |
| 1628 | } | | |
| 1629 | const encoder = try Encoder.init(code, 4); | 1654 | const encoder = try Encoder.init(code, 4); |
| 1630 | encoder.rex(.{ | 1655 | encoder.rex(.{ |
| 1631 | .w = setRexWRegister(reg) or setRexWRegister(src_reg), | 1656 | .w = setRexWRegister(reg) or setRexWRegister(src_reg), |
| ... | @@ -1636,9 +1661,6 @@ fn lowerToRmEnc( | ... | @@ -1636,9 +1661,6 @@ fn lowerToRmEnc( |
| 1636 | encoder.modRm_direct(reg.lowId(), src_reg.lowId()); | 1661 | encoder.modRm_direct(reg.lowId(), src_reg.lowId()); |
| 1637 | }, | 1662 | }, |
| 1638 | .memory => |src_mem| { | 1663 | .memory => |src_mem| { |
| 1639 | if (reg.size() != src_mem.ptr_size.size()) { | | |
| 1640 | return error.OperandSizeMismatch; | | |
| 1641 | } | | |
| 1642 | const encoder = try Encoder.init(code, 9); | 1664 | const encoder = try Encoder.init(code, 9); |
| 1643 | if (reg.size() == 16) { | 1665 | if (reg.size() == 16) { |
| 1644 | encoder.prefix16BitMode(); | 1666 | encoder.prefix16BitMode(); |
| ... | @@ -1646,9 +1668,6 @@ fn lowerToRmEnc( | ... | @@ -1646,9 +1668,6 @@ fn lowerToRmEnc( |
| 1646 | if (src_mem.base) |base| { | 1668 | if (src_mem.base) |base| { |
| 1647 | // TODO handle 32-bit base register - requires prefix 0x67 | 1669 | // TODO handle 32-bit base register - requires prefix 0x67 |
| 1648 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 | 1670 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 |
| 1649 | if (base.size() != 64) { | | |
| 1650 | return error.OperandSizeMismatch; | | |
| 1651 | } | | |
| 1652 | encoder.rex(.{ | 1671 | encoder.rex(.{ |
| 1653 | .w = setRexWRegister(reg), | 1672 | .w = setRexWRegister(reg), |
| 1654 | .r = reg.isExtended(), | 1673 | .r = reg.isExtended(), |
| ... | @@ -1671,13 +1690,10 @@ fn lowerToMrEnc( | ... | @@ -1671,13 +1690,10 @@ fn lowerToMrEnc( |
| 1671 | reg_or_mem: RegisterOrMemory, | 1690 | reg_or_mem: RegisterOrMemory, |
| 1672 | reg: Register, | 1691 | reg: Register, |
| 1673 | code: *std.ArrayList(u8), | 1692 | code: *std.ArrayList(u8), |
| 1674 | ) LoweringError!void { | 1693 | ) InnerError!void { |
| 1675 | const opc = getOpCode(tag, .mr, reg.size() == 8).?; | 1694 | const opc = getOpCode(tag, .mr, reg.size() == 8 or reg_or_mem.size() == 8).?; |
| 1676 | switch (reg_or_mem) { | 1695 | switch (reg_or_mem) { |
| 1677 | .register => |dst_reg| { | 1696 | .register => |dst_reg| { |
| 1678 | if (dst_reg.size() != reg.size()) { | | |
| 1679 | return error.OperandSizeMismatch; | | |
| 1680 | } | | |
| 1681 | const encoder = try Encoder.init(code, 3); | 1697 | const encoder = try Encoder.init(code, 3); |
| 1682 | encoder.rex(.{ | 1698 | encoder.rex(.{ |
| 1683 | .w = setRexWRegister(dst_reg) or setRexWRegister(reg), | 1699 | .w = setRexWRegister(dst_reg) or setRexWRegister(reg), |
| ... | @@ -1688,17 +1704,11 @@ fn lowerToMrEnc( | ... | @@ -1688,17 +1704,11 @@ fn lowerToMrEnc( |
| 1688 | encoder.modRm_direct(reg.lowId(), dst_reg.lowId()); | 1704 | encoder.modRm_direct(reg.lowId(), dst_reg.lowId()); |
| 1689 | }, | 1705 | }, |
| 1690 | .memory => |dst_mem| { | 1706 | .memory => |dst_mem| { |
| 1691 | if (dst_mem.ptr_size.size() != reg.size()) { | | |
| 1692 | return error.OperandSizeMismatch; | | |
| 1693 | } | | |
| 1694 | const encoder = try Encoder.init(code, 9); | 1707 | const encoder = try Encoder.init(code, 9); |
| 1695 | if (reg.size() == 16) { | 1708 | if (reg.size() == 16) { |
| 1696 | encoder.prefix16BitMode(); | 1709 | encoder.prefix16BitMode(); |
| 1697 | } | 1710 | } |
| 1698 | if (dst_mem.base) |base| { | 1711 | if (dst_mem.base) |base| { |
| 1699 | if (base.size() != 64) { | | |
| 1700 | return error.OperandSizeMismatch; | | |
| 1701 | } | | |
| 1702 | encoder.rex(.{ | 1712 | encoder.rex(.{ |
| 1703 | .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg), | 1713 | .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg), |
| 1704 | .r = reg.isExtended(), | 1714 | .r = reg.isExtended(), |
| ... | @@ -1722,10 +1732,7 @@ fn lowerToRmiEnc( | ... | @@ -1722,10 +1732,7 @@ fn lowerToRmiEnc( |
| 1722 | reg_or_mem: RegisterOrMemory, | 1732 | reg_or_mem: RegisterOrMemory, |
| 1723 | imm: u32, | 1733 | imm: u32, |
| 1724 | code: *std.ArrayList(u8), | 1734 | code: *std.ArrayList(u8), |
| 1725 | ) LoweringError!void { | 1735 | ) InnerError!void { |
| 1726 | if (reg.size() == 8) { | | |
| 1727 | return error.OperandSizeMismatch; | | |
| 1728 | } | | |
| 1729 | const opc = getOpCode(tag, .rmi, false).?; | 1736 | const opc = getOpCode(tag, .rmi, false).?; |
| 1730 | const encoder = try Encoder.init(code, 13); | 1737 | const encoder = try Encoder.init(code, 13); |
| 1731 | if (reg.size() == 16) { | 1738 | if (reg.size() == 16) { |
| ... | @@ -1733,9 +1740,6 @@ fn lowerToRmiEnc( | ... | @@ -1733,9 +1740,6 @@ fn lowerToRmiEnc( |
| 1733 | } | 1740 | } |
| 1734 | switch (reg_or_mem) { | 1741 | switch (reg_or_mem) { |
| 1735 | .register => |src_reg| { | 1742 | .register => |src_reg| { |
| 1736 | if (reg.size() != src_reg.size()) { | | |
| 1737 | return error.OperandSizeMismatch; | | |
| 1738 | } | | |
| 1739 | encoder.rex(.{ | 1743 | encoder.rex(.{ |
| 1740 | .w = setRexWRegister(reg) or setRexWRegister(src_reg), | 1744 | .w = setRexWRegister(reg) or setRexWRegister(src_reg), |
| 1741 | .r = reg.isExtended(), | 1745 | .r = reg.isExtended(), |
| ... | @@ -1748,12 +1752,6 @@ fn lowerToRmiEnc( | ... | @@ -1748,12 +1752,6 @@ fn lowerToRmiEnc( |
| 1748 | if (src_mem.base) |base| { | 1752 | if (src_mem.base) |base| { |
| 1749 | // TODO handle 32-bit base register - requires prefix 0x67 | 1753 | // TODO handle 32-bit base register - requires prefix 0x67 |
| 1750 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 | 1754 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 |
| 1751 | if (base.size() != 64) { | | |
| 1752 | return error.OperandSizeMismatch; | | |
| 1753 | } | | |
| 1754 | if (src_mem.ptr_size == .byte_ptr) { | | |
| 1755 | return error.OperandSizeMismatch; | | |
| 1756 | } | | |
| 1757 | encoder.rex(.{ | 1755 | encoder.rex(.{ |
| 1758 | .w = setRexWRegister(reg), | 1756 | .w = setRexWRegister(reg), |
| 1759 | .r = reg.isExtended(), | 1757 | .r = reg.isExtended(), |