github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/cmd/asm/internal/arch/arm.go (about)

     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 ARM
     6  // instruction set, to minimize its interaction with the core of the
     7  // assembler.
     8  
     9  package arch
    10  
    11  import (
    12  	"strings"
    13  
    14  	"cmd/internal/obj"
    15  	"cmd/internal/obj/arm"
    16  )
    17  
    18  var armLS = map[string]uint8{
    19  	"U":  arm.C_UBIT,
    20  	"S":  arm.C_SBIT,
    21  	"W":  arm.C_WBIT,
    22  	"P":  arm.C_PBIT,
    23  	"PW": arm.C_WBIT | arm.C_PBIT,
    24  	"WP": arm.C_WBIT | arm.C_PBIT,
    25  }
    26  
    27  var armSCOND = map[string]uint8{
    28  	"EQ":  arm.C_SCOND_EQ,
    29  	"NE":  arm.C_SCOND_NE,
    30  	"CS":  arm.C_SCOND_HS,
    31  	"HS":  arm.C_SCOND_HS,
    32  	"CC":  arm.C_SCOND_LO,
    33  	"LO":  arm.C_SCOND_LO,
    34  	"MI":  arm.C_SCOND_MI,
    35  	"PL":  arm.C_SCOND_PL,
    36  	"VS":  arm.C_SCOND_VS,
    37  	"VC":  arm.C_SCOND_VC,
    38  	"HI":  arm.C_SCOND_HI,
    39  	"LS":  arm.C_SCOND_LS,
    40  	"GE":  arm.C_SCOND_GE,
    41  	"LT":  arm.C_SCOND_LT,
    42  	"GT":  arm.C_SCOND_GT,
    43  	"LE":  arm.C_SCOND_LE,
    44  	"AL":  arm.C_SCOND_NONE,
    45  	"U":   arm.C_UBIT,
    46  	"S":   arm.C_SBIT,
    47  	"W":   arm.C_WBIT,
    48  	"P":   arm.C_PBIT,
    49  	"PW":  arm.C_WBIT | arm.C_PBIT,
    50  	"WP":  arm.C_WBIT | arm.C_PBIT,
    51  	"F":   arm.C_FBIT,
    52  	"IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT,
    53  	"IAW": arm.C_WBIT | arm.C_UBIT,
    54  	"DBW": arm.C_WBIT | arm.C_PBIT,
    55  	"DAW": arm.C_WBIT,
    56  	"IB":  arm.C_PBIT | arm.C_UBIT,
    57  	"IA":  arm.C_UBIT,
    58  	"DB":  arm.C_PBIT,
    59  	"DA":  0,
    60  }
    61  
    62  var armJump = map[string]bool{
    63  	"B":    true,
    64  	"BL":   true,
    65  	"BX":   true,
    66  	"BEQ":  true,
    67  	"BNE":  true,
    68  	"BCS":  true,
    69  	"BHS":  true,
    70  	"BCC":  true,
    71  	"BLO":  true,
    72  	"BMI":  true,
    73  	"BPL":  true,
    74  	"BVS":  true,
    75  	"BVC":  true,
    76  	"BHI":  true,
    77  	"BLS":  true,
    78  	"BGE":  true,
    79  	"BLT":  true,
    80  	"BGT":  true,
    81  	"BLE":  true,
    82  	"CALL": true,
    83  	"JMP":  true,
    84  }
    85  
    86  func jumpArm(word string) bool {
    87  	return armJump[word]
    88  }
    89  
    90  // IsARMCMP reports whether the op (as defined by an arm.A* constant) is
    91  // one of the comparison instructions that require special handling.
    92  func IsARMCMP(op obj.As) bool {
    93  	switch op {
    94  	case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
    95  		return true
    96  	}
    97  	return false
    98  }
    99  
   100  // IsARMSTREX reports whether the op (as defined by an arm.A* constant) is
   101  // one of the STREX-like instructions that require special handling.
   102  func IsARMSTREX(op obj.As) bool {
   103  	switch op {
   104  	case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
   105  		return true
   106  	}
   107  	return false
   108  }
   109  
   110  // MCR is not defined by the obj/arm; instead we define it privately here.
   111  // It is encoded as an MRC with a bit inside the instruction word,
   112  // passed to arch.ARMMRCOffset.
   113  const aMCR = arm.ALAST + 1
   114  
   115  // IsARMMRC reports whether the op (as defined by an arm.A* constant) is
   116  // MRC or MCR
   117  func IsARMMRC(op obj.As) bool {
   118  	switch op {
   119  	case arm.AMRC, aMCR: // Note: aMCR is defined in this package.
   120  		return true
   121  	}
   122  	return false
   123  }
   124  
   125  // IsARMBFX reports whether the op is arm.BFX or arm.BFXU
   126  func IsARMBFX(op obj.As) bool {
   127  	switch op {
   128  	case arm.ABFX, arm.ABFXU:
   129  		return true
   130  	}
   131  	return false
   132  }
   133  
   134  // IsARMFloatCmp reports whether the op is a floating comparison instruction.
   135  func IsARMFloatCmp(op obj.As) bool {
   136  	switch op {
   137  	case arm.ACMPF, arm.ACMPD:
   138  		return true
   139  	}
   140  	return false
   141  }
   142  
   143  // ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
   144  // The difference between MRC and MCR is represented by a bit high in the word, not
   145  // in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
   146  // we return the opcode for MRC so that asm doesn't need to import obj/arm.
   147  func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 obj.As, ok bool) {
   148  	op1 := int64(0)
   149  	if op == arm.AMRC {
   150  		op1 = 1
   151  	}
   152  	bits, ok := ParseARMCondition(cond)
   153  	if !ok {
   154  		return
   155  	}
   156  	offset = (0xe << 24) | // opcode
   157  		(op1 << 20) | // MCR/MRC
   158  		((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
   159  		((x0 & 15) << 8) | //coprocessor number
   160  		((x1 & 7) << 21) | // coprocessor operation
   161  		((x2 & 15) << 12) | // ARM register
   162  		((x3 & 15) << 16) | // Crn
   163  		((x4 & 15) << 0) | // Crm
   164  		((x5 & 7) << 5) | // coprocessor information
   165  		(1 << 4) /* must be set */
   166  	return offset, arm.AMRC, true
   167  }
   168  
   169  // IsARMMULA reports whether the op (as defined by an arm.A* constant) is
   170  // MULA, MULS, MMULA, MMULS, MULABB, MULAWB or MULAWT, the 4-operand instructions.
   171  func IsARMMULA(op obj.As) bool {
   172  	switch op {
   173  	case arm.AMULA, arm.AMULS, arm.AMMULA, arm.AMMULS, arm.AMULABB, arm.AMULAWB, arm.AMULAWT:
   174  		return true
   175  	}
   176  	return false
   177  }
   178  
   179  var bcode = []obj.As{
   180  	arm.ABEQ,
   181  	arm.ABNE,
   182  	arm.ABCS,
   183  	arm.ABCC,
   184  	arm.ABMI,
   185  	arm.ABPL,
   186  	arm.ABVS,
   187  	arm.ABVC,
   188  	arm.ABHI,
   189  	arm.ABLS,
   190  	arm.ABGE,
   191  	arm.ABLT,
   192  	arm.ABGT,
   193  	arm.ABLE,
   194  	arm.AB,
   195  	obj.ANOP,
   196  }
   197  
   198  // ARMConditionCodes handles the special condition code situation for the ARM.
   199  // It returns a boolean to indicate success; failure means cond was unrecognized.
   200  func ARMConditionCodes(prog *obj.Prog, cond string) bool {
   201  	if cond == "" {
   202  		return true
   203  	}
   204  	bits, ok := ParseARMCondition(cond)
   205  	if !ok {
   206  		return false
   207  	}
   208  	/* hack to make B.NE etc. work: turn it into the corresponding conditional */
   209  	if prog.As == arm.AB {
   210  		prog.As = bcode[(bits^arm.C_SCOND_XOR)&0xf]
   211  		bits = (bits &^ 0xf) | arm.C_SCOND_NONE
   212  	}
   213  	prog.Scond = bits
   214  	return true
   215  }
   216  
   217  // ParseARMCondition parses the conditions attached to an ARM instruction.
   218  // The input is a single string consisting of period-separated condition
   219  // codes, such as ".P.W". An initial period is ignored.
   220  func ParseARMCondition(cond string) (uint8, bool) {
   221  	return parseARMCondition(cond, armLS, armSCOND)
   222  }
   223  
   224  func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
   225  	if strings.HasPrefix(cond, ".") {
   226  		cond = cond[1:]
   227  	}
   228  	if cond == "" {
   229  		return arm.C_SCOND_NONE, true
   230  	}
   231  	names := strings.Split(cond, ".")
   232  	bits := uint8(0)
   233  	for _, name := range names {
   234  		if b, present := ls[name]; present {
   235  			bits |= b
   236  			continue
   237  		}
   238  		if b, present := scond[name]; present {
   239  			bits = (bits &^ arm.C_SCOND) | b
   240  			continue
   241  		}
   242  		return 0, false
   243  	}
   244  	return bits, true
   245  }
   246  
   247  func armRegisterNumber(name string, n int16) (int16, bool) {
   248  	if n < 0 || 15 < n {
   249  		return 0, false
   250  	}
   251  	switch name {
   252  	case "R":
   253  		return arm.REG_R0 + n, true
   254  	case "F":
   255  		return arm.REG_F0 + n, true
   256  	}
   257  	return 0, false
   258  }