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 }