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

Documentation: cmd/asm/internal/arch

     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  		arm64.ASWPB, arm64.ASWPH, arm64.ASWPW, arm64.ASWPD,
    77  		arm64.ASWPALB, arm64.ASWPALH, arm64.ASWPALW, arm64.ASWPALD,
    78  		arm64.ALDADDB, arm64.ALDADDH, arm64.ALDADDW, arm64.ALDADDD,
    79  		arm64.ALDANDB, arm64.ALDANDH, arm64.ALDANDW, arm64.ALDANDD,
    80  		arm64.ALDEORB, arm64.ALDEORH, arm64.ALDEORW, arm64.ALDEORD,
    81  		arm64.ALDORB, arm64.ALDORH, arm64.ALDORW, arm64.ALDORD,
    82  		arm64.ALDADDALD, arm64.ALDADDALW, arm64.ALDADDALH, arm64.ALDADDALB:
    83  		return true
    84  	}
    85  	return false
    86  }
    87  
    88  // ARM64Suffix handles the special suffix for the ARM64.
    89  // It returns a boolean to indicate success; failure means
    90  // cond was unrecognized.
    91  func ARM64Suffix(prog *obj.Prog, cond string) bool {
    92  	if cond == "" {
    93  		return true
    94  	}
    95  	bits, ok := parseARM64Suffix(cond)
    96  	if !ok {
    97  		return false
    98  	}
    99  	prog.Scond = bits
   100  	return true
   101  }
   102  
   103  // parseARM64Suffix parses the suffix attached to an ARM64 instruction.
   104  // The input is a single string consisting of period-separated condition
   105  // codes, such as ".P.W". An initial period is ignored.
   106  func parseARM64Suffix(cond string) (uint8, bool) {
   107  	if cond == "" {
   108  		return 0, true
   109  	}
   110  	return parseARMCondition(cond, arm64LS, nil)
   111  }
   112  
   113  func arm64RegisterNumber(name string, n int16) (int16, bool) {
   114  	switch name {
   115  	case "F":
   116  		if 0 <= n && n <= 31 {
   117  			return arm64.REG_F0 + n, true
   118  		}
   119  	case "R":
   120  		if 0 <= n && n <= 30 { // not 31
   121  			return arm64.REG_R0 + n, true
   122  		}
   123  	case "V":
   124  		if 0 <= n && n <= 31 {
   125  			return arm64.REG_V0 + n, true
   126  		}
   127  	}
   128  	return 0, false
   129  }
   130  
   131  // IsARM64TBL reports whether the op (as defined by an arm64.A*
   132  // constant) is one of the table lookup instructions that require special
   133  // handling.
   134  func IsARM64TBL(op obj.As) bool {
   135  	return op == arm64.AVTBL
   136  }
   137  
   138  // ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
   139  func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
   140  	Rnum := (reg & 31) + int16(num<<5)
   141  	if isAmount {
   142  		if num < 0 || num > 7 {
   143  			return errors.New("index shift amount is out of range")
   144  		}
   145  	}
   146  	switch ext {
   147  	case "UXTB":
   148  		if !isAmount {
   149  			return errors.New("invalid register extension")
   150  		}
   151  		if a.Type == obj.TYPE_MEM {
   152  			return errors.New("invalid shift for the register offset addressing mode")
   153  		}
   154  		a.Reg = arm64.REG_UXTB + Rnum
   155  	case "UXTH":
   156  		if !isAmount {
   157  			return errors.New("invalid register extension")
   158  		}
   159  		if a.Type == obj.TYPE_MEM {
   160  			return errors.New("invalid shift for the register offset addressing mode")
   161  		}
   162  		a.Reg = arm64.REG_UXTH + Rnum
   163  	case "UXTW":
   164  		if !isAmount {
   165  			return errors.New("invalid register extension")
   166  		}
   167  		// effective address of memory is a base register value and an offset register value.
   168  		if a.Type == obj.TYPE_MEM {
   169  			a.Index = arm64.REG_UXTW + Rnum
   170  		} else {
   171  			a.Reg = arm64.REG_UXTW + Rnum
   172  		}
   173  	case "UXTX":
   174  		if !isAmount {
   175  			return errors.New("invalid register extension")
   176  		}
   177  		if a.Type == obj.TYPE_MEM {
   178  			return errors.New("invalid shift for the register offset addressing mode")
   179  		}
   180  		a.Reg = arm64.REG_UXTX + Rnum
   181  	case "SXTB":
   182  		if !isAmount {
   183  			return errors.New("invalid register extension")
   184  		}
   185  		a.Reg = arm64.REG_SXTB + Rnum
   186  	case "SXTH":
   187  		if !isAmount {
   188  			return errors.New("invalid register extension")
   189  		}
   190  		if a.Type == obj.TYPE_MEM {
   191  			return errors.New("invalid shift for the register offset addressing mode")
   192  		}
   193  		a.Reg = arm64.REG_SXTH + Rnum
   194  	case "SXTW":
   195  		if !isAmount {
   196  			return errors.New("invalid register extension")
   197  		}
   198  		if a.Type == obj.TYPE_MEM {
   199  			a.Index = arm64.REG_SXTW + Rnum
   200  		} else {
   201  			a.Reg = arm64.REG_SXTW + Rnum
   202  		}
   203  	case "SXTX":
   204  		if !isAmount {
   205  			return errors.New("invalid register extension")
   206  		}
   207  		if a.Type == obj.TYPE_MEM {
   208  			a.Index = arm64.REG_SXTX + Rnum
   209  		} else {
   210  			a.Reg = arm64.REG_SXTX + Rnum
   211  		}
   212  	case "LSL":
   213  		if !isAmount {
   214  			return errors.New("invalid register extension")
   215  		}
   216  		a.Index = arm64.REG_LSL + Rnum
   217  	case "B8":
   218  		if isIndex {
   219  			return errors.New("invalid register extension")
   220  		}
   221  		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5)
   222  	case "B16":
   223  		if isIndex {
   224  			return errors.New("invalid register extension")
   225  		}
   226  		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5)
   227  	case "H4":
   228  		if isIndex {
   229  			return errors.New("invalid register extension")
   230  		}
   231  		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5)
   232  	case "H8":
   233  		if isIndex {
   234  			return errors.New("invalid register extension")
   235  		}
   236  		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5)
   237  	case "S2":
   238  		if isIndex {
   239  			return errors.New("invalid register extension")
   240  		}
   241  		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5)
   242  	case "S4":
   243  		if isIndex {
   244  			return errors.New("invalid register extension")
   245  		}
   246  		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5)
   247  	case "D1":
   248  		if isIndex {
   249  			return errors.New("invalid register extension")
   250  		}
   251  		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5)
   252  	case "D2":
   253  		if isIndex {
   254  			return errors.New("invalid register extension")
   255  		}
   256  		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5)
   257  	case "Q1":
   258  		if isIndex {
   259  			return errors.New("invalid register extension")
   260  		}
   261  		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5)
   262  	case "B":
   263  		if !isIndex {
   264  			return nil
   265  		}
   266  		a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5)
   267  		a.Index = num
   268  	case "H":
   269  		if !isIndex {
   270  			return nil
   271  		}
   272  		a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5)
   273  		a.Index = num
   274  	case "S":
   275  		if !isIndex {
   276  			return nil
   277  		}
   278  		a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5)
   279  		a.Index = num
   280  	case "D":
   281  		if !isIndex {
   282  			return nil
   283  		}
   284  		a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5)
   285  		a.Index = num
   286  	default:
   287  		return errors.New("unsupported register extension type: " + ext)
   288  	}
   289  
   290  	return nil
   291  }
   292  
   293  // ARM64RegisterArrangement parses an ARM64 vector register arrangement.
   294  func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) {
   295  	var curQ, curSize uint16
   296  	if name[0] != 'V' {
   297  		return 0, errors.New("expect V0 through V31; found: " + name)
   298  	}
   299  	if reg < 0 {
   300  		return 0, errors.New("invalid register number: " + name)
   301  	}
   302  	switch arng {
   303  	case "B8":
   304  		curSize = 0
   305  		curQ = 0
   306  	case "B16":
   307  		curSize = 0
   308  		curQ = 1
   309  	case "H4":
   310  		curSize = 1
   311  		curQ = 0
   312  	case "H8":
   313  		curSize = 1
   314  		curQ = 1
   315  	case "S2":
   316  		curSize = 2
   317  		curQ = 0
   318  	case "S4":
   319  		curSize = 2
   320  		curQ = 1
   321  	case "D1":
   322  		curSize = 3
   323  		curQ = 0
   324  	case "D2":
   325  		curSize = 3
   326  		curQ = 1
   327  	default:
   328  		return 0, errors.New("invalid arrangement in ARM64 register list")
   329  	}
   330  	return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil
   331  }
   332  
   333  // ARM64RegisterListOffset generates offset encoding according to AArch64 specification.
   334  func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) {
   335  	offset := int64(firstReg)
   336  	switch regCnt {
   337  	case 1:
   338  		offset |= 0x7 << 12
   339  	case 2:
   340  		offset |= 0xa << 12
   341  	case 3:
   342  		offset |= 0x6 << 12
   343  	case 4:
   344  		offset |= 0x2 << 12
   345  	default:
   346  		return 0, errors.New("invalid register numbers in ARM64 register list")
   347  	}
   348  	offset |= arrangement
   349  	// arm64 uses the 60th bit to differentiate from other archs
   350  	// For more details, refer to: obj/arm64/list7.go
   351  	offset |= 1 << 60
   352  	return offset, nil
   353  }
   354  

View as plain text