1 // Inferno utils/5l/span.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6 // Portions Copyright © 1997-1999 Vita Nuova Limited
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8 // Portions Copyright © 2004,2006 Bruce Ellis
9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11 // Portions Copyright © 2009 The Go Authors. All rights reserved.
13 // Permission is hereby granted, free of charge, to any person obtaining a copy
14 // of this software and associated documentation files (the "Software"), to deal
15 // in the Software without restriction, including without limitation the rights
16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 // copies of the Software, and to permit persons to whom the Software is
18 // furnished to do so, subject to the following conditions:
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
53 type Opcross [32][2][32]uint8
64 OPCODE, from, prog->reg, to, type,size,param,flag */
65 {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0},
66 {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
67 {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
68 {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
69 {AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
70 {ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0},
71 {AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0},
72 {AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
73 {AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
74 {AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
75 {ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0},
76 {AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0},
77 {AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
78 {AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
79 {ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0},
80 {AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0},
81 {AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0},
82 {ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
83 {ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0},
84 {ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
85 {ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // prediction hinted form, hint ignored
87 {AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0},
88 {ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0},
89 {ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0},
90 {ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0},
91 {ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0},
92 {ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0},
93 {ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0},
94 {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0},
95 {ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0},
96 {ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0},
97 {ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0, 0, 0},
98 {ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0},
99 {AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0},
100 {AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0},
101 {AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0},
102 {AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0},
103 {AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0},
104 {AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0},
105 {AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
106 {AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4},
107 {AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0},
108 {AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
109 {AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
110 {ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0},
111 {AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0},
112 {AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
113 {AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
114 {ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0},
115 {AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
116 {AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0},
117 {AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0},
118 {AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
119 {AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0},
120 {AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0},
121 {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
122 {AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0},
123 {ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0},
124 {ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0},
125 {AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0},
126 {AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0, 0, 0},
127 {AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
128 {AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
129 {AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
130 {AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
131 {AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
132 {AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
133 {AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
134 {AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
135 {AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
136 {AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
137 {AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
138 {AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
139 {AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
140 {AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
141 {AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
142 {AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
143 {AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
144 {AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
145 {AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
146 {AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
147 {AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
148 {AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
149 {AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
150 {AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
151 {AMOVW, C_TLS_LE, C_NONE, C_REG, 101, 4, 0, LFROM, 0},
152 {AMOVW, C_TLS_IE, C_NONE, C_REG, 102, 8, 0, LFROM, 0},
153 {AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
154 {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
155 {AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4},
156 {AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
157 {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
158 {AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4},
159 {AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0},
160 {AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0},
161 {AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0},
162 {AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0},
163 {AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0},
164 {AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0},
165 {ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0},
166 {ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0},
167 {AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0},
168 {AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0},
169 {AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0},
170 {AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0},
171 {AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0},
172 {AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0},
173 {AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0},
174 {AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0},
175 {AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4},
176 {AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4},
177 {AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
178 {AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0, 0, 0},
179 {AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
180 {AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0},
181 {AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0},
182 {AMOVW, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0},
183 {AMOVBU, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0},
184 {AMOVB, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0},
185 {AMOVBS, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0},
186 {AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
187 {AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
188 {AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
189 {AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
190 {AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0},
191 {AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0},
192 {AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0},
193 {AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0},
194 {AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0},
195 {AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0},
196 {AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
197 {AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
198 {AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
199 {AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
200 {AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
201 {AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
202 {AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
203 {AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
204 {AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
205 {AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
206 {AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0},
207 {AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0},
208 {AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4},
209 {AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0},
210 {AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0},
211 {AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4},
212 {AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0},
213 {AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0},
214 {AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4},
215 {AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
216 {AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
217 {AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
218 {AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
219 {AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
220 {AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
221 {AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
222 {AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
223 {AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
224 {AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
225 {AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
226 {AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
227 {AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
228 {AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
229 {AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
230 {ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0},
231 {ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0},
232 {AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0},
233 {AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0},
234 {ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0, 0, 0},
235 {ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0},
236 {AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0},
237 {AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0},
238 {AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0},
239 {AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0},
240 {AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0},
241 {AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0},
242 {ATST, C_REG, C_NONE, C_NONE, 90, 4, 0, 0, 0},
243 {ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0},
244 {ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0},
245 {APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0},
246 {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0},
247 {ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0},
248 {AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0},
249 {AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0},
250 {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0},
251 {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0},
252 {obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
253 {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
254 {obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL
255 {obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL
257 {ADATABUNDLE, C_NONE, C_NONE, C_NONE, 100, 4, 0, 0, 0},
258 {ADATABUNDLEEND, C_NONE, C_NONE, C_NONE, 100, 0, 0, 0, 0},
259 {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0},
268 var oprange [ALAST & obj.AMask][]Optab
270 var xcmp [C_GOK + 1][C_GOK + 1]bool
272 var deferreturn *obj.LSym
274 // Note about encoding: Prog.scond holds the condition encoding,
275 // but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0.
276 // The code that shifts the value << 28 has the responsibility
277 // for XORing with C_SCOND_XOR too.
279 // asmoutnacl assembles the instruction p. It replaces asmout for NaCl.
280 // It returns the total number of bytes put in out, and it can change
281 // p->pc if extra padding is necessary.
282 // In rare cases, asmoutnacl might split p into two instructions.
283 // origPC is the PC for this Prog (no padding is taken into account).
284 func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint32) int {
287 // instruction specific
291 asmout(ctxt, p, o, out)
294 case ADATABUNDLE, // align to 16-byte boundary
295 ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary
296 p.Pc = (p.Pc + 15) &^ 15
299 asmout(ctxt, p, o, out)
308 out[0] = 0xe7fedef0 // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
311 out[0] = 0xe1a01001 // (MOVW R1, R1)
316 if p.To.Type != obj.TYPE_MEM {
318 asmout(ctxt, p, o, out)
321 if p.To.Offset != 0 || size != 4 || p.To.Reg > REG_R15 || p.To.Reg < REG_R0 {
322 ctxt.Diag("unsupported instruction: %v", p)
328 out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c0013f | (uint32(p.To.Reg)&15)<<12 | (uint32(p.To.Reg)&15)<<16 // BIC $0xc000000f, Rx
330 out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff10 | (uint32(p.To.Reg)&15)<<0 // BX Rx
332 out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff30 | (uint32(p.To.Reg)&15)<<0 // BLX Rx
339 // align the last instruction (the actual BL) to the last instruction in a bundle
341 if deferreturn == nil {
342 deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0)
344 if p.To.Sym == deferreturn {
345 p.Pc = ((int64(origPC) + 15) &^ 15) + 16 - int64(size)
347 p.Pc += (16 - ((p.Pc + int64(size)) & 15)) & 15
365 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 && p.From.Reg == REG_R13 { // MOVW.W x(R13), PC
367 asmout(ctxt, p, o, out)
371 // Note: 5c and 5g reg.c know that DIV/MOD smashes R12
372 // so that this return instruction expansion is valid.
373 out[0] = out[0] &^ 0x3000 // change PC to R12
374 out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12
375 out[2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12
379 if (p.Pc+int64(size))&15 == 4 {
384 // if the instruction used more than 4 bytes, then it must have used a very large
385 // offset to update R13, so we need to additionally mask R13.
387 out[size/4-1] &^= 0x3000 // change PC to R12
388 out[size/4] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03cdd103 // BIC $0xc0000000, R13
389 out[size/4+1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12
390 out[size/4+2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12
393 // p->pc+size is only ok at 4 or 12 mod 16.
394 if (p.Pc+int64(size))%8 == 0 {
402 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 {
403 ctxt.Diag("unsupported instruction (move to another register and use indirect jump instead): %v", p)
406 if p.To.Type == obj.TYPE_MEM && p.To.Reg == REG_R13 && (p.Scond&C_WBIT != 0) && size > 4 {
407 // function prolog with very large frame size: MOVW.W R14,-100004(R13)
408 // split it into two instructions:
417 if p.To.Type == obj.TYPE_MEM {
431 // make p into ADD $X, R13
436 p.From.Type = obj.TYPE_CONST
438 p.To.Type = obj.TYPE_REG
441 // make q into p but load/store from 0(R13)
445 a2.Type = obj.TYPE_MEM
449 size = int(oplook(ctxt, p).size)
453 if (p.To.Type == obj.TYPE_MEM && p.To.Reg != REG_R9) || // MOVW Rx, X(Ry), y != 9
454 (p.From.Type == obj.TYPE_MEM && p.From.Reg != REG_R9) { // MOVW X(Rx), Ry, x != 9
456 if p.To.Type == obj.TYPE_MEM {
463 // if addr.reg == 0, then it is probably load from x(FP) with small x, no need to modify.
466 asmout(ctxt, p, o, out)
470 out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c00103 | (uint32(reg)&15)<<16 | (uint32(reg)&15)<<12 // BIC $0xc0000000, Rx
477 asmout(ctxt, p, o, out[1:])
483 // if a load/store instruction takes more than 1 word to implement, then
484 // we need to separate the instruction into two:
485 // 1. explicitly load the address into R11.
486 // 2. load/store from R11.
487 // This won't handle .W/.P, so we should reject such code.
488 if p.Scond&(C_PBIT|C_WBIT) != 0 {
489 ctxt.Diag("unsupported instruction (.P/.W): %v", p)
494 if p.To.Type == obj.TYPE_MEM {
508 // make p into MOVW $X(R), R11
512 p.From.Type = obj.TYPE_ADDR
514 p.To.Type = obj.TYPE_REG
517 // make q into p but load/store from 0(R11)
520 a2.Type = obj.TYPE_MEM
524 size = int(oplook(ctxt, p).size)
527 } else if out != nil {
528 asmout(ctxt, p, o, out)
532 // destination register specific
533 if p.To.Type == obj.TYPE_REG {
536 ctxt.Diag("invalid instruction, cannot write to R9: %v", p)
540 out[size/4] = 0xe3cdd103 // BIC $0xc0000000, R13
542 if (p.Pc+int64(size))&15 == 0 {
552 func span5(ctxt *obj.Link, cursym *obj.LSym) {
557 if p == nil || p.Link == nil { // handle external functions and ELF section symbols
561 if oprange[AAND&obj.AMask] == nil {
567 ctxt.Autosize = int32(p.To.Offset + 4)
575 for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link {
577 if checkpool(ctxt, op, 0) {
582 // can't happen: blitrl is not nil, but checkpool didn't flushpool
583 ctxt.Diag("internal inconsistency")
591 if ctxt.Headtype != obj.Hnacl {
594 m = asmoutnacl(ctxt, c, p, o, nil)
595 c = int32(p.Pc) // asmoutnacl might change pc for alignment
596 o = oplook(ctxt, p) // asmoutnacl might change p in rare cases
599 if m%4 != 0 || p.Pc%4 != 0 {
600 ctxt.Diag("!pc invalid: %v size=%d", p, m)
603 // must check literal pool here in case p generates many instructions
604 if ctxt.Blitrl != nil {
606 if checkpool(ctxt, op, i) {
612 if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) {
613 ctxt.Diag("zero-width instruction\n%v", p)
617 switch o.flag & (LFROM | LTO | LPOOL) {
619 addpool(ctxt, p, &p.From)
622 addpool(ctxt, p, &p.To)
625 if p.Scond&C_SCOND == C_SCOND_NONE {
626 flushpool(ctxt, p, 0, 0)
630 if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE {
631 flushpool(ctxt, p, 0, 0)
636 cursym.Size = int64(c)
639 * if any procedure is large enough to
640 * generate a large SBRA branch, then
641 * generate extra passes putting branches
642 * around jmps to fix. this is rare.
648 var out [6 + 3]uint32
650 if ctxt.Debugvlog != 0 {
651 fmt.Fprintf(ctxt.Bso, "%5.2f span1\n", obj.Cputime())
656 cursym.Text.Pc = 0 // force re-layout the code.
657 for p = cursym.Text; p != nil; p = p.Link {
664 /* very large branches
665 if(o->type == 6 && p->pcond) {
666 otxt = p->pcond->pc - c;
669 if(otxt >= (1L<<17) - 10) {
670 q = emallocz(sizeof(Prog));
674 q->to.type = TYPE_BRANCH;
677 q = emallocz(sizeof(Prog));
681 q->to.type = TYPE_BRANCH;
682 q->pcond = q->link->link;
689 if ctxt.Headtype != obj.Hnacl {
692 m = asmoutnacl(ctxt, c, p, o, nil)
694 if p.Pc != int64(opc) {
698 //print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
699 c = int32(p.Pc + int64(m))
701 if m%4 != 0 || p.Pc%4 != 0 {
702 ctxt.Diag("pc invalid: %v size=%d", p, m)
706 ctxt.Diag("instruction size too large: %d > %d", m/4, len(out))
708 if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) {
709 if p.As == obj.ATEXT {
710 ctxt.Autosize = int32(p.To.Offset + 4)
714 ctxt.Diag("zero-width instruction\n%v", p)
719 cursym.Size = int64(c)
726 ctxt.Diag("sym->size=%d, invalid", c)
730 * lay out the code. all the pc-relative code references,
731 * even cross-function, are resolved now;
732 * only data references need to be relocated.
733 * with more work we could leave cross-function
734 * code references to be relocated too, and then
735 * perhaps we'd be able to parallelize the span loop above.
739 ctxt.Autosize = int32(p.To.Offset + 4)
740 cursym.Grow(cursym.Size)
743 c = int32(p.Pc) // even p->link might need extra padding
745 for p = p.Link; p != nil; p = p.Link {
750 if ctxt.Headtype != obj.Hnacl {
751 asmout(ctxt, p, o, out[:])
754 m = asmoutnacl(ctxt, c, p, o, out[:])
755 if int64(opc) != p.Pc {
756 ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p)
760 if m%4 != 0 || p.Pc%4 != 0 {
761 ctxt.Diag("final stage: pc invalid: %v size=%d", p, m)
765 ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, c, p)
767 for int64(c) != p.Pc {
768 // emit 0xe1a00000 (MOVW R0, R0)
781 for i = 0; i < m/4; i++ {
787 bp[0] = byte(v >> 16)
789 bp[0] = byte(v >> 24)
798 * when the first reference to the literal pool threatens
799 * to go out of range of a 12-bit PC-relative offset,
800 * drop the pool now, and branch round it.
801 * this happens only in extended basic blocks that exceed 4k.
803 func checkpool(ctxt *obj.Link, p *obj.Prog, sz int) bool {
804 if pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+pool.size)-int64(pool.start+8))) == 0 {
805 return flushpool(ctxt, p, 1, 0)
806 } else if p.Link == nil {
807 return flushpool(ctxt, p, 2, 0)
812 func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool {
813 if ctxt.Blitrl != nil {
815 if false && skip == 1 {
816 fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start)
820 q.To.Type = obj.TYPE_BRANCH
825 } else if force == 0 && (p.Pc+int64(12+pool.size)-int64(pool.start) < 2048) { // 12 take into account the maximum nacl literal pool alignment padding size
828 if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 {
829 // if pool is not multiple of 16 bytes, add an alignment marker
832 q.As = ADATABUNDLEEND
837 // The line number for constant pool entries doesn't really matter.
838 // We set it to the line number of the preceding instruction so that
839 // there are no deltas to encode in the pc-line tables.
840 for q := ctxt.Blitrl; q != nil; q = q.Link {
844 ctxt.Elitrl.Link = p.Link
847 ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */
858 func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
868 t.To.Offset = a.Offset
873 if ctxt.Flag_shared && t.To.Sym != nil {
887 t.To.Type = obj.TYPE_CONST
888 t.To.Offset = ctxt.Instoffset
892 for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
893 if q.Rel == nil && q.To == t.To {
900 if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 {
901 // start a new data bundle
904 q.Pc = int64(pool.size)
906 if ctxt.Blitrl == nil {
908 pool.start = uint32(p.Pc)
918 q.Pc = int64(pool.size)
920 if ctxt.Blitrl == nil {
922 pool.start = uint32(p.Pc)
932 func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
935 return int32(ctxt.Instoffset)
938 func immrot(v uint32) int32 {
939 for i := 0; i < 16; i++ {
941 return int32(uint32(int32(i)<<8) | v | 1<<25)
949 func immaddr(v int32) int32 {
950 if v >= 0 && v <= 0xfff {
951 return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */
953 if v >= -0xfff && v < 0 {
954 return -v&0xfff | 1<<24 /* pre indexing */
959 func immfloat(v int32) bool {
960 return v&0xC03 == 0 /* offset will fit in floating-point load/store */
963 func immhalf(v int32) bool {
964 if v >= 0 && v <= 0xff {
965 return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */
967 if v >= -0xff && v < 0 {
968 return -v&0xff|1<<24 != 0 /* pre indexing */
973 func aclass(ctxt *obj.Link, a *obj.Addr) int {
980 if REG_R0 <= a.Reg && a.Reg <= REG_R15 {
983 if REG_F0 <= a.Reg && a.Reg <= REG_F15 {
986 if a.Reg == REG_FPSR || a.Reg == REG_FPCR {
989 if a.Reg == REG_CPSR || a.Reg == REG_SPSR {
994 case obj.TYPE_REGREG:
997 case obj.TYPE_REGREG2:
1000 case obj.TYPE_REGLIST:
1003 case obj.TYPE_SHIFT:
1008 case obj.NAME_EXTERN,
1011 if a.Sym == nil || a.Sym.Name == "" {
1012 fmt.Printf("null sym external\n")
1016 ctxt.Instoffset = 0 // s.b. unused but just in case
1017 if a.Sym.Type == obj.STLSBSS {
1018 if ctxt.Flag_shared {
1028 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
1029 t := int(immaddr(int32(ctxt.Instoffset)))
1031 if immhalf(int32(ctxt.Instoffset)) {
1032 if immfloat(int32(t)) {
1038 if immfloat(int32(t)) {
1046 case obj.NAME_PARAM:
1047 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
1048 t := int(immaddr(int32(ctxt.Instoffset)))
1050 if immhalf(int32(ctxt.Instoffset)) {
1051 if immfloat(int32(t)) {
1057 if immfloat(int32(t)) {
1066 ctxt.Instoffset = a.Offset
1067 t := int(immaddr(int32(ctxt.Instoffset)))
1069 if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */
1070 if immfloat(int32(t)) {
1076 if immfloat(int32(t)) {
1077 return C_FOREG /* n.b. that it will also satisfy immrot */
1079 t := int(immrot(uint32(ctxt.Instoffset)))
1083 if immhalf(int32(ctxt.Instoffset)) {
1089 t = int(immrot(uint32(ctxt.Instoffset)))
1098 case obj.TYPE_FCONST:
1099 if chipzero5(ctxt, a.Val.(float64)) >= 0 {
1102 if chipfloat5(ctxt, a.Val.(float64)) >= 0 {
1107 case obj.TYPE_TEXTSIZE:
1110 case obj.TYPE_CONST,
1114 ctxt.Instoffset = a.Offset
1116 return aconsize(ctxt)
1119 t := int(immrot(uint32(ctxt.Instoffset)))
1123 t = int(immrot(^uint32(ctxt.Instoffset)))
1129 case obj.NAME_EXTERN,
1136 ctxt.Instoffset = 0 // s.b. unused but just in case
1140 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
1141 return aconsize(ctxt)
1143 case obj.NAME_PARAM:
1144 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
1145 return aconsize(ctxt)
1150 case obj.TYPE_BRANCH:
1157 func aconsize(ctxt *obj.Link) int {
1158 t := int(immrot(uint32(ctxt.Instoffset)))
1165 func prasm(p *obj.Prog) {
1166 fmt.Printf("%v\n", p)
1169 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
1174 a1 = int(p.From.Class)
1176 a1 = aclass(ctxt, &p.From) + 1
1177 p.From.Class = int8(a1)
1181 a3 := int(p.To.Class)
1183 a3 = aclass(ctxt, &p.To) + 1
1184 p.To.Class = int8(a3)
1193 if false { /*debug['O']*/
1194 fmt.Printf("oplook %v %v %v %v\n", obj.Aconv(p.As), DRconv(a1), DRconv(a2), DRconv(a3))
1195 fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
1198 ops := oprange[p.As&obj.AMask]
1201 for i := range ops {
1203 if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] {
1204 p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
1209 ctxt.Diag("illegal combination %v; %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.To.Type)
1210 ctxt.Diag("from %d %d to %d %d\n", p.From.Type, p.From.Name, p.To.Type, p.To.Name)
1218 func cmp(a int, b int) bool {
1224 if b == C_RCON || b == C_NCON {
1234 if b == C_ZFCON || b == C_SFCON {
1239 return b == C_HAUTO || b == C_FAUTO
1241 case C_FAUTO, C_HAUTO:
1242 return b == C_HFAUTO
1245 return cmp(C_HFAUTO, b)
1248 return cmp(C_SAUTO, b)
1251 return b == C_HOREG || b == C_FOREG
1253 case C_FOREG, C_HOREG:
1254 return b == C_HFOREG
1257 return cmp(C_SOREG, b) || cmp(C_ROREG, b)
1259 case C_SOREG, C_ROREG:
1260 return b == C_SROREG || cmp(C_HFOREG, b)
1263 return cmp(C_SROREG, b)
1271 return cmp(C_SP, b) || cmp(C_PC, b)
1279 func (x ocmp) Len() int {
1283 func (x ocmp) Swap(i, j int) {
1284 x[i], x[j] = x[j], x[i]
1287 func (x ocmp) Less(i, j int) bool {
1290 n := int(p1.as) - int(p2.as)
1294 n = int(p1.a1) - int(p2.a1)
1298 n = int(p1.a2) - int(p2.a2)
1302 n = int(p1.a3) - int(p2.a3)
1309 func opset(a, b0 obj.As) {
1310 oprange[a&obj.AMask] = oprange[b0]
1313 func buildop(ctxt *obj.Link) {
1316 for i := 0; i < C_GOK; i++ {
1317 for n = 0; n < C_GOK; n++ {
1323 for n = 0; optab[n].as != obj.AXXX; n++ {
1324 if optab[n].flag&LPCREL != 0 {
1325 if ctxt.Flag_shared {
1326 optab[n].size += int8(optab[n].pcrelsiz)
1328 optab[n].flag &^= LPCREL
1333 sort.Sort(ocmp(optab[:n]))
1334 for i := 0; i < n; i++ {
1338 for optab[i].as == r {
1341 oprange[r0] = optab[start:i]
1346 ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
1347 log.Fatalf("bad code")
1480 func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
1488 ctxt.Armsize += int32(o.size)
1489 if false { /*debug['P']*/
1490 fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
1494 ctxt.Diag("unknown asm %d", o.type_)
1497 case 0: /* pseudo ops */
1498 if false { /*debug['G']*/
1499 fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
1502 case 1: /* op R,[R],R */
1503 o1 = oprrr(ctxt, p.As, int(p.Scond))
1505 rf := int(p.From.Reg)
1508 if p.To.Type == obj.TYPE_NONE {
1511 if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN {
1516 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1518 case 2: /* movbu $I,[R],R */
1519 aclass(ctxt, &p.From)
1521 o1 = oprrr(ctxt, p.As, int(p.Scond))
1522 o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
1525 if p.To.Type == obj.TYPE_NONE {
1528 if p.As == AMOVW || p.As == AMVN {
1533 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1535 case 3: /* add R<<[IR],[R],R */
1538 case 4: /* add $I,[R],R */
1539 aclass(ctxt, &p.From)
1541 o1 = oprrr(ctxt, AADD, int(p.Scond))
1542 o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
1543 r := int(p.From.Reg)
1547 o1 |= (uint32(r) & 15) << 16
1548 o1 |= (uint32(p.To.Reg) & 15) << 12
1551 o1 = opbra(ctxt, p, p.As, int(p.Scond))
1554 if p.To.Sym != nil {
1555 rel := obj.Addrel(ctxt.Cursym)
1556 rel.Off = int32(ctxt.Pc)
1559 v += int32(p.To.Offset)
1560 rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
1561 rel.Type = obj.R_CALLARM
1566 v = int32((p.Pcond.Pc - ctxt.Pc) - 8)
1568 o1 |= (uint32(v) >> 2) & 0xffffff
1570 case 6: /* b ,O(R) -> add $O,R,PC */
1573 o1 = oprrr(ctxt, AADD, int(p.Scond))
1574 o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
1575 o1 |= (uint32(p.To.Reg) & 15) << 16
1576 o1 |= (REGPC & 15) << 12
1578 case 7: /* bl (R) -> blx R */
1581 if ctxt.Instoffset != 0 {
1582 ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, ctxt.Instoffset)
1584 o1 = oprrr(ctxt, ABL, int(p.Scond))
1585 o1 |= (uint32(p.To.Reg) & 15) << 0
1586 rel := obj.Addrel(ctxt.Cursym)
1587 rel.Off = int32(ctxt.Pc)
1589 rel.Type = obj.R_CALLIND
1591 case 8: /* sll $c,[R],R -> mov (R<<$c),R */
1592 aclass(ctxt, &p.From)
1594 o1 = oprrr(ctxt, p.As, int(p.Scond))
1599 o1 |= (uint32(r) & 15) << 0
1600 o1 |= uint32((ctxt.Instoffset & 31) << 7)
1601 o1 |= (uint32(p.To.Reg) & 15) << 12
1603 case 9: /* sll R,[R],R -> mov (R<<R),R */
1604 o1 = oprrr(ctxt, p.As, int(p.Scond))
1610 o1 |= (uint32(r) & 15) << 0
1611 o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4
1612 o1 |= (uint32(p.To.Reg) & 15) << 12
1614 case 10: /* swi [$con] */
1615 o1 = oprrr(ctxt, p.As, int(p.Scond))
1617 if p.To.Type != obj.TYPE_NONE {
1619 o1 |= uint32(ctxt.Instoffset & 0xffffff)
1625 o1 = uint32(ctxt.Instoffset)
1626 if p.To.Sym != nil {
1627 // This case happens with words generated
1628 // in the PC stream as part of the literal pool.
1629 rel := obj.Addrel(ctxt.Cursym)
1631 rel.Off = int32(ctxt.Pc)
1634 rel.Add = p.To.Offset
1636 if ctxt.Flag_shared {
1637 if p.To.Name == obj.NAME_GOTREF {
1638 rel.Type = obj.R_GOTPCREL
1640 rel.Type = obj.R_PCREL
1642 rel.Add += ctxt.Pc - p.Rel.Pc - 8
1644 rel.Type = obj.R_ADDR
1649 case 12: /* movw $lcon, reg */
1650 o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
1652 if o.flag&LPCREL != 0 {
1653 o2 = oprrr(ctxt, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
1656 case 13: /* op $lcon, [R], R */
1657 o1 = omvl(ctxt, p, &p.From, REGTMP)
1662 o2 = oprrr(ctxt, p.As, int(p.Scond))
1665 if p.As == AMOVW || p.As == AMVN {
1670 o2 |= (uint32(r) & 15) << 16
1671 if p.To.Type != obj.TYPE_NONE {
1672 o2 |= (uint32(p.To.Reg) & 15) << 12
1675 case 14: /* movb/movbu/movh/movhu R,R */
1676 o1 = oprrr(ctxt, ASLL, int(p.Scond))
1678 if p.As == AMOVBU || p.As == AMOVHU {
1679 o2 = oprrr(ctxt, ASRL, int(p.Scond))
1681 o2 = oprrr(ctxt, ASRA, int(p.Scond))
1685 o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12
1686 o2 |= uint32(r)&15 | (uint32(r)&15)<<12
1687 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
1695 case 15: /* mul r,[r,]r */
1696 o1 = oprrr(ctxt, p.As, int(p.Scond))
1698 rf := int(p.From.Reg)
1710 if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 {
1711 ctxt.Diag("bad registers in MUL")
1716 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
1718 case 16: /* div r,[r,]r */
1724 o1 = oprrr(ctxt, p.As, int(p.Scond))
1725 rf := int(p.From.Reg)
1727 rt2 := int(p.To.Offset)
1729 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
1731 case 20: /* mov/movb/movbu R,O(R) */
1738 o1 = osr(ctxt, p.As, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
1740 case 21: /* mov/movbu O(R),R -> lr */
1741 aclass(ctxt, &p.From)
1743 r := int(p.From.Reg)
1747 o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
1752 case 30: /* mov/movb/movbu R,L(R) */
1753 o1 = omvl(ctxt, p, &p.To, REGTMP)
1762 o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
1767 case 31: /* mov/movbu L(R),R -> lr[b] */
1768 o1 = omvl(ctxt, p, &p.From, REGTMP)
1773 r := int(p.From.Reg)
1777 o2 = olrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
1778 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
1782 case 34: /* mov $lacon,R */
1783 o1 = omvl(ctxt, p, &p.From, REGTMP)
1789 o2 = oprrr(ctxt, AADD, int(p.Scond))
1791 r := int(p.From.Reg)
1795 o2 |= (uint32(r) & 15) << 16
1796 if p.To.Type != obj.TYPE_NONE {
1797 o2 |= (uint32(p.To.Reg) & 15) << 12
1800 case 35: /* mov PSR,R */
1801 o1 = 2<<23 | 0xf<<16 | 0<<0
1803 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1804 o1 |= (uint32(p.From.Reg) & 1) << 22
1805 o1 |= (uint32(p.To.Reg) & 15) << 12
1807 case 36: /* mov R,PSR */
1808 o1 = 2<<23 | 0x29f<<12 | 0<<4
1810 if p.Scond&C_FBIT != 0 {
1813 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1814 o1 |= (uint32(p.To.Reg) & 1) << 22
1815 o1 |= (uint32(p.From.Reg) & 15) << 0
1817 case 37: /* mov $con,PSR */
1818 aclass(ctxt, &p.From)
1820 o1 = 2<<23 | 0x29f<<12 | 0<<4
1821 if p.Scond&C_FBIT != 0 {
1824 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1825 o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
1826 o1 |= (uint32(p.To.Reg) & 1) << 22
1827 o1 |= (uint32(p.From.Reg) & 15) << 0
1831 case 38: /* movm $con,oreg -> stm */
1834 o1 |= uint32(p.From.Offset & 0xffff)
1835 o1 |= (uint32(p.To.Reg) & 15) << 16
1838 case 39: /* movm oreg,$con -> ldm */
1839 o1 = 0x4<<25 | 1<<20
1841 o1 |= uint32(p.To.Offset & 0xffff)
1842 o1 |= (uint32(p.From.Reg) & 15) << 16
1843 aclass(ctxt, &p.From)
1846 if ctxt.Instoffset != 0 {
1847 ctxt.Diag("offset must be zero in MOVM; %v", p)
1849 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1850 if p.Scond&C_PBIT != 0 {
1853 if p.Scond&C_UBIT != 0 {
1856 if p.Scond&C_SBIT != 0 {
1859 if p.Scond&C_WBIT != 0 {
1863 case 40: /* swp oreg,reg,reg */
1864 aclass(ctxt, &p.From)
1866 if ctxt.Instoffset != 0 {
1867 ctxt.Diag("offset must be zero in SWP")
1869 o1 = 0x2<<23 | 0x9<<4
1873 o1 |= (uint32(p.From.Reg) & 15) << 16
1874 o1 |= (uint32(p.Reg) & 15) << 0
1875 o1 |= (uint32(p.To.Reg) & 15) << 12
1876 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1878 case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
1881 case 50: /* floating point store */
1882 v := regoff(ctxt, &p.To)
1888 o1 = ofsr(ctxt, p.As, int(p.From.Reg), v, r, int(p.Scond), p)
1890 case 51: /* floating point load */
1891 v := regoff(ctxt, &p.From)
1893 r := int(p.From.Reg)
1897 o1 = ofsr(ctxt, p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
1899 case 52: /* floating point store, int32 offset UGLY */
1900 o1 = omvl(ctxt, p, &p.To, REGTMP)
1909 o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
1910 o3 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
1912 case 53: /* floating point load, int32 offset UGLY */
1913 o1 = omvl(ctxt, p, &p.From, REGTMP)
1918 r := int(p.From.Reg)
1922 o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
1923 o3 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
1925 case 54: /* floating point arith */
1926 o1 = oprrr(ctxt, p.As, int(p.Scond))
1928 rf := int(p.From.Reg)
1933 if p.As == AMOVF || p.As == AMOVD || p.As == AMOVFD || p.As == AMOVDF || p.As == ASQRTF || p.As == ASQRTD || p.As == AABSF || p.As == AABSD {
1938 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1940 case 56: /* move to FP[CS]R */
1941 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
1943 o1 |= ((uint32(p.To.Reg)&1)+1)<<21 | (uint32(p.From.Reg)&15)<<12
1945 case 57: /* move from FP[CS]R */
1946 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
1948 o1 |= ((uint32(p.From.Reg)&1)+1)<<21 | (uint32(p.To.Reg)&15)<<12 | 1<<20
1950 case 58: /* movbu R,R */
1951 o1 = oprrr(ctxt, AAND, int(p.Scond))
1953 o1 |= uint32(immrot(0xff))
1955 r := int(p.From.Reg)
1956 if p.To.Type == obj.TYPE_NONE {
1962 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1964 case 59: /* movw/bu R<<I(R),R -> ldr indexed */
1965 if p.From.Reg == 0 {
1967 ctxt.Diag("byte MOV from shifter operand")
1973 if p.From.Offset&(1<<4) != 0 {
1974 ctxt.Diag("bad shift in LDR")
1976 o1 = olrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
1981 case 60: /* movb R(R),R -> ldrsb indexed */
1982 if p.From.Reg == 0 {
1983 ctxt.Diag("byte MOV from shifter operand")
1988 if p.From.Offset&(^0xf) != 0 {
1989 ctxt.Diag("bad shift in LDRSB")
1991 o1 = olhrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
1994 case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
1996 ctxt.Diag("MOV to shifter operand")
1998 o1 = osrr(ctxt, int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
1999 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
2004 case 64: /* mov/movb/movbu R,addr */
2005 o1 = omvl(ctxt, p, &p.To, REGTMP)
2010 o2 = osr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond))
2011 if o.flag&LPCREL != 0 {
2013 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2016 case 65: /* mov/movbu addr,R */
2017 o1 = omvl(ctxt, p, &p.From, REGTMP)
2022 o2 = olr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
2023 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
2026 if o.flag&LPCREL != 0 {
2028 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2031 case 101: /* movw tlsvar,R, local exec*/
2032 if p.Scond&C_SCOND != C_SCOND_NONE {
2033 ctxt.Diag("conditional tls")
2035 o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
2037 case 102: /* movw tlsvar,R, initial exec*/
2038 if p.Scond&C_SCOND != C_SCOND_NONE {
2039 ctxt.Diag("conditional tls")
2041 o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
2042 o2 = olrr(ctxt, int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond))
2044 case 103: /* word tlsvar, local exec */
2045 if p.To.Sym == nil {
2046 ctxt.Diag("nil sym in tls %v", p)
2048 if p.To.Offset != 0 {
2049 ctxt.Diag("offset against tls var in %v", p)
2051 // This case happens with words generated in the PC stream as part of
2052 // the literal pool.
2053 rel := obj.Addrel(ctxt.Cursym)
2055 rel.Off = int32(ctxt.Pc)
2058 rel.Type = obj.R_TLS_LE
2061 case 104: /* word tlsvar, initial exec */
2062 if p.To.Sym == nil {
2063 ctxt.Diag("nil sym in tls %v", p)
2065 if p.To.Offset != 0 {
2066 ctxt.Diag("offset against tls var in %v", p)
2068 rel := obj.Addrel(ctxt.Cursym)
2069 rel.Off = int32(ctxt.Pc)
2072 rel.Type = obj.R_TLS_IE
2073 rel.Add = ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz)
2075 case 68: /* floating point store -> ADDR */
2076 o1 = omvl(ctxt, p, &p.To, REGTMP)
2081 o2 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
2082 if o.flag&LPCREL != 0 {
2084 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2087 case 69: /* floating point load <- ADDR */
2088 o1 = omvl(ctxt, p, &p.From, REGTMP)
2093 o2 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
2094 if o.flag&LPCREL != 0 {
2096 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2100 case 70: /* movh/movhu R,O(R) -> strh */
2107 o1 = oshr(ctxt, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
2109 case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
2110 aclass(ctxt, &p.From)
2112 r := int(p.From.Reg)
2116 o1 = olhr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
2117 if p.As == AMOVB || p.As == AMOVBS {
2119 } else if p.As == AMOVH || p.As == AMOVHS {
2123 case 72: /* movh/movhu R,L(R) -> strh */
2124 o1 = omvl(ctxt, p, &p.To, REGTMP)
2133 o2 = oshrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
2135 case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
2136 o1 = omvl(ctxt, p, &p.From, REGTMP)
2141 r := int(p.From.Reg)
2145 o2 = olhrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
2146 if p.As == AMOVB || p.As == AMOVBS {
2148 } else if p.As == AMOVH || p.As == AMOVHS {
2152 case 74: /* bx $I */
2155 case 75: /* bx O(R) */
2158 if ctxt.Instoffset != 0 {
2159 ctxt.Diag("non-zero offset in ABX")
2163 o1 = oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR
2164 o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R
2166 // p->to.reg may be REGLINK
2167 o1 = oprrr(ctxt, AADD, int(p.Scond))
2169 o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
2170 o1 |= (uint32(p.To.Reg) & 15) << 16
2171 o1 |= (REGTMP & 15) << 12
2172 o2 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
2173 o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp
2175 case 76: /* bx O(R) when returning from fn*/
2178 case 77: /* ldrex oreg,reg */
2179 aclass(ctxt, &p.From)
2181 if ctxt.Instoffset != 0 {
2182 ctxt.Diag("offset must be zero in LDREX")
2184 o1 = 0x19<<20 | 0xf9f
2185 o1 |= (uint32(p.From.Reg) & 15) << 16
2186 o1 |= (uint32(p.To.Reg) & 15) << 12
2187 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2189 case 78: /* strex reg,oreg,reg */
2190 aclass(ctxt, &p.From)
2192 if ctxt.Instoffset != 0 {
2193 ctxt.Diag("offset must be zero in STREX")
2195 o1 = 0x18<<20 | 0xf90
2196 o1 |= (uint32(p.From.Reg) & 15) << 16
2197 o1 |= (uint32(p.Reg) & 15) << 0
2198 o1 |= (uint32(p.To.Reg) & 15) << 12
2199 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2201 case 80: /* fmov zfcon,freg */
2203 o1 = 0xeeb00b00 // VMOV imm 64
2204 o2 = oprrr(ctxt, ASUBD, int(p.Scond))
2206 o1 = 0x0eb00a00 // VMOV imm 32
2207 o2 = oprrr(ctxt, ASUBF, int(p.Scond))
2210 v := int32(0x70) // 1.0
2211 r := (int(p.To.Reg) & 15) << 0
2214 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2216 o1 |= (uint32(r) & 15) << 12
2217 o1 |= (uint32(v) & 0xf) << 0
2218 o1 |= (uint32(v) & 0xf0) << 12
2221 o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12
2223 case 81: /* fmov sfcon,freg */
2224 o1 = 0x0eb00a00 // VMOV imm 32
2226 o1 = 0xeeb00b00 // VMOV imm 64
2228 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2229 o1 |= (uint32(p.To.Reg) & 15) << 12
2230 v := int32(chipfloat5(ctxt, p.From.Val.(float64)))
2231 o1 |= (uint32(v) & 0xf) << 0
2232 o1 |= (uint32(v) & 0xf0) << 12
2234 case 82: /* fcmp freg,freg, */
2235 o1 = oprrr(ctxt, p.As, int(p.Scond))
2237 o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0
2238 o2 = 0x0ef1fa10 // VMRS R15
2239 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2241 case 83: /* fcmp freg,, */
2242 o1 = oprrr(ctxt, p.As, int(p.Scond))
2244 o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16
2245 o2 = 0x0ef1fa10 // VMRS R15
2246 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2248 case 84: /* movfw freg,freg - truncate float-to-fix */
2249 o1 = oprrr(ctxt, p.As, int(p.Scond))
2251 o1 |= (uint32(p.From.Reg) & 15) << 0
2252 o1 |= (uint32(p.To.Reg) & 15) << 12
2254 case 85: /* movwf freg,freg - fix-to-float */
2255 o1 = oprrr(ctxt, p.As, int(p.Scond))
2257 o1 |= (uint32(p.From.Reg) & 15) << 0
2258 o1 |= (uint32(p.To.Reg) & 15) << 12
2260 // macro for movfw freg,FTMP; movw FTMP,reg
2261 case 86: /* movfw freg,reg - truncate float-to-fix */
2262 o1 = oprrr(ctxt, p.As, int(p.Scond))
2264 o1 |= (uint32(p.From.Reg) & 15) << 0
2265 o1 |= (FREGTMP & 15) << 12
2266 o2 = oprrr(ctxt, -AMOVFW, int(p.Scond))
2267 o2 |= (FREGTMP & 15) << 16
2268 o2 |= (uint32(p.To.Reg) & 15) << 12
2270 // macro for movw reg,FTMP; movwf FTMP,freg
2271 case 87: /* movwf reg,freg - fix-to-float */
2272 o1 = oprrr(ctxt, -AMOVWF, int(p.Scond))
2274 o1 |= (uint32(p.From.Reg) & 15) << 12
2275 o1 |= (FREGTMP & 15) << 16
2276 o2 = oprrr(ctxt, p.As, int(p.Scond))
2277 o2 |= (FREGTMP & 15) << 0
2278 o2 |= (uint32(p.To.Reg) & 15) << 12
2280 case 88: /* movw reg,freg */
2281 o1 = oprrr(ctxt, -AMOVWF, int(p.Scond))
2283 o1 |= (uint32(p.From.Reg) & 15) << 12
2284 o1 |= (uint32(p.To.Reg) & 15) << 16
2286 case 89: /* movw freg,reg */
2287 o1 = oprrr(ctxt, -AMOVFW, int(p.Scond))
2289 o1 |= (uint32(p.From.Reg) & 15) << 16
2290 o1 |= (uint32(p.To.Reg) & 15) << 12
2292 case 90: /* tst reg */
2293 o1 = oprrr(ctxt, -ACMP, int(p.Scond))
2295 o1 |= (uint32(p.From.Reg) & 15) << 16
2297 case 91: /* ldrexd oreg,reg */
2298 aclass(ctxt, &p.From)
2300 if ctxt.Instoffset != 0 {
2301 ctxt.Diag("offset must be zero in LDREX")
2303 o1 = 0x1b<<20 | 0xf9f
2304 o1 |= (uint32(p.From.Reg) & 15) << 16
2305 o1 |= (uint32(p.To.Reg) & 15) << 12
2306 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2308 case 92: /* strexd reg,oreg,reg */
2309 aclass(ctxt, &p.From)
2311 if ctxt.Instoffset != 0 {
2312 ctxt.Diag("offset must be zero in STREX")
2314 o1 = 0x1a<<20 | 0xf90
2315 o1 |= (uint32(p.From.Reg) & 15) << 16
2316 o1 |= (uint32(p.Reg) & 15) << 0
2317 o1 |= (uint32(p.To.Reg) & 15) << 12
2318 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2320 case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
2321 o1 = omvl(ctxt, p, &p.From, REGTMP)
2326 o2 = olhr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
2327 if p.As == AMOVB || p.As == AMOVBS {
2329 } else if p.As == AMOVH || p.As == AMOVHS {
2332 if o.flag&LPCREL != 0 {
2334 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2337 case 94: /* movh/movhu R,addr -> strh */
2338 o1 = omvl(ctxt, p, &p.To, REGTMP)
2343 o2 = oshr(ctxt, int(p.From.Reg), 0, REGTMP, int(p.Scond))
2344 if o.flag&LPCREL != 0 {
2346 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2349 case 95: /* PLD off(reg) */
2352 o1 |= (uint32(p.From.Reg) & 15) << 16
2353 if p.From.Offset < 0 {
2355 o1 |= uint32((-p.From.Offset) & 0xfff)
2357 o1 |= uint32(p.From.Offset & 0xfff)
2360 // This is supposed to be something that stops execution.
2361 // It's not supposed to be reached, ever, but if it is, we'd
2362 // like to be able to tell how we got there. Assemble as
2363 // 0xf7fabcfd which is guaranteed to raise undefined instruction
2365 case 96: /* UNDEF */
2368 case 97: /* CLZ Rm, Rd */
2369 o1 = oprrr(ctxt, p.As, int(p.Scond))
2371 o1 |= (uint32(p.To.Reg) & 15) << 12
2372 o1 |= (uint32(p.From.Reg) & 15) << 0
2374 case 98: /* MULW{T,B} Rs, Rm, Rd */
2375 o1 = oprrr(ctxt, p.As, int(p.Scond))
2377 o1 |= (uint32(p.To.Reg) & 15) << 16
2378 o1 |= (uint32(p.From.Reg) & 15) << 8
2379 o1 |= (uint32(p.Reg) & 15) << 0
2381 case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
2382 o1 = oprrr(ctxt, p.As, int(p.Scond))
2384 o1 |= (uint32(p.To.Reg) & 15) << 12
2385 o1 |= (uint32(p.From.Reg) & 15) << 8
2386 o1 |= (uint32(p.Reg) & 15) << 0
2387 o1 |= uint32((p.To.Offset & 15) << 16)
2389 // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
2390 // DATABUNDLEEND: zero width alignment marker
2392 if p.As == ADATABUNDLE {
2406 func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
2407 aclass(ctxt, &p.From)
2408 o1 := oprrr(ctxt, p.As, int(p.Scond))
2409 o1 |= uint32(p.From.Offset)
2411 if p.To.Type == obj.TYPE_NONE {
2415 if p.As == AMOVW || p.As == AMVN {
2420 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
2424 func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
2425 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2429 if sc&(C_PBIT|C_WBIT) != 0 {
2430 ctxt.Diag(".nil/.W on dp instruction")
2434 return o | 0x0<<21 | 0x9<<4
2436 return o | 0x1<<21 | 0x9<<4
2438 return o | 0x4<<21 | 0x9<<4
2440 return o | 0x6<<21 | 0x9<<4
2442 return o | 0x5<<21 | 0x9<<4
2444 return o | 0x7<<21 | 0x9<<4
2462 return o | 0x8<<21 | 1<<20
2464 return o | 0x9<<21 | 1<<20
2466 return o | 0xa<<21 | 1<<20
2468 return o | 0xb<<21 | 1<<20
2472 case AMOVB, AMOVH, AMOVW:
2479 return o | 0xd<<21 | 0<<5
2481 return o | 0xd<<21 | 1<<5
2483 return o | 0xd<<21 | 2<<5
2488 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4
2490 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4
2492 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4
2494 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4
2496 return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4
2498 return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4
2500 return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4
2502 return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4
2504 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4
2506 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4
2508 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
2510 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
2512 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
2514 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4
2517 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4
2519 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4
2522 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof
2524 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof
2528 o |= 1 << 7 /* signed */
2530 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double
2534 o |= 1 << 7 /* signed */
2536 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double
2540 o |= 1 << 16 /* signed */
2542 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc
2546 o |= 1 << 16 /* signed */
2548 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc
2550 case -AMOVWF: // copy WtoF
2551 return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
2553 case -AMOVFW: // copy FtoW
2554 return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
2556 case -ACMP: // cmp imm
2557 return o | 0x3<<24 | 0x5<<20
2559 // CLZ doesn't support .nil
2561 return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
2564 return o&(0xf<<28) | 0x12<<20 | 0xe<<4
2567 return o&(0xf<<28) | 0x12<<20 | 0xa<<4
2570 return o&(0xf<<28) | 0x12<<20 | 0xc<<4
2573 return o&(0xf<<28) | 0x12<<20 | 0x8<<4
2575 case ABL: // BLX REG
2576 return o&(0xf<<28) | 0x12fff3<<4
2579 ctxt.Diag("bad rrr %d", a)
2584 func opbra(ctxt *obj.Link, p *obj.Prog, a obj.As, sc int) uint32 {
2585 if sc&(C_SBIT|C_PBIT|C_WBIT) != 0 {
2586 ctxt.Diag("%v: .nil/.nil/.W on bra instruction", p)
2590 if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
2591 return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
2594 ctxt.Diag("%v: .COND on bcond instruction", p)
2598 return 0x0<<28 | 0x5<<25
2600 return 0x1<<28 | 0x5<<25
2602 return 0x2<<28 | 0x5<<25
2604 return 0x2<<28 | 0x5<<25
2606 return 0x3<<28 | 0x5<<25
2608 return 0x3<<28 | 0x5<<25
2610 return 0x4<<28 | 0x5<<25
2612 return 0x5<<28 | 0x5<<25
2614 return 0x6<<28 | 0x5<<25
2616 return 0x7<<28 | 0x5<<25
2618 return 0x8<<28 | 0x5<<25
2620 return 0x9<<28 | 0x5<<25
2622 return 0xa<<28 | 0x5<<25
2624 return 0xb<<28 | 0x5<<25
2626 return 0xc<<28 | 0x5<<25
2628 return 0xd<<28 | 0x5<<25
2630 return 0xe<<28 | 0x5<<25
2633 ctxt.Diag("bad bra %v", obj.Aconv(a))
2638 func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
2640 ctxt.Diag(".nil on LDR/STR instruction")
2642 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2655 ctxt.Diag(".U on neg offset")
2661 if v >= 1<<12 || v < 0 {
2662 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
2665 o |= (uint32(b) & 15) << 16
2666 o |= (uint32(r) & 15) << 12
2670 func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
2672 ctxt.Diag(".nil on LDRH/STRH instruction")
2674 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2681 o |= 1<<23 | 1<<20 | 0xb<<4
2687 if v >= 1<<8 || v < 0 {
2688 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
2690 o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
2691 o |= (uint32(b) & 15) << 16
2692 o |= (uint32(r) & 15) << 12
2696 func osr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int) uint32 {
2697 o := olr(ctxt, v, b, r, sc) ^ (1 << 20)
2704 func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 {
2705 o := olhr(ctxt, v, b, r, sc) ^ (1 << 20)
2709 func osrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
2710 return olr(ctxt, int32(i), b, r, sc) ^ (1<<25 | 1<<20)
2713 func oshrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
2714 return olhr(ctxt, int32(i), b, r, sc) ^ (1<<22 | 1<<20)
2717 func olrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
2718 return olr(ctxt, int32(i), b, r, sc) ^ (1 << 25)
2721 func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
2722 return olhr(ctxt, int32(i), b, r, sc) ^ (1 << 22)
2725 func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
2727 ctxt.Diag(".nil on FLDR/FSTR instruction: %v", p)
2729 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2736 o |= 6<<25 | 1<<24 | 1<<23 | 10<<8
2743 ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
2744 } else if v >= 1<<10 || v < 0 {
2745 ctxt.Diag("literal span too large: %d\n%v", v, p)
2747 o |= (uint32(v) >> 2) & 0xFF
2748 o |= (uint32(b) & 15) << 16
2749 o |= (uint32(r) & 15) << 12
2753 ctxt.Diag("bad fst %v", obj.Aconv(a))
2767 func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 {
2771 v := immrot(^uint32(ctxt.Instoffset))
2773 ctxt.Diag("missing literal")
2778 o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND)
2780 o1 |= (uint32(dr) & 15) << 12
2782 v := int32(p.Pcond.Pc - p.Pc - 8)
2783 o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND)
2789 func chipzero5(ctxt *obj.Link, e float64) int {
2790 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
2791 if ctxt.Goarm < 7 || e != 0 {
2797 func chipfloat5(ctxt *obj.Link, e float64) int {
2798 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
2803 ei := math.Float64bits(e)
2805 h := uint32(ei >> 32)
2807 if l != 0 || h&0xffff != 0 {
2810 h1 := h & 0x7fc00000
2811 if h1 != 0x40000000 && h1 != 0x3fc00000 {
2817 if h&0x80000000 != 0 {
2822 if h1 == 0x3fc00000 {
2826 // rest of exp and mantissa (cd-efgh)
2827 n |= int((h >> 16) & 0x3f)
2829 //print("match %.8lux %.8lux %d\n", l, h, n);
2833 func nocache(p *obj.Prog) {