fix(asm): encode the CMOV condition the renderer prints
The renderer spells a conditional move CMOV plus the condition alone (CMOVLE, CMOVG), the width carried by the operand registers, so CMOVLE parsed as the size L and the condition E and encoded CMOVE. A suffix that is itself a condition name now reads as that condition with the width from the destination register, and the Plan 9 size-prefixed spellings keep their parse. Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
11cac26508
commit
abc2d32b83
3 files changed
+64
-30
No files matched your search
+42
-17
@@ -1068,29 +1068,46 @@ func immediate(v int64, size int, full64 bool) ([]byte, error) {
|
||||
|
||||
// --- CMOVcc / SETcc ---------------------------------------------------------
|
||||
|
||||
// cmovCondition splits a CMOVcc suffix into an optional size letter and the
|
||||
// condition code. Two vocabularies meet here: the Plan 9 spellings prefix
|
||||
// the condition with a size letter (CMOVLGT, CMOVQEQ), while the toolchain's
|
||||
// renderer prints the condition alone (CMOVLE, CMOVG) and leaves the width
|
||||
// to the operand registers. A suffix that is itself a condition name reads
|
||||
// as that condition, so the renderer's text re-encodes; CMOVBGT, CMOVWXX and
|
||||
// the bare CMOV still find no condition and stay rejected.
|
||||
func cmovCondition(rest string) (size int, cc int, ok bool) {
|
||||
if cc, ok := jccMap[rest]; ok {
|
||||
return 0, cc, true
|
||||
}
|
||||
if len(rest) >= 2 {
|
||||
switch rest[0] {
|
||||
case 'W':
|
||||
if cc, ok := jccMap[rest[1:]]; ok {
|
||||
return 2, cc, true
|
||||
}
|
||||
case 'L':
|
||||
if cc, ok := jccMap[rest[1:]]; ok {
|
||||
return 4, cc, true
|
||||
}
|
||||
case 'Q':
|
||||
if cc, ok := jccMap[rest[1:]]; ok {
|
||||
return 8, cc, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
// encodeCmov encodes a conditional move: CMOV + size (W/L/Q) + condition
|
||||
// (CMOVLGT, CMOVQEQ, …). The condition reads exactly like the Jcc spellings;
|
||||
// the instruction is 0F 40+cc with reg = dst, rm = src.
|
||||
// (CMOVLGT, CMOVQEQ, …), or the renderer's condition alone (CMOVLE) with the
|
||||
// width taken from the destination register. The instruction is 0F 40+cc
|
||||
// with reg = dst, rm = src.
|
||||
func (e *enc) encodeCmov(upper string, ops []Operand) error {
|
||||
if len(ops) != 2 {
|
||||
return fmt.Errorf("CMOVcc expects 2 operands, got %d", len(ops))
|
||||
}
|
||||
rest := upper[len("CMOV"):]
|
||||
if len(rest) < 2 {
|
||||
return fmt.Errorf("unsupported instruction %q", upper)
|
||||
}
|
||||
var size int
|
||||
switch rest[0] {
|
||||
case 'W':
|
||||
size = 2
|
||||
case 'L':
|
||||
size = 4
|
||||
case 'Q':
|
||||
size = 8
|
||||
default:
|
||||
return fmt.Errorf("unsupported instruction %q", upper)
|
||||
}
|
||||
cc, ok := jccMap[rest[1:]]
|
||||
size, cc, ok := cmovCondition(rest)
|
||||
if !ok {
|
||||
return fmt.Errorf("unsupported instruction %q", upper)
|
||||
}
|
||||
@@ -1099,6 +1116,14 @@ func (e *enc) encodeCmov(upper string, ops []Operand) error {
|
||||
if !ok {
|
||||
return fmt.Errorf("CMOVcc destination must be a register")
|
||||
}
|
||||
if size == 0 {
|
||||
// The renderer's spelling carries no size letter: the width rides
|
||||
// the destination register's own size class.
|
||||
size = dstReg.size
|
||||
if size != 1 && size != 2 && size != 4 && size != 8 {
|
||||
return fmt.Errorf("CMOVcc destination must be a general register")
|
||||
}
|
||||
}
|
||||
i := newInstr(size, []byte{0x0F, byte(0x40 + cc)})
|
||||
if err := setRM(i, dstReg, src, size); err != nil {
|
||||
return err
|
||||
|
||||
Reference in new issue
Block a user