| ... | @@ -260,149 +260,60 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -260,149 +260,60 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 260 | return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code); | 260 | return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code); |
| 261 | } | 261 | } |
| 262 | | 262 | |
| 263 | const CondType = enum { | 263 | fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { |
| 264 | /// greater than or equal | 264 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 265 | gte, | 265 | const target = emit.mir.instructions.items(.data)[inst].inst; |
| 266 | | 266 | const tag = switch (mir_tag) { |
| 267 | /// greater than | 267 | .cond_jmp_greater_less => switch (ops.flags) { |
| 268 | gt, | 268 | 0b00 => Tag.jge, |
| 269 | | 269 | 0b01 => Tag.jg, |
| 270 | /// less than | 270 | 0b10 => Tag.jl, |
| 271 | lt, | 271 | 0b11 => Tag.jle, |
| 272 | | | |
| 273 | /// less than or equal | | |
| 274 | lte, | | |
| 275 | | | |
| 276 | /// above or equal | | |
| 277 | ae, | | |
| 278 | | | |
| 279 | /// above | | |
| 280 | a, | | |
| 281 | | | |
| 282 | /// below | | |
| 283 | b, | | |
| 284 | | | |
| 285 | /// below or equal | | |
| 286 | be, | | |
| 287 | | | |
| 288 | /// not equal | | |
| 289 | ne, | | |
| 290 | | | |
| 291 | /// equal | | |
| 292 | eq, | | |
| 293 | | | |
| 294 | fn fromTagAndFlags(tag: Mir.Inst.Tag, flags: u2) CondType { | | |
| 295 | return switch (tag) { | | |
| 296 | .cond_jmp_greater_less, | | |
| 297 | .cond_set_byte_greater_less, | | |
| 298 | => switch (flags) { | | |
| 299 | 0b00 => CondType.gte, | | |
| 300 | 0b01 => CondType.gt, | | |
| 301 | 0b10 => CondType.lt, | | |
| 302 | 0b11 => CondType.lte, | | |
| 303 | }, | | |
| 304 | .cond_jmp_above_below, | | |
| 305 | .cond_set_byte_above_below, | | |
| 306 | => switch (flags) { | | |
| 307 | 0b00 => CondType.ae, | | |
| 308 | 0b01 => CondType.a, | | |
| 309 | 0b10 => CondType.b, | | |
| 310 | 0b11 => CondType.be, | | |
| 311 | }, | | |
| 312 | .cond_jmp_eq_ne, | | |
| 313 | .cond_set_byte_eq_ne, | | |
| 314 | => switch (@truncate(u1, flags)) { | | |
| 315 | 0b0 => CondType.ne, | | |
| 316 | 0b1 => CondType.eq, | | |
| 317 | }, | | |
| 318 | else => unreachable, | | |
| 319 | }; | | |
| 320 | } | | |
| 321 | }; | | |
| 322 | | | |
| 323 | inline fn getCondOpCode(tag: Mir.Inst.Tag, cond: CondType) u8 { | | |
| 324 | switch (cond) { | | |
| 325 | .gte => return switch (tag) { | | |
| 326 | .cond_jmp_greater_less => 0x8d, | | |
| 327 | .cond_set_byte_greater_less => 0x9d, | | |
| 328 | else => unreachable, | | |
| 329 | }, | | |
| 330 | .gt => return switch (tag) { | | |
| 331 | .cond_jmp_greater_less => 0x8f, | | |
| 332 | .cond_set_byte_greater_less => 0x9f, | | |
| 333 | else => unreachable, | | |
| 334 | }, | | |
| 335 | .lt => return switch (tag) { | | |
| 336 | .cond_jmp_greater_less => 0x8c, | | |
| 337 | .cond_set_byte_greater_less => 0x9c, | | |
| 338 | else => unreachable, | | |
| 339 | }, | | |
| 340 | .lte => return switch (tag) { | | |
| 341 | .cond_jmp_greater_less => 0x8e, | | |
| 342 | .cond_set_byte_greater_less => 0x9e, | | |
| 343 | else => unreachable, | | |
| 344 | }, | | |
| 345 | .ae => return switch (tag) { | | |
| 346 | .cond_jmp_above_below => 0x83, | | |
| 347 | .cond_set_byte_above_below => 0x93, | | |
| 348 | else => unreachable, | | |
| 349 | }, | | |
| 350 | .a => return switch (tag) { | | |
| 351 | .cond_jmp_above_below => 0x87, | | |
| 352 | .cond_set_byte_greater_less => 0x97, | | |
| 353 | else => unreachable, | | |
| 354 | }, | | |
| 355 | .b => return switch (tag) { | | |
| 356 | .cond_jmp_above_below => 0x82, | | |
| 357 | .cond_set_byte_greater_less => 0x92, | | |
| 358 | else => unreachable, | | |
| 359 | }, | | |
| 360 | .be => return switch (tag) { | | |
| 361 | .cond_jmp_above_below => 0x86, | | |
| 362 | .cond_set_byte_greater_less => 0x96, | | |
| 363 | else => unreachable, | | |
| 364 | }, | 272 | }, |
| 365 | .eq => return switch (tag) { | 273 | .cond_jmp_above_below => switch (ops.flags) { |
| 366 | .cond_jmp_eq_ne => 0x84, | 274 | 0b00 => Tag.jae, |
| 367 | .cond_set_byte_eq_ne => 0x94, | 275 | 0b01 => Tag.ja, |
| 368 | else => unreachable, | 276 | 0b10 => Tag.jb, |
| | 277 | 0b11 => Tag.jbe, |
| 369 | }, | 278 | }, |
| 370 | .ne => return switch (tag) { | 279 | .cond_jmp_eq_ne => switch (@truncate(u1, ops.flags)) { |
| 371 | .cond_jmp_eq_ne => 0x85, | 280 | 0b0 => Tag.jne, |
| 372 | .cond_set_byte_eq_ne => 0x95, | 281 | 0b1 => Tag.je, |
| 373 | else => unreachable, | | |
| 374 | }, | 282 | }, |
| 375 | } | 283 | else => unreachable, |
| 376 | } | 284 | }; |
| 377 | | | |
| 378 | fn mirCondJmp(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { | | |
| 379 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | | |
| 380 | const target = emit.mir.instructions.items(.data)[inst].inst; | | |
| 381 | const cond = CondType.fromTagAndFlags(tag, ops.flags); | | |
| 382 | const opc = getCondOpCode(tag, cond); | | |
| 383 | const source = emit.code.items.len; | 285 | const source = emit.code.items.len; |
| 384 | const encoder = try Encoder.init(emit.code, 6); | 286 | try lowerToDEnc(tag, 0, emit.code); |
| 385 | encoder.opcode_2byte(0x0f, opc); | | |
| 386 | try emit.relocs.append(emit.bin_file.allocator, .{ | 287 | try emit.relocs.append(emit.bin_file.allocator, .{ |
| 387 | .source = source, | 288 | .source = source, |
| 388 | .target = target, | 289 | .target = target, |
| 389 | .offset = emit.code.items.len, | 290 | .offset = emit.code.items.len - 4, |
| 390 | .length = 6, | 291 | .length = 6, |
| 391 | }); | 292 | }); |
| 392 | encoder.imm32(0); | | |
| 393 | } | 293 | } |
| 394 | | 294 | |
| 395 | fn mirCondSetByte(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { | 295 | fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { |
| 396 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 296 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 397 | const cond = CondType.fromTagAndFlags(tag, ops.flags); | 297 | const tag = switch (mir_tag) { |
| 398 | const opc = getCondOpCode(tag, cond); | 298 | .cond_set_byte_greater_less => switch (ops.flags) { |
| 399 | const encoder = try Encoder.init(emit.code, 4); | 299 | 0b00 => Tag.setge, |
| 400 | encoder.rex(.{ | 300 | 0b01 => Tag.setg, |
| 401 | .w = true, | 301 | 0b10 => Tag.setl, |
| 402 | .b = ops.reg1.isExtended(), | 302 | 0b11 => Tag.setle, |
| 403 | }); | 303 | }, |
| 404 | encoder.opcode_2byte(0x0f, opc); | 304 | .cond_set_byte_above_below => switch (ops.flags) { |
| 405 | encoder.modRm_direct(0x0, ops.reg1.lowId()); | 305 | 0b00 => Tag.setae, |
| | 306 | 0b01 => Tag.seta, |
| | 307 | 0b10 => Tag.setb, |
| | 308 | 0b11 => Tag.setbe, |
| | 309 | }, |
| | 310 | .cond_set_byte_eq_ne => switch (@truncate(u1, ops.flags)) { |
| | 311 | 0b0 => Tag.setne, |
| | 312 | 0b1 => Tag.sete, |
| | 313 | }, |
| | 314 | else => unreachable, |
| | 315 | }; |
| | 316 | return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code); |
| 406 | } | 317 | } |
| 407 | | 318 | |
| 408 | fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 319 | fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| ... | @@ -472,6 +383,103 @@ const Tag = enum { | ... | @@ -472,6 +383,103 @@ const Tag = enum { |
| 472 | syscall, | 383 | syscall, |
| 473 | ret_near, | 384 | ret_near, |
| 474 | ret_far, | 385 | ret_far, |
| | 386 | jo, |
| | 387 | jno, |
| | 388 | jb, |
| | 389 | jbe, |
| | 390 | jc, |
| | 391 | jnae, |
| | 392 | jnc, |
| | 393 | jae, |
| | 394 | je, |
| | 395 | jz, |
| | 396 | jne, |
| | 397 | jnz, |
| | 398 | jna, |
| | 399 | jnb, |
| | 400 | jnbe, |
| | 401 | ja, |
| | 402 | js, |
| | 403 | jns, |
| | 404 | jpe, |
| | 405 | jp, |
| | 406 | jpo, |
| | 407 | jnp, |
| | 408 | jnge, |
| | 409 | jl, |
| | 410 | jge, |
| | 411 | jnl, |
| | 412 | jle, |
| | 413 | jng, |
| | 414 | jg, |
| | 415 | jnle, |
| | 416 | seto, |
| | 417 | setno, |
| | 418 | setb, |
| | 419 | setc, |
| | 420 | setnae, |
| | 421 | setnb, |
| | 422 | setnc, |
| | 423 | setae, |
| | 424 | sete, |
| | 425 | setz, |
| | 426 | setne, |
| | 427 | setnz, |
| | 428 | setbe, |
| | 429 | setna, |
| | 430 | seta, |
| | 431 | setnbe, |
| | 432 | sets, |
| | 433 | setns, |
| | 434 | setp, |
| | 435 | setpe, |
| | 436 | setnp, |
| | 437 | setop, |
| | 438 | setl, |
| | 439 | setnge, |
| | 440 | setnl, |
| | 441 | setge, |
| | 442 | setle, |
| | 443 | setng, |
| | 444 | setnle, |
| | 445 | setg, |
| | 446 | |
| | 447 | fn isSetCC(tag: Tag) bool { |
| | 448 | return switch (tag) { |
| | 449 | .seto, |
| | 450 | .setno, |
| | 451 | .setb, |
| | 452 | .setc, |
| | 453 | .setnae, |
| | 454 | .setnb, |
| | 455 | .setnc, |
| | 456 | .setae, |
| | 457 | .sete, |
| | 458 | .setz, |
| | 459 | .setne, |
| | 460 | .setnz, |
| | 461 | .setbe, |
| | 462 | .setna, |
| | 463 | .seta, |
| | 464 | .setnbe, |
| | 465 | .sets, |
| | 466 | .setns, |
| | 467 | .setp, |
| | 468 | .setpe, |
| | 469 | .setnp, |
| | 470 | .setop, |
| | 471 | .setl, |
| | 472 | .setnge, |
| | 473 | .setnl, |
| | 474 | .setge, |
| | 475 | .setle, |
| | 476 | .setng, |
| | 477 | .setnle, |
| | 478 | .setg, |
| | 479 | => true, |
| | 480 | else => false, |
| | 481 | }; |
| | 482 | } |
| 475 | }; | 483 | }; |
| 476 | | 484 | |
| 477 | const Encoding = enum { | 485 | const Encoding = enum { |
| ... | @@ -547,11 +555,43 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { | ... | @@ -547,11 +555,43 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { |
| 547 | .d => return switch (tag) { | 555 | .d => return switch (tag) { |
| 548 | .jmp_near => OpCode.oneByte(0xe9), | 556 | .jmp_near => OpCode.oneByte(0xe9), |
| 549 | .call_near => OpCode.oneByte(0xe8), | 557 | .call_near => OpCode.oneByte(0xe8), |
| | 558 | .jo => if (is_one_byte) OpCode.oneByte(0x70) else OpCode.twoByte(0x0f, 0x80), |
| | 559 | .jno => if (is_one_byte) OpCode.oneByte(0x71) else OpCode.twoByte(0x0f, 0x81), |
| | 560 | .jb, .jc, .jnae => if (is_one_byte) OpCode.oneByte(0x72) else OpCode.twoByte(0x0f, 0x82), |
| | 561 | .jnb, .jnc, .jae => if (is_one_byte) OpCode.oneByte(0x73) else OpCode.twoByte(0x0f, 0x83), |
| | 562 | .je, .jz => if (is_one_byte) OpCode.oneByte(0x74) else OpCode.twoByte(0x0f, 0x84), |
| | 563 | .jne, .jnz => if (is_one_byte) OpCode.oneByte(0x75) else OpCode.twoByte(0x0f, 0x85), |
| | 564 | .jna, .jbe => if (is_one_byte) OpCode.oneByte(0x76) else OpCode.twoByte(0x0f, 0x86), |
| | 565 | .jnbe, .ja => if (is_one_byte) OpCode.oneByte(0x77) else OpCode.twoByte(0x0f, 0x87), |
| | 566 | .js => if (is_one_byte) OpCode.oneByte(0x78) else OpCode.twoByte(0x0f, 0x88), |
| | 567 | .jns => if (is_one_byte) OpCode.oneByte(0x79) else OpCode.twoByte(0x0f, 0x89), |
| | 568 | .jpe, .jp => if (is_one_byte) OpCode.oneByte(0x7a) else OpCode.twoByte(0x0f, 0x8a), |
| | 569 | .jpo, .jnp => if (is_one_byte) OpCode.oneByte(0x7b) else OpCode.twoByte(0x0f, 0x8b), |
| | 570 | .jnge, .jl => if (is_one_byte) OpCode.oneByte(0x7c) else OpCode.twoByte(0x0f, 0x8c), |
| | 571 | .jge, .jnl => if (is_one_byte) OpCode.oneByte(0x7d) else OpCode.twoByte(0x0f, 0x8d), |
| | 572 | .jle, .jng => if (is_one_byte) OpCode.oneByte(0x7e) else OpCode.twoByte(0x0f, 0x8e), |
| | 573 | .jg, .jnle => if (is_one_byte) OpCode.oneByte(0x7f) else OpCode.twoByte(0x0f, 0x8f), |
| 550 | else => null, | 574 | else => null, |
| 551 | }, | 575 | }, |
| 552 | .m => return switch (tag) { | 576 | .m => return switch (tag) { |
| 553 | .jmp_near, .call_near, .push => OpCode.oneByte(0xff), | 577 | .jmp_near, .call_near, .push => OpCode.oneByte(0xff), |
| 554 | .pop => OpCode.oneByte(0x8f), | 578 | .pop => OpCode.oneByte(0x8f), |
| | 579 | .seto => OpCode.twoByte(0x0f, 0x90), |
| | 580 | .setno => OpCode.twoByte(0x0f, 0x91), |
| | 581 | .setb, .setc, .setnae => OpCode.twoByte(0x0f, 0x92), |
| | 582 | .setnb, .setnc, .setae => OpCode.twoByte(0x0f, 0x93), |
| | 583 | .sete, .setz => OpCode.twoByte(0x0f, 0x94), |
| | 584 | .setne, .setnz => OpCode.twoByte(0x0f, 0x95), |
| | 585 | .setbe, .setna => OpCode.twoByte(0x0f, 0x96), |
| | 586 | .seta, .setnbe => OpCode.twoByte(0x0f, 0x97), |
| | 587 | .sets => OpCode.twoByte(0x0f, 0x98), |
| | 588 | .setns => OpCode.twoByte(0x0f, 0x99), |
| | 589 | .setp, .setpe => OpCode.twoByte(0x0f, 0x9a), |
| | 590 | .setnp, .setop => OpCode.twoByte(0x0f, 0x9b), |
| | 591 | .setl, .setnge => OpCode.twoByte(0x0f, 0x9c), |
| | 592 | .setnl, .setge => OpCode.twoByte(0x0f, 0x9d), |
| | 593 | .setle, .setng => OpCode.twoByte(0x0f, 0x9e), |
| | 594 | .setnle, .setg => OpCode.twoByte(0x0f, 0x9f), |
| 555 | else => null, | 595 | else => null, |
| 556 | }, | 596 | }, |
| 557 | .o => return switch (tag) { | 597 | .o => return switch (tag) { |
| ... | @@ -628,6 +668,37 @@ inline fn getModRmExt(tag: Tag) ?u3 { | ... | @@ -628,6 +668,37 @@ inline fn getModRmExt(tag: Tag) ?u3 { |
| 628 | .push => 0x6, | 668 | .push => 0x6, |
| 629 | .pop => 0x0, | 669 | .pop => 0x0, |
| 630 | .@"test" => 0x0, | 670 | .@"test" => 0x0, |
| | 671 | .seto, |
| | 672 | .setno, |
| | 673 | .setb, |
| | 674 | .setc, |
| | 675 | .setnae, |
| | 676 | .setnb, |
| | 677 | .setnc, |
| | 678 | .setae, |
| | 679 | .sete, |
| | 680 | .setz, |
| | 681 | .setne, |
| | 682 | .setnz, |
| | 683 | .setbe, |
| | 684 | .setna, |
| | 685 | .seta, |
| | 686 | .setnbe, |
| | 687 | .sets, |
| | 688 | .setns, |
| | 689 | .setp, |
| | 690 | .setpe, |
| | 691 | .setnp, |
| | 692 | .setop, |
| | 693 | .setl, |
| | 694 | .setnge, |
| | 695 | .setnl, |
| | 696 | .setge, |
| | 697 | .setle, |
| | 698 | .setng, |
| | 699 | .setnle, |
| | 700 | .setg, |
| | 701 | => 0x0, |
| 631 | else => null, | 702 | else => null, |
| 632 | }; | 703 | }; |
| 633 | } | 704 | } |
| ... | @@ -718,7 +789,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi | ... | @@ -718,7 +789,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi |
| 718 | | 789 | |
| 719 | fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void { | 790 | fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void { |
| 720 | const opc = getOpCode(tag, .d, false).?; | 791 | const opc = getOpCode(tag, .d, false).?; |
| 721 | const encoder = try Encoder.init(code, 5); | 792 | const encoder = try Encoder.init(code, 6); |
| 722 | opc.encode(encoder); | 793 | opc.encode(encoder); |
| 723 | encoder.imm32(imm); | 794 | encoder.imm32(imm); |
| 724 | } | 795 | } |
| ... | @@ -728,10 +799,13 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) | ... | @@ -728,10 +799,13 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) |
| 728 | const modrm_ext = getModRmExt(tag).?; | 799 | const modrm_ext = getModRmExt(tag).?; |
| 729 | switch (reg_or_mem) { | 800 | switch (reg_or_mem) { |
| 730 | .register => |reg| { | 801 | .register => |reg| { |
| 731 | if (reg.size() != 64) return error.EmitFail; | 802 | // TODO clean this up! |
| | 803 | if (reg.size() != 64) { |
| | 804 | if (reg.size() != 8 and !tag.isSetCC()) return error.EmitFail; |
| | 805 | } |
| 732 | const encoder = try Encoder.init(code, 3); | 806 | const encoder = try Encoder.init(code, 3); |
| 733 | encoder.rex(.{ | 807 | encoder.rex(.{ |
| 734 | .w = false, | 808 | .w = tag.isSetCC(), |
| 735 | .b = reg.isExtended(), | 809 | .b = reg.isExtended(), |
| 736 | }); | 810 | }); |
| 737 | opc.encode(encoder); | 811 | opc.encode(encoder); |
| ... | @@ -740,9 +814,12 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) | ... | @@ -740,9 +814,12 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) |
| 740 | .memory => |mem_op| { | 814 | .memory => |mem_op| { |
| 741 | const encoder = try Encoder.init(code, 8); | 815 | const encoder = try Encoder.init(code, 8); |
| 742 | if (mem_op.reg) |reg| { | 816 | if (mem_op.reg) |reg| { |
| 743 | if (reg.size() != 64) return error.EmitFail; | 817 | // TODO clean this up! |
| | 818 | if (reg.size() != 64) { |
| | 819 | if (reg.size() != 8 and !tag.isSetCC()) return error.EmitFail; |
| | 820 | } |
| 744 | encoder.rex(.{ | 821 | encoder.rex(.{ |
| 745 | .w = false, | 822 | .w = tag.isSetCC(), |
| 746 | .b = reg.isExtended(), | 823 | .b = reg.isExtended(), |
| 747 | }); | 824 | }); |
| 748 | opc.encode(encoder); | 825 | opc.encode(encoder); |
| ... | @@ -1172,6 +1249,7 @@ fn immOpSize(imm: i64) u8 { | ... | @@ -1172,6 +1249,7 @@ fn immOpSize(imm: i64) u8 { |
| 1172 | return 64; | 1249 | return 64; |
| 1173 | } | 1250 | } |
| 1174 | | 1251 | |
| | 1252 | // TODO |
| 1175 | fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 1253 | fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 1176 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 1254 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 1177 | const scale = ops.flags; | 1255 | const scale = ops.flags; |
| ... | @@ -1196,6 +1274,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void | ... | @@ -1196,6 +1274,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 1196 | } | 1274 | } |
| 1197 | } | 1275 | } |
| 1198 | | 1276 | |
| | 1277 | // TODO |
| 1199 | fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 1278 | fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 1200 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 1279 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 1201 | const scale = ops.flags; | 1280 | const scale = ops.flags; |
| ... | @@ -1243,6 +1322,7 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void | ... | @@ -1243,6 +1322,7 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 1243 | } | 1322 | } |
| 1244 | } | 1323 | } |
| 1245 | | 1324 | |
| | 1325 | // TODO |
| 1246 | fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 1326 | fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 1247 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 1327 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 1248 | const scale = ops.flags; | 1328 | const scale = ops.flags; |
| ... | @@ -1757,6 +1837,8 @@ test "lower M encoding" { | ... | @@ -1757,6 +1837,8 @@ test "lower M encoding" { |
| 1757 | try expectEqualHexStrings("\xFF\x25\x10\x00\x00\x00", code.emitted(), "jmp qword ptr [rip + 0x10]"); | 1837 | try expectEqualHexStrings("\xFF\x25\x10\x00\x00\x00", code.emitted(), "jmp qword ptr [rip + 0x10]"); |
| 1758 | try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(null, 0x10), code.buffer()); | 1838 | try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(null, 0x10), code.buffer()); |
| 1759 | try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", code.emitted(), "jmp qword ptr [ds:0x10]"); | 1839 | try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", code.emitted(), "jmp qword ptr [ds:0x10]"); |
| | 1840 | try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), code.buffer()); |
| | 1841 | try expectEqualHexStrings("\x49\x0F\x97\xC3", code.emitted(), "seta r11b"); |
| 1760 | } | 1842 | } |
| 1761 | | 1843 | |
| 1762 | test "lower O encoding" { | 1844 | test "lower O encoding" { |