github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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  // IsARMFloatCmp reports whether the op is a floating comparison instruction.
   126  func IsARMFloatCmp(op obj.As) bool {
   127  	switch op {
   128  	case arm.ACMPF, arm.ACMPD:
   129  		return true
   130  	}
   131  	return false
   132  }
   133  
   134  // ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
   135  // The difference between MRC and MCR is represented by a bit high in the word, not
   136  // in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
   137  // we return the opcode for MRC so that asm doesn't need to import obj/arm.
   138  func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 obj.As, ok bool) {
   139  	op1 := int64(0)
   140  	if op == arm.AMRC {
   141  		op1 = 1
   142  	}
   143  	bits, ok := ParseARMCondition(cond)
   144  	if !ok {
   145  		return
   146  	}
   147  	offset = (0xe << 24) | // opcode
   148  		(op1 << 20) | // MCR/MRC
   149  		((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
   150  		((x0 & 15) << 8) | //coprocessor number
   151  		((x1 & 7) << 21) | // coprocessor operation
   152  		((x2 & 15) << 12) | // ARM register
   153  		((x3 & 15) << 16) | // Crn
   154  		((x4 & 15) << 0) | // Crm
   155  		((x5 & 7) << 5) | // coprocessor information
   156  		(1 << 4) /* must be set */
   157  	return offset, arm.AMRC, true
   158  }
   159  
   160  // IsARMMULA reports whether the op (as defined by an arm.A* constant) is
   161  // MULA, MULAWT or MULAWB, the 4-operand instructions.
   162  func IsARMMULA(op obj.As) bool {
   163  	switch op {
   164  	case arm.AMULA, arm.AMULAWB, arm.AMULAWT:
   165  		return true
   166  	}
   167  	return false
   168  }
   169  
   170  var bcode = []obj.As{
   171  	arm.ABEQ,
   172  	arm.ABNE,
   173  	arm.ABCS,
   174  	arm.ABCC,
   175  	arm.ABMI,
   176  	arm.ABPL,
   177  	arm.ABVS,
   178  	arm.ABVC,
   179  	arm.ABHI,
   180  	arm.ABLS,
   181  	arm.ABGE,
   182  	arm.ABLT,
   183  	arm.ABGT,
   184  	arm.ABLE,
   185  	arm.AB,
   186  	obj.ANOP,
   187  }
   188  
   189  // ARMConditionCodes handles the special condition code situation for the ARM.
   190  // It returns a boolean to indicate success; failure means cond was unrecognized.
   191  func ARMConditionCodes(prog *obj.Prog, cond string) bool {
   192  	if cond == "" {
   193  		return true
   194  	}
   195  	bits, ok := ParseARMCondition(cond)
   196  	if !ok {
   197  		return false
   198  	}
   199  	/* hack to make B.NE etc. work: turn it into the corresponding conditional */
   200  	if prog.As == arm.AB {
   201  		prog.As = bcode[(bits^arm.C_SCOND_XOR)&0xf]
   202  		bits = (bits &^ 0xf) | arm.C_SCOND_NONE
   203  	}
   204  	prog.Scond = bits
   205  	return true
   206  }
   207  
   208  // ParseARMCondition parses the conditions attached to an ARM instruction.
   209  // The input is a single string consisting of period-separated condition
   210  // codes, such as ".P.W". An initial period is ignored.
   211  func ParseARMCondition(cond string) (uint8, bool) {
   212  	return parseARMCondition(cond, armLS, armSCOND)
   213  }
   214  
   215  func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
   216  	if strings.HasPrefix(cond, ".") {
   217  		cond = cond[1:]
   218  	}
   219  	if cond == "" {
   220  		return arm.C_SCOND_NONE, true
   221  	}
   222  	names := strings.Split(cond, ".")
   223  	bits := uint8(0)
   224  	for _, name := range names {
   225  		if b, present := ls[name]; present {
   226  			bits |= b
   227  			continue
   228  		}
   229  		if b, present := scond[name]; present {
   230  			bits = (bits &^ arm.C_SCOND) | b
   231  			continue
   232  		}
   233  		return 0, false
   234  	}
   235  	return bits, true
   236  }
   237  
   238  func armRegisterNumber(name string, n int16) (int16, bool) {
   239  	if n < 0 || 15 < n {
   240  		return 0, false
   241  	}
   242  	switch name {
   243  	case "R":
   244  		return arm.REG_R0 + n, true
   245  	case "F":
   246  		return arm.REG_F0 + n, true
   247  	}
   248  	return 0, false
   249  }