Home | History | Annotate | Download | only in 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 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 }
    250