Improve instruction selection for SLT/ULT
6cd41da36ba1045497f1bfb6b30032c8311dc61669b59ad951edf5c6a56b3396
1 parent
3d0bcffc
lib/std/arch/rv64/isel.rad
+11 -0
| 538 | 538 | ||
| 539 | 539 | // Normalize sub-word operands so that both registers have the same |
|
| 540 | 540 | // canonical representation. Without this, eg. `-1 : i8 ` loaded as |
|
| 541 | 541 | // `0xFFFFFFFFFFFFFFFF` and `255 : i8` loaded as `0xFF` would compare |
|
| 542 | 542 | // unequal even though they are the same 8-bit pattern. |
|
| 543 | + | // |
|
| 544 | + | // For SLT: sign-extension needed (signed comparison). |
|
| 545 | + | // For ULT: zero-extension needed (unsigned magnitude comparison). |
|
| 546 | + | // For EQ/NE with W32: sign-extension is cheaper. |
|
| 547 | + | // For EQ/NE with W8/W16: keep zero-extension. |
|
| 543 | 548 | // Skip extension for zero register. |
|
| 544 | 549 | if let case il::CmpOp::Slt = op { |
|
| 545 | 550 | if not aIsZero { emitSext(s.e, rs1, rs1, typ); } |
|
| 546 | 551 | if not bIsZero { emitSext(s.e, rs2, rs2, typ); } |
|
| 552 | + | } else if let case il::CmpOp::Ult = op { |
|
| 553 | + | if not aIsZero { emitZext(s.e, rs1, rs1, typ); } |
|
| 554 | + | if not bIsZero { emitZext(s.e, rs2, rs2, typ); } |
|
| 555 | + | } else if typ == il::Type::W32 { |
|
| 556 | + | if not aIsZero { emitSext(s.e, rs1, rs1, typ); } |
|
| 557 | + | if not bIsZero { emitSext(s.e, rs2, rs2, typ); } |
|
| 547 | 558 | } else { |
|
| 548 | 559 | if not aIsZero { emitZext(s.e, rs1, rs1, typ); } |
|
| 549 | 560 | if not bIsZero { emitZext(s.e, rs2, rs2, typ); } |
|
| 550 | 561 | } |
|
| 551 | 562 | // Block-argument moves must only execute on the taken path. |