fix(asm): encode the flag-setting logicals to ZR and fold immediate expressions
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
c1cef7b6e8
commit
5f6be4584d
2 files changed
+82
-31
No files matched your search
+36
-31
@@ -477,10 +477,11 @@ func arm64InstrSize(instr *ast.Instr, fi arm64FrameInfo, pos int) int {
|
||||
return arm64MovSize(mnem, ops, fi)
|
||||
}
|
||||
// The logical-immediate family: one word on the bitmask fast path (a
|
||||
// real destination, or the flags-only TST spellings), otherwise the
|
||||
// constant materialisation into REGTMP plus the register-form tail.
|
||||
// Mirrors encodeARM64DPSR's decision exactly, the materialisation word
|
||||
// count included: a MOVZ plus up to three MOVKs makes five words.
|
||||
// real destination, the flags-only TST spellings, or the flag-setting
|
||||
// forms to ZR), otherwise the constant materialisation into REGTMP plus
|
||||
// the register-form tail. Mirrors encodeARM64DPSR's decision exactly,
|
||||
// the materialisation word count included: a MOVZ plus up to three MOVKs
|
||||
// makes five words.
|
||||
if len(ops) >= 2 && len(ops) <= 3 && isImmOperand(ops[0]) {
|
||||
switch mnem {
|
||||
case "AND", "ANDW", "ANDS", "ANDSW", "ORR", "ORRW", "EOR", "EORW",
|
||||
@@ -498,11 +499,12 @@ func arm64InstrSize(instr *ast.Instr, fi arm64FrameInfo, pos int) int {
|
||||
width = 32
|
||||
mwMnem = "MOVW"
|
||||
}
|
||||
sLogical := mnem == "ANDS" || mnem == "ANDSW" || mnem == "BICS" || mnem == "BICSW"
|
||||
zrDest := false
|
||||
if mnem != "TST" && mnem != "TSTW" {
|
||||
zrDest = strings.EqualFold(operandRegName(ops[len(ops)-1]), "ZR")
|
||||
}
|
||||
if _, _, _, bc := a64LogicalImm(v, width); bc && (mnem == "TST" || mnem == "TSTW" || !zrDest) {
|
||||
if _, _, _, bc := a64LogicalImm(v, width); bc && (sLogical || mnem == "TST" || mnem == "TSTW" || !zrDest) {
|
||||
return 4
|
||||
}
|
||||
if mw, err := encodeARM64LoadImm(27, written, mwMnem); err == nil {
|
||||
@@ -1110,20 +1112,22 @@ func encodeARM64DPSR(mnem string, baseOp uint32, ops []*ast.Operand) ([]byte, er
|
||||
return nil, fmt.Errorf("%s: illegal combination: the destination cannot be RSP", mnem)
|
||||
}
|
||||
n, immr, imms, ok := a64LogicalImm(v, width)
|
||||
// The toolchain.s logical-immediate rows take a real destination
|
||||
// only (omovconst guards the bitmask path with rt != REGZERO): a
|
||||
// non-flag-setting logical to ZR materialises the constant into
|
||||
// REGTMP (R27) and takes the register form. RSP is a real
|
||||
// register here, but keeps the fast bitmask path inside the
|
||||
// addcon band alone, and the flags-only TST spellings keep the
|
||||
// fast path: ANDS ZR, Rn, #imm is their form.
|
||||
// The toolchain's logical-immediate rows take a real destination
|
||||
// only for the non-flag-setting forms (omovconst guards the
|
||||
// bitmask path with rt != REGZERO): a plain AND/ORR/EOR to ZR
|
||||
// materialises the constant into REGTMP (R27) and takes the
|
||||
// register form. The flag-setting forms (ANDS, BICS, the TST
|
||||
// spellings) keep the fast path with a ZR destination: case 53
|
||||
// encodes ANDS ZR, Rn, #imm directly. RSP is a real register
|
||||
// here, but keeps the fast bitmask path inside the addcon band
|
||||
// alone.
|
||||
if rspDest {
|
||||
inBand := writtenImm > 0 && (writtenImm <= 0xFFF || (writtenImm&0xFFF == 0 && writtenImm>>12 <= 0xFFF))
|
||||
if !ok || !inBand {
|
||||
return nil, fmt.Errorf("%s: illegal combination: the destination cannot be RSP", mnem)
|
||||
}
|
||||
}
|
||||
if ok && (isCmp || !zrDest) {
|
||||
if ok && (isCmp || !zrDest || sLogical) {
|
||||
opc := (baseOp >> 29) & 7
|
||||
sf := (baseOp >> 31) & 1
|
||||
return a64wordLE(sf<<31 | opc<<29 | 0x24<<23 | n<<22 | immr<<16 | imms<<10 |
|
||||
@@ -2895,16 +2899,11 @@ func encodeARM64SBStore(sym *ast.Symbol, rs int, mnem string, relocs *[]Reloc) (
|
||||
|
||||
// ---- operand helpers ----
|
||||
|
||||
// arm64Imm64 returns the full 64-bit immediate value of an operand.
|
||||
// arm64Imm64 returns the full 64-bit immediate value of an operand, the
|
||||
// raw-spelling-aware value arm64ImmOperandValue recovers.
|
||||
func arm64Imm64(op *ast.Operand) int64 {
|
||||
if op.Imm.HasVal {
|
||||
v := op.Imm.Val
|
||||
if op.Imm.Neg {
|
||||
v = -v
|
||||
}
|
||||
return v
|
||||
}
|
||||
return 0
|
||||
v, _ := arm64ImmOperandValue(op)
|
||||
return v
|
||||
}
|
||||
|
||||
// arm64ImmOperandValue returns the immediate an operand stands for, falling
|
||||
@@ -2917,6 +2916,15 @@ func arm64ImmOperandValue(op *ast.Operand) (int64, bool) {
|
||||
if op.Imm.Neg {
|
||||
v = -v
|
||||
}
|
||||
// The parser folds a leading literal and drops the arithmetic that
|
||||
// trails it ($14*16 parses as 14), so an operator-bearing spelling
|
||||
// re-evaluates in full: the raw text is the statement's truth.
|
||||
s := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(op.Raw), "$"))
|
||||
if s != "" && strings.ContainsAny(s, "+-*/^|") {
|
||||
if e, ok := arm64EvalExpr(s); ok {
|
||||
return e, true
|
||||
}
|
||||
}
|
||||
return v, true
|
||||
}
|
||||
s := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(op.Raw), "$"))
|
||||
@@ -3069,7 +3077,7 @@ func arm64EvalExpr(s string) (int64, bool) {
|
||||
if t[0] < '0' || t[0] > '9' {
|
||||
return 0, false
|
||||
}
|
||||
v, err := strconv.ParseInt(strings.TrimPrefix(strings.TrimPrefix(t, "0X"), "0x"), 0, 64)
|
||||
v, err := strconv.ParseInt(t, 0, 64)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
@@ -3078,16 +3086,13 @@ func arm64EvalExpr(s string) (int64, bool) {
|
||||
}
|
||||
var binop func(minLevel int) (int64, bool)
|
||||
level := func(op string) int {
|
||||
// Go's own precedence (the toolchain's evaluator folds with Go
|
||||
// semantics): multiply, shift and AND bind tighter than add, OR and
|
||||
// XOR.
|
||||
switch op {
|
||||
case "|", "^":
|
||||
return 1
|
||||
case "&":
|
||||
return 2
|
||||
case "<<", ">>":
|
||||
return 3
|
||||
case "*":
|
||||
case "|", "^", "+", "-":
|
||||
return 4
|
||||
case "+", "-":
|
||||
case "&", "<<", ">>", "*":
|
||||
return 5
|
||||
}
|
||||
return 0
|
||||
|
||||
Reference in new issue
Block a user