podman
350 строк · 8.5 Кб
1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// This file encapsulates some of the odd characteristics of the ARM64
6// instruction set, to minimize its interaction with the core of the
7// assembler.
8
9package arch10
11import (12"github.com/twitchyliquid64/golang-asm/obj"13"github.com/twitchyliquid64/golang-asm/obj/arm64"14"errors"15)
16
17var arm64LS = map[string]uint8{18"P": arm64.C_XPOST,19"W": arm64.C_XPRE,20}
21
22var arm64Jump = map[string]bool{23"B": true,24"BL": true,25"BEQ": true,26"BNE": true,27"BCS": true,28"BHS": true,29"BCC": true,30"BLO": true,31"BMI": true,32"BPL": true,33"BVS": true,34"BVC": true,35"BHI": true,36"BLS": true,37"BGE": true,38"BLT": true,39"BGT": true,40"BLE": true,41"CALL": true,42"CBZ": true,43"CBZW": true,44"CBNZ": true,45"CBNZW": true,46"JMP": true,47"TBNZ": true,48"TBZ": true,49}
50
51func jumpArm64(word string) bool {52return arm64Jump[word]53}
54
55// IsARM64CMP reports whether the op (as defined by an arm.A* constant) is
56// one of the comparison instructions that require special handling.
57func IsARM64CMP(op obj.As) bool {58switch op {59case arm64.ACMN, arm64.ACMP, arm64.ATST,60arm64.ACMNW, arm64.ACMPW, arm64.ATSTW,61arm64.AFCMPS, arm64.AFCMPD,62arm64.AFCMPES, arm64.AFCMPED:63return true64}65return false66}
67
68// IsARM64STLXR reports whether the op (as defined by an arm64.A*
69// constant) is one of the STLXR-like instructions that require special
70// handling.
71func IsARM64STLXR(op obj.As) bool {72switch op {73case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR,74arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR,75arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:76return true77}78// atomic instructions79if arm64.IsAtomicInstruction(op) {80return true81}82return false83}
84
85// ARM64Suffix handles the special suffix for the ARM64.
86// It returns a boolean to indicate success; failure means
87// cond was unrecognized.
88func ARM64Suffix(prog *obj.Prog, cond string) bool {89if cond == "" {90return true91}92bits, ok := parseARM64Suffix(cond)93if !ok {94return false95}96prog.Scond = bits97return true98}
99
100// parseARM64Suffix parses the suffix attached to an ARM64 instruction.
101// The input is a single string consisting of period-separated condition
102// codes, such as ".P.W". An initial period is ignored.
103func parseARM64Suffix(cond string) (uint8, bool) {104if cond == "" {105return 0, true106}107return parseARMCondition(cond, arm64LS, nil)108}
109
110func arm64RegisterNumber(name string, n int16) (int16, bool) {111switch name {112case "F":113if 0 <= n && n <= 31 {114return arm64.REG_F0 + n, true115}116case "R":117if 0 <= n && n <= 30 { // not 31118return arm64.REG_R0 + n, true119}120case "V":121if 0 <= n && n <= 31 {122return arm64.REG_V0 + n, true123}124}125return 0, false126}
127
128// IsARM64TBL reports whether the op (as defined by an arm64.A*
129// constant) is one of the table lookup instructions that require special
130// handling.
131func IsARM64TBL(op obj.As) bool {132return op == arm64.AVTBL133}
134
135// ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
136func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {137Rnum := (reg & 31) + int16(num<<5)138if isAmount {139if num < 0 || num > 7 {140return errors.New("index shift amount is out of range")141}142}143switch ext {144case "UXTB":145if !isAmount {146return errors.New("invalid register extension")147}148if a.Type == obj.TYPE_MEM {149return errors.New("invalid shift for the register offset addressing mode")150}151a.Reg = arm64.REG_UXTB + Rnum152case "UXTH":153if !isAmount {154return errors.New("invalid register extension")155}156if a.Type == obj.TYPE_MEM {157return errors.New("invalid shift for the register offset addressing mode")158}159a.Reg = arm64.REG_UXTH + Rnum160case "UXTW":161if !isAmount {162return errors.New("invalid register extension")163}164// effective address of memory is a base register value and an offset register value.165if a.Type == obj.TYPE_MEM {166a.Index = arm64.REG_UXTW + Rnum167} else {168a.Reg = arm64.REG_UXTW + Rnum169}170case "UXTX":171if !isAmount {172return errors.New("invalid register extension")173}174if a.Type == obj.TYPE_MEM {175return errors.New("invalid shift for the register offset addressing mode")176}177a.Reg = arm64.REG_UXTX + Rnum178case "SXTB":179if !isAmount {180return errors.New("invalid register extension")181}182a.Reg = arm64.REG_SXTB + Rnum183case "SXTH":184if !isAmount {185return errors.New("invalid register extension")186}187if a.Type == obj.TYPE_MEM {188return errors.New("invalid shift for the register offset addressing mode")189}190a.Reg = arm64.REG_SXTH + Rnum191case "SXTW":192if !isAmount {193return errors.New("invalid register extension")194}195if a.Type == obj.TYPE_MEM {196a.Index = arm64.REG_SXTW + Rnum197} else {198a.Reg = arm64.REG_SXTW + Rnum199}200case "SXTX":201if !isAmount {202return errors.New("invalid register extension")203}204if a.Type == obj.TYPE_MEM {205a.Index = arm64.REG_SXTX + Rnum206} else {207a.Reg = arm64.REG_SXTX + Rnum208}209case "LSL":210if !isAmount {211return errors.New("invalid register extension")212}213a.Index = arm64.REG_LSL + Rnum214case "B8":215if isIndex {216return errors.New("invalid register extension")217}218a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5)219case "B16":220if isIndex {221return errors.New("invalid register extension")222}223a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5)224case "H4":225if isIndex {226return errors.New("invalid register extension")227}228a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5)229case "H8":230if isIndex {231return errors.New("invalid register extension")232}233a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5)234case "S2":235if isIndex {236return errors.New("invalid register extension")237}238a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5)239case "S4":240if isIndex {241return errors.New("invalid register extension")242}243a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5)244case "D1":245if isIndex {246return errors.New("invalid register extension")247}248a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5)249case "D2":250if isIndex {251return errors.New("invalid register extension")252}253a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5)254case "Q1":255if isIndex {256return errors.New("invalid register extension")257}258a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5)259case "B":260if !isIndex {261return nil262}263a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5)264a.Index = num265case "H":266if !isIndex {267return nil268}269a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5)270a.Index = num271case "S":272if !isIndex {273return nil274}275a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5)276a.Index = num277case "D":278if !isIndex {279return nil280}281a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5)282a.Index = num283default:284return errors.New("unsupported register extension type: " + ext)285}286
287return nil288}
289
290// ARM64RegisterArrangement parses an ARM64 vector register arrangement.
291func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) {292var curQ, curSize uint16293if name[0] != 'V' {294return 0, errors.New("expect V0 through V31; found: " + name)295}296if reg < 0 {297return 0, errors.New("invalid register number: " + name)298}299switch arng {300case "B8":301curSize = 0302curQ = 0303case "B16":304curSize = 0305curQ = 1306case "H4":307curSize = 1308curQ = 0309case "H8":310curSize = 1311curQ = 1312case "S2":313curSize = 2314curQ = 0315case "S4":316curSize = 2317curQ = 1318case "D1":319curSize = 3320curQ = 0321case "D2":322curSize = 3323curQ = 1324default:325return 0, errors.New("invalid arrangement in ARM64 register list")326}327return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil328}
329
330// ARM64RegisterListOffset generates offset encoding according to AArch64 specification.
331func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) {332offset := int64(firstReg)333switch regCnt {334case 1:335offset |= 0x7 << 12336case 2:337offset |= 0xa << 12338case 3:339offset |= 0x6 << 12340case 4:341offset |= 0x2 << 12342default:343return 0, errors.New("invalid register numbers in ARM64 register list")344}345offset |= arrangement346// arm64 uses the 60th bit to differentiate from other archs347// For more details, refer to: obj/arm64/list7.go348offset |= 1 << 60349return offset, nil350}
351