return 0, false
}
-// rm is the Rm register value, o is the extension, amount is the left shift value.
-func roff(rm uint32, o uint32, amount int16) int64 {
- return int64((rm&31)<<16 | o<<13 | uint32(amount)<<10)
-}
-
// ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
- rm := uint32(reg)
Rnum := (reg & 31) + int16(num<<5)
if isAmount {
if num < 0 || num > 7 {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_UXTB + Rnum
- a.Offset = roff(rm, 0, num)
case "UXTH":
if !isAmount {
return errors.New("invalid register extension")
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_UXTH + Rnum
- a.Offset = roff(rm, 1, num)
case "UXTW":
if !isAmount {
return errors.New("invalid register extension")
// effective address of memory is a base register value and an offset register value.
if a.Type == obj.TYPE_MEM {
a.Index = arm64.REG_UXTW + Rnum
- if num == 0 {
- a.Offset = roff(rm, 2, 2)
- } else {
- a.Offset = roff(rm, 2, 6)
- }
} else {
a.Reg = arm64.REG_UXTW + Rnum
- a.Offset = roff(rm, 2, num)
}
case "UXTX":
if !isAmount {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_UXTX + Rnum
- a.Offset = roff(rm, 3, num)
case "SXTB":
if !isAmount {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_SXTB + Rnum
- a.Offset = roff(rm, 4, num)
case "SXTH":
if !isAmount {
return errors.New("invalid register extension")
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_SXTH + Rnum
- a.Offset = roff(rm, 5, num)
case "SXTW":
if !isAmount {
return errors.New("invalid register extension")
}
if a.Type == obj.TYPE_MEM {
a.Index = arm64.REG_SXTW + Rnum
- if num == 0 {
- a.Offset = roff(rm, 6, 2)
- } else {
- a.Offset = roff(rm, 6, 6)
- }
} else {
a.Reg = arm64.REG_SXTW + Rnum
- a.Offset = roff(rm, 6, num)
}
case "SXTX":
if !isAmount {
}
if a.Type == obj.TYPE_MEM {
a.Index = arm64.REG_SXTX + Rnum
- if num == 0 {
- a.Offset = roff(rm, 7, 2)
- } else {
- a.Offset = roff(rm, 7, 6)
- }
} else {
a.Reg = arm64.REG_SXTX + Rnum
- a.Offset = roff(rm, 7, num)
}
case "LSL":
if !isAmount {
return errors.New("invalid register extension")
}
a.Index = arm64.REG_LSL + Rnum
- a.Offset = roff(rm, 3, 6)
case "B8":
if isIndex {
return errors.New("invalid register extension")
if amount != 2 && amount != 0 {
c.ctxt.Diag("invalid index shift amount: %v", p)
}
-
case AMOVD:
if amount != 3 && amount != 0 {
c.ctxt.Diag("invalid index shift amount: %v", p)
}
+ default:
+ panic("invalid operation")
}
}
o1 |= (REGZERO & 31 << 5) | uint32(rt&31)
case 27: /* op Rm<<n[,Rn],Rd (extended register) */
-
if (p.From.Reg-obj.RBaseARM64)®_EXT != 0 {
amount := (p.From.Reg >> 5) & 7
if amount > 4 {
c.ctxt.Diag("shift amount out of range 0 to 4: %v", p)
}
o1 = c.opxrrr(p, p.As, true)
- o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
+ o1 |= c.encRegShiftOrExt(&p.From, p.From.Reg) /* includes reg, op, etc */
} else {
o1 = c.opxrrr(p, p.As, false)
o1 |= uint32(p.From.Reg&31) << 16
o1 |= (uint32(Q&1) << 30) | (uint32(r&31) << 16) | ((opcode & 7) << 13) | (uint32(S&1) << 12) | (uint32(size&3) << 10) | (uint32(rf&31) << 5) | uint32(rt&31)
case 98: /* MOVD (Rn)(Rm.SXTW[<<amount]),Rd */
- if p.From.Offset != 0 {
+ if isRegShiftOrExt(&p.From) {
// extended or shifted offset register.
c.checkShiftAmount(p, &p.From)
+
o1 = c.opldrr(p, p.As, true)
- o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
+ o1 |= c.encRegShiftOrExt(&p.From, p.From.Index) /* includes reg, op, etc */
} else {
// (Rn)(Rm), no extension or shift.
o1 = c.opldrr(p, p.As, false)
o1 |= uint32(rt & 31)
case 99: /* MOVD Rt, (Rn)(Rm.SXTW[<<amount]) */
- if p.To.Offset != 0 {
+ if isRegShiftOrExt(&p.To) {
// extended or shifted offset register.
c.checkShiftAmount(p, &p.To)
+
o1 = c.opstrr(p, p.As, true)
- o1 |= uint32(p.To.Offset) /* includes reg, op, etc */
+ o1 |= c.encRegShiftOrExt(&p.To, p.To.Index) /* includes reg, op, etc */
} else {
// (Rn)(Rm), no extension or shift.
o1 = c.opstrr(p, p.As, false)
return -1
}
}
+
+// rm is the Rm register value, o is the extension, amount is the left shift value.
+func roff(rm int16, o uint32, amount int16) uint32 {
+ return uint32(rm&31)<<16 | o<<13 | uint32(amount)<<10
+}
+
+// encRegShiftOrExt returns the encoding of shifted/extended register, Rx<<n and Rx.UXTW<<n, etc.
+func (c *ctxt7) encRegShiftOrExt(a *obj.Addr, r int16) uint32 {
+ var num, rm int16
+ num = (r >> 5) & 7
+ rm = r & 31
+ switch {
+ case REG_UXTB <= r && r < REG_UXTH:
+ return roff(rm, 0, num)
+ case REG_UXTH <= r && r < REG_UXTW:
+ return roff(rm, 1, num)
+ case REG_UXTW <= r && r < REG_UXTX:
+ if a.Type == obj.TYPE_MEM {
+ if num == 0 {
+ return roff(rm, 2, 2)
+ } else {
+ return roff(rm, 2, 6)
+ }
+ } else {
+ return roff(rm, 2, num)
+ }
+ case REG_UXTX <= r && r < REG_SXTB:
+ return roff(rm, 3, num)
+ case REG_SXTB <= r && r < REG_SXTH:
+ return roff(rm, 4, num)
+ case REG_SXTH <= r && r < REG_SXTW:
+ return roff(rm, 5, num)
+ case REG_SXTW <= r && r < REG_SXTX:
+ if a.Type == obj.TYPE_MEM {
+ if num == 0 {
+ return roff(rm, 6, 2)
+ } else {
+ return roff(rm, 6, 6)
+ }
+ } else {
+ return roff(rm, 6, num)
+ }
+ case REG_SXTX <= r && r < REG_SPECIAL:
+ if a.Type == obj.TYPE_MEM {
+ if num == 0 {
+ return roff(rm, 7, 2)
+ } else {
+ return roff(rm, 7, 6)
+ }
+ } else {
+ return roff(rm, 7, num)
+ }
+ case REG_LSL <= r && r < (REG_LSL+1<<8):
+ return roff(rm, 3, 6)
+ default:
+ c.ctxt.Diag("unsupported register extension type.")
+ }
+
+ return 0
+}