podman
3096 строк · 78.3 Кб
1// Inferno utils/5l/span.c
2// https://bitbucket.org/inferno-os/inferno-os/src/master/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
31package arm
32
33import (
34"github.com/twitchyliquid64/golang-asm/obj"
35"github.com/twitchyliquid64/golang-asm/objabi"
36"fmt"
37"log"
38"math"
39"sort"
40)
41
42// ctxt5 holds state while assembling a single function.
43// Each function gets a fresh ctxt5.
44// This allows for multiple functions to be safely concurrently assembled.
45type ctxt5 struct {
46ctxt *obj.Link
47newprog obj.ProgAlloc
48cursym *obj.LSym
49printp *obj.Prog
50blitrl *obj.Prog
51elitrl *obj.Prog
52autosize int64
53instoffset int64
54pc int64
55pool struct {
56start uint32
57size uint32
58extra uint32
59}
60}
61
62type Optab struct {
63as obj.As
64a1 uint8
65a2 int8
66a3 uint8
67type_ uint8
68size int8
69param int16
70flag int8
71pcrelsiz uint8
72scond uint8 // optional flags accepted by the instruction
73}
74
75type Opcross [32][2][32]uint8
76
77const (
78LFROM = 1 << 0
79LTO = 1 << 1
80LPOOL = 1 << 2
81LPCREL = 1 << 3
82)
83
84var optab = []Optab{
85/* struct Optab:
86OPCODE, from, prog->reg, to, type, size, param, flag, extra data size, optional suffix */
87{obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0, 0},
88{AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT},
89{AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
90{AAND, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT},
91{AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
92{AORR, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT},
93{AORR, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
94{AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
95{AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
96{ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0, 0},
97{AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT},
98{AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT},
99{AAND, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT},
100{AAND, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT},
101{AORR, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT},
102{AORR, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT},
103{AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0},
104{AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0},
105{ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0, 0},
106{AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT},
107{AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT},
108{AAND, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT},
109{AAND, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT},
110{AORR, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT},
111{AORR, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT},
112{AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT},
113{ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0, 0},
114{AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0, C_SBIT},
115{AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0, 0},
116{ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0},
117{ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0, 0},
118{ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0},
119{ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // prediction hinted form, hint ignored
120{AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0, 0},
121{ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0},
122{ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0},
123{ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0, 0},
124{ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0, 0},
125{ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0, C_SBIT},
126{ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0, C_SBIT},
127{ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0, C_SBIT},
128{ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0, C_SBIT},
129{ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0, 0},
130{ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0, 0},
131{AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0, 0},
132{AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0, 0},
133{AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0, 0},
134{AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0, 0},
135{AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0, 0},
136{AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0},
137{AMOVW, C_SCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0},
138{AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0, 0},
139{AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4, 0},
140{AMVN, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0},
141{AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
142{AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
143{AAND, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
144{AAND, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
145{AORR, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
146{AORR, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
147{ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0},
148{AADD, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
149{AADD, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
150{AAND, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
151{AAND, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
152{AORR, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
153{AORR, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
154{AMVN, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, 0},
155{ACMP, C_SCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0},
156{AADD, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0},
157{AADD, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0},
158{AORR, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0},
159{AORR, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0},
160{AADD, C_RCON2S, C_REG, C_REG, 107, 8, 0, 0, 0, 0},
161{AADD, C_RCON2S, C_NONE, C_REG, 107, 8, 0, 0, 0, 0},
162{AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
163{AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
164{AAND, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
165{AAND, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
166{AORR, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
167{AORR, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
168{AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, 0},
169{ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0, 0},
170{AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0},
171{AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0},
172{AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0, 0},
173{AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0},
174{AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0},
175{AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0},
176{AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0, C_SBIT},
177{AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0, C_SBIT},
178{ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0, 0},
179{ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0, 0},
180{ADIVHW, C_REG, C_REG, C_REG, 105, 4, 0, 0, 0, 0},
181{ADIVHW, C_REG, C_NONE, C_REG, 105, 4, 0, 0, 0, 0},
182{AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0, C_SBIT},
183{ABFX, C_LCON, C_REG, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3
184{ABFX, C_LCON, C_NONE, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3
185{AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
186{AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
187{AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
188{AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
189{AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
190{AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
191{AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
192{AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
193{AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
194{AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
195{AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
196{AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
197{AXTAB, C_SHIFT, C_REG, C_REG, 22, 4, 0, 0, 0, 0},
198{AXTAB, C_SHIFT, C_NONE, C_REG, 22, 4, 0, 0, 0, 0},
199{AMOVW, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, C_SBIT},
200{AMOVB, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
201{AMOVBS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
202{AMOVBU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
203{AMOVH, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
204{AMOVHS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
205{AMOVHU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
206{AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
207{AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
208{AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
209{AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
210{AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
211{AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
212{AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
213{AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
214{AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
215{AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
216{AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
217{AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
218{AMOVW, C_TLS_LE, C_NONE, C_REG, 101, 4, 0, LFROM, 0, 0},
219{AMOVW, C_TLS_IE, C_NONE, C_REG, 102, 8, 0, LFROM, 0, 0},
220{AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
221{AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
222{AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
223{AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
224{AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
225{AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
226{AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0, C_SBIT},
227{AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0, 0},
228{AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0, 0},
229{AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0, 0},
230{AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
231{AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
232{ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0, 0},
233{ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0, 0},
234{AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
235{AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
236{AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
237{AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
238{AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
239{AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
240{AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
241{AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
242{AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
243{AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
244{AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0, 0},
245{AADDF, C_FREG, C_FREG, C_FREG, 54, 4, 0, 0, 0, 0},
246{AMOVF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0},
247{ANEGF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0},
248{AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0, 0},
249{AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0, 0},
250{AMOVW, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
251{AMOVBU, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
252{AMOVB, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
253{AMOVBS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
254{AMOVH, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
255{AMOVHS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
256{AMOVHU, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
257{AMOVW, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
258{AMOVB, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
259{AMOVBS, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
260{AMOVBU, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
261{AMOVH, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
262{AMOVHS, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
263{AMOVHU, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
264{AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
265{AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
266{AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
267{AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
268{AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
269{AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
270{AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
271{AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
272{AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
273{AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
274{AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
275{AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
276{AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
277{AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
278{AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
279{AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
280{AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
281{AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
282{AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
283{AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
284{AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
285{AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
286{AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
287{AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
288{AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
289{AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
290{AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
291{AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
292{AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
293{AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
294{AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
295{AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
296{AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
297{AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
298{AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
299{AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
300{AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
301{AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
302{AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
303{AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
304{ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0, 0},
305{ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0, 0},
306{ADMB, C_NONE, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0},
307{ADMB, C_LCON, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0},
308{ADMB, C_SPR, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0},
309{AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0, 0},
310{AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0, 0},
311{ACMPF, C_FREG, C_FREG, C_NONE, 82, 8, 0, 0, 0, 0},
312{ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0, 0},
313{AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0, C_UBIT},
314{AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0, C_UBIT},
315{AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0, C_UBIT},
316{AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0, C_UBIT},
317{AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0, 0},
318{AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0, 0},
319{ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0, 0},
320{ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0, 0},
321{APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0, 0},
322{obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0, 0},
323{ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0, 0},
324{AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0, 0},
325{AMULA, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, C_SBIT},
326{AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, 0},
327{obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0, 0},
328{obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0, 0},
329{obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0},
330{obj.ANOP, C_LCON, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, // nop variants, see #40689
331{obj.ANOP, C_REG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0},
332{obj.ANOP, C_FREG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0},
333{obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL
334{obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL
335{obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0, 0},
336}
337
338var mbOp = []struct {
339reg int16
340enc uint32
341}{
342{REG_MB_SY, 15},
343{REG_MB_ST, 14},
344{REG_MB_ISH, 11},
345{REG_MB_ISHST, 10},
346{REG_MB_NSH, 7},
347{REG_MB_NSHST, 6},
348{REG_MB_OSH, 3},
349{REG_MB_OSHST, 2},
350}
351
352var oprange [ALAST & obj.AMask][]Optab
353
354var xcmp [C_GOK + 1][C_GOK + 1]bool
355
356var (
357deferreturn *obj.LSym
358symdiv *obj.LSym
359symdivu *obj.LSym
360symmod *obj.LSym
361symmodu *obj.LSym
362)
363
364// Note about encoding: Prog.scond holds the condition encoding,
365// but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0.
366// The code that shifts the value << 28 has the responsibility
367// for XORing with C_SCOND_XOR too.
368
369func checkSuffix(c *ctxt5, p *obj.Prog, o *Optab) {
370if p.Scond&C_SBIT != 0 && o.scond&C_SBIT == 0 {
371c.ctxt.Diag("invalid .S suffix: %v", p)
372}
373if p.Scond&C_PBIT != 0 && o.scond&C_PBIT == 0 {
374c.ctxt.Diag("invalid .P suffix: %v", p)
375}
376if p.Scond&C_WBIT != 0 && o.scond&C_WBIT == 0 {
377c.ctxt.Diag("invalid .W suffix: %v", p)
378}
379if p.Scond&C_UBIT != 0 && o.scond&C_UBIT == 0 {
380c.ctxt.Diag("invalid .U suffix: %v", p)
381}
382}
383
384func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
385if ctxt.Retpoline {
386ctxt.Diag("-spectre=ret not supported on arm")
387ctxt.Retpoline = false // don't keep printing
388}
389
390var p *obj.Prog
391var op *obj.Prog
392
393p = cursym.Func.Text
394if p == nil || p.Link == nil { // handle external functions and ELF section symbols
395return
396}
397
398if oprange[AAND&obj.AMask] == nil {
399ctxt.Diag("arm ops not initialized, call arm.buildop first")
400}
401
402c := ctxt5{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: p.To.Offset + 4}
403pc := int32(0)
404
405op = p
406p = p.Link
407var m int
408var o *Optab
409for ; p != nil || c.blitrl != nil; op, p = p, p.Link {
410if p == nil {
411if c.checkpool(op, pc) {
412p = op
413continue
414}
415
416// can't happen: blitrl is not nil, but checkpool didn't flushpool
417ctxt.Diag("internal inconsistency")
418
419break
420}
421
422p.Pc = int64(pc)
423o = c.oplook(p)
424m = int(o.size)
425
426if m%4 != 0 || p.Pc%4 != 0 {
427ctxt.Diag("!pc invalid: %v size=%d", p, m)
428}
429
430// must check literal pool here in case p generates many instructions
431if c.blitrl != nil {
432// Emit the constant pool just before p if p
433// would push us over the immediate size limit.
434if c.checkpool(op, pc+int32(m)) {
435// Back up to the instruction just
436// before the pool and continue with
437// the first instruction of the pool.
438p = op
439continue
440}
441}
442
443if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) {
444ctxt.Diag("zero-width instruction\n%v", p)
445continue
446}
447
448switch o.flag & (LFROM | LTO | LPOOL) {
449case LFROM:
450c.addpool(p, &p.From)
451
452case LTO:
453c.addpool(p, &p.To)
454
455case LPOOL:
456if p.Scond&C_SCOND == C_SCOND_NONE {
457c.flushpool(p, 0, 0)
458}
459}
460
461if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE {
462c.flushpool(p, 0, 0)
463}
464
465pc += int32(m)
466}
467
468c.cursym.Size = int64(pc)
469
470/*
471* if any procedure is large enough to
472* generate a large SBRA branch, then
473* generate extra passes putting branches
474* around jmps to fix. this is rare.
475*/
476times := 0
477
478var bflag int
479var opc int32
480var out [6 + 3]uint32
481for {
482bflag = 0
483pc = 0
484times++
485c.cursym.Func.Text.Pc = 0 // force re-layout the code.
486for p = c.cursym.Func.Text; p != nil; p = p.Link {
487o = c.oplook(p)
488if int64(pc) > p.Pc {
489p.Pc = int64(pc)
490}
491
492/* very large branches
493if(o->type == 6 && p->pcond) {
494otxt = p->pcond->pc - c;
495if(otxt < 0)
496otxt = -otxt;
497if(otxt >= (1L<<17) - 10) {
498q = emallocz(sizeof(Prog));
499q->link = p->link;
500p->link = q;
501q->as = AB;
502q->to.type = TYPE_BRANCH;
503q->pcond = p->pcond;
504p->pcond = q;
505q = emallocz(sizeof(Prog));
506q->link = p->link;
507p->link = q;
508q->as = AB;
509q->to.type = TYPE_BRANCH;
510q->pcond = q->link->link;
511bflag = 1;
512}
513}
514*/
515opc = int32(p.Pc)
516m = int(o.size)
517if p.Pc != int64(opc) {
518bflag = 1
519}
520
521//print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
522pc = int32(p.Pc + int64(m))
523
524if m%4 != 0 || p.Pc%4 != 0 {
525ctxt.Diag("pc invalid: %v size=%d", p, m)
526}
527
528if m/4 > len(out) {
529ctxt.Diag("instruction size too large: %d > %d", m/4, len(out))
530}
531if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) {
532if p.As == obj.ATEXT {
533c.autosize = p.To.Offset + 4
534continue
535}
536
537ctxt.Diag("zero-width instruction\n%v", p)
538continue
539}
540}
541
542c.cursym.Size = int64(pc)
543if bflag == 0 {
544break
545}
546}
547
548if pc%4 != 0 {
549ctxt.Diag("sym->size=%d, invalid", pc)
550}
551
552/*
553* lay out the code. all the pc-relative code references,
554* even cross-function, are resolved now;
555* only data references need to be relocated.
556* with more work we could leave cross-function
557* code references to be relocated too, and then
558* perhaps we'd be able to parallelize the span loop above.
559*/
560
561p = c.cursym.Func.Text
562c.autosize = p.To.Offset + 4
563c.cursym.Grow(c.cursym.Size)
564
565bp := c.cursym.P
566pc = int32(p.Pc) // even p->link might need extra padding
567var v int
568for p = p.Link; p != nil; p = p.Link {
569c.pc = p.Pc
570o = c.oplook(p)
571opc = int32(p.Pc)
572c.asmout(p, o, out[:])
573m = int(o.size)
574
575if m%4 != 0 || p.Pc%4 != 0 {
576ctxt.Diag("final stage: pc invalid: %v size=%d", p, m)
577}
578
579if int64(pc) > p.Pc {
580ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, pc, p)
581}
582for int64(pc) != p.Pc {
583// emit 0xe1a00000 (MOVW R0, R0)
584bp[0] = 0x00
585bp = bp[1:]
586
587bp[0] = 0x00
588bp = bp[1:]
589bp[0] = 0xa0
590bp = bp[1:]
591bp[0] = 0xe1
592bp = bp[1:]
593pc += 4
594}
595
596for i := 0; i < m/4; i++ {
597v = int(out[i])
598bp[0] = byte(v)
599bp = bp[1:]
600bp[0] = byte(v >> 8)
601bp = bp[1:]
602bp[0] = byte(v >> 16)
603bp = bp[1:]
604bp[0] = byte(v >> 24)
605bp = bp[1:]
606}
607
608pc += int32(m)
609}
610}
611
612// checkpool flushes the literal pool when the first reference to
613// it threatens to go out of range of a 12-bit PC-relative offset.
614//
615// nextpc is the tentative next PC at which the pool could be emitted.
616// checkpool should be called *before* emitting the instruction that
617// would cause the PC to reach nextpc.
618// If nextpc is too far from the first pool reference, checkpool will
619// flush the pool immediately after p.
620// The caller should resume processing a p.Link.
621func (c *ctxt5) checkpool(p *obj.Prog, nextpc int32) bool {
622poolLast := nextpc
623poolLast += 4 // the AB instruction to jump around the pool
624poolLast += int32(c.pool.size) - 4 // the offset of the last pool entry
625
626refPC := int32(c.pool.start) // PC of the first pool reference
627
628v := poolLast - refPC - 8 // 12-bit PC-relative offset (see omvl)
629
630if c.pool.size >= 0xff0 || immaddr(v) == 0 {
631return c.flushpool(p, 1, 0)
632} else if p.Link == nil {
633return c.flushpool(p, 2, 0)
634}
635return false
636}
637
638func (c *ctxt5) flushpool(p *obj.Prog, skip int, force int) bool {
639if c.blitrl != nil {
640if skip != 0 {
641if false && skip == 1 {
642fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start)
643}
644q := c.newprog()
645q.As = AB
646q.To.Type = obj.TYPE_BRANCH
647q.To.SetTarget(p.Link)
648q.Link = c.blitrl
649q.Pos = p.Pos
650c.blitrl = q
651} else if force == 0 && (p.Pc+int64(c.pool.size)-int64(c.pool.start) < 2048) {
652return false
653}
654
655// The line number for constant pool entries doesn't really matter.
656// We set it to the line number of the preceding instruction so that
657// there are no deltas to encode in the pc-line tables.
658for q := c.blitrl; q != nil; q = q.Link {
659q.Pos = p.Pos
660}
661
662c.elitrl.Link = p.Link
663p.Link = c.blitrl
664
665c.blitrl = nil /* BUG: should refer back to values until out-of-range */
666c.elitrl = nil
667c.pool.size = 0
668c.pool.start = 0
669c.pool.extra = 0
670return true
671}
672
673return false
674}
675
676func (c *ctxt5) addpool(p *obj.Prog, a *obj.Addr) {
677t := c.newprog()
678t.As = AWORD
679
680switch c.aclass(a) {
681default:
682t.To.Offset = a.Offset
683t.To.Sym = a.Sym
684t.To.Type = a.Type
685t.To.Name = a.Name
686
687if c.ctxt.Flag_shared && t.To.Sym != nil {
688t.Rel = p
689}
690
691case C_SROREG,
692C_LOREG,
693C_ROREG,
694C_FOREG,
695C_SOREG,
696C_HOREG,
697C_FAUTO,
698C_SAUTO,
699C_LAUTO,
700C_LACON:
701t.To.Type = obj.TYPE_CONST
702t.To.Offset = c.instoffset
703}
704
705if t.Rel == nil {
706for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
707if q.Rel == nil && q.To == t.To {
708p.Pool = q
709return
710}
711}
712}
713
714q := c.newprog()
715*q = *t
716q.Pc = int64(c.pool.size)
717
718if c.blitrl == nil {
719c.blitrl = q
720c.pool.start = uint32(p.Pc)
721} else {
722c.elitrl.Link = q
723}
724c.elitrl = q
725c.pool.size += 4
726
727// Store the link to the pool entry in Pool.
728p.Pool = q
729}
730
731func (c *ctxt5) regoff(a *obj.Addr) int32 {
732c.instoffset = 0
733c.aclass(a)
734return int32(c.instoffset)
735}
736
737func immrot(v uint32) int32 {
738for i := 0; i < 16; i++ {
739if v&^0xff == 0 {
740return int32(uint32(int32(i)<<8) | v | 1<<25)
741}
742v = v<<2 | v>>30
743}
744
745return 0
746}
747
748// immrot2a returns bits encoding the immediate constant fields of two instructions,
749// such that the encoded constants x, y satisfy x|y==v, x&y==0.
750// Returns 0,0 if no such decomposition of v exists.
751func immrot2a(v uint32) (uint32, uint32) {
752for i := uint(1); i < 32; i++ {
753m := uint32(1<<i - 1)
754if x, y := immrot(v&m), immrot(v&^m); x != 0 && y != 0 {
755return uint32(x), uint32(y)
756}
757}
758// TODO: handle some more cases, like where
759// the wraparound from the rotate could help.
760return 0, 0
761}
762
763// immrot2s returns bits encoding the immediate constant fields of two instructions,
764// such that the encoded constants y, x satisfy y-x==v, y&x==0.
765// Returns 0,0 if no such decomposition of v exists.
766func immrot2s(v uint32) (uint32, uint32) {
767if immrot(v) != 0 {
768return v, 0
769}
770// suppose v in the form of {leading 00, upper effective bits, lower 8 effective bits, trailing 00}
771// omit trailing 00
772var i uint32
773for i = 2; i < 32; i += 2 {
774if v&(1<<i-1) != 0 {
775break
776}
777}
778// i must be <= 24, then adjust i just above lower 8 effective bits of v
779i += 6
780// let x = {the complement of lower 8 effective bits, trailing 00}, y = x + v
781x := 1<<i - v&(1<<i-1)
782y := v + x
783if y, x = uint32(immrot(y)), uint32(immrot(x)); y != 0 && x != 0 {
784return y, x
785}
786return 0, 0
787}
788
789func immaddr(v int32) int32 {
790if v >= 0 && v <= 0xfff {
791return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */
792}
793if v >= -0xfff && v < 0 {
794return -v&0xfff | 1<<24 /* pre indexing */
795}
796return 0
797}
798
799func immfloat(v int32) bool {
800return v&0xC03 == 0 /* offset will fit in floating-point load/store */
801}
802
803func immhalf(v int32) bool {
804if v >= 0 && v <= 0xff {
805return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */
806}
807if v >= -0xff && v < 0 {
808return -v&0xff|1<<24 != 0 /* pre indexing */
809}
810return false
811}
812
813func (c *ctxt5) aclass(a *obj.Addr) int {
814switch a.Type {
815case obj.TYPE_NONE:
816return C_NONE
817
818case obj.TYPE_REG:
819c.instoffset = 0
820if REG_R0 <= a.Reg && a.Reg <= REG_R15 {
821return C_REG
822}
823if REG_F0 <= a.Reg && a.Reg <= REG_F15 {
824return C_FREG
825}
826if a.Reg == REG_FPSR || a.Reg == REG_FPCR {
827return C_FCR
828}
829if a.Reg == REG_CPSR || a.Reg == REG_SPSR {
830return C_PSR
831}
832if a.Reg >= REG_SPECIAL {
833return C_SPR
834}
835return C_GOK
836
837case obj.TYPE_REGREG:
838return C_REGREG
839
840case obj.TYPE_REGREG2:
841return C_REGREG2
842
843case obj.TYPE_REGLIST:
844return C_REGLIST
845
846case obj.TYPE_SHIFT:
847if a.Reg == 0 {
848// register shift R>>i
849return C_SHIFT
850} else {
851// memory address with shifted offset R>>i(R)
852return C_SHIFTADDR
853}
854
855case obj.TYPE_MEM:
856switch a.Name {
857case obj.NAME_EXTERN,
858obj.NAME_GOTREF,
859obj.NAME_STATIC:
860if a.Sym == nil || a.Sym.Name == "" {
861fmt.Printf("null sym external\n")
862return C_GOK
863}
864
865c.instoffset = 0 // s.b. unused but just in case
866if a.Sym.Type == objabi.STLSBSS {
867if c.ctxt.Flag_shared {
868return C_TLS_IE
869} else {
870return C_TLS_LE
871}
872}
873
874return C_ADDR
875
876case obj.NAME_AUTO:
877if a.Reg == REGSP {
878// unset base register for better printing, since
879// a.Offset is still relative to pseudo-SP.
880a.Reg = obj.REG_NONE
881}
882c.instoffset = c.autosize + a.Offset
883if t := immaddr(int32(c.instoffset)); t != 0 {
884if immhalf(int32(c.instoffset)) {
885if immfloat(t) {
886return C_HFAUTO
887}
888return C_HAUTO
889}
890
891if immfloat(t) {
892return C_FAUTO
893}
894return C_SAUTO
895}
896
897return C_LAUTO
898
899case obj.NAME_PARAM:
900if a.Reg == REGSP {
901// unset base register for better printing, since
902// a.Offset is still relative to pseudo-FP.
903a.Reg = obj.REG_NONE
904}
905c.instoffset = c.autosize + a.Offset + 4
906if t := immaddr(int32(c.instoffset)); t != 0 {
907if immhalf(int32(c.instoffset)) {
908if immfloat(t) {
909return C_HFAUTO
910}
911return C_HAUTO
912}
913
914if immfloat(t) {
915return C_FAUTO
916}
917return C_SAUTO
918}
919
920return C_LAUTO
921
922case obj.NAME_NONE:
923c.instoffset = a.Offset
924if t := immaddr(int32(c.instoffset)); t != 0 {
925if immhalf(int32(c.instoffset)) { /* n.b. that it will also satisfy immrot */
926if immfloat(t) {
927return C_HFOREG
928}
929return C_HOREG
930}
931
932if immfloat(t) {
933return C_FOREG /* n.b. that it will also satisfy immrot */
934}
935if immrot(uint32(c.instoffset)) != 0 {
936return C_SROREG
937}
938if immhalf(int32(c.instoffset)) {
939return C_HOREG
940}
941return C_SOREG
942}
943
944if immrot(uint32(c.instoffset)) != 0 {
945return C_ROREG
946}
947return C_LOREG
948}
949
950return C_GOK
951
952case obj.TYPE_FCONST:
953if c.chipzero5(a.Val.(float64)) >= 0 {
954return C_ZFCON
955}
956if c.chipfloat5(a.Val.(float64)) >= 0 {
957return C_SFCON
958}
959return C_LFCON
960
961case obj.TYPE_TEXTSIZE:
962return C_TEXTSIZE
963
964case obj.TYPE_CONST,
965obj.TYPE_ADDR:
966switch a.Name {
967case obj.NAME_NONE:
968c.instoffset = a.Offset
969if a.Reg != 0 {
970return c.aconsize()
971}
972
973if immrot(uint32(c.instoffset)) != 0 {
974return C_RCON
975}
976if immrot(^uint32(c.instoffset)) != 0 {
977return C_NCON
978}
979if uint32(c.instoffset) <= 0xffff && objabi.GOARM == 7 {
980return C_SCON
981}
982if x, y := immrot2a(uint32(c.instoffset)); x != 0 && y != 0 {
983return C_RCON2A
984}
985if y, x := immrot2s(uint32(c.instoffset)); x != 0 && y != 0 {
986return C_RCON2S
987}
988return C_LCON
989
990case obj.NAME_EXTERN,
991obj.NAME_GOTREF,
992obj.NAME_STATIC:
993s := a.Sym
994if s == nil {
995break
996}
997c.instoffset = 0 // s.b. unused but just in case
998return C_LCONADDR
999
1000case obj.NAME_AUTO:
1001if a.Reg == REGSP {
1002// unset base register for better printing, since
1003// a.Offset is still relative to pseudo-SP.
1004a.Reg = obj.REG_NONE
1005}
1006c.instoffset = c.autosize + a.Offset
1007return c.aconsize()
1008
1009case obj.NAME_PARAM:
1010if a.Reg == REGSP {
1011// unset base register for better printing, since
1012// a.Offset is still relative to pseudo-FP.
1013a.Reg = obj.REG_NONE
1014}
1015c.instoffset = c.autosize + a.Offset + 4
1016return c.aconsize()
1017}
1018
1019return C_GOK
1020
1021case obj.TYPE_BRANCH:
1022return C_SBRA
1023}
1024
1025return C_GOK
1026}
1027
1028func (c *ctxt5) aconsize() int {
1029if immrot(uint32(c.instoffset)) != 0 {
1030return C_RACON
1031}
1032if immrot(uint32(-c.instoffset)) != 0 {
1033return C_RACON
1034}
1035return C_LACON
1036}
1037
1038func (c *ctxt5) oplook(p *obj.Prog) *Optab {
1039a1 := int(p.Optab)
1040if a1 != 0 {
1041return &optab[a1-1]
1042}
1043a1 = int(p.From.Class)
1044if a1 == 0 {
1045a1 = c.aclass(&p.From) + 1
1046p.From.Class = int8(a1)
1047}
1048
1049a1--
1050a3 := int(p.To.Class)
1051if a3 == 0 {
1052a3 = c.aclass(&p.To) + 1
1053p.To.Class = int8(a3)
1054}
1055
1056a3--
1057a2 := C_NONE
1058if p.Reg != 0 {
1059switch {
1060case REG_F0 <= p.Reg && p.Reg <= REG_F15:
1061a2 = C_FREG
1062case REG_R0 <= p.Reg && p.Reg <= REG_R15:
1063a2 = C_REG
1064default:
1065c.ctxt.Diag("invalid register in %v", p)
1066}
1067}
1068
1069// check illegal base register
1070switch a1 {
1071case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR:
1072if p.From.Reg < REG_R0 || REG_R15 < p.From.Reg {
1073c.ctxt.Diag("illegal base register: %v", p)
1074}
1075default:
1076}
1077switch a3 {
1078case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR:
1079if p.To.Reg < REG_R0 || REG_R15 < p.To.Reg {
1080c.ctxt.Diag("illegal base register: %v", p)
1081}
1082default:
1083}
1084
1085// If current instruction has a .S suffix (flags update),
1086// we must use the constant pool instead of splitting it.
1087if (a1 == C_RCON2A || a1 == C_RCON2S) && p.Scond&C_SBIT != 0 {
1088a1 = C_LCON
1089}
1090if (a3 == C_RCON2A || a3 == C_RCON2S) && p.Scond&C_SBIT != 0 {
1091a3 = C_LCON
1092}
1093
1094if false { /*debug['O']*/
1095fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3))
1096fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
1097}
1098
1099ops := oprange[p.As&obj.AMask]
1100c1 := &xcmp[a1]
1101c3 := &xcmp[a3]
1102for i := range ops {
1103op := &ops[i]
1104if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] {
1105p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
1106checkSuffix(c, p, op)
1107return op
1108}
1109}
1110
1111c.ctxt.Diag("illegal combination %v; %v %v %v; from %d %d; to %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.From.Name, p.To.Type, p.To.Name)
1112if ops == nil {
1113ops = optab
1114}
1115return &ops[0]
1116}
1117
1118func cmp(a int, b int) bool {
1119if a == b {
1120return true
1121}
1122switch a {
1123case C_LCON:
1124if b == C_RCON || b == C_NCON || b == C_SCON || b == C_RCON2A || b == C_RCON2S {
1125return true
1126}
1127
1128case C_LACON:
1129if b == C_RACON {
1130return true
1131}
1132
1133case C_LFCON:
1134if b == C_ZFCON || b == C_SFCON {
1135return true
1136}
1137
1138case C_HFAUTO:
1139return b == C_HAUTO || b == C_FAUTO
1140
1141case C_FAUTO, C_HAUTO:
1142return b == C_HFAUTO
1143
1144case C_SAUTO:
1145return cmp(C_HFAUTO, b)
1146
1147case C_LAUTO:
1148return cmp(C_SAUTO, b)
1149
1150case C_HFOREG:
1151return b == C_HOREG || b == C_FOREG
1152
1153case C_FOREG, C_HOREG:
1154return b == C_HFOREG
1155
1156case C_SROREG:
1157return cmp(C_SOREG, b) || cmp(C_ROREG, b)
1158
1159case C_SOREG, C_ROREG:
1160return b == C_SROREG || cmp(C_HFOREG, b)
1161
1162case C_LOREG:
1163return cmp(C_SROREG, b)
1164
1165case C_LBRA:
1166if b == C_SBRA {
1167return true
1168}
1169
1170case C_HREG:
1171return cmp(C_SP, b) || cmp(C_PC, b)
1172}
1173
1174return false
1175}
1176
1177type ocmp []Optab
1178
1179func (x ocmp) Len() int {
1180return len(x)
1181}
1182
1183func (x ocmp) Swap(i, j int) {
1184x[i], x[j] = x[j], x[i]
1185}
1186
1187func (x ocmp) Less(i, j int) bool {
1188p1 := &x[i]
1189p2 := &x[j]
1190n := int(p1.as) - int(p2.as)
1191if n != 0 {
1192return n < 0
1193}
1194n = int(p1.a1) - int(p2.a1)
1195if n != 0 {
1196return n < 0
1197}
1198n = int(p1.a2) - int(p2.a2)
1199if n != 0 {
1200return n < 0
1201}
1202n = int(p1.a3) - int(p2.a3)
1203if n != 0 {
1204return n < 0
1205}
1206return false
1207}
1208
1209func opset(a, b0 obj.As) {
1210oprange[a&obj.AMask] = oprange[b0]
1211}
1212
1213func buildop(ctxt *obj.Link) {
1214if oprange[AAND&obj.AMask] != nil {
1215// Already initialized; stop now.
1216// This happens in the cmd/asm tests,
1217// each of which re-initializes the arch.
1218return
1219}
1220
1221deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal)
1222
1223symdiv = ctxt.Lookup("runtime._div")
1224symdivu = ctxt.Lookup("runtime._divu")
1225symmod = ctxt.Lookup("runtime._mod")
1226symmodu = ctxt.Lookup("runtime._modu")
1227
1228var n int
1229
1230for i := 0; i < C_GOK; i++ {
1231for n = 0; n < C_GOK; n++ {
1232if cmp(n, i) {
1233xcmp[i][n] = true
1234}
1235}
1236}
1237for n = 0; optab[n].as != obj.AXXX; n++ {
1238if optab[n].flag&LPCREL != 0 {
1239if ctxt.Flag_shared {
1240optab[n].size += int8(optab[n].pcrelsiz)
1241} else {
1242optab[n].flag &^= LPCREL
1243}
1244}
1245}
1246
1247sort.Sort(ocmp(optab[:n]))
1248for i := 0; i < n; i++ {
1249r := optab[i].as
1250r0 := r & obj.AMask
1251start := i
1252for optab[i].as == r {
1253i++
1254}
1255oprange[r0] = optab[start:i]
1256i--
1257
1258switch r {
1259default:
1260ctxt.Diag("unknown op in build: %v", r)
1261ctxt.DiagFlush()
1262log.Fatalf("bad code")
1263
1264case AADD:
1265opset(ASUB, r0)
1266opset(ARSB, r0)
1267opset(AADC, r0)
1268opset(ASBC, r0)
1269opset(ARSC, r0)
1270
1271case AORR:
1272opset(AEOR, r0)
1273opset(ABIC, r0)
1274
1275case ACMP:
1276opset(ATEQ, r0)
1277opset(ACMN, r0)
1278opset(ATST, r0)
1279
1280case AMVN:
1281break
1282
1283case ABEQ:
1284opset(ABNE, r0)
1285opset(ABCS, r0)
1286opset(ABHS, r0)
1287opset(ABCC, r0)
1288opset(ABLO, r0)
1289opset(ABMI, r0)
1290opset(ABPL, r0)
1291opset(ABVS, r0)
1292opset(ABVC, r0)
1293opset(ABHI, r0)
1294opset(ABLS, r0)
1295opset(ABGE, r0)
1296opset(ABLT, r0)
1297opset(ABGT, r0)
1298opset(ABLE, r0)
1299
1300case ASLL:
1301opset(ASRL, r0)
1302opset(ASRA, r0)
1303
1304case AMUL:
1305opset(AMULU, r0)
1306
1307case ADIV:
1308opset(AMOD, r0)
1309opset(AMODU, r0)
1310opset(ADIVU, r0)
1311
1312case ADIVHW:
1313opset(ADIVUHW, r0)
1314
1315case AMOVW,
1316AMOVB,
1317AMOVBS,
1318AMOVBU,
1319AMOVH,
1320AMOVHS,
1321AMOVHU:
1322break
1323
1324case ASWPW:
1325opset(ASWPBU, r0)
1326
1327case AB,
1328ABL,
1329ABX,
1330ABXRET,
1331obj.ADUFFZERO,
1332obj.ADUFFCOPY,
1333ASWI,
1334AWORD,
1335AMOVM,
1336ARFE,
1337obj.ATEXT:
1338break
1339
1340case AADDF:
1341opset(AADDD, r0)
1342opset(ASUBF, r0)
1343opset(ASUBD, r0)
1344opset(AMULF, r0)
1345opset(AMULD, r0)
1346opset(ANMULF, r0)
1347opset(ANMULD, r0)
1348opset(AMULAF, r0)
1349opset(AMULAD, r0)
1350opset(AMULSF, r0)
1351opset(AMULSD, r0)
1352opset(ANMULAF, r0)
1353opset(ANMULAD, r0)
1354opset(ANMULSF, r0)
1355opset(ANMULSD, r0)
1356opset(AFMULAF, r0)
1357opset(AFMULAD, r0)
1358opset(AFMULSF, r0)
1359opset(AFMULSD, r0)
1360opset(AFNMULAF, r0)
1361opset(AFNMULAD, r0)
1362opset(AFNMULSF, r0)
1363opset(AFNMULSD, r0)
1364opset(ADIVF, r0)
1365opset(ADIVD, r0)
1366
1367case ANEGF:
1368opset(ANEGD, r0)
1369opset(ASQRTF, r0)
1370opset(ASQRTD, r0)
1371opset(AMOVFD, r0)
1372opset(AMOVDF, r0)
1373opset(AABSF, r0)
1374opset(AABSD, r0)
1375
1376case ACMPF:
1377opset(ACMPD, r0)
1378
1379case AMOVF:
1380opset(AMOVD, r0)
1381
1382case AMOVFW:
1383opset(AMOVDW, r0)
1384
1385case AMOVWF:
1386opset(AMOVWD, r0)
1387
1388case AMULL:
1389opset(AMULAL, r0)
1390opset(AMULLU, r0)
1391opset(AMULALU, r0)
1392
1393case AMULWT:
1394opset(AMULWB, r0)
1395opset(AMULBB, r0)
1396opset(AMMUL, r0)
1397
1398case AMULAWT:
1399opset(AMULAWB, r0)
1400opset(AMULABB, r0)
1401opset(AMULS, r0)
1402opset(AMMULA, r0)
1403opset(AMMULS, r0)
1404
1405case ABFX:
1406opset(ABFXU, r0)
1407opset(ABFC, r0)
1408opset(ABFI, r0)
1409
1410case ACLZ:
1411opset(AREV, r0)
1412opset(AREV16, r0)
1413opset(AREVSH, r0)
1414opset(ARBIT, r0)
1415
1416case AXTAB:
1417opset(AXTAH, r0)
1418opset(AXTABU, r0)
1419opset(AXTAHU, r0)
1420
1421case ALDREX,
1422ASTREX,
1423ALDREXD,
1424ASTREXD,
1425ADMB,
1426APLD,
1427AAND,
1428AMULA,
1429obj.AUNDEF,
1430obj.AFUNCDATA,
1431obj.APCDATA,
1432obj.ANOP:
1433break
1434}
1435}
1436}
1437
1438func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) {
1439c.printp = p
1440o1 := uint32(0)
1441o2 := uint32(0)
1442o3 := uint32(0)
1443o4 := uint32(0)
1444o5 := uint32(0)
1445o6 := uint32(0)
1446if false { /*debug['P']*/
1447fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
1448}
1449switch o.type_ {
1450default:
1451c.ctxt.Diag("%v: unknown asm %d", p, o.type_)
1452
1453case 0: /* pseudo ops */
1454if false { /*debug['G']*/
1455fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
1456}
1457
1458case 1: /* op R,[R],R */
1459o1 = c.oprrr(p, p.As, int(p.Scond))
1460
1461rf := int(p.From.Reg)
1462rt := int(p.To.Reg)
1463r := int(p.Reg)
1464if p.To.Type == obj.TYPE_NONE {
1465rt = 0
1466}
1467if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN {
1468r = 0
1469} else if r == 0 {
1470r = rt
1471}
1472o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1473
1474case 2: /* movbu $I,[R],R */
1475c.aclass(&p.From)
1476
1477o1 = c.oprrr(p, p.As, int(p.Scond))
1478o1 |= uint32(immrot(uint32(c.instoffset)))
1479rt := int(p.To.Reg)
1480r := int(p.Reg)
1481if p.To.Type == obj.TYPE_NONE {
1482rt = 0
1483}
1484if p.As == AMOVW || p.As == AMVN {
1485r = 0
1486} else if r == 0 {
1487r = rt
1488}
1489o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1490
1491case 106: /* op $I,R,R where I can be decomposed into 2 immediates */
1492c.aclass(&p.From)
1493r := int(p.Reg)
1494rt := int(p.To.Reg)
1495if r == 0 {
1496r = rt
1497}
1498x, y := immrot2a(uint32(c.instoffset))
1499var as2 obj.As
1500switch p.As {
1501case AADD, ASUB, AORR, AEOR, ABIC:
1502as2 = p.As // ADD, SUB, ORR, EOR, BIC
1503case ARSB:
1504as2 = AADD // RSB -> RSB/ADD pair
1505case AADC:
1506as2 = AADD // ADC -> ADC/ADD pair
1507case ASBC:
1508as2 = ASUB // SBC -> SBC/SUB pair
1509case ARSC:
1510as2 = AADD // RSC -> RSC/ADD pair
1511default:
1512c.ctxt.Diag("unknown second op for %v", p)
1513}
1514o1 = c.oprrr(p, p.As, int(p.Scond))
1515o2 = c.oprrr(p, as2, int(p.Scond))
1516o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1517o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12
1518o1 |= x
1519o2 |= y
1520
1521case 107: /* op $I,R,R where I can be decomposed into 2 immediates */
1522c.aclass(&p.From)
1523r := int(p.Reg)
1524rt := int(p.To.Reg)
1525if r == 0 {
1526r = rt
1527}
1528y, x := immrot2s(uint32(c.instoffset))
1529var as2 obj.As
1530switch p.As {
1531case AADD:
1532as2 = ASUB // ADD -> ADD/SUB pair
1533case ASUB:
1534as2 = AADD // SUB -> SUB/ADD pair
1535case ARSB:
1536as2 = ASUB // RSB -> RSB/SUB pair
1537case AADC:
1538as2 = ASUB // ADC -> ADC/SUB pair
1539case ASBC:
1540as2 = AADD // SBC -> SBC/ADD pair
1541case ARSC:
1542as2 = ASUB // RSC -> RSC/SUB pair
1543default:
1544c.ctxt.Diag("unknown second op for %v", p)
1545}
1546o1 = c.oprrr(p, p.As, int(p.Scond))
1547o2 = c.oprrr(p, as2, int(p.Scond))
1548o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1549o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12
1550o1 |= y
1551o2 |= x
1552
1553case 3: /* add R<<[IR],[R],R */
1554o1 = c.mov(p)
1555
1556case 4: /* MOVW $off(R), R -> add $off,[R],R */
1557c.aclass(&p.From)
1558if c.instoffset < 0 {
1559o1 = c.oprrr(p, ASUB, int(p.Scond))
1560o1 |= uint32(immrot(uint32(-c.instoffset)))
1561} else {
1562o1 = c.oprrr(p, AADD, int(p.Scond))
1563o1 |= uint32(immrot(uint32(c.instoffset)))
1564}
1565r := int(p.From.Reg)
1566if r == 0 {
1567r = int(o.param)
1568}
1569o1 |= (uint32(r) & 15) << 16
1570o1 |= (uint32(p.To.Reg) & 15) << 12
1571
1572case 5: /* bra s */
1573o1 = c.opbra(p, p.As, int(p.Scond))
1574
1575v := int32(-8)
1576if p.To.Sym != nil {
1577rel := obj.Addrel(c.cursym)
1578rel.Off = int32(c.pc)
1579rel.Siz = 4
1580rel.Sym = p.To.Sym
1581v += int32(p.To.Offset)
1582rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
1583rel.Type = objabi.R_CALLARM
1584break
1585}
1586
1587if p.To.Target() != nil {
1588v = int32((p.To.Target().Pc - c.pc) - 8)
1589}
1590o1 |= (uint32(v) >> 2) & 0xffffff
1591
1592case 6: /* b ,O(R) -> add $O,R,PC */
1593c.aclass(&p.To)
1594
1595o1 = c.oprrr(p, AADD, int(p.Scond))
1596o1 |= uint32(immrot(uint32(c.instoffset)))
1597o1 |= (uint32(p.To.Reg) & 15) << 16
1598o1 |= (REGPC & 15) << 12
1599
1600case 7: /* bl (R) -> blx R */
1601c.aclass(&p.To)
1602
1603if c.instoffset != 0 {
1604c.ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, c.instoffset)
1605}
1606o1 = c.oprrr(p, ABL, int(p.Scond))
1607o1 |= (uint32(p.To.Reg) & 15) << 0
1608rel := obj.Addrel(c.cursym)
1609rel.Off = int32(c.pc)
1610rel.Siz = 0
1611rel.Type = objabi.R_CALLIND
1612
1613case 8: /* sll $c,[R],R -> mov (R<<$c),R */
1614c.aclass(&p.From)
1615
1616o1 = c.oprrr(p, p.As, int(p.Scond))
1617r := int(p.Reg)
1618if r == 0 {
1619r = int(p.To.Reg)
1620}
1621o1 |= (uint32(r) & 15) << 0
1622o1 |= uint32((c.instoffset & 31) << 7)
1623o1 |= (uint32(p.To.Reg) & 15) << 12
1624
1625case 9: /* sll R,[R],R -> mov (R<<R),R */
1626o1 = c.oprrr(p, p.As, int(p.Scond))
1627
1628r := int(p.Reg)
1629if r == 0 {
1630r = int(p.To.Reg)
1631}
1632o1 |= (uint32(r) & 15) << 0
1633o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4
1634o1 |= (uint32(p.To.Reg) & 15) << 12
1635
1636case 10: /* swi [$con] */
1637o1 = c.oprrr(p, p.As, int(p.Scond))
1638
1639if p.To.Type != obj.TYPE_NONE {
1640c.aclass(&p.To)
1641o1 |= uint32(c.instoffset & 0xffffff)
1642}
1643
1644case 11: /* word */
1645c.aclass(&p.To)
1646
1647o1 = uint32(c.instoffset)
1648if p.To.Sym != nil {
1649// This case happens with words generated
1650// in the PC stream as part of the literal pool (c.pool).
1651rel := obj.Addrel(c.cursym)
1652
1653rel.Off = int32(c.pc)
1654rel.Siz = 4
1655rel.Sym = p.To.Sym
1656rel.Add = p.To.Offset
1657
1658if c.ctxt.Flag_shared {
1659if p.To.Name == obj.NAME_GOTREF {
1660rel.Type = objabi.R_GOTPCREL
1661} else {
1662rel.Type = objabi.R_PCREL
1663}
1664rel.Add += c.pc - p.Rel.Pc - 8
1665} else {
1666rel.Type = objabi.R_ADDR
1667}
1668o1 = 0
1669}
1670
1671case 12: /* movw $lcon, reg */
1672if o.a1 == C_SCON {
1673o1 = c.omvs(p, &p.From, int(p.To.Reg))
1674} else if p.As == AMVN {
1675o1 = c.omvr(p, &p.From, int(p.To.Reg))
1676} else {
1677o1 = c.omvl(p, &p.From, int(p.To.Reg))
1678}
1679
1680if o.flag&LPCREL != 0 {
1681o2 = c.oprrr(p, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
1682}
1683
1684case 13: /* op $lcon, [R], R */
1685if o.a1 == C_SCON {
1686o1 = c.omvs(p, &p.From, REGTMP)
1687} else {
1688o1 = c.omvl(p, &p.From, REGTMP)
1689}
1690
1691if o1 == 0 {
1692break
1693}
1694o2 = c.oprrr(p, p.As, int(p.Scond))
1695o2 |= REGTMP & 15
1696r := int(p.Reg)
1697if p.As == AMVN {
1698r = 0
1699} else if r == 0 {
1700r = int(p.To.Reg)
1701}
1702o2 |= (uint32(r) & 15) << 16
1703if p.To.Type != obj.TYPE_NONE {
1704o2 |= (uint32(p.To.Reg) & 15) << 12
1705}
1706
1707case 14: /* movb/movbu/movh/movhu R,R */
1708o1 = c.oprrr(p, ASLL, int(p.Scond))
1709
1710if p.As == AMOVBU || p.As == AMOVHU {
1711o2 = c.oprrr(p, ASRL, int(p.Scond))
1712} else {
1713o2 = c.oprrr(p, ASRA, int(p.Scond))
1714}
1715
1716r := int(p.To.Reg)
1717o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12
1718o2 |= uint32(r)&15 | (uint32(r)&15)<<12
1719if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
1720o1 |= 24 << 7
1721o2 |= 24 << 7
1722} else {
1723o1 |= 16 << 7
1724o2 |= 16 << 7
1725}
1726
1727case 15: /* mul r,[r,]r */
1728o1 = c.oprrr(p, p.As, int(p.Scond))
1729
1730rf := int(p.From.Reg)
1731rt := int(p.To.Reg)
1732r := int(p.Reg)
1733if r == 0 {
1734r = rt
1735}
1736
1737o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
1738
1739case 16: /* div r,[r,]r */
1740o1 = 0xf << 28
1741
1742o2 = 0
1743
1744case 17:
1745o1 = c.oprrr(p, p.As, int(p.Scond))
1746rf := int(p.From.Reg)
1747rt := int(p.To.Reg)
1748rt2 := int(p.To.Offset)
1749r := int(p.Reg)
1750o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
1751
1752case 18: /* BFX/BFXU/BFC/BFI */
1753o1 = c.oprrr(p, p.As, int(p.Scond))
1754rt := int(p.To.Reg)
1755r := int(p.Reg)
1756if r == 0 {
1757r = rt
1758} else if p.As == ABFC { // only "BFC $width, $lsb, Reg" is accepted, p.Reg must be 0
1759c.ctxt.Diag("illegal combination: %v", p)
1760}
1761if p.GetFrom3() == nil || p.GetFrom3().Type != obj.TYPE_CONST {
1762c.ctxt.Diag("%v: missing or wrong LSB", p)
1763break
1764}
1765lsb := p.GetFrom3().Offset
1766width := p.From.Offset
1767if lsb < 0 || lsb > 31 || width <= 0 || (lsb+width) > 32 {
1768c.ctxt.Diag("%v: wrong width or LSB", p)
1769}
1770switch p.As {
1771case ABFX, ABFXU: // (width-1) is encoded
1772o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(width-1)<<16
1773case ABFC, ABFI: // MSB is encoded
1774o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(lsb+width-1)<<16
1775default:
1776c.ctxt.Diag("illegal combination: %v", p)
1777}
1778
1779case 20: /* mov/movb/movbu R,O(R) */
1780c.aclass(&p.To)
1781
1782r := int(p.To.Reg)
1783if r == 0 {
1784r = int(o.param)
1785}
1786o1 = c.osr(p.As, int(p.From.Reg), int32(c.instoffset), r, int(p.Scond))
1787
1788case 21: /* mov/movbu O(R),R -> lr */
1789c.aclass(&p.From)
1790
1791r := int(p.From.Reg)
1792if r == 0 {
1793r = int(o.param)
1794}
1795o1 = c.olr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond))
1796if p.As != AMOVW {
1797o1 |= 1 << 22
1798}
1799
1800case 22: /* XTAB R@>i, [R], R */
1801o1 = c.oprrr(p, p.As, int(p.Scond))
1802switch p.From.Offset &^ 0xf {
1803// only 0/8/16/24 bits rotation is accepted
1804case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7:
1805o1 |= uint32(p.From.Offset) & 0xc0f
1806default:
1807c.ctxt.Diag("illegal shift: %v", p)
1808}
1809rt := p.To.Reg
1810r := p.Reg
1811if r == 0 {
1812r = rt
1813}
1814o1 |= (uint32(rt)&15)<<12 | (uint32(r)&15)<<16
1815
1816case 23: /* MOVW/MOVB/MOVH R@>i, R */
1817switch p.As {
1818case AMOVW:
1819o1 = c.mov(p)
1820case AMOVBU, AMOVBS, AMOVB, AMOVHU, AMOVHS, AMOVH:
1821o1 = c.movxt(p)
1822default:
1823c.ctxt.Diag("illegal combination: %v", p)
1824}
1825
1826case 30: /* mov/movb/movbu R,L(R) */
1827o1 = c.omvl(p, &p.To, REGTMP)
1828
1829if o1 == 0 {
1830break
1831}
1832r := int(p.To.Reg)
1833if r == 0 {
1834r = int(o.param)
1835}
1836o2 = c.osrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond))
1837if p.As != AMOVW {
1838o2 |= 1 << 22
1839}
1840
1841case 31: /* mov/movbu L(R),R -> lr[b] */
1842o1 = c.omvl(p, &p.From, REGTMP)
1843
1844if o1 == 0 {
1845break
1846}
1847r := int(p.From.Reg)
1848if r == 0 {
1849r = int(o.param)
1850}
1851o2 = c.olrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond))
1852if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
1853o2 |= 1 << 22
1854}
1855
1856case 34: /* mov $lacon,R */
1857o1 = c.omvl(p, &p.From, REGTMP)
1858
1859if o1 == 0 {
1860break
1861}
1862
1863o2 = c.oprrr(p, AADD, int(p.Scond))
1864o2 |= REGTMP & 15
1865r := int(p.From.Reg)
1866if r == 0 {
1867r = int(o.param)
1868}
1869o2 |= (uint32(r) & 15) << 16
1870if p.To.Type != obj.TYPE_NONE {
1871o2 |= (uint32(p.To.Reg) & 15) << 12
1872}
1873
1874case 35: /* mov PSR,R */
1875o1 = 2<<23 | 0xf<<16 | 0<<0
1876
1877o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1878o1 |= (uint32(p.From.Reg) & 1) << 22
1879o1 |= (uint32(p.To.Reg) & 15) << 12
1880
1881case 36: /* mov R,PSR */
1882o1 = 2<<23 | 0x2cf<<12 | 0<<4
1883
1884if p.Scond&C_FBIT != 0 {
1885o1 ^= 0x010 << 12
1886}
1887o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1888o1 |= (uint32(p.To.Reg) & 1) << 22
1889o1 |= (uint32(p.From.Reg) & 15) << 0
1890
1891case 37: /* mov $con,PSR */
1892c.aclass(&p.From)
1893
1894o1 = 2<<23 | 0x2cf<<12 | 0<<4
1895if p.Scond&C_FBIT != 0 {
1896o1 ^= 0x010 << 12
1897}
1898o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1899o1 |= uint32(immrot(uint32(c.instoffset)))
1900o1 |= (uint32(p.To.Reg) & 1) << 22
1901o1 |= (uint32(p.From.Reg) & 15) << 0
1902
1903case 38, 39:
1904switch o.type_ {
1905case 38: /* movm $con,oreg -> stm */
1906o1 = 0x4 << 25
1907
1908o1 |= uint32(p.From.Offset & 0xffff)
1909o1 |= (uint32(p.To.Reg) & 15) << 16
1910c.aclass(&p.To)
1911
1912case 39: /* movm oreg,$con -> ldm */
1913o1 = 0x4<<25 | 1<<20
1914
1915o1 |= uint32(p.To.Offset & 0xffff)
1916o1 |= (uint32(p.From.Reg) & 15) << 16
1917c.aclass(&p.From)
1918}
1919
1920if c.instoffset != 0 {
1921c.ctxt.Diag("offset must be zero in MOVM; %v", p)
1922}
1923o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1924if p.Scond&C_PBIT != 0 {
1925o1 |= 1 << 24
1926}
1927if p.Scond&C_UBIT != 0 {
1928o1 |= 1 << 23
1929}
1930if p.Scond&C_WBIT != 0 {
1931o1 |= 1 << 21
1932}
1933
1934case 40: /* swp oreg,reg,reg */
1935c.aclass(&p.From)
1936
1937if c.instoffset != 0 {
1938c.ctxt.Diag("offset must be zero in SWP")
1939}
1940o1 = 0x2<<23 | 0x9<<4
1941if p.As != ASWPW {
1942o1 |= 1 << 22
1943}
1944o1 |= (uint32(p.From.Reg) & 15) << 16
1945o1 |= (uint32(p.Reg) & 15) << 0
1946o1 |= (uint32(p.To.Reg) & 15) << 12
1947o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1948
1949case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
1950o1 = 0xe8fd8000
1951
1952case 50: /* floating point store */
1953v := c.regoff(&p.To)
1954
1955r := int(p.To.Reg)
1956if r == 0 {
1957r = int(o.param)
1958}
1959o1 = c.ofsr(p.As, int(p.From.Reg), v, r, int(p.Scond), p)
1960
1961case 51: /* floating point load */
1962v := c.regoff(&p.From)
1963
1964r := int(p.From.Reg)
1965if r == 0 {
1966r = int(o.param)
1967}
1968o1 = c.ofsr(p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
1969
1970case 52: /* floating point store, int32 offset UGLY */
1971o1 = c.omvl(p, &p.To, REGTMP)
1972
1973if o1 == 0 {
1974break
1975}
1976r := int(p.To.Reg)
1977if r == 0 {
1978r = int(o.param)
1979}
1980o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
1981o3 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
1982
1983case 53: /* floating point load, int32 offset UGLY */
1984o1 = c.omvl(p, &p.From, REGTMP)
1985
1986if o1 == 0 {
1987break
1988}
1989r := int(p.From.Reg)
1990if r == 0 {
1991r = int(o.param)
1992}
1993o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
1994o3 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
1995
1996case 54: /* floating point arith */
1997o1 = c.oprrr(p, p.As, int(p.Scond))
1998
1999rf := int(p.From.Reg)
2000rt := int(p.To.Reg)
2001r := int(p.Reg)
2002if r == 0 {
2003switch p.As {
2004case AMULAD, AMULAF, AMULSF, AMULSD, ANMULAF, ANMULAD, ANMULSF, ANMULSD,
2005AFMULAD, AFMULAF, AFMULSF, AFMULSD, AFNMULAF, AFNMULAD, AFNMULSF, AFNMULSD:
2006c.ctxt.Diag("illegal combination: %v", p)
2007default:
2008r = rt
2009}
2010}
2011
2012o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
2013
2014case 55: /* negf freg, freg */
2015o1 = c.oprrr(p, p.As, int(p.Scond))
2016
2017rf := int(p.From.Reg)
2018rt := int(p.To.Reg)
2019
2020o1 |= (uint32(rf)&15)<<0 | (uint32(rt)&15)<<12
2021
2022case 56: /* move to FP[CS]R */
2023o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xee1<<16 | 0xa1<<4
2024
2025o1 |= (uint32(p.From.Reg) & 15) << 12
2026
2027case 57: /* move from FP[CS]R */
2028o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xef1<<16 | 0xa1<<4
2029
2030o1 |= (uint32(p.To.Reg) & 15) << 12
2031
2032case 58: /* movbu R,R */
2033o1 = c.oprrr(p, AAND, int(p.Scond))
2034
2035o1 |= uint32(immrot(0xff))
2036rt := int(p.To.Reg)
2037r := int(p.From.Reg)
2038if p.To.Type == obj.TYPE_NONE {
2039rt = 0
2040}
2041if r == 0 {
2042r = rt
2043}
2044o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
2045
2046case 59: /* movw/bu R<<I(R),R -> ldr indexed */
2047if p.From.Reg == 0 {
2048c.ctxt.Diag("source operand is not a memory address: %v", p)
2049break
2050}
2051if p.From.Offset&(1<<4) != 0 {
2052c.ctxt.Diag("bad shift in LDR")
2053break
2054}
2055o1 = c.olrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
2056if p.As == AMOVBU {
2057o1 |= 1 << 22
2058}
2059
2060case 60: /* movb R(R),R -> ldrsb indexed */
2061if p.From.Reg == 0 {
2062c.ctxt.Diag("source operand is not a memory address: %v", p)
2063break
2064}
2065if p.From.Offset&(^0xf) != 0 {
2066c.ctxt.Diag("bad shift: %v", p)
2067break
2068}
2069o1 = c.olhrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
2070switch p.As {
2071case AMOVB, AMOVBS:
2072o1 ^= 1<<5 | 1<<6
2073case AMOVH, AMOVHS:
2074o1 ^= 1 << 6
2075default:
2076}
2077if p.Scond&C_UBIT != 0 {
2078o1 &^= 1 << 23
2079}
2080
2081case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
2082if p.To.Reg == 0 {
2083c.ctxt.Diag("MOV to shifter operand")
2084}
2085o1 = c.osrr(int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
2086if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
2087o1 |= 1 << 22
2088}
2089
2090case 62: /* MOVH/MOVHS/MOVHU Reg, Reg<<0(Reg) -> strh */
2091if p.To.Reg == 0 {
2092c.ctxt.Diag("MOV to shifter operand")
2093}
2094if p.To.Offset&(^0xf) != 0 {
2095c.ctxt.Diag("bad shift: %v", p)
2096}
2097o1 = c.olhrr(int(p.To.Offset), int(p.To.Reg), int(p.From.Reg), int(p.Scond))
2098o1 ^= 1 << 20
2099if p.Scond&C_UBIT != 0 {
2100o1 &^= 1 << 23
2101}
2102
2103/* reloc ops */
2104case 64: /* mov/movb/movbu R,addr */
2105o1 = c.omvl(p, &p.To, REGTMP)
2106
2107if o1 == 0 {
2108break
2109}
2110o2 = c.osr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond))
2111if o.flag&LPCREL != 0 {
2112o3 = o2
2113o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2114}
2115
2116case 65: /* mov/movbu addr,R */
2117o1 = c.omvl(p, &p.From, REGTMP)
2118
2119if o1 == 0 {
2120break
2121}
2122o2 = c.olr(0, REGTMP, int(p.To.Reg), int(p.Scond))
2123if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
2124o2 |= 1 << 22
2125}
2126if o.flag&LPCREL != 0 {
2127o3 = o2
2128o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2129}
2130
2131case 101: /* movw tlsvar,R, local exec*/
2132o1 = c.omvl(p, &p.From, int(p.To.Reg))
2133
2134case 102: /* movw tlsvar,R, initial exec*/
2135o1 = c.omvl(p, &p.From, int(p.To.Reg))
2136o2 = c.olrr(int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond))
2137
2138case 103: /* word tlsvar, local exec */
2139if p.To.Sym == nil {
2140c.ctxt.Diag("nil sym in tls %v", p)
2141}
2142if p.To.Offset != 0 {
2143c.ctxt.Diag("offset against tls var in %v", p)
2144}
2145// This case happens with words generated in the PC stream as part of
2146// the literal c.pool.
2147rel := obj.Addrel(c.cursym)
2148
2149rel.Off = int32(c.pc)
2150rel.Siz = 4
2151rel.Sym = p.To.Sym
2152rel.Type = objabi.R_TLS_LE
2153o1 = 0
2154
2155case 104: /* word tlsvar, initial exec */
2156if p.To.Sym == nil {
2157c.ctxt.Diag("nil sym in tls %v", p)
2158}
2159if p.To.Offset != 0 {
2160c.ctxt.Diag("offset against tls var in %v", p)
2161}
2162rel := obj.Addrel(c.cursym)
2163rel.Off = int32(c.pc)
2164rel.Siz = 4
2165rel.Sym = p.To.Sym
2166rel.Type = objabi.R_TLS_IE
2167rel.Add = c.pc - p.Rel.Pc - 8 - int64(rel.Siz)
2168
2169case 68: /* floating point store -> ADDR */
2170o1 = c.omvl(p, &p.To, REGTMP)
2171
2172if o1 == 0 {
2173break
2174}
2175o2 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
2176if o.flag&LPCREL != 0 {
2177o3 = o2
2178o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2179}
2180
2181case 69: /* floating point load <- ADDR */
2182o1 = c.omvl(p, &p.From, REGTMP)
2183
2184if o1 == 0 {
2185break
2186}
2187o2 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
2188if o.flag&LPCREL != 0 {
2189o3 = o2
2190o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2191}
2192
2193/* ArmV4 ops: */
2194case 70: /* movh/movhu R,O(R) -> strh */
2195c.aclass(&p.To)
2196
2197r := int(p.To.Reg)
2198if r == 0 {
2199r = int(o.param)
2200}
2201o1 = c.oshr(int(p.From.Reg), int32(c.instoffset), r, int(p.Scond))
2202
2203case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
2204c.aclass(&p.From)
2205
2206r := int(p.From.Reg)
2207if r == 0 {
2208r = int(o.param)
2209}
2210o1 = c.olhr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond))
2211if p.As == AMOVB || p.As == AMOVBS {
2212o1 ^= 1<<5 | 1<<6
2213} else if p.As == AMOVH || p.As == AMOVHS {
2214o1 ^= (1 << 6)
2215}
2216
2217case 72: /* movh/movhu R,L(R) -> strh */
2218o1 = c.omvl(p, &p.To, REGTMP)
2219
2220if o1 == 0 {
2221break
2222}
2223r := int(p.To.Reg)
2224if r == 0 {
2225r = int(o.param)
2226}
2227o2 = c.oshrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond))
2228
2229case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
2230o1 = c.omvl(p, &p.From, REGTMP)
2231
2232if o1 == 0 {
2233break
2234}
2235r := int(p.From.Reg)
2236if r == 0 {
2237r = int(o.param)
2238}
2239o2 = c.olhrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond))
2240if p.As == AMOVB || p.As == AMOVBS {
2241o2 ^= 1<<5 | 1<<6
2242} else if p.As == AMOVH || p.As == AMOVHS {
2243o2 ^= (1 << 6)
2244}
2245
2246case 74: /* bx $I */
2247c.ctxt.Diag("ABX $I")
2248
2249case 75: /* bx O(R) */
2250c.aclass(&p.To)
2251
2252if c.instoffset != 0 {
2253c.ctxt.Diag("non-zero offset in ABX")
2254}
2255
2256/*
2257o1 = c.oprrr(p, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR
2258o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R
2259*/
2260// p->to.reg may be REGLINK
2261o1 = c.oprrr(p, AADD, int(p.Scond))
2262
2263o1 |= uint32(immrot(uint32(c.instoffset)))
2264o1 |= (uint32(p.To.Reg) & 15) << 16
2265o1 |= (REGTMP & 15) << 12
2266o2 = c.oprrr(p, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
2267o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp
2268
2269case 76: /* bx O(R) when returning from fn*/
2270c.ctxt.Diag("ABXRET")
2271
2272case 77: /* ldrex oreg,reg */
2273c.aclass(&p.From)
2274
2275if c.instoffset != 0 {
2276c.ctxt.Diag("offset must be zero in LDREX")
2277}
2278o1 = 0x19<<20 | 0xf9f
2279o1 |= (uint32(p.From.Reg) & 15) << 16
2280o1 |= (uint32(p.To.Reg) & 15) << 12
2281o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2282
2283case 78: /* strex reg,oreg,reg */
2284c.aclass(&p.From)
2285
2286if c.instoffset != 0 {
2287c.ctxt.Diag("offset must be zero in STREX")
2288}
2289if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg {
2290c.ctxt.Diag("cannot use same register as both source and destination: %v", p)
2291}
2292o1 = 0x18<<20 | 0xf90
2293o1 |= (uint32(p.From.Reg) & 15) << 16
2294o1 |= (uint32(p.Reg) & 15) << 0
2295o1 |= (uint32(p.To.Reg) & 15) << 12
2296o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2297
2298case 80: /* fmov zfcon,freg */
2299if p.As == AMOVD {
2300o1 = 0xeeb00b00 // VMOV imm 64
2301o2 = c.oprrr(p, ASUBD, int(p.Scond))
2302} else {
2303o1 = 0x0eb00a00 // VMOV imm 32
2304o2 = c.oprrr(p, ASUBF, int(p.Scond))
2305}
2306
2307v := int32(0x70) // 1.0
2308r := (int(p.To.Reg) & 15) << 0
2309
2310// movf $1.0, r
2311o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2312
2313o1 |= (uint32(r) & 15) << 12
2314o1 |= (uint32(v) & 0xf) << 0
2315o1 |= (uint32(v) & 0xf0) << 12
2316
2317// subf r,r,r
2318o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12
2319
2320case 81: /* fmov sfcon,freg */
2321o1 = 0x0eb00a00 // VMOV imm 32
2322if p.As == AMOVD {
2323o1 = 0xeeb00b00 // VMOV imm 64
2324}
2325o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2326o1 |= (uint32(p.To.Reg) & 15) << 12
2327v := int32(c.chipfloat5(p.From.Val.(float64)))
2328o1 |= (uint32(v) & 0xf) << 0
2329o1 |= (uint32(v) & 0xf0) << 12
2330
2331case 82: /* fcmp freg,freg, */
2332o1 = c.oprrr(p, p.As, int(p.Scond))
2333
2334o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0
2335o2 = 0x0ef1fa10 // VMRS R15
2336o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2337
2338case 83: /* fcmp freg,, */
2339o1 = c.oprrr(p, p.As, int(p.Scond))
2340
2341o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16
2342o2 = 0x0ef1fa10 // VMRS R15
2343o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2344
2345case 84: /* movfw freg,freg - truncate float-to-fix */
2346o1 = c.oprrr(p, p.As, int(p.Scond))
2347
2348o1 |= (uint32(p.From.Reg) & 15) << 0
2349o1 |= (uint32(p.To.Reg) & 15) << 12
2350
2351case 85: /* movwf freg,freg - fix-to-float */
2352o1 = c.oprrr(p, p.As, int(p.Scond))
2353
2354o1 |= (uint32(p.From.Reg) & 15) << 0
2355o1 |= (uint32(p.To.Reg) & 15) << 12
2356
2357// macro for movfw freg,FTMP; movw FTMP,reg
2358case 86: /* movfw freg,reg - truncate float-to-fix */
2359o1 = c.oprrr(p, p.As, int(p.Scond))
2360
2361o1 |= (uint32(p.From.Reg) & 15) << 0
2362o1 |= (FREGTMP & 15) << 12
2363o2 = c.oprrr(p, -AMOVFW, int(p.Scond))
2364o2 |= (FREGTMP & 15) << 16
2365o2 |= (uint32(p.To.Reg) & 15) << 12
2366
2367// macro for movw reg,FTMP; movwf FTMP,freg
2368case 87: /* movwf reg,freg - fix-to-float */
2369o1 = c.oprrr(p, -AMOVWF, int(p.Scond))
2370
2371o1 |= (uint32(p.From.Reg) & 15) << 12
2372o1 |= (FREGTMP & 15) << 16
2373o2 = c.oprrr(p, p.As, int(p.Scond))
2374o2 |= (FREGTMP & 15) << 0
2375o2 |= (uint32(p.To.Reg) & 15) << 12
2376
2377case 88: /* movw reg,freg */
2378o1 = c.oprrr(p, -AMOVWF, int(p.Scond))
2379
2380o1 |= (uint32(p.From.Reg) & 15) << 12
2381o1 |= (uint32(p.To.Reg) & 15) << 16
2382
2383case 89: /* movw freg,reg */
2384o1 = c.oprrr(p, -AMOVFW, int(p.Scond))
2385
2386o1 |= (uint32(p.From.Reg) & 15) << 16
2387o1 |= (uint32(p.To.Reg) & 15) << 12
2388
2389case 91: /* ldrexd oreg,reg */
2390c.aclass(&p.From)
2391
2392if c.instoffset != 0 {
2393c.ctxt.Diag("offset must be zero in LDREX")
2394}
2395o1 = 0x1b<<20 | 0xf9f
2396o1 |= (uint32(p.From.Reg) & 15) << 16
2397o1 |= (uint32(p.To.Reg) & 15) << 12
2398o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2399
2400case 92: /* strexd reg,oreg,reg */
2401c.aclass(&p.From)
2402
2403if c.instoffset != 0 {
2404c.ctxt.Diag("offset must be zero in STREX")
2405}
2406if p.Reg&1 != 0 {
2407c.ctxt.Diag("source register must be even in STREXD: %v", p)
2408}
2409if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg || p.To.Reg == p.Reg+1 {
2410c.ctxt.Diag("cannot use same register as both source and destination: %v", p)
2411}
2412o1 = 0x1a<<20 | 0xf90
2413o1 |= (uint32(p.From.Reg) & 15) << 16
2414o1 |= (uint32(p.Reg) & 15) << 0
2415o1 |= (uint32(p.To.Reg) & 15) << 12
2416o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2417
2418case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
2419o1 = c.omvl(p, &p.From, REGTMP)
2420
2421if o1 == 0 {
2422break
2423}
2424o2 = c.olhr(0, REGTMP, int(p.To.Reg), int(p.Scond))
2425if p.As == AMOVB || p.As == AMOVBS {
2426o2 ^= 1<<5 | 1<<6
2427} else if p.As == AMOVH || p.As == AMOVHS {
2428o2 ^= (1 << 6)
2429}
2430if o.flag&LPCREL != 0 {
2431o3 = o2
2432o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2433}
2434
2435case 94: /* movh/movhu R,addr -> strh */
2436o1 = c.omvl(p, &p.To, REGTMP)
2437
2438if o1 == 0 {
2439break
2440}
2441o2 = c.oshr(int(p.From.Reg), 0, REGTMP, int(p.Scond))
2442if o.flag&LPCREL != 0 {
2443o3 = o2
2444o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2445}
2446
2447case 95: /* PLD off(reg) */
2448o1 = 0xf5d0f000
2449
2450o1 |= (uint32(p.From.Reg) & 15) << 16
2451if p.From.Offset < 0 {
2452o1 &^= (1 << 23)
2453o1 |= uint32((-p.From.Offset) & 0xfff)
2454} else {
2455o1 |= uint32(p.From.Offset & 0xfff)
2456}
2457
2458// This is supposed to be something that stops execution.
2459// It's not supposed to be reached, ever, but if it is, we'd
2460// like to be able to tell how we got there. Assemble as
2461// 0xf7fabcfd which is guaranteed to raise undefined instruction
2462// exception.
2463case 96: /* UNDEF */
2464o1 = 0xf7fabcfd
2465
2466case 97: /* CLZ Rm, Rd */
2467o1 = c.oprrr(p, p.As, int(p.Scond))
2468
2469o1 |= (uint32(p.To.Reg) & 15) << 12
2470o1 |= (uint32(p.From.Reg) & 15) << 0
2471
2472case 98: /* MULW{T,B} Rs, Rm, Rd */
2473o1 = c.oprrr(p, p.As, int(p.Scond))
2474
2475o1 |= (uint32(p.To.Reg) & 15) << 16
2476o1 |= (uint32(p.From.Reg) & 15) << 8
2477o1 |= (uint32(p.Reg) & 15) << 0
2478
2479case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
2480o1 = c.oprrr(p, p.As, int(p.Scond))
2481
2482o1 |= (uint32(p.To.Reg) & 15) << 16
2483o1 |= (uint32(p.From.Reg) & 15) << 8
2484o1 |= (uint32(p.Reg) & 15) << 0
2485o1 |= uint32((p.To.Offset & 15) << 12)
2486
2487case 105: /* divhw r,[r,]r */
2488o1 = c.oprrr(p, p.As, int(p.Scond))
2489rf := int(p.From.Reg)
2490rt := int(p.To.Reg)
2491r := int(p.Reg)
2492if r == 0 {
2493r = rt
2494}
2495o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
2496
2497case 110: /* dmb [mbop | $con] */
2498o1 = 0xf57ff050
2499mbop := uint32(0)
2500
2501switch c.aclass(&p.From) {
2502case C_SPR:
2503for _, f := range mbOp {
2504if f.reg == p.From.Reg {
2505mbop = f.enc
2506break
2507}
2508}
2509case C_RCON:
2510for _, f := range mbOp {
2511enc := uint32(c.instoffset)
2512if f.enc == enc {
2513mbop = enc
2514break
2515}
2516}
2517case C_NONE:
2518mbop = 0xf
2519}
2520
2521if mbop == 0 {
2522c.ctxt.Diag("illegal mb option:\n%v", p)
2523}
2524o1 |= mbop
2525}
2526
2527out[0] = o1
2528out[1] = o2
2529out[2] = o3
2530out[3] = o4
2531out[4] = o5
2532out[5] = o6
2533}
2534
2535func (c *ctxt5) movxt(p *obj.Prog) uint32 {
2536o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2537switch p.As {
2538case AMOVB, AMOVBS:
2539o1 |= 0x6af<<16 | 0x7<<4
2540case AMOVH, AMOVHS:
2541o1 |= 0x6bf<<16 | 0x7<<4
2542case AMOVBU:
2543o1 |= 0x6ef<<16 | 0x7<<4
2544case AMOVHU:
2545o1 |= 0x6ff<<16 | 0x7<<4
2546default:
2547c.ctxt.Diag("illegal combination: %v", p)
2548}
2549switch p.From.Offset &^ 0xf {
2550// only 0/8/16/24 bits rotation is accepted
2551case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7:
2552o1 |= uint32(p.From.Offset) & 0xc0f
2553default:
2554c.ctxt.Diag("illegal shift: %v", p)
2555}
2556o1 |= (uint32(p.To.Reg) & 15) << 12
2557return o1
2558}
2559
2560func (c *ctxt5) mov(p *obj.Prog) uint32 {
2561c.aclass(&p.From)
2562o1 := c.oprrr(p, p.As, int(p.Scond))
2563o1 |= uint32(p.From.Offset)
2564rt := int(p.To.Reg)
2565if p.To.Type == obj.TYPE_NONE {
2566rt = 0
2567}
2568r := int(p.Reg)
2569if p.As == AMOVW || p.As == AMVN {
2570r = 0
2571} else if r == 0 {
2572r = rt
2573}
2574o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
2575return o1
2576}
2577
2578func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 {
2579o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2580if sc&C_SBIT != 0 {
2581o |= 1 << 20
2582}
2583switch a {
2584case ADIVHW:
2585return o | 0x71<<20 | 0xf<<12 | 0x1<<4
2586case ADIVUHW:
2587return o | 0x73<<20 | 0xf<<12 | 0x1<<4
2588case AMMUL:
2589return o | 0x75<<20 | 0xf<<12 | 0x1<<4
2590case AMULS:
2591return o | 0x6<<20 | 0x9<<4
2592case AMMULA:
2593return o | 0x75<<20 | 0x1<<4
2594case AMMULS:
2595return o | 0x75<<20 | 0xd<<4
2596case AMULU, AMUL:
2597return o | 0x0<<21 | 0x9<<4
2598case AMULA:
2599return o | 0x1<<21 | 0x9<<4
2600case AMULLU:
2601return o | 0x4<<21 | 0x9<<4
2602case AMULL:
2603return o | 0x6<<21 | 0x9<<4
2604case AMULALU:
2605return o | 0x5<<21 | 0x9<<4
2606case AMULAL:
2607return o | 0x7<<21 | 0x9<<4
2608case AAND:
2609return o | 0x0<<21
2610case AEOR:
2611return o | 0x1<<21
2612case ASUB:
2613return o | 0x2<<21
2614case ARSB:
2615return o | 0x3<<21
2616case AADD:
2617return o | 0x4<<21
2618case AADC:
2619return o | 0x5<<21
2620case ASBC:
2621return o | 0x6<<21
2622case ARSC:
2623return o | 0x7<<21
2624case ATST:
2625return o | 0x8<<21 | 1<<20
2626case ATEQ:
2627return o | 0x9<<21 | 1<<20
2628case ACMP:
2629return o | 0xa<<21 | 1<<20
2630case ACMN:
2631return o | 0xb<<21 | 1<<20
2632case AORR:
2633return o | 0xc<<21
2634
2635case AMOVB, AMOVH, AMOVW:
2636if sc&(C_PBIT|C_WBIT) != 0 {
2637c.ctxt.Diag("invalid .P/.W suffix: %v", p)
2638}
2639return o | 0xd<<21
2640case ABIC:
2641return o | 0xe<<21
2642case AMVN:
2643return o | 0xf<<21
2644case ASLL:
2645return o | 0xd<<21 | 0<<5
2646case ASRL:
2647return o | 0xd<<21 | 1<<5
2648case ASRA:
2649return o | 0xd<<21 | 2<<5
2650case ASWI:
2651return o | 0xf<<24
2652
2653case AADDD:
2654return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4
2655case AADDF:
2656return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4
2657case ASUBD:
2658return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4
2659case ASUBF:
2660return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4
2661case AMULD:
2662return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4
2663case AMULF:
2664return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4
2665case ANMULD:
2666return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0x4<<4
2667case ANMULF:
2668return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0x4<<4
2669case AMULAD:
2670return o | 0xe<<24 | 0xb<<8
2671case AMULAF:
2672return o | 0xe<<24 | 0xa<<8
2673case AMULSD:
2674return o | 0xe<<24 | 0xb<<8 | 0x4<<4
2675case AMULSF:
2676return o | 0xe<<24 | 0xa<<8 | 0x4<<4
2677case ANMULAD:
2678return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 0x4<<4
2679case ANMULAF:
2680return o | 0xe<<24 | 0x1<<20 | 0xa<<8 | 0x4<<4
2681case ANMULSD:
2682return o | 0xe<<24 | 0x1<<20 | 0xb<<8
2683case ANMULSF:
2684return o | 0xe<<24 | 0x1<<20 | 0xa<<8
2685case AFMULAD:
2686return o | 0xe<<24 | 0xa<<20 | 0xb<<8
2687case AFMULAF:
2688return o | 0xe<<24 | 0xa<<20 | 0xa<<8
2689case AFMULSD:
2690return o | 0xe<<24 | 0xa<<20 | 0xb<<8 | 0x4<<4
2691case AFMULSF:
2692return o | 0xe<<24 | 0xa<<20 | 0xa<<8 | 0x4<<4
2693case AFNMULAD:
2694return o | 0xe<<24 | 0x9<<20 | 0xb<<8 | 0x4<<4
2695case AFNMULAF:
2696return o | 0xe<<24 | 0x9<<20 | 0xa<<8 | 0x4<<4
2697case AFNMULSD:
2698return o | 0xe<<24 | 0x9<<20 | 0xb<<8
2699case AFNMULSF:
2700return o | 0xe<<24 | 0x9<<20 | 0xa<<8
2701case ADIVD:
2702return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4
2703case ADIVF:
2704return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4
2705case ASQRTD:
2706return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4
2707case ASQRTF:
2708return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4
2709case AABSD:
2710return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
2711case AABSF:
2712return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
2713case ANEGD:
2714return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4
2715case ANEGF:
2716return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4
2717case ACMPD:
2718return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
2719case ACMPF:
2720return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4
2721
2722case AMOVF:
2723return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4
2724case AMOVD:
2725return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4
2726
2727case AMOVDF:
2728return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof
2729case AMOVFD:
2730return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof
2731
2732case AMOVWF:
2733if sc&C_UBIT == 0 {
2734o |= 1 << 7 /* signed */
2735}
2736return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double
2737
2738case AMOVWD:
2739if sc&C_UBIT == 0 {
2740o |= 1 << 7 /* signed */
2741}
2742return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double
2743
2744case AMOVFW:
2745if sc&C_UBIT == 0 {
2746o |= 1 << 16 /* signed */
2747}
2748return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc
2749
2750case AMOVDW:
2751if sc&C_UBIT == 0 {
2752o |= 1 << 16 /* signed */
2753}
2754return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc
2755
2756case -AMOVWF: // copy WtoF
2757return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
2758
2759case -AMOVFW: // copy FtoW
2760return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
2761
2762case -ACMP: // cmp imm
2763return o | 0x3<<24 | 0x5<<20
2764
2765case ABFX:
2766return o | 0x3d<<21 | 0x5<<4
2767
2768case ABFXU:
2769return o | 0x3f<<21 | 0x5<<4
2770
2771case ABFC:
2772return o | 0x3e<<21 | 0x1f
2773
2774case ABFI:
2775return o | 0x3e<<21 | 0x1<<4
2776
2777case AXTAB:
2778return o | 0x6a<<20 | 0x7<<4
2779
2780case AXTAH:
2781return o | 0x6b<<20 | 0x7<<4
2782
2783case AXTABU:
2784return o | 0x6e<<20 | 0x7<<4
2785
2786case AXTAHU:
2787return o | 0x6f<<20 | 0x7<<4
2788
2789// CLZ doesn't support .nil
2790case ACLZ:
2791return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
2792
2793case AREV:
2794return o&(0xf<<28) | 0x6bf<<16 | 0xf3<<4
2795
2796case AREV16:
2797return o&(0xf<<28) | 0x6bf<<16 | 0xfb<<4
2798
2799case AREVSH:
2800return o&(0xf<<28) | 0x6ff<<16 | 0xfb<<4
2801
2802case ARBIT:
2803return o&(0xf<<28) | 0x6ff<<16 | 0xf3<<4
2804
2805case AMULWT:
2806return o&(0xf<<28) | 0x12<<20 | 0xe<<4
2807
2808case AMULWB:
2809return o&(0xf<<28) | 0x12<<20 | 0xa<<4
2810
2811case AMULBB:
2812return o&(0xf<<28) | 0x16<<20 | 0x8<<4
2813
2814case AMULAWT:
2815return o&(0xf<<28) | 0x12<<20 | 0xc<<4
2816
2817case AMULAWB:
2818return o&(0xf<<28) | 0x12<<20 | 0x8<<4
2819
2820case AMULABB:
2821return o&(0xf<<28) | 0x10<<20 | 0x8<<4
2822
2823case ABL: // BLX REG
2824return o&(0xf<<28) | 0x12fff3<<4
2825}
2826
2827c.ctxt.Diag("%v: bad rrr %d", p, a)
2828return 0
2829}
2830
2831func (c *ctxt5) opbra(p *obj.Prog, a obj.As, sc int) uint32 {
2832sc &= C_SCOND
2833sc ^= C_SCOND_XOR
2834if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
2835return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
2836}
2837if sc != 0xe {
2838c.ctxt.Diag("%v: .COND on bcond instruction", p)
2839}
2840switch a {
2841case ABEQ:
2842return 0x0<<28 | 0x5<<25
2843case ABNE:
2844return 0x1<<28 | 0x5<<25
2845case ABCS:
2846return 0x2<<28 | 0x5<<25
2847case ABHS:
2848return 0x2<<28 | 0x5<<25
2849case ABCC:
2850return 0x3<<28 | 0x5<<25
2851case ABLO:
2852return 0x3<<28 | 0x5<<25
2853case ABMI:
2854return 0x4<<28 | 0x5<<25
2855case ABPL:
2856return 0x5<<28 | 0x5<<25
2857case ABVS:
2858return 0x6<<28 | 0x5<<25
2859case ABVC:
2860return 0x7<<28 | 0x5<<25
2861case ABHI:
2862return 0x8<<28 | 0x5<<25
2863case ABLS:
2864return 0x9<<28 | 0x5<<25
2865case ABGE:
2866return 0xa<<28 | 0x5<<25
2867case ABLT:
2868return 0xb<<28 | 0x5<<25
2869case ABGT:
2870return 0xc<<28 | 0x5<<25
2871case ABLE:
2872return 0xd<<28 | 0x5<<25
2873case AB:
2874return 0xe<<28 | 0x5<<25
2875}
2876
2877c.ctxt.Diag("%v: bad bra %v", p, a)
2878return 0
2879}
2880
2881func (c *ctxt5) olr(v int32, b int, r int, sc int) uint32 {
2882o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2883if sc&C_PBIT == 0 {
2884o |= 1 << 24
2885}
2886if sc&C_UBIT == 0 {
2887o |= 1 << 23
2888}
2889if sc&C_WBIT != 0 {
2890o |= 1 << 21
2891}
2892o |= 1<<26 | 1<<20
2893if v < 0 {
2894if sc&C_UBIT != 0 {
2895c.ctxt.Diag(".U on neg offset")
2896}
2897v = -v
2898o ^= 1 << 23
2899}
2900
2901if v >= 1<<12 || v < 0 {
2902c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp)
2903}
2904o |= uint32(v)
2905o |= (uint32(b) & 15) << 16
2906o |= (uint32(r) & 15) << 12
2907return o
2908}
2909
2910func (c *ctxt5) olhr(v int32, b int, r int, sc int) uint32 {
2911o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2912if sc&C_PBIT == 0 {
2913o |= 1 << 24
2914}
2915if sc&C_WBIT != 0 {
2916o |= 1 << 21
2917}
2918o |= 1<<23 | 1<<20 | 0xb<<4
2919if v < 0 {
2920v = -v
2921o ^= 1 << 23
2922}
2923
2924if v >= 1<<8 || v < 0 {
2925c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp)
2926}
2927o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
2928o |= (uint32(b) & 15) << 16
2929o |= (uint32(r) & 15) << 12
2930return o
2931}
2932
2933func (c *ctxt5) osr(a obj.As, r int, v int32, b int, sc int) uint32 {
2934o := c.olr(v, b, r, sc) ^ (1 << 20)
2935if a != AMOVW {
2936o |= 1 << 22
2937}
2938return o
2939}
2940
2941func (c *ctxt5) oshr(r int, v int32, b int, sc int) uint32 {
2942o := c.olhr(v, b, r, sc) ^ (1 << 20)
2943return o
2944}
2945
2946func (c *ctxt5) osrr(r int, i int, b int, sc int) uint32 {
2947return c.olr(int32(i), b, r, sc) ^ (1<<25 | 1<<20)
2948}
2949
2950func (c *ctxt5) oshrr(r int, i int, b int, sc int) uint32 {
2951return c.olhr(int32(i), b, r, sc) ^ (1<<22 | 1<<20)
2952}
2953
2954func (c *ctxt5) olrr(i int, b int, r int, sc int) uint32 {
2955return c.olr(int32(i), b, r, sc) ^ (1 << 25)
2956}
2957
2958func (c *ctxt5) olhrr(i int, b int, r int, sc int) uint32 {
2959return c.olhr(int32(i), b, r, sc) ^ (1 << 22)
2960}
2961
2962func (c *ctxt5) ofsr(a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
2963o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2964if sc&C_PBIT == 0 {
2965o |= 1 << 24
2966}
2967if sc&C_WBIT != 0 {
2968o |= 1 << 21
2969}
2970o |= 6<<25 | 1<<24 | 1<<23 | 10<<8
2971if v < 0 {
2972v = -v
2973o ^= 1 << 23
2974}
2975
2976if v&3 != 0 {
2977c.ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
2978} else if v >= 1<<10 || v < 0 {
2979c.ctxt.Diag("literal span too large: %d\n%v", v, p)
2980}
2981o |= (uint32(v) >> 2) & 0xFF
2982o |= (uint32(b) & 15) << 16
2983o |= (uint32(r) & 15) << 12
2984
2985switch a {
2986default:
2987c.ctxt.Diag("bad fst %v", a)
2988fallthrough
2989
2990case AMOVD:
2991o |= 1 << 8
2992fallthrough
2993
2994case AMOVF:
2995break
2996}
2997
2998return o
2999}
3000
3001// MOVW $"lower 16-bit", Reg
3002func (c *ctxt5) omvs(p *obj.Prog, a *obj.Addr, dr int) uint32 {
3003o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
3004o1 |= 0x30 << 20
3005o1 |= (uint32(dr) & 15) << 12
3006o1 |= uint32(a.Offset) & 0x0fff
3007o1 |= (uint32(a.Offset) & 0xf000) << 4
3008return o1
3009}
3010
3011// MVN $C_NCON, Reg -> MOVW $C_RCON, Reg
3012func (c *ctxt5) omvr(p *obj.Prog, a *obj.Addr, dr int) uint32 {
3013o1 := c.oprrr(p, AMOVW, int(p.Scond))
3014o1 |= (uint32(dr) & 15) << 12
3015v := immrot(^uint32(a.Offset))
3016if v == 0 {
3017c.ctxt.Diag("%v: missing literal", p)
3018return 0
3019}
3020o1 |= uint32(v)
3021return o1
3022}
3023
3024func (c *ctxt5) omvl(p *obj.Prog, a *obj.Addr, dr int) uint32 {
3025var o1 uint32
3026if p.Pool == nil {
3027c.aclass(a)
3028v := immrot(^uint32(c.instoffset))
3029if v == 0 {
3030c.ctxt.Diag("%v: missing literal", p)
3031return 0
3032}
3033
3034o1 = c.oprrr(p, AMVN, int(p.Scond)&C_SCOND)
3035o1 |= uint32(v)
3036o1 |= (uint32(dr) & 15) << 12
3037} else {
3038v := int32(p.Pool.Pc - p.Pc - 8)
3039o1 = c.olr(v, REGPC, dr, int(p.Scond)&C_SCOND)
3040}
3041
3042return o1
3043}
3044
3045func (c *ctxt5) chipzero5(e float64) int {
3046// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
3047if objabi.GOARM < 7 || math.Float64bits(e) != 0 {
3048return -1
3049}
3050return 0
3051}
3052
3053func (c *ctxt5) chipfloat5(e float64) int {
3054// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
3055if objabi.GOARM < 7 {
3056return -1
3057}
3058
3059ei := math.Float64bits(e)
3060l := uint32(ei)
3061h := uint32(ei >> 32)
3062
3063if l != 0 || h&0xffff != 0 {
3064return -1
3065}
3066h1 := h & 0x7fc00000
3067if h1 != 0x40000000 && h1 != 0x3fc00000 {
3068return -1
3069}
3070n := 0
3071
3072// sign bit (a)
3073if h&0x80000000 != 0 {
3074n |= 1 << 7
3075}
3076
3077// exp sign bit (b)
3078if h1 == 0x3fc00000 {
3079n |= 1 << 6
3080}
3081
3082// rest of exp and mantissa (cd-efgh)
3083n |= int((h >> 16) & 0x3f)
3084
3085//print("match %.8lux %.8lux %d\n", l, h, n);
3086return n
3087}
3088
3089func nocache(p *obj.Prog) {
3090p.Optab = 0
3091p.From.Class = 0
3092if p.GetFrom3() != nil {
3093p.GetFrom3().Class = 0
3094}
3095p.To.Class = 0
3096}
3097