]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/obj/arm/asm5.go
all: make copyright headers consistent with one space after period
[gostls13.git] / src / cmd / internal / obj / arm / asm5.go
1 // Inferno utils/5l/span.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
3 //
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.
12 //
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:
19 //
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
22 //
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
29 // THE SOFTWARE.
30
31 package arm
32
33 import (
34         "cmd/internal/obj"
35         "fmt"
36         "log"
37         "math"
38         "sort"
39 )
40
41 type Optab struct {
42         as       obj.As
43         a1       uint8
44         a2       int8
45         a3       uint8
46         type_    uint8
47         size     int8
48         param    int16
49         flag     int8
50         pcrelsiz uint8
51 }
52
53 type Opcross [32][2][32]uint8
54
55 const (
56         LFROM  = 1 << 0
57         LTO    = 1 << 1
58         LPOOL  = 1 << 2
59         LPCREL = 1 << 3
60 )
61
62 var optab = []Optab{
63         /* struct Optab:
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
86
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
256
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},
260 }
261
262 var pool struct {
263         start uint32
264         size  uint32
265         extra uint32
266 }
267
268 var oprange [ALAST & obj.AMask][]Optab
269
270 var xcmp [C_GOK + 1][C_GOK + 1]bool
271
272 var deferreturn *obj.LSym
273
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.
278
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 {
285         size := int(o.size)
286
287         // instruction specific
288         switch p.As {
289         default:
290                 if out != nil {
291                         asmout(ctxt, p, o, out)
292                 }
293
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
297
298                 if out != nil {
299                         asmout(ctxt, p, o, out)
300                 }
301
302         case obj.AUNDEF,
303                 APLD:
304                 size = 4
305                 if out != nil {
306                         switch p.As {
307                         case obj.AUNDEF:
308                                 out[0] = 0xe7fedef0 // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
309
310                         case APLD:
311                                 out[0] = 0xe1a01001 // (MOVW R1, R1)
312                         }
313                 }
314
315         case AB, ABL:
316                 if p.To.Type != obj.TYPE_MEM {
317                         if out != nil {
318                                 asmout(ctxt, p, o, out)
319                         }
320                 } else {
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)
323                         }
324                         if p.Pc&15 == 12 {
325                                 p.Pc += 4
326                         }
327                         if out != nil {
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
329                                 if p.As == AB {
330                                         out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff10 | (uint32(p.To.Reg)&15)<<0 // BX Rx
331                                 } else { // ABL
332                                         out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff30 | (uint32(p.To.Reg)&15)<<0 // BLX Rx
333                                 }
334                         }
335
336                         size = 8
337                 }
338
339                 // align the last instruction (the actual BL) to the last instruction in a bundle
340                 if p.As == ABL {
341                         if deferreturn == nil {
342                                 deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0)
343                         }
344                         if p.To.Sym == deferreturn {
345                                 p.Pc = ((int64(origPC) + 15) &^ 15) + 16 - int64(size)
346                         } else {
347                                 p.Pc += (16 - ((p.Pc + int64(size)) & 15)) & 15
348                         }
349                 }
350
351         case ALDREX,
352                 ALDREXD,
353                 AMOVB,
354                 AMOVBS,
355                 AMOVBU,
356                 AMOVD,
357                 AMOVF,
358                 AMOVH,
359                 AMOVHS,
360                 AMOVHU,
361                 AMOVM,
362                 AMOVW,
363                 ASTREX,
364                 ASTREXD:
365                 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 && p.From.Reg == REG_R13 { // MOVW.W x(R13), PC
366                         if out != nil {
367                                 asmout(ctxt, p, o, out)
368                         }
369                         if size == 4 {
370                                 if out != nil {
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
376                                 }
377
378                                 size += 8
379                                 if (p.Pc+int64(size))&15 == 4 {
380                                         p.Pc += 4
381                                 }
382                                 break
383                         } else {
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.
386                                 if out != nil {
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
391                                 }
392
393                                 // p->pc+size is only ok at 4 or 12 mod 16.
394                                 if (p.Pc+int64(size))%8 == 0 {
395                                         p.Pc += 4
396                                 }
397                                 size += 12
398                                 break
399                         }
400                 }
401
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)
404                 }
405
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:
409                         //      ADD $-100004, R13
410                         //      MOVW R14, 0(R13)
411                         q := ctxt.NewProg()
412
413                         p.Scond &^= C_WBIT
414                         *q = *p
415                         a := &p.To
416                         var a2 *obj.Addr
417                         if p.To.Type == obj.TYPE_MEM {
418                                 a2 = &q.To
419                         } else {
420                                 a2 = &q.From
421                         }
422                         nocache(q)
423                         nocache(p)
424
425                         // insert q after p
426                         q.Link = p.Link
427
428                         p.Link = q
429                         q.Pcond = nil
430
431                         // make p into ADD $X, R13
432                         p.As = AADD
433
434                         p.From = *a
435                         p.From.Reg = 0
436                         p.From.Type = obj.TYPE_CONST
437                         p.To = obj.Addr{}
438                         p.To.Type = obj.TYPE_REG
439                         p.To.Reg = REG_R13
440
441                         // make q into p but load/store from 0(R13)
442                         q.Spadj = 0
443
444                         *a2 = obj.Addr{}
445                         a2.Type = obj.TYPE_MEM
446                         a2.Reg = REG_R13
447                         a2.Sym = nil
448                         a2.Offset = 0
449                         size = int(oplook(ctxt, p).size)
450                         break
451                 }
452
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
455                         var a *obj.Addr
456                         if p.To.Type == obj.TYPE_MEM {
457                                 a = &p.To
458                         } else {
459                                 a = &p.From
460                         }
461                         reg := int(a.Reg)
462                         if size == 4 {
463                                 // if addr.reg == 0, then it is probably load from x(FP) with small x, no need to modify.
464                                 if reg == 0 {
465                                         if out != nil {
466                                                 asmout(ctxt, p, o, out)
467                                         }
468                                 } else {
469                                         if out != nil {
470                                                 out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c00103 | (uint32(reg)&15)<<16 | (uint32(reg)&15)<<12 // BIC $0xc0000000, Rx
471                                         }
472                                         if p.Pc&15 == 12 {
473                                                 p.Pc += 4
474                                         }
475                                         size += 4
476                                         if out != nil {
477                                                 asmout(ctxt, p, o, out[1:])
478                                         }
479                                 }
480
481                                 break
482                         } else {
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)
490                                 }
491                                 q := ctxt.NewProg()
492                                 *q = *p
493                                 var a2 *obj.Addr
494                                 if p.To.Type == obj.TYPE_MEM {
495                                         a2 = &q.To
496                                 } else {
497                                         a2 = &q.From
498                                 }
499                                 nocache(q)
500                                 nocache(p)
501
502                                 // insert q after p
503                                 q.Link = p.Link
504
505                                 p.Link = q
506                                 q.Pcond = nil
507
508                                 // make p into MOVW $X(R), R11
509                                 p.As = AMOVW
510
511                                 p.From = *a
512                                 p.From.Type = obj.TYPE_ADDR
513                                 p.To = obj.Addr{}
514                                 p.To.Type = obj.TYPE_REG
515                                 p.To.Reg = REG_R11
516
517                                 // make q into p but load/store from 0(R11)
518                                 *a2 = obj.Addr{}
519
520                                 a2.Type = obj.TYPE_MEM
521                                 a2.Reg = REG_R11
522                                 a2.Sym = nil
523                                 a2.Offset = 0
524                                 size = int(oplook(ctxt, p).size)
525                                 break
526                         }
527                 } else if out != nil {
528                         asmout(ctxt, p, o, out)
529                 }
530         }
531
532         // destination register specific
533         if p.To.Type == obj.TYPE_REG {
534                 switch p.To.Reg {
535                 case REG_R9:
536                         ctxt.Diag("invalid instruction, cannot write to R9: %v", p)
537
538                 case REG_R13:
539                         if out != nil {
540                                 out[size/4] = 0xe3cdd103 // BIC $0xc0000000, R13
541                         }
542                         if (p.Pc+int64(size))&15 == 0 {
543                                 p.Pc += 4
544                         }
545                         size += 4
546                 }
547         }
548
549         return size
550 }
551
552 func span5(ctxt *obj.Link, cursym *obj.LSym) {
553         var p *obj.Prog
554         var op *obj.Prog
555
556         p = cursym.Text
557         if p == nil || p.Link == nil { // handle external functions and ELF section symbols
558                 return
559         }
560
561         if oprange[AAND&obj.AMask] == nil {
562                 buildop(ctxt)
563         }
564
565         ctxt.Cursym = cursym
566
567         ctxt.Autosize = int32(p.To.Offset + 4)
568         c := int32(0)
569
570         op = p
571         p = p.Link
572         var i int
573         var m int
574         var o *Optab
575         for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link {
576                 if p == nil {
577                         if checkpool(ctxt, op, 0) {
578                                 p = op
579                                 continue
580                         }
581
582                         // can't happen: blitrl is not nil, but checkpool didn't flushpool
583                         ctxt.Diag("internal inconsistency")
584
585                         break
586                 }
587
588                 ctxt.Curp = p
589                 p.Pc = int64(c)
590                 o = oplook(ctxt, p)
591                 if ctxt.Headtype != obj.Hnacl {
592                         m = int(o.size)
593                 } else {
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
597                 }
598
599                 if m%4 != 0 || p.Pc%4 != 0 {
600                         ctxt.Diag("!pc invalid: %v size=%d", p, m)
601                 }
602
603                 // must check literal pool here in case p generates many instructions
604                 if ctxt.Blitrl != nil {
605                         i = m
606                         if checkpool(ctxt, op, i) {
607                                 p = op
608                                 continue
609                         }
610                 }
611
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)
614                         continue
615                 }
616
617                 switch o.flag & (LFROM | LTO | LPOOL) {
618                 case LFROM:
619                         addpool(ctxt, p, &p.From)
620
621                 case LTO:
622                         addpool(ctxt, p, &p.To)
623
624                 case LPOOL:
625                         if p.Scond&C_SCOND == C_SCOND_NONE {
626                                 flushpool(ctxt, p, 0, 0)
627                         }
628                 }
629
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)
632                 }
633                 c += int32(m)
634         }
635
636         cursym.Size = int64(c)
637
638         /*
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.
643          */
644         times := 0
645
646         var bflag int
647         var opc int32
648         var out [6 + 3]uint32
649         for {
650                 if ctxt.Debugvlog != 0 {
651                         fmt.Fprintf(ctxt.Bso, "%5.2f span1\n", obj.Cputime())
652                 }
653                 bflag = 0
654                 c = 0
655                 times++
656                 cursym.Text.Pc = 0 // force re-layout the code.
657                 for p = cursym.Text; p != nil; p = p.Link {
658                         ctxt.Curp = p
659                         o = oplook(ctxt, p)
660                         if int64(c) > p.Pc {
661                                 p.Pc = int64(c)
662                         }
663
664                         /* very large branches
665                         if(o->type == 6 && p->pcond) {
666                                 otxt = p->pcond->pc - c;
667                                 if(otxt < 0)
668                                         otxt = -otxt;
669                                 if(otxt >= (1L<<17) - 10) {
670                                         q = emallocz(sizeof(Prog));
671                                         q->link = p->link;
672                                         p->link = q;
673                                         q->as = AB;
674                                         q->to.type = TYPE_BRANCH;
675                                         q->pcond = p->pcond;
676                                         p->pcond = q;
677                                         q = emallocz(sizeof(Prog));
678                                         q->link = p->link;
679                                         p->link = q;
680                                         q->as = AB;
681                                         q->to.type = TYPE_BRANCH;
682                                         q->pcond = q->link->link;
683                                         bflag = 1;
684                                 }
685                         }
686                         */
687                         opc = int32(p.Pc)
688
689                         if ctxt.Headtype != obj.Hnacl {
690                                 m = int(o.size)
691                         } else {
692                                 m = asmoutnacl(ctxt, c, p, o, nil)
693                         }
694                         if p.Pc != int64(opc) {
695                                 bflag = 1
696                         }
697
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))
700
701                         if m%4 != 0 || p.Pc%4 != 0 {
702                                 ctxt.Diag("pc invalid: %v size=%d", p, m)
703                         }
704
705                         if m/4 > len(out) {
706                                 ctxt.Diag("instruction size too large: %d > %d", m/4, len(out))
707                         }
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)
711                                         continue
712                                 }
713
714                                 ctxt.Diag("zero-width instruction\n%v", p)
715                                 continue
716                         }
717                 }
718
719                 cursym.Size = int64(c)
720                 if bflag == 0 {
721                         break
722                 }
723         }
724
725         if c%4 != 0 {
726                 ctxt.Diag("sym->size=%d, invalid", c)
727         }
728
729         /*
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.
736          */
737
738         p = cursym.Text
739         ctxt.Autosize = int32(p.To.Offset + 4)
740         cursym.Grow(cursym.Size)
741
742         bp := cursym.P
743         c = int32(p.Pc) // even p->link might need extra padding
744         var v int
745         for p = p.Link; p != nil; p = p.Link {
746                 ctxt.Pc = p.Pc
747                 ctxt.Curp = p
748                 o = oplook(ctxt, p)
749                 opc = int32(p.Pc)
750                 if ctxt.Headtype != obj.Hnacl {
751                         asmout(ctxt, p, o, out[:])
752                         m = int(o.size)
753                 } else {
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)
757                         }
758                 }
759
760                 if m%4 != 0 || p.Pc%4 != 0 {
761                         ctxt.Diag("final stage: pc invalid: %v size=%d", p, m)
762                 }
763
764                 if int64(c) > p.Pc {
765                         ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, c, p)
766                 }
767                 for int64(c) != p.Pc {
768                         // emit 0xe1a00000 (MOVW R0, R0)
769                         bp[0] = 0x00
770                         bp = bp[1:]
771
772                         bp[0] = 0x00
773                         bp = bp[1:]
774                         bp[0] = 0xa0
775                         bp = bp[1:]
776                         bp[0] = 0xe1
777                         bp = bp[1:]
778                         c += 4
779                 }
780
781                 for i = 0; i < m/4; i++ {
782                         v = int(out[i])
783                         bp[0] = byte(v)
784                         bp = bp[1:]
785                         bp[0] = byte(v >> 8)
786                         bp = bp[1:]
787                         bp[0] = byte(v >> 16)
788                         bp = bp[1:]
789                         bp[0] = byte(v >> 24)
790                         bp = bp[1:]
791                 }
792
793                 c += int32(m)
794         }
795 }
796
797 /*
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.
802  */
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)
808         }
809         return false
810 }
811
812 func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool {
813         if ctxt.Blitrl != nil {
814                 if skip != 0 {
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)
817                         }
818                         q := ctxt.NewProg()
819                         q.As = AB
820                         q.To.Type = obj.TYPE_BRANCH
821                         q.Pcond = p.Link
822                         q.Link = ctxt.Blitrl
823                         q.Lineno = p.Lineno
824                         ctxt.Blitrl = q
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
826                         return false
827                 }
828                 if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 {
829                         // if pool is not multiple of 16 bytes, add an alignment marker
830                         q := ctxt.NewProg()
831
832                         q.As = ADATABUNDLEEND
833                         ctxt.Elitrl.Link = q
834                         ctxt.Elitrl = q
835                 }
836
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 {
841                         q.Lineno = p.Lineno
842                 }
843
844                 ctxt.Elitrl.Link = p.Link
845                 p.Link = ctxt.Blitrl
846
847                 ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */
848                 ctxt.Elitrl = nil
849                 pool.size = 0
850                 pool.start = 0
851                 pool.extra = 0
852                 return true
853         }
854
855         return false
856 }
857
858 func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
859         var t obj.Prog
860
861         c := aclass(ctxt, a)
862
863         t.Ctxt = ctxt
864         t.As = AWORD
865
866         switch c {
867         default:
868                 t.To.Offset = a.Offset
869                 t.To.Sym = a.Sym
870                 t.To.Type = a.Type
871                 t.To.Name = a.Name
872
873                 if ctxt.Flag_shared && t.To.Sym != nil {
874                         t.Rel = p
875                 }
876
877         case C_SROREG,
878                 C_LOREG,
879                 C_ROREG,
880                 C_FOREG,
881                 C_SOREG,
882                 C_HOREG,
883                 C_FAUTO,
884                 C_SAUTO,
885                 C_LAUTO,
886                 C_LACON:
887                 t.To.Type = obj.TYPE_CONST
888                 t.To.Offset = ctxt.Instoffset
889         }
890
891         if t.Rel == nil {
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 {
894                                 p.Pcond = q
895                                 return
896                         }
897                 }
898         }
899
900         if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 {
901                 // start a new data bundle
902                 q := ctxt.NewProg()
903                 q.As = ADATABUNDLE
904                 q.Pc = int64(pool.size)
905                 pool.size += 4
906                 if ctxt.Blitrl == nil {
907                         ctxt.Blitrl = q
908                         pool.start = uint32(p.Pc)
909                 } else {
910                         ctxt.Elitrl.Link = q
911                 }
912
913                 ctxt.Elitrl = q
914         }
915
916         q := ctxt.NewProg()
917         *q = t
918         q.Pc = int64(pool.size)
919
920         if ctxt.Blitrl == nil {
921                 ctxt.Blitrl = q
922                 pool.start = uint32(p.Pc)
923         } else {
924                 ctxt.Elitrl.Link = q
925         }
926         ctxt.Elitrl = q
927         pool.size += 4
928
929         p.Pcond = q
930 }
931
932 func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
933         ctxt.Instoffset = 0
934         aclass(ctxt, a)
935         return int32(ctxt.Instoffset)
936 }
937
938 func immrot(v uint32) int32 {
939         for i := 0; i < 16; i++ {
940                 if v&^0xff == 0 {
941                         return int32(uint32(int32(i)<<8) | v | 1<<25)
942                 }
943                 v = v<<2 | v>>30
944         }
945
946         return 0
947 }
948
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 */
952         }
953         if v >= -0xfff && v < 0 {
954                 return -v&0xfff | 1<<24 /* pre indexing */
955         }
956         return 0
957 }
958
959 func immfloat(v int32) bool {
960         return v&0xC03 == 0 /* offset will fit in floating-point load/store */
961 }
962
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 */
966         }
967         if v >= -0xff && v < 0 {
968                 return -v&0xff|1<<24 != 0 /* pre indexing */
969         }
970         return false
971 }
972
973 func aclass(ctxt *obj.Link, a *obj.Addr) int {
974         switch a.Type {
975         case obj.TYPE_NONE:
976                 return C_NONE
977
978         case obj.TYPE_REG:
979                 ctxt.Instoffset = 0
980                 if REG_R0 <= a.Reg && a.Reg <= REG_R15 {
981                         return C_REG
982                 }
983                 if REG_F0 <= a.Reg && a.Reg <= REG_F15 {
984                         return C_FREG
985                 }
986                 if a.Reg == REG_FPSR || a.Reg == REG_FPCR {
987                         return C_FCR
988                 }
989                 if a.Reg == REG_CPSR || a.Reg == REG_SPSR {
990                         return C_PSR
991                 }
992                 return C_GOK
993
994         case obj.TYPE_REGREG:
995                 return C_REGREG
996
997         case obj.TYPE_REGREG2:
998                 return C_REGREG2
999
1000         case obj.TYPE_REGLIST:
1001                 return C_REGLIST
1002
1003         case obj.TYPE_SHIFT:
1004                 return C_SHIFT
1005
1006         case obj.TYPE_MEM:
1007                 switch a.Name {
1008                 case obj.NAME_EXTERN,
1009                         obj.NAME_GOTREF,
1010                         obj.NAME_STATIC:
1011                         if a.Sym == nil || a.Sym.Name == "" {
1012                                 fmt.Printf("null sym external\n")
1013                                 return C_GOK
1014                         }
1015
1016                         ctxt.Instoffset = 0 // s.b. unused but just in case
1017                         if a.Sym.Type == obj.STLSBSS {
1018                                 if ctxt.Flag_shared {
1019                                         return C_TLS_IE
1020                                 } else {
1021                                         return C_TLS_LE
1022                                 }
1023                         }
1024
1025                         return C_ADDR
1026
1027                 case obj.NAME_AUTO:
1028                         ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
1029                         t := int(immaddr(int32(ctxt.Instoffset)))
1030                         if t != 0 {
1031                                 if immhalf(int32(ctxt.Instoffset)) {
1032                                         if immfloat(int32(t)) {
1033                                                 return C_HFAUTO
1034                                         }
1035                                         return C_HAUTO
1036                                 }
1037
1038                                 if immfloat(int32(t)) {
1039                                         return C_FAUTO
1040                                 }
1041                                 return C_SAUTO
1042                         }
1043
1044                         return C_LAUTO
1045
1046                 case obj.NAME_PARAM:
1047                         ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
1048                         t := int(immaddr(int32(ctxt.Instoffset)))
1049                         if t != 0 {
1050                                 if immhalf(int32(ctxt.Instoffset)) {
1051                                         if immfloat(int32(t)) {
1052                                                 return C_HFAUTO
1053                                         }
1054                                         return C_HAUTO
1055                                 }
1056
1057                                 if immfloat(int32(t)) {
1058                                         return C_FAUTO
1059                                 }
1060                                 return C_SAUTO
1061                         }
1062
1063                         return C_LAUTO
1064
1065                 case obj.NAME_NONE:
1066                         ctxt.Instoffset = a.Offset
1067                         t := int(immaddr(int32(ctxt.Instoffset)))
1068                         if t != 0 {
1069                                 if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */
1070                                         if immfloat(int32(t)) {
1071                                                 return C_HFOREG
1072                                         }
1073                                         return C_HOREG
1074                                 }
1075
1076                                 if immfloat(int32(t)) {
1077                                         return C_FOREG /* n.b. that it will also satisfy immrot */
1078                                 }
1079                                 t := int(immrot(uint32(ctxt.Instoffset)))
1080                                 if t != 0 {
1081                                         return C_SROREG
1082                                 }
1083                                 if immhalf(int32(ctxt.Instoffset)) {
1084                                         return C_HOREG
1085                                 }
1086                                 return C_SOREG
1087                         }
1088
1089                         t = int(immrot(uint32(ctxt.Instoffset)))
1090                         if t != 0 {
1091                                 return C_ROREG
1092                         }
1093                         return C_LOREG
1094                 }
1095
1096                 return C_GOK
1097
1098         case obj.TYPE_FCONST:
1099                 if chipzero5(ctxt, a.Val.(float64)) >= 0 {
1100                         return C_ZFCON
1101                 }
1102                 if chipfloat5(ctxt, a.Val.(float64)) >= 0 {
1103                         return C_SFCON
1104                 }
1105                 return C_LFCON
1106
1107         case obj.TYPE_TEXTSIZE:
1108                 return C_TEXTSIZE
1109
1110         case obj.TYPE_CONST,
1111                 obj.TYPE_ADDR:
1112                 switch a.Name {
1113                 case obj.NAME_NONE:
1114                         ctxt.Instoffset = a.Offset
1115                         if a.Reg != 0 {
1116                                 return aconsize(ctxt)
1117                         }
1118
1119                         t := int(immrot(uint32(ctxt.Instoffset)))
1120                         if t != 0 {
1121                                 return C_RCON
1122                         }
1123                         t = int(immrot(^uint32(ctxt.Instoffset)))
1124                         if t != 0 {
1125                                 return C_NCON
1126                         }
1127                         return C_LCON
1128
1129                 case obj.NAME_EXTERN,
1130                         obj.NAME_GOTREF,
1131                         obj.NAME_STATIC:
1132                         s := a.Sym
1133                         if s == nil {
1134                                 break
1135                         }
1136                         ctxt.Instoffset = 0 // s.b. unused but just in case
1137                         return C_LCONADDR
1138
1139                 case obj.NAME_AUTO:
1140                         ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
1141                         return aconsize(ctxt)
1142
1143                 case obj.NAME_PARAM:
1144                         ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
1145                         return aconsize(ctxt)
1146                 }
1147
1148                 return C_GOK
1149
1150         case obj.TYPE_BRANCH:
1151                 return C_SBRA
1152         }
1153
1154         return C_GOK
1155 }
1156
1157 func aconsize(ctxt *obj.Link) int {
1158         t := int(immrot(uint32(ctxt.Instoffset)))
1159         if t != 0 {
1160                 return C_RACON
1161         }
1162         return C_LACON
1163 }
1164
1165 func prasm(p *obj.Prog) {
1166         fmt.Printf("%v\n", p)
1167 }
1168
1169 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
1170         a1 := int(p.Optab)
1171         if a1 != 0 {
1172                 return &optab[a1-1]
1173         }
1174         a1 = int(p.From.Class)
1175         if a1 == 0 {
1176                 a1 = aclass(ctxt, &p.From) + 1
1177                 p.From.Class = int8(a1)
1178         }
1179
1180         a1--
1181         a3 := int(p.To.Class)
1182         if a3 == 0 {
1183                 a3 = aclass(ctxt, &p.To) + 1
1184                 p.To.Class = int8(a3)
1185         }
1186
1187         a3--
1188         a2 := C_NONE
1189         if p.Reg != 0 {
1190                 a2 = C_REG
1191         }
1192
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)
1196         }
1197
1198         ops := oprange[p.As&obj.AMask]
1199         c1 := &xcmp[a1]
1200         c3 := &xcmp[a3]
1201         for i := range ops {
1202                 op := &ops[i]
1203                 if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] {
1204                         p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
1205                         return op
1206                 }
1207         }
1208
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)
1211         prasm(p)
1212         if ops == nil {
1213                 ops = optab
1214         }
1215         return &ops[0]
1216 }
1217
1218 func cmp(a int, b int) bool {
1219         if a == b {
1220                 return true
1221         }
1222         switch a {
1223         case C_LCON:
1224                 if b == C_RCON || b == C_NCON {
1225                         return true
1226                 }
1227
1228         case C_LACON:
1229                 if b == C_RACON {
1230                         return true
1231                 }
1232
1233         case C_LFCON:
1234                 if b == C_ZFCON || b == C_SFCON {
1235                         return true
1236                 }
1237
1238         case C_HFAUTO:
1239                 return b == C_HAUTO || b == C_FAUTO
1240
1241         case C_FAUTO, C_HAUTO:
1242                 return b == C_HFAUTO
1243
1244         case C_SAUTO:
1245                 return cmp(C_HFAUTO, b)
1246
1247         case C_LAUTO:
1248                 return cmp(C_SAUTO, b)
1249
1250         case C_HFOREG:
1251                 return b == C_HOREG || b == C_FOREG
1252
1253         case C_FOREG, C_HOREG:
1254                 return b == C_HFOREG
1255
1256         case C_SROREG:
1257                 return cmp(C_SOREG, b) || cmp(C_ROREG, b)
1258
1259         case C_SOREG, C_ROREG:
1260                 return b == C_SROREG || cmp(C_HFOREG, b)
1261
1262         case C_LOREG:
1263                 return cmp(C_SROREG, b)
1264
1265         case C_LBRA:
1266                 if b == C_SBRA {
1267                         return true
1268                 }
1269
1270         case C_HREG:
1271                 return cmp(C_SP, b) || cmp(C_PC, b)
1272         }
1273
1274         return false
1275 }
1276
1277 type ocmp []Optab
1278
1279 func (x ocmp) Len() int {
1280         return len(x)
1281 }
1282
1283 func (x ocmp) Swap(i, j int) {
1284         x[i], x[j] = x[j], x[i]
1285 }
1286
1287 func (x ocmp) Less(i, j int) bool {
1288         p1 := &x[i]
1289         p2 := &x[j]
1290         n := int(p1.as) - int(p2.as)
1291         if n != 0 {
1292                 return n < 0
1293         }
1294         n = int(p1.a1) - int(p2.a1)
1295         if n != 0 {
1296                 return n < 0
1297         }
1298         n = int(p1.a2) - int(p2.a2)
1299         if n != 0 {
1300                 return n < 0
1301         }
1302         n = int(p1.a3) - int(p2.a3)
1303         if n != 0 {
1304                 return n < 0
1305         }
1306         return false
1307 }
1308
1309 func opset(a, b0 obj.As) {
1310         oprange[a&obj.AMask] = oprange[b0]
1311 }
1312
1313 func buildop(ctxt *obj.Link) {
1314         var n int
1315
1316         for i := 0; i < C_GOK; i++ {
1317                 for n = 0; n < C_GOK; n++ {
1318                         if cmp(n, i) {
1319                                 xcmp[i][n] = true
1320                         }
1321                 }
1322         }
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)
1327                         } else {
1328                                 optab[n].flag &^= LPCREL
1329                         }
1330                 }
1331         }
1332
1333         sort.Sort(ocmp(optab[:n]))
1334         for i := 0; i < n; i++ {
1335                 r := optab[i].as
1336                 r0 := r & obj.AMask
1337                 start := i
1338                 for optab[i].as == r {
1339                         i++
1340                 }
1341                 oprange[r0] = optab[start:i]
1342                 i--
1343
1344                 switch r {
1345                 default:
1346                         ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
1347                         log.Fatalf("bad code")
1348
1349                 case AADD:
1350                         opset(AAND, r0)
1351                         opset(AEOR, r0)
1352                         opset(ASUB, r0)
1353                         opset(ARSB, r0)
1354                         opset(AADC, r0)
1355                         opset(ASBC, r0)
1356                         opset(ARSC, r0)
1357                         opset(AORR, r0)
1358                         opset(ABIC, r0)
1359
1360                 case ACMP:
1361                         opset(ATEQ, r0)
1362                         opset(ACMN, r0)
1363
1364                 case AMVN:
1365                         break
1366
1367                 case ABEQ:
1368                         opset(ABNE, r0)
1369                         opset(ABCS, r0)
1370                         opset(ABHS, r0)
1371                         opset(ABCC, r0)
1372                         opset(ABLO, r0)
1373                         opset(ABMI, r0)
1374                         opset(ABPL, r0)
1375                         opset(ABVS, r0)
1376                         opset(ABVC, r0)
1377                         opset(ABHI, r0)
1378                         opset(ABLS, r0)
1379                         opset(ABGE, r0)
1380                         opset(ABLT, r0)
1381                         opset(ABGT, r0)
1382                         opset(ABLE, r0)
1383
1384                 case ASLL:
1385                         opset(ASRL, r0)
1386                         opset(ASRA, r0)
1387
1388                 case AMUL:
1389                         opset(AMULU, r0)
1390
1391                 case ADIV:
1392                         opset(AMOD, r0)
1393                         opset(AMODU, r0)
1394                         opset(ADIVU, r0)
1395
1396                 case AMOVW,
1397                         AMOVB,
1398                         AMOVBS,
1399                         AMOVBU,
1400                         AMOVH,
1401                         AMOVHS,
1402                         AMOVHU:
1403                         break
1404
1405                 case ASWPW:
1406                         opset(ASWPBU, r0)
1407
1408                 case AB,
1409                         ABL,
1410                         ABX,
1411                         ABXRET,
1412                         obj.ADUFFZERO,
1413                         obj.ADUFFCOPY,
1414                         ASWI,
1415                         AWORD,
1416                         AMOVM,
1417                         ARFE,
1418                         obj.ATEXT,
1419                         obj.AUSEFIELD,
1420                         obj.ATYPE:
1421                         break
1422
1423                 case AADDF:
1424                         opset(AADDD, r0)
1425                         opset(ASUBF, r0)
1426                         opset(ASUBD, r0)
1427                         opset(AMULF, r0)
1428                         opset(AMULD, r0)
1429                         opset(ADIVF, r0)
1430                         opset(ADIVD, r0)
1431                         opset(ASQRTF, r0)
1432                         opset(ASQRTD, r0)
1433                         opset(AMOVFD, r0)
1434                         opset(AMOVDF, r0)
1435                         opset(AABSF, r0)
1436                         opset(AABSD, r0)
1437
1438                 case ACMPF:
1439                         opset(ACMPD, r0)
1440
1441                 case AMOVF:
1442                         opset(AMOVD, r0)
1443
1444                 case AMOVFW:
1445                         opset(AMOVDW, r0)
1446
1447                 case AMOVWF:
1448                         opset(AMOVWD, r0)
1449
1450                 case AMULL:
1451                         opset(AMULAL, r0)
1452                         opset(AMULLU, r0)
1453                         opset(AMULALU, r0)
1454
1455                 case AMULWT:
1456                         opset(AMULWB, r0)
1457
1458                 case AMULAWT:
1459                         opset(AMULAWB, r0)
1460
1461                 case AMULA,
1462                         ALDREX,
1463                         ASTREX,
1464                         ALDREXD,
1465                         ASTREXD,
1466                         ATST,
1467                         APLD,
1468                         obj.AUNDEF,
1469                         ACLZ,
1470                         obj.AFUNCDATA,
1471                         obj.APCDATA,
1472                         obj.ANOP,
1473                         ADATABUNDLE,
1474                         ADATABUNDLEEND:
1475                         break
1476                 }
1477         }
1478 }
1479
1480 func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
1481         ctxt.Printp = p
1482         o1 := uint32(0)
1483         o2 := uint32(0)
1484         o3 := uint32(0)
1485         o4 := uint32(0)
1486         o5 := uint32(0)
1487         o6 := uint32(0)
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_)
1491         }
1492         switch o.type_ {
1493         default:
1494                 ctxt.Diag("unknown asm %d", o.type_)
1495                 prasm(p)
1496
1497         case 0: /* pseudo ops */
1498                 if false { /*debug['G']*/
1499                         fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
1500                 }
1501
1502         case 1: /* op R,[R],R */
1503                 o1 = oprrr(ctxt, p.As, int(p.Scond))
1504
1505                 rf := int(p.From.Reg)
1506                 rt := int(p.To.Reg)
1507                 r := int(p.Reg)
1508                 if p.To.Type == obj.TYPE_NONE {
1509                         rt = 0
1510                 }
1511                 if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN {
1512                         r = 0
1513                 } else if r == 0 {
1514                         r = rt
1515                 }
1516                 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1517
1518         case 2: /* movbu $I,[R],R */
1519                 aclass(ctxt, &p.From)
1520
1521                 o1 = oprrr(ctxt, p.As, int(p.Scond))
1522                 o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
1523                 rt := int(p.To.Reg)
1524                 r := int(p.Reg)
1525                 if p.To.Type == obj.TYPE_NONE {
1526                         rt = 0
1527                 }
1528                 if p.As == AMOVW || p.As == AMVN {
1529                         r = 0
1530                 } else if r == 0 {
1531                         r = rt
1532                 }
1533                 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1534
1535         case 3: /* add R<<[IR],[R],R */
1536                 o1 = mov(ctxt, p)
1537
1538         case 4: /* add $I,[R],R */
1539                 aclass(ctxt, &p.From)
1540
1541                 o1 = oprrr(ctxt, AADD, int(p.Scond))
1542                 o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
1543                 r := int(p.From.Reg)
1544                 if r == 0 {
1545                         r = int(o.param)
1546                 }
1547                 o1 |= (uint32(r) & 15) << 16
1548                 o1 |= (uint32(p.To.Reg) & 15) << 12
1549
1550         case 5: /* bra s */
1551                 o1 = opbra(ctxt, p, p.As, int(p.Scond))
1552
1553                 v := int32(-8)
1554                 if p.To.Sym != nil {
1555                         rel := obj.Addrel(ctxt.Cursym)
1556                         rel.Off = int32(ctxt.Pc)
1557                         rel.Siz = 4
1558                         rel.Sym = p.To.Sym
1559                         v += int32(p.To.Offset)
1560                         rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
1561                         rel.Type = obj.R_CALLARM
1562                         break
1563                 }
1564
1565                 if p.Pcond != nil {
1566                         v = int32((p.Pcond.Pc - ctxt.Pc) - 8)
1567                 }
1568                 o1 |= (uint32(v) >> 2) & 0xffffff
1569
1570         case 6: /* b ,O(R) -> add $O,R,PC */
1571                 aclass(ctxt, &p.To)
1572
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
1577
1578         case 7: /* bl (R) -> blx R */
1579                 aclass(ctxt, &p.To)
1580
1581                 if ctxt.Instoffset != 0 {
1582                         ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, ctxt.Instoffset)
1583                 }
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)
1588                 rel.Siz = 0
1589                 rel.Type = obj.R_CALLIND
1590
1591         case 8: /* sll $c,[R],R -> mov (R<<$c),R */
1592                 aclass(ctxt, &p.From)
1593
1594                 o1 = oprrr(ctxt, p.As, int(p.Scond))
1595                 r := int(p.Reg)
1596                 if r == 0 {
1597                         r = int(p.To.Reg)
1598                 }
1599                 o1 |= (uint32(r) & 15) << 0
1600                 o1 |= uint32((ctxt.Instoffset & 31) << 7)
1601                 o1 |= (uint32(p.To.Reg) & 15) << 12
1602
1603         case 9: /* sll R,[R],R -> mov (R<<R),R */
1604                 o1 = oprrr(ctxt, p.As, int(p.Scond))
1605
1606                 r := int(p.Reg)
1607                 if r == 0 {
1608                         r = int(p.To.Reg)
1609                 }
1610                 o1 |= (uint32(r) & 15) << 0
1611                 o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4
1612                 o1 |= (uint32(p.To.Reg) & 15) << 12
1613
1614         case 10: /* swi [$con] */
1615                 o1 = oprrr(ctxt, p.As, int(p.Scond))
1616
1617                 if p.To.Type != obj.TYPE_NONE {
1618                         aclass(ctxt, &p.To)
1619                         o1 |= uint32(ctxt.Instoffset & 0xffffff)
1620                 }
1621
1622         case 11: /* word */
1623                 aclass(ctxt, &p.To)
1624
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)
1630
1631                         rel.Off = int32(ctxt.Pc)
1632                         rel.Siz = 4
1633                         rel.Sym = p.To.Sym
1634                         rel.Add = p.To.Offset
1635
1636                         if ctxt.Flag_shared {
1637                                 if p.To.Name == obj.NAME_GOTREF {
1638                                         rel.Type = obj.R_GOTPCREL
1639                                 } else {
1640                                         rel.Type = obj.R_PCREL
1641                                 }
1642                                 rel.Add += ctxt.Pc - p.Rel.Pc - 8
1643                         } else {
1644                                 rel.Type = obj.R_ADDR
1645                         }
1646                         o1 = 0
1647                 }
1648
1649         case 12: /* movw $lcon, reg */
1650                 o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
1651
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
1654                 }
1655
1656         case 13: /* op $lcon, [R], R */
1657                 o1 = omvl(ctxt, p, &p.From, REGTMP)
1658
1659                 if o1 == 0 {
1660                         break
1661                 }
1662                 o2 = oprrr(ctxt, p.As, int(p.Scond))
1663                 o2 |= REGTMP & 15
1664                 r := int(p.Reg)
1665                 if p.As == AMOVW || p.As == AMVN {
1666                         r = 0
1667                 } else if r == 0 {
1668                         r = int(p.To.Reg)
1669                 }
1670                 o2 |= (uint32(r) & 15) << 16
1671                 if p.To.Type != obj.TYPE_NONE {
1672                         o2 |= (uint32(p.To.Reg) & 15) << 12
1673                 }
1674
1675         case 14: /* movb/movbu/movh/movhu R,R */
1676                 o1 = oprrr(ctxt, ASLL, int(p.Scond))
1677
1678                 if p.As == AMOVBU || p.As == AMOVHU {
1679                         o2 = oprrr(ctxt, ASRL, int(p.Scond))
1680                 } else {
1681                         o2 = oprrr(ctxt, ASRA, int(p.Scond))
1682                 }
1683
1684                 r := int(p.To.Reg)
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 {
1688                         o1 |= 24 << 7
1689                         o2 |= 24 << 7
1690                 } else {
1691                         o1 |= 16 << 7
1692                         o2 |= 16 << 7
1693                 }
1694
1695         case 15: /* mul r,[r,]r */
1696                 o1 = oprrr(ctxt, p.As, int(p.Scond))
1697
1698                 rf := int(p.From.Reg)
1699                 rt := int(p.To.Reg)
1700                 r := int(p.Reg)
1701                 if r == 0 {
1702                         r = rt
1703                 }
1704                 if rt == r {
1705                         r = rf
1706                         rf = rt
1707                 }
1708
1709                 if false {
1710                         if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 {
1711                                 ctxt.Diag("bad registers in MUL")
1712                                 prasm(p)
1713                         }
1714                 }
1715
1716                 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
1717
1718         case 16: /* div r,[r,]r */
1719                 o1 = 0xf << 28
1720
1721                 o2 = 0
1722
1723         case 17:
1724                 o1 = oprrr(ctxt, p.As, int(p.Scond))
1725                 rf := int(p.From.Reg)
1726                 rt := int(p.To.Reg)
1727                 rt2 := int(p.To.Offset)
1728                 r := int(p.Reg)
1729                 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
1730
1731         case 20: /* mov/movb/movbu R,O(R) */
1732                 aclass(ctxt, &p.To)
1733
1734                 r := int(p.To.Reg)
1735                 if r == 0 {
1736                         r = int(o.param)
1737                 }
1738                 o1 = osr(ctxt, p.As, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
1739
1740         case 21: /* mov/movbu O(R),R -> lr */
1741                 aclass(ctxt, &p.From)
1742
1743                 r := int(p.From.Reg)
1744                 if r == 0 {
1745                         r = int(o.param)
1746                 }
1747                 o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
1748                 if p.As != AMOVW {
1749                         o1 |= 1 << 22
1750                 }
1751
1752         case 30: /* mov/movb/movbu R,L(R) */
1753                 o1 = omvl(ctxt, p, &p.To, REGTMP)
1754
1755                 if o1 == 0 {
1756                         break
1757                 }
1758                 r := int(p.To.Reg)
1759                 if r == 0 {
1760                         r = int(o.param)
1761                 }
1762                 o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
1763                 if p.As != AMOVW {
1764                         o2 |= 1 << 22
1765                 }
1766
1767         case 31: /* mov/movbu L(R),R -> lr[b] */
1768                 o1 = omvl(ctxt, p, &p.From, REGTMP)
1769
1770                 if o1 == 0 {
1771                         break
1772                 }
1773                 r := int(p.From.Reg)
1774                 if r == 0 {
1775                         r = int(o.param)
1776                 }
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 {
1779                         o2 |= 1 << 22
1780                 }
1781
1782         case 34: /* mov $lacon,R */
1783                 o1 = omvl(ctxt, p, &p.From, REGTMP)
1784
1785                 if o1 == 0 {
1786                         break
1787                 }
1788
1789                 o2 = oprrr(ctxt, AADD, int(p.Scond))
1790                 o2 |= REGTMP & 15
1791                 r := int(p.From.Reg)
1792                 if r == 0 {
1793                         r = int(o.param)
1794                 }
1795                 o2 |= (uint32(r) & 15) << 16
1796                 if p.To.Type != obj.TYPE_NONE {
1797                         o2 |= (uint32(p.To.Reg) & 15) << 12
1798                 }
1799
1800         case 35: /* mov PSR,R */
1801                 o1 = 2<<23 | 0xf<<16 | 0<<0
1802
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
1806
1807         case 36: /* mov R,PSR */
1808                 o1 = 2<<23 | 0x29f<<12 | 0<<4
1809
1810                 if p.Scond&C_FBIT != 0 {
1811                         o1 ^= 0x010 << 12
1812                 }
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
1816
1817         case 37: /* mov $con,PSR */
1818                 aclass(ctxt, &p.From)
1819
1820                 o1 = 2<<23 | 0x29f<<12 | 0<<4
1821                 if p.Scond&C_FBIT != 0 {
1822                         o1 ^= 0x010 << 12
1823                 }
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
1828
1829         case 38, 39:
1830                 switch o.type_ {
1831                 case 38: /* movm $con,oreg -> stm */
1832                         o1 = 0x4 << 25
1833
1834                         o1 |= uint32(p.From.Offset & 0xffff)
1835                         o1 |= (uint32(p.To.Reg) & 15) << 16
1836                         aclass(ctxt, &p.To)
1837
1838                 case 39: /* movm oreg,$con -> ldm */
1839                         o1 = 0x4<<25 | 1<<20
1840
1841                         o1 |= uint32(p.To.Offset & 0xffff)
1842                         o1 |= (uint32(p.From.Reg) & 15) << 16
1843                         aclass(ctxt, &p.From)
1844                 }
1845
1846                 if ctxt.Instoffset != 0 {
1847                         ctxt.Diag("offset must be zero in MOVM; %v", p)
1848                 }
1849                 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1850                 if p.Scond&C_PBIT != 0 {
1851                         o1 |= 1 << 24
1852                 }
1853                 if p.Scond&C_UBIT != 0 {
1854                         o1 |= 1 << 23
1855                 }
1856                 if p.Scond&C_SBIT != 0 {
1857                         o1 |= 1 << 22
1858                 }
1859                 if p.Scond&C_WBIT != 0 {
1860                         o1 |= 1 << 21
1861                 }
1862
1863         case 40: /* swp oreg,reg,reg */
1864                 aclass(ctxt, &p.From)
1865
1866                 if ctxt.Instoffset != 0 {
1867                         ctxt.Diag("offset must be zero in SWP")
1868                 }
1869                 o1 = 0x2<<23 | 0x9<<4
1870                 if p.As != ASWPW {
1871                         o1 |= 1 << 22
1872                 }
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
1877
1878         case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
1879                 o1 = 0xe8fd8000
1880
1881         case 50: /* floating point store */
1882                 v := regoff(ctxt, &p.To)
1883
1884                 r := int(p.To.Reg)
1885                 if r == 0 {
1886                         r = int(o.param)
1887                 }
1888                 o1 = ofsr(ctxt, p.As, int(p.From.Reg), v, r, int(p.Scond), p)
1889
1890         case 51: /* floating point load */
1891                 v := regoff(ctxt, &p.From)
1892
1893                 r := int(p.From.Reg)
1894                 if r == 0 {
1895                         r = int(o.param)
1896                 }
1897                 o1 = ofsr(ctxt, p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
1898
1899         case 52: /* floating point store, int32 offset UGLY */
1900                 o1 = omvl(ctxt, p, &p.To, REGTMP)
1901
1902                 if o1 == 0 {
1903                         break
1904                 }
1905                 r := int(p.To.Reg)
1906                 if r == 0 {
1907                         r = int(o.param)
1908                 }
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)
1911
1912         case 53: /* floating point load, int32 offset UGLY */
1913                 o1 = omvl(ctxt, p, &p.From, REGTMP)
1914
1915                 if o1 == 0 {
1916                         break
1917                 }
1918                 r := int(p.From.Reg)
1919                 if r == 0 {
1920                         r = int(o.param)
1921                 }
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
1924
1925         case 54: /* floating point arith */
1926                 o1 = oprrr(ctxt, p.As, int(p.Scond))
1927
1928                 rf := int(p.From.Reg)
1929                 rt := int(p.To.Reg)
1930                 r := int(p.Reg)
1931                 if r == 0 {
1932                         r = rt
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 {
1934                                 r = 0
1935                         }
1936                 }
1937
1938                 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1939
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
1942
1943                 o1 |= ((uint32(p.To.Reg)&1)+1)<<21 | (uint32(p.From.Reg)&15)<<12
1944
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
1947
1948                 o1 |= ((uint32(p.From.Reg)&1)+1)<<21 | (uint32(p.To.Reg)&15)<<12 | 1<<20
1949
1950         case 58: /* movbu R,R */
1951                 o1 = oprrr(ctxt, AAND, int(p.Scond))
1952
1953                 o1 |= uint32(immrot(0xff))
1954                 rt := int(p.To.Reg)
1955                 r := int(p.From.Reg)
1956                 if p.To.Type == obj.TYPE_NONE {
1957                         rt = 0
1958                 }
1959                 if r == 0 {
1960                         r = rt
1961                 }
1962                 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1963
1964         case 59: /* movw/bu R<<I(R),R -> ldr indexed */
1965                 if p.From.Reg == 0 {
1966                         if p.As != AMOVW {
1967                                 ctxt.Diag("byte MOV from shifter operand")
1968                         }
1969                         o1 = mov(ctxt, p)
1970                         break
1971                 }
1972
1973                 if p.From.Offset&(1<<4) != 0 {
1974                         ctxt.Diag("bad shift in LDR")
1975                 }
1976                 o1 = olrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
1977                 if p.As == AMOVBU {
1978                         o1 |= 1 << 22
1979                 }
1980
1981         case 60: /* movb R(R),R -> ldrsb indexed */
1982                 if p.From.Reg == 0 {
1983                         ctxt.Diag("byte MOV from shifter operand")
1984                         o1 = mov(ctxt, p)
1985                         break
1986                 }
1987
1988                 if p.From.Offset&(^0xf) != 0 {
1989                         ctxt.Diag("bad shift in LDRSB")
1990                 }
1991                 o1 = olhrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
1992                 o1 ^= 1<<5 | 1<<6
1993
1994         case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
1995                 if p.To.Reg == 0 {
1996                         ctxt.Diag("MOV to shifter operand")
1997                 }
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 {
2000                         o1 |= 1 << 22
2001                 }
2002
2003                 /* reloc ops */
2004         case 64: /* mov/movb/movbu R,addr */
2005                 o1 = omvl(ctxt, p, &p.To, REGTMP)
2006
2007                 if o1 == 0 {
2008                         break
2009                 }
2010                 o2 = osr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond))
2011                 if o.flag&LPCREL != 0 {
2012                         o3 = o2
2013                         o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2014                 }
2015
2016         case 65: /* mov/movbu addr,R */
2017                 o1 = omvl(ctxt, p, &p.From, REGTMP)
2018
2019                 if o1 == 0 {
2020                         break
2021                 }
2022                 o2 = olr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
2023                 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
2024                         o2 |= 1 << 22
2025                 }
2026                 if o.flag&LPCREL != 0 {
2027                         o3 = o2
2028                         o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2029                 }
2030
2031         case 101: /* movw tlsvar,R, local exec*/
2032                 if p.Scond&C_SCOND != C_SCOND_NONE {
2033                         ctxt.Diag("conditional tls")
2034                 }
2035                 o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
2036
2037         case 102: /* movw tlsvar,R, initial exec*/
2038                 if p.Scond&C_SCOND != C_SCOND_NONE {
2039                         ctxt.Diag("conditional tls")
2040                 }
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))
2043
2044         case 103: /* word tlsvar, local exec */
2045                 if p.To.Sym == nil {
2046                         ctxt.Diag("nil sym in tls %v", p)
2047                 }
2048                 if p.To.Offset != 0 {
2049                         ctxt.Diag("offset against tls var in %v", p)
2050                 }
2051                 // This case happens with words generated in the PC stream as part of
2052                 // the literal pool.
2053                 rel := obj.Addrel(ctxt.Cursym)
2054
2055                 rel.Off = int32(ctxt.Pc)
2056                 rel.Siz = 4
2057                 rel.Sym = p.To.Sym
2058                 rel.Type = obj.R_TLS_LE
2059                 o1 = 0
2060
2061         case 104: /* word tlsvar, initial exec */
2062                 if p.To.Sym == nil {
2063                         ctxt.Diag("nil sym in tls %v", p)
2064                 }
2065                 if p.To.Offset != 0 {
2066                         ctxt.Diag("offset against tls var in %v", p)
2067                 }
2068                 rel := obj.Addrel(ctxt.Cursym)
2069                 rel.Off = int32(ctxt.Pc)
2070                 rel.Siz = 4
2071                 rel.Sym = p.To.Sym
2072                 rel.Type = obj.R_TLS_IE
2073                 rel.Add = ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz)
2074
2075         case 68: /* floating point store -> ADDR */
2076                 o1 = omvl(ctxt, p, &p.To, REGTMP)
2077
2078                 if o1 == 0 {
2079                         break
2080                 }
2081                 o2 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
2082                 if o.flag&LPCREL != 0 {
2083                         o3 = o2
2084                         o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2085                 }
2086
2087         case 69: /* floating point load <- ADDR */
2088                 o1 = omvl(ctxt, p, &p.From, REGTMP)
2089
2090                 if o1 == 0 {
2091                         break
2092                 }
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 {
2095                         o3 = o2
2096                         o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2097                 }
2098
2099                 /* ArmV4 ops: */
2100         case 70: /* movh/movhu R,O(R) -> strh */
2101                 aclass(ctxt, &p.To)
2102
2103                 r := int(p.To.Reg)
2104                 if r == 0 {
2105                         r = int(o.param)
2106                 }
2107                 o1 = oshr(ctxt, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
2108
2109         case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
2110                 aclass(ctxt, &p.From)
2111
2112                 r := int(p.From.Reg)
2113                 if r == 0 {
2114                         r = int(o.param)
2115                 }
2116                 o1 = olhr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
2117                 if p.As == AMOVB || p.As == AMOVBS {
2118                         o1 ^= 1<<5 | 1<<6
2119                 } else if p.As == AMOVH || p.As == AMOVHS {
2120                         o1 ^= (1 << 6)
2121                 }
2122
2123         case 72: /* movh/movhu R,L(R) -> strh */
2124                 o1 = omvl(ctxt, p, &p.To, REGTMP)
2125
2126                 if o1 == 0 {
2127                         break
2128                 }
2129                 r := int(p.To.Reg)
2130                 if r == 0 {
2131                         r = int(o.param)
2132                 }
2133                 o2 = oshrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
2134
2135         case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
2136                 o1 = omvl(ctxt, p, &p.From, REGTMP)
2137
2138                 if o1 == 0 {
2139                         break
2140                 }
2141                 r := int(p.From.Reg)
2142                 if r == 0 {
2143                         r = int(o.param)
2144                 }
2145                 o2 = olhrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
2146                 if p.As == AMOVB || p.As == AMOVBS {
2147                         o2 ^= 1<<5 | 1<<6
2148                 } else if p.As == AMOVH || p.As == AMOVHS {
2149                         o2 ^= (1 << 6)
2150                 }
2151
2152         case 74: /* bx $I */
2153                 ctxt.Diag("ABX $I")
2154
2155         case 75: /* bx O(R) */
2156                 aclass(ctxt, &p.To)
2157
2158                 if ctxt.Instoffset != 0 {
2159                         ctxt.Diag("non-zero offset in ABX")
2160                 }
2161
2162                 /*
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
2165                 */
2166                 // p->to.reg may be REGLINK
2167                 o1 = oprrr(ctxt, AADD, int(p.Scond))
2168
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
2174
2175         case 76: /* bx O(R) when returning from fn*/
2176                 ctxt.Diag("ABXRET")
2177
2178         case 77: /* ldrex oreg,reg */
2179                 aclass(ctxt, &p.From)
2180
2181                 if ctxt.Instoffset != 0 {
2182                         ctxt.Diag("offset must be zero in LDREX")
2183                 }
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
2188
2189         case 78: /* strex reg,oreg,reg */
2190                 aclass(ctxt, &p.From)
2191
2192                 if ctxt.Instoffset != 0 {
2193                         ctxt.Diag("offset must be zero in STREX")
2194                 }
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
2200
2201         case 80: /* fmov zfcon,freg */
2202                 if p.As == AMOVD {
2203                         o1 = 0xeeb00b00 // VMOV imm 64
2204                         o2 = oprrr(ctxt, ASUBD, int(p.Scond))
2205                 } else {
2206                         o1 = 0x0eb00a00 // VMOV imm 32
2207                         o2 = oprrr(ctxt, ASUBF, int(p.Scond))
2208                 }
2209
2210                 v := int32(0x70) // 1.0
2211                 r := (int(p.To.Reg) & 15) << 0
2212
2213                 // movf $1.0, r
2214                 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2215
2216                 o1 |= (uint32(r) & 15) << 12
2217                 o1 |= (uint32(v) & 0xf) << 0
2218                 o1 |= (uint32(v) & 0xf0) << 12
2219
2220                 // subf r,r,r
2221                 o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12
2222
2223         case 81: /* fmov sfcon,freg */
2224                 o1 = 0x0eb00a00 // VMOV imm 32
2225                 if p.As == AMOVD {
2226                         o1 = 0xeeb00b00 // VMOV imm 64
2227                 }
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
2233
2234         case 82: /* fcmp freg,freg, */
2235                 o1 = oprrr(ctxt, p.As, int(p.Scond))
2236
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
2240
2241         case 83: /* fcmp freg,, */
2242                 o1 = oprrr(ctxt, p.As, int(p.Scond))
2243
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
2247
2248         case 84: /* movfw freg,freg - truncate float-to-fix */
2249                 o1 = oprrr(ctxt, p.As, int(p.Scond))
2250
2251                 o1 |= (uint32(p.From.Reg) & 15) << 0
2252                 o1 |= (uint32(p.To.Reg) & 15) << 12
2253
2254         case 85: /* movwf freg,freg - fix-to-float */
2255                 o1 = oprrr(ctxt, p.As, int(p.Scond))
2256
2257                 o1 |= (uint32(p.From.Reg) & 15) << 0
2258                 o1 |= (uint32(p.To.Reg) & 15) << 12
2259
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))
2263
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
2269
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))
2273
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
2279
2280         case 88: /* movw reg,freg  */
2281                 o1 = oprrr(ctxt, -AMOVWF, int(p.Scond))
2282
2283                 o1 |= (uint32(p.From.Reg) & 15) << 12
2284                 o1 |= (uint32(p.To.Reg) & 15) << 16
2285
2286         case 89: /* movw freg,reg  */
2287                 o1 = oprrr(ctxt, -AMOVFW, int(p.Scond))
2288
2289                 o1 |= (uint32(p.From.Reg) & 15) << 16
2290                 o1 |= (uint32(p.To.Reg) & 15) << 12
2291
2292         case 90: /* tst reg  */
2293                 o1 = oprrr(ctxt, -ACMP, int(p.Scond))
2294
2295                 o1 |= (uint32(p.From.Reg) & 15) << 16
2296
2297         case 91: /* ldrexd oreg,reg */
2298                 aclass(ctxt, &p.From)
2299
2300                 if ctxt.Instoffset != 0 {
2301                         ctxt.Diag("offset must be zero in LDREX")
2302                 }
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
2307
2308         case 92: /* strexd reg,oreg,reg */
2309                 aclass(ctxt, &p.From)
2310
2311                 if ctxt.Instoffset != 0 {
2312                         ctxt.Diag("offset must be zero in STREX")
2313                 }
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
2319
2320         case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
2321                 o1 = omvl(ctxt, p, &p.From, REGTMP)
2322
2323                 if o1 == 0 {
2324                         break
2325                 }
2326                 o2 = olhr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
2327                 if p.As == AMOVB || p.As == AMOVBS {
2328                         o2 ^= 1<<5 | 1<<6
2329                 } else if p.As == AMOVH || p.As == AMOVHS {
2330                         o2 ^= (1 << 6)
2331                 }
2332                 if o.flag&LPCREL != 0 {
2333                         o3 = o2
2334                         o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2335                 }
2336
2337         case 94: /* movh/movhu R,addr -> strh */
2338                 o1 = omvl(ctxt, p, &p.To, REGTMP)
2339
2340                 if o1 == 0 {
2341                         break
2342                 }
2343                 o2 = oshr(ctxt, int(p.From.Reg), 0, REGTMP, int(p.Scond))
2344                 if o.flag&LPCREL != 0 {
2345                         o3 = o2
2346                         o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2347                 }
2348
2349         case 95: /* PLD off(reg) */
2350                 o1 = 0xf5d0f000
2351
2352                 o1 |= (uint32(p.From.Reg) & 15) << 16
2353                 if p.From.Offset < 0 {
2354                         o1 &^= (1 << 23)
2355                         o1 |= uint32((-p.From.Offset) & 0xfff)
2356                 } else {
2357                         o1 |= uint32(p.From.Offset & 0xfff)
2358                 }
2359
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
2364         // exception.
2365         case 96: /* UNDEF */
2366                 o1 = 0xf7fabcfd
2367
2368         case 97: /* CLZ Rm, Rd */
2369                 o1 = oprrr(ctxt, p.As, int(p.Scond))
2370
2371                 o1 |= (uint32(p.To.Reg) & 15) << 12
2372                 o1 |= (uint32(p.From.Reg) & 15) << 0
2373
2374         case 98: /* MULW{T,B} Rs, Rm, Rd */
2375                 o1 = oprrr(ctxt, p.As, int(p.Scond))
2376
2377                 o1 |= (uint32(p.To.Reg) & 15) << 16
2378                 o1 |= (uint32(p.From.Reg) & 15) << 8
2379                 o1 |= (uint32(p.Reg) & 15) << 0
2380
2381         case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
2382                 o1 = oprrr(ctxt, p.As, int(p.Scond))
2383
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)
2388
2389                 // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
2390         // DATABUNDLEEND: zero width alignment marker
2391         case 100:
2392                 if p.As == ADATABUNDLE {
2393                         o1 = 0xe125be70
2394                 }
2395         }
2396
2397         out[0] = o1
2398         out[1] = o2
2399         out[2] = o3
2400         out[3] = o4
2401         out[4] = o5
2402         out[5] = o6
2403         return
2404 }
2405
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)
2410         rt := int(p.To.Reg)
2411         if p.To.Type == obj.TYPE_NONE {
2412                 rt = 0
2413         }
2414         r := int(p.Reg)
2415         if p.As == AMOVW || p.As == AMVN {
2416                 r = 0
2417         } else if r == 0 {
2418                 r = rt
2419         }
2420         o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
2421         return o1
2422 }
2423
2424 func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
2425         o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2426         if sc&C_SBIT != 0 {
2427                 o |= 1 << 20
2428         }
2429         if sc&(C_PBIT|C_WBIT) != 0 {
2430                 ctxt.Diag(".nil/.W on dp instruction")
2431         }
2432         switch a {
2433         case AMULU, AMUL:
2434                 return o | 0x0<<21 | 0x9<<4
2435         case AMULA:
2436                 return o | 0x1<<21 | 0x9<<4
2437         case AMULLU:
2438                 return o | 0x4<<21 | 0x9<<4
2439         case AMULL:
2440                 return o | 0x6<<21 | 0x9<<4
2441         case AMULALU:
2442                 return o | 0x5<<21 | 0x9<<4
2443         case AMULAL:
2444                 return o | 0x7<<21 | 0x9<<4
2445         case AAND:
2446                 return o | 0x0<<21
2447         case AEOR:
2448                 return o | 0x1<<21
2449         case ASUB:
2450                 return o | 0x2<<21
2451         case ARSB:
2452                 return o | 0x3<<21
2453         case AADD:
2454                 return o | 0x4<<21
2455         case AADC:
2456                 return o | 0x5<<21
2457         case ASBC:
2458                 return o | 0x6<<21
2459         case ARSC:
2460                 return o | 0x7<<21
2461         case ATST:
2462                 return o | 0x8<<21 | 1<<20
2463         case ATEQ:
2464                 return o | 0x9<<21 | 1<<20
2465         case ACMP:
2466                 return o | 0xa<<21 | 1<<20
2467         case ACMN:
2468                 return o | 0xb<<21 | 1<<20
2469         case AORR:
2470                 return o | 0xc<<21
2471
2472         case AMOVB, AMOVH, AMOVW:
2473                 return o | 0xd<<21
2474         case ABIC:
2475                 return o | 0xe<<21
2476         case AMVN:
2477                 return o | 0xf<<21
2478         case ASLL:
2479                 return o | 0xd<<21 | 0<<5
2480         case ASRL:
2481                 return o | 0xd<<21 | 1<<5
2482         case ASRA:
2483                 return o | 0xd<<21 | 2<<5
2484         case ASWI:
2485                 return o | 0xf<<24
2486
2487         case AADDD:
2488                 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4
2489         case AADDF:
2490                 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4
2491         case ASUBD:
2492                 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4
2493         case ASUBF:
2494                 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4
2495         case AMULD:
2496                 return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4
2497         case AMULF:
2498                 return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4
2499         case ADIVD:
2500                 return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4
2501         case ADIVF:
2502                 return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4
2503         case ASQRTD:
2504                 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4
2505         case ASQRTF:
2506                 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4
2507         case AABSD:
2508                 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
2509         case AABSF:
2510                 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
2511         case ACMPD:
2512                 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
2513         case ACMPF:
2514                 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4
2515
2516         case AMOVF:
2517                 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4
2518         case AMOVD:
2519                 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4
2520
2521         case AMOVDF:
2522                 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof
2523         case AMOVFD:
2524                 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof
2525
2526         case AMOVWF:
2527                 if sc&C_UBIT == 0 {
2528                         o |= 1 << 7 /* signed */
2529                 }
2530                 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double
2531
2532         case AMOVWD:
2533                 if sc&C_UBIT == 0 {
2534                         o |= 1 << 7 /* signed */
2535                 }
2536                 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double
2537
2538         case AMOVFW:
2539                 if sc&C_UBIT == 0 {
2540                         o |= 1 << 16 /* signed */
2541                 }
2542                 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc
2543
2544         case AMOVDW:
2545                 if sc&C_UBIT == 0 {
2546                         o |= 1 << 16 /* signed */
2547                 }
2548                 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc
2549
2550         case -AMOVWF: // copy WtoF
2551                 return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
2552
2553         case -AMOVFW: // copy FtoW
2554                 return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
2555
2556         case -ACMP: // cmp imm
2557                 return o | 0x3<<24 | 0x5<<20
2558
2559                 // CLZ doesn't support .nil
2560         case ACLZ:
2561                 return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
2562
2563         case AMULWT:
2564                 return o&(0xf<<28) | 0x12<<20 | 0xe<<4
2565
2566         case AMULWB:
2567                 return o&(0xf<<28) | 0x12<<20 | 0xa<<4
2568
2569         case AMULAWT:
2570                 return o&(0xf<<28) | 0x12<<20 | 0xc<<4
2571
2572         case AMULAWB:
2573                 return o&(0xf<<28) | 0x12<<20 | 0x8<<4
2574
2575         case ABL: // BLX REG
2576                 return o&(0xf<<28) | 0x12fff3<<4
2577         }
2578
2579         ctxt.Diag("bad rrr %d", a)
2580         prasm(ctxt.Curp)
2581         return 0
2582 }
2583
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)
2587         }
2588         sc &= C_SCOND
2589         sc ^= C_SCOND_XOR
2590         if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
2591                 return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
2592         }
2593         if sc != 0xe {
2594                 ctxt.Diag("%v: .COND on bcond instruction", p)
2595         }
2596         switch a {
2597         case ABEQ:
2598                 return 0x0<<28 | 0x5<<25
2599         case ABNE:
2600                 return 0x1<<28 | 0x5<<25
2601         case ABCS:
2602                 return 0x2<<28 | 0x5<<25
2603         case ABHS:
2604                 return 0x2<<28 | 0x5<<25
2605         case ABCC:
2606                 return 0x3<<28 | 0x5<<25
2607         case ABLO:
2608                 return 0x3<<28 | 0x5<<25
2609         case ABMI:
2610                 return 0x4<<28 | 0x5<<25
2611         case ABPL:
2612                 return 0x5<<28 | 0x5<<25
2613         case ABVS:
2614                 return 0x6<<28 | 0x5<<25
2615         case ABVC:
2616                 return 0x7<<28 | 0x5<<25
2617         case ABHI:
2618                 return 0x8<<28 | 0x5<<25
2619         case ABLS:
2620                 return 0x9<<28 | 0x5<<25
2621         case ABGE:
2622                 return 0xa<<28 | 0x5<<25
2623         case ABLT:
2624                 return 0xb<<28 | 0x5<<25
2625         case ABGT:
2626                 return 0xc<<28 | 0x5<<25
2627         case ABLE:
2628                 return 0xd<<28 | 0x5<<25
2629         case AB:
2630                 return 0xe<<28 | 0x5<<25
2631         }
2632
2633         ctxt.Diag("bad bra %v", obj.Aconv(a))
2634         prasm(ctxt.Curp)
2635         return 0
2636 }
2637
2638 func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
2639         if sc&C_SBIT != 0 {
2640                 ctxt.Diag(".nil on LDR/STR instruction")
2641         }
2642         o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2643         if sc&C_PBIT == 0 {
2644                 o |= 1 << 24
2645         }
2646         if sc&C_UBIT == 0 {
2647                 o |= 1 << 23
2648         }
2649         if sc&C_WBIT != 0 {
2650                 o |= 1 << 21
2651         }
2652         o |= 1<<26 | 1<<20
2653         if v < 0 {
2654                 if sc&C_UBIT != 0 {
2655                         ctxt.Diag(".U on neg offset")
2656                 }
2657                 v = -v
2658                 o ^= 1 << 23
2659         }
2660
2661         if v >= 1<<12 || v < 0 {
2662                 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
2663         }
2664         o |= uint32(v)
2665         o |= (uint32(b) & 15) << 16
2666         o |= (uint32(r) & 15) << 12
2667         return o
2668 }
2669
2670 func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
2671         if sc&C_SBIT != 0 {
2672                 ctxt.Diag(".nil on LDRH/STRH instruction")
2673         }
2674         o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2675         if sc&C_PBIT == 0 {
2676                 o |= 1 << 24
2677         }
2678         if sc&C_WBIT != 0 {
2679                 o |= 1 << 21
2680         }
2681         o |= 1<<23 | 1<<20 | 0xb<<4
2682         if v < 0 {
2683                 v = -v
2684                 o ^= 1 << 23
2685         }
2686
2687         if v >= 1<<8 || v < 0 {
2688                 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
2689         }
2690         o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
2691         o |= (uint32(b) & 15) << 16
2692         o |= (uint32(r) & 15) << 12
2693         return o
2694 }
2695
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)
2698         if a != AMOVW {
2699                 o |= 1 << 22
2700         }
2701         return o
2702 }
2703
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)
2706         return o
2707 }
2708
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)
2711 }
2712
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)
2715 }
2716
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)
2719 }
2720
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)
2723 }
2724
2725 func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
2726         if sc&C_SBIT != 0 {
2727                 ctxt.Diag(".nil on FLDR/FSTR instruction: %v", p)
2728         }
2729         o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2730         if sc&C_PBIT == 0 {
2731                 o |= 1 << 24
2732         }
2733         if sc&C_WBIT != 0 {
2734                 o |= 1 << 21
2735         }
2736         o |= 6<<25 | 1<<24 | 1<<23 | 10<<8
2737         if v < 0 {
2738                 v = -v
2739                 o ^= 1 << 23
2740         }
2741
2742         if v&3 != 0 {
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)
2746         }
2747         o |= (uint32(v) >> 2) & 0xFF
2748         o |= (uint32(b) & 15) << 16
2749         o |= (uint32(r) & 15) << 12
2750
2751         switch a {
2752         default:
2753                 ctxt.Diag("bad fst %v", obj.Aconv(a))
2754                 fallthrough
2755
2756         case AMOVD:
2757                 o |= 1 << 8
2758                 fallthrough
2759
2760         case AMOVF:
2761                 break
2762         }
2763
2764         return o
2765 }
2766
2767 func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 {
2768         var o1 uint32
2769         if p.Pcond == nil {
2770                 aclass(ctxt, a)
2771                 v := immrot(^uint32(ctxt.Instoffset))
2772                 if v == 0 {
2773                         ctxt.Diag("missing literal")
2774                         prasm(p)
2775                         return 0
2776                 }
2777
2778                 o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND)
2779                 o1 |= uint32(v)
2780                 o1 |= (uint32(dr) & 15) << 12
2781         } else {
2782                 v := int32(p.Pcond.Pc - p.Pc - 8)
2783                 o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND)
2784         }
2785
2786         return o1
2787 }
2788
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 {
2792                 return -1
2793         }
2794         return 0
2795 }
2796
2797 func chipfloat5(ctxt *obj.Link, e float64) int {
2798         // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
2799         if ctxt.Goarm < 7 {
2800                 return -1
2801         }
2802
2803         ei := math.Float64bits(e)
2804         l := uint32(ei)
2805         h := uint32(ei >> 32)
2806
2807         if l != 0 || h&0xffff != 0 {
2808                 return -1
2809         }
2810         h1 := h & 0x7fc00000
2811         if h1 != 0x40000000 && h1 != 0x3fc00000 {
2812                 return -1
2813         }
2814         n := 0
2815
2816         // sign bit (a)
2817         if h&0x80000000 != 0 {
2818                 n |= 1 << 7
2819         }
2820
2821         // exp sign bit (b)
2822         if h1 == 0x3fc00000 {
2823                 n |= 1 << 6
2824         }
2825
2826         // rest of exp and mantissa (cd-efgh)
2827         n |= int((h >> 16) & 0x3f)
2828
2829         //print("match %.8lux %.8lux %d\n", l, h, n);
2830         return n
2831 }
2832
2833 func nocache(p *obj.Prog) {
2834         p.Optab = 0
2835         p.From.Class = 0
2836         if p.From3 != nil {
2837                 p.From3.Class = 0
2838         }
2839         p.To.Class = 0
2840 }