...

Source file src/pkg/cmd/asm/internal/arch/arm64.go

     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	
     9	package arch
    10	
    11	import (
    12		"cmd/internal/obj"
    13		"cmd/internal/obj/arm64"
    14		"errors"
    15	)
    16	
    17	var arm64LS = map[string]uint8{
    18		"P": arm64.C_XPOST,
    19		"W": arm64.C_XPRE,
    20	}
    21	
    22	var 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	
    51	func jumpArm64(word string) bool {
    52		return 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.
    57	func IsARM64CMP(op obj.As) bool {
    58		switch op {
    59		case arm64.ACMN, arm64.ACMP, arm64.ATST,
    60			arm64.ACMNW, arm64.ACMPW, arm64.ATSTW,
    61			arm64.AFCMPS, arm64.AFCMPD,
    62			arm64.AFCMPES, arm64.AFCMPED:
    63			return true
    64		}
    65		return false
    66	}
    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.
    71	func IsARM64STLXR(op obj.As) bool {
    72		switch op {
    73		case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR,
    74			arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR,
    75			arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:
    76			return true
    77		}
    78		// atomic instructions
    79		if arm64.IsAtomicInstruction(op) {
    80			return true
    81		}
    82		return false
    83	}
    84	
    85	// ARM64Suffix handles the special suffix for the ARM64.
    86	// It returns a boolean to indicate success; failure means
    87	// cond was unrecognized.
    88	func ARM64Suffix(prog *obj.Prog, cond string) bool {
    89		if cond == "" {
    90			return true
    91		}
    92		bits, ok := parseARM64Suffix(cond)
    93		if !ok {
    94			return false
    95		}
    96		prog.Scond = bits
    97		return true
    98	}
    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.
   103	func parseARM64Suffix(cond string) (uint8, bool) {
   104		if cond == "" {
   105			return 0, true
   106		}
   107		return parseARMCondition(cond, arm64LS, nil)
   108	}
   109	
   110	func arm64RegisterNumber(name string, n int16) (int16, bool) {
   111		switch name {
   112		case "F":
   113			if 0 <= n && n <= 31 {
   114				return arm64.REG_F0 + n, true
   115			}
   116		case "R":
   117			if 0 <= n && n <= 30 { // not 31
   118				return arm64.REG_R0 + n, true
   119			}
   120		case "V":
   121			if 0 <= n && n <= 31 {
   122				return arm64.REG_V0 + n, true
   123			}
   124		}
   125		return 0, false
   126	}
   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.
   131	func IsARM64TBL(op obj.As) bool {
   132		return op == arm64.AVTBL
   133	}
   134	
   135	// ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
   136	func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
   137		Rnum := (reg & 31) + int16(num<<5)
   138		if isAmount {
   139			if num < 0 || num > 7 {
   140				return errors.New("index shift amount is out of range")
   141			}
   142		}
   143		switch ext {
   144		case "UXTB":
   145			if !isAmount {
   146				return errors.New("invalid register extension")
   147			}
   148			if a.Type == obj.TYPE_MEM {
   149				return errors.New("invalid shift for the register offset addressing mode")
   150			}
   151			a.Reg = arm64.REG_UXTB + Rnum
   152		case "UXTH":
   153			if !isAmount {
   154				return errors.New("invalid register extension")
   155			}
   156			if a.Type == obj.TYPE_MEM {
   157				return errors.New("invalid shift for the register offset addressing mode")
   158			}
   159			a.Reg = arm64.REG_UXTH + Rnum
   160		case "UXTW":
   161			if !isAmount {
   162				return errors.New("invalid register extension")
   163			}
   164			// effective address of memory is a base register value and an offset register value.
   165			if a.Type == obj.TYPE_MEM {
   166				a.Index = arm64.REG_UXTW + Rnum
   167			} else {
   168				a.Reg = arm64.REG_UXTW + Rnum
   169			}
   170		case "UXTX":
   171			if !isAmount {
   172				return errors.New("invalid register extension")
   173			}
   174			if a.Type == obj.TYPE_MEM {
   175				return errors.New("invalid shift for the register offset addressing mode")
   176			}
   177			a.Reg = arm64.REG_UXTX + Rnum
   178		case "SXTB":
   179			if !isAmount {
   180				return errors.New("invalid register extension")
   181			}
   182			a.Reg = arm64.REG_SXTB + Rnum
   183		case "SXTH":
   184			if !isAmount {
   185				return errors.New("invalid register extension")
   186			}
   187			if a.Type == obj.TYPE_MEM {
   188				return errors.New("invalid shift for the register offset addressing mode")
   189			}
   190			a.Reg = arm64.REG_SXTH + Rnum
   191		case "SXTW":
   192			if !isAmount {
   193				return errors.New("invalid register extension")
   194			}
   195			if a.Type == obj.TYPE_MEM {
   196				a.Index = arm64.REG_SXTW + Rnum
   197			} else {
   198				a.Reg = arm64.REG_SXTW + Rnum
   199			}
   200		case "SXTX":
   201			if !isAmount {
   202				return errors.New("invalid register extension")
   203			}
   204			if a.Type == obj.TYPE_MEM {
   205				a.Index = arm64.REG_SXTX + Rnum
   206			} else {
   207				a.Reg = arm64.REG_SXTX + Rnum
   208			}
   209		case "LSL":
   210			if !isAmount {
   211				return errors.New("invalid register extension")
   212			}
   213			a.Index = arm64.REG_LSL + Rnum
   214		case "B8":
   215			if isIndex {
   216				return errors.New("invalid register extension")
   217			}
   218			a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5)
   219		case "B16":
   220			if isIndex {
   221				return errors.New("invalid register extension")
   222			}
   223			a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5)
   224		case "H4":
   225			if isIndex {
   226				return errors.New("invalid register extension")
   227			}
   228			a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5)
   229		case "H8":
   230			if isIndex {
   231				return errors.New("invalid register extension")
   232			}
   233			a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5)
   234		case "S2":
   235			if isIndex {
   236				return errors.New("invalid register extension")
   237			}
   238			a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5)
   239		case "S4":
   240			if isIndex {
   241				return errors.New("invalid register extension")
   242			}
   243			a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5)
   244		case "D1":
   245			if isIndex {
   246				return errors.New("invalid register extension")
   247			}
   248			a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5)
   249		case "D2":
   250			if isIndex {
   251				return errors.New("invalid register extension")
   252			}
   253			a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5)
   254		case "Q1":
   255			if isIndex {
   256				return errors.New("invalid register extension")
   257			}
   258			a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5)
   259		case "B":
   260			if !isIndex {
   261				return nil
   262			}
   263			a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5)
   264			a.Index = num
   265		case "H":
   266			if !isIndex {
   267				return nil
   268			}
   269			a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5)
   270			a.Index = num
   271		case "S":
   272			if !isIndex {
   273				return nil
   274			}
   275			a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5)
   276			a.Index = num
   277		case "D":
   278			if !isIndex {
   279				return nil
   280			}
   281			a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5)
   282			a.Index = num
   283		default:
   284			return errors.New("unsupported register extension type: " + ext)
   285		}
   286	
   287		return nil
   288	}
   289	
   290	// ARM64RegisterArrangement parses an ARM64 vector register arrangement.
   291	func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) {
   292		var curQ, curSize uint16
   293		if name[0] != 'V' {
   294			return 0, errors.New("expect V0 through V31; found: " + name)
   295		}
   296		if reg < 0 {
   297			return 0, errors.New("invalid register number: " + name)
   298		}
   299		switch arng {
   300		case "B8":
   301			curSize = 0
   302			curQ = 0
   303		case "B16":
   304			curSize = 0
   305			curQ = 1
   306		case "H4":
   307			curSize = 1
   308			curQ = 0
   309		case "H8":
   310			curSize = 1
   311			curQ = 1
   312		case "S2":
   313			curSize = 2
   314			curQ = 0
   315		case "S4":
   316			curSize = 2
   317			curQ = 1
   318		case "D1":
   319			curSize = 3
   320			curQ = 0
   321		case "D2":
   322			curSize = 3
   323			curQ = 1
   324		default:
   325			return 0, errors.New("invalid arrangement in ARM64 register list")
   326		}
   327		return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil
   328	}
   329	
   330	// ARM64RegisterListOffset generates offset encoding according to AArch64 specification.
   331	func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) {
   332		offset := int64(firstReg)
   333		switch regCnt {
   334		case 1:
   335			offset |= 0x7 << 12
   336		case 2:
   337			offset |= 0xa << 12
   338		case 3:
   339			offset |= 0x6 << 12
   340		case 4:
   341			offset |= 0x2 << 12
   342		default:
   343			return 0, errors.New("invalid register numbers in ARM64 register list")
   344		}
   345		offset |= arrangement
   346		// arm64 uses the 60th bit to differentiate from other archs
   347		// For more details, refer to: obj/arm64/list7.go
   348		offset |= 1 << 60
   349		return offset, nil
   350	}
   351	

View as plain text