podman

Форк
0
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

31
package arm
32

33
import (
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.
45
type ctxt5 struct {
46
	ctxt       *obj.Link
47
	newprog    obj.ProgAlloc
48
	cursym     *obj.LSym
49
	printp     *obj.Prog
50
	blitrl     *obj.Prog
51
	elitrl     *obj.Prog
52
	autosize   int64
53
	instoffset int64
54
	pc         int64
55
	pool       struct {
56
		start uint32
57
		size  uint32
58
		extra uint32
59
	}
60
}
61

62
type Optab struct {
63
	as       obj.As
64
	a1       uint8
65
	a2       int8
66
	a3       uint8
67
	type_    uint8
68
	size     int8
69
	param    int16
70
	flag     int8
71
	pcrelsiz uint8
72
	scond    uint8 // optional flags accepted by the instruction
73
}
74

75
type Opcross [32][2][32]uint8
76

77
const (
78
	LFROM  = 1 << 0
79
	LTO    = 1 << 1
80
	LPOOL  = 1 << 2
81
	LPCREL = 1 << 3
82
)
83

84
var optab = []Optab{
85
	/* struct Optab:
86
	OPCODE, 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

338
var mbOp = []struct {
339
	reg int16
340
	enc 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

352
var oprange [ALAST & obj.AMask][]Optab
353

354
var xcmp [C_GOK + 1][C_GOK + 1]bool
355

356
var (
357
	deferreturn *obj.LSym
358
	symdiv      *obj.LSym
359
	symdivu     *obj.LSym
360
	symmod      *obj.LSym
361
	symmodu     *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

369
func checkSuffix(c *ctxt5, p *obj.Prog, o *Optab) {
370
	if p.Scond&C_SBIT != 0 && o.scond&C_SBIT == 0 {
371
		c.ctxt.Diag("invalid .S suffix: %v", p)
372
	}
373
	if p.Scond&C_PBIT != 0 && o.scond&C_PBIT == 0 {
374
		c.ctxt.Diag("invalid .P suffix: %v", p)
375
	}
376
	if p.Scond&C_WBIT != 0 && o.scond&C_WBIT == 0 {
377
		c.ctxt.Diag("invalid .W suffix: %v", p)
378
	}
379
	if p.Scond&C_UBIT != 0 && o.scond&C_UBIT == 0 {
380
		c.ctxt.Diag("invalid .U suffix: %v", p)
381
	}
382
}
383

384
func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
385
	if ctxt.Retpoline {
386
		ctxt.Diag("-spectre=ret not supported on arm")
387
		ctxt.Retpoline = false // don't keep printing
388
	}
389

390
	var p *obj.Prog
391
	var op *obj.Prog
392

393
	p = cursym.Func.Text
394
	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
395
		return
396
	}
397

398
	if oprange[AAND&obj.AMask] == nil {
399
		ctxt.Diag("arm ops not initialized, call arm.buildop first")
400
	}
401

402
	c := ctxt5{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: p.To.Offset + 4}
403
	pc := int32(0)
404

405
	op = p
406
	p = p.Link
407
	var m int
408
	var o *Optab
409
	for ; p != nil || c.blitrl != nil; op, p = p, p.Link {
410
		if p == nil {
411
			if c.checkpool(op, pc) {
412
				p = op
413
				continue
414
			}
415

416
			// can't happen: blitrl is not nil, but checkpool didn't flushpool
417
			ctxt.Diag("internal inconsistency")
418

419
			break
420
		}
421

422
		p.Pc = int64(pc)
423
		o = c.oplook(p)
424
		m = int(o.size)
425

426
		if m%4 != 0 || p.Pc%4 != 0 {
427
			ctxt.Diag("!pc invalid: %v size=%d", p, m)
428
		}
429

430
		// must check literal pool here in case p generates many instructions
431
		if c.blitrl != nil {
432
			// Emit the constant pool just before p if p
433
			// would push us over the immediate size limit.
434
			if 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.
438
				p = op
439
				continue
440
			}
441
		}
442

443
		if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) {
444
			ctxt.Diag("zero-width instruction\n%v", p)
445
			continue
446
		}
447

448
		switch o.flag & (LFROM | LTO | LPOOL) {
449
		case LFROM:
450
			c.addpool(p, &p.From)
451

452
		case LTO:
453
			c.addpool(p, &p.To)
454

455
		case LPOOL:
456
			if p.Scond&C_SCOND == C_SCOND_NONE {
457
				c.flushpool(p, 0, 0)
458
			}
459
		}
460

461
		if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE {
462
			c.flushpool(p, 0, 0)
463
		}
464

465
		pc += int32(m)
466
	}
467

468
	c.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
	 */
476
	times := 0
477

478
	var bflag int
479
	var opc int32
480
	var out [6 + 3]uint32
481
	for {
482
		bflag = 0
483
		pc = 0
484
		times++
485
		c.cursym.Func.Text.Pc = 0 // force re-layout the code.
486
		for p = c.cursym.Func.Text; p != nil; p = p.Link {
487
			o = c.oplook(p)
488
			if int64(pc) > p.Pc {
489
				p.Pc = int64(pc)
490
			}
491

492
			/* very large branches
493
			if(o->type == 6 && p->pcond) {
494
				otxt = p->pcond->pc - c;
495
				if(otxt < 0)
496
					otxt = -otxt;
497
				if(otxt >= (1L<<17) - 10) {
498
					q = emallocz(sizeof(Prog));
499
					q->link = p->link;
500
					p->link = q;
501
					q->as = AB;
502
					q->to.type = TYPE_BRANCH;
503
					q->pcond = p->pcond;
504
					p->pcond = q;
505
					q = emallocz(sizeof(Prog));
506
					q->link = p->link;
507
					p->link = q;
508
					q->as = AB;
509
					q->to.type = TYPE_BRANCH;
510
					q->pcond = q->link->link;
511
					bflag = 1;
512
				}
513
			}
514
			*/
515
			opc = int32(p.Pc)
516
			m = int(o.size)
517
			if p.Pc != int64(opc) {
518
				bflag = 1
519
			}
520

521
			//print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
522
			pc = int32(p.Pc + int64(m))
523

524
			if m%4 != 0 || p.Pc%4 != 0 {
525
				ctxt.Diag("pc invalid: %v size=%d", p, m)
526
			}
527

528
			if m/4 > len(out) {
529
				ctxt.Diag("instruction size too large: %d > %d", m/4, len(out))
530
			}
531
			if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) {
532
				if p.As == obj.ATEXT {
533
					c.autosize = p.To.Offset + 4
534
					continue
535
				}
536

537
				ctxt.Diag("zero-width instruction\n%v", p)
538
				continue
539
			}
540
		}
541

542
		c.cursym.Size = int64(pc)
543
		if bflag == 0 {
544
			break
545
		}
546
	}
547

548
	if pc%4 != 0 {
549
		ctxt.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

561
	p = c.cursym.Func.Text
562
	c.autosize = p.To.Offset + 4
563
	c.cursym.Grow(c.cursym.Size)
564

565
	bp := c.cursym.P
566
	pc = int32(p.Pc) // even p->link might need extra padding
567
	var v int
568
	for p = p.Link; p != nil; p = p.Link {
569
		c.pc = p.Pc
570
		o = c.oplook(p)
571
		opc = int32(p.Pc)
572
		c.asmout(p, o, out[:])
573
		m = int(o.size)
574

575
		if m%4 != 0 || p.Pc%4 != 0 {
576
			ctxt.Diag("final stage: pc invalid: %v size=%d", p, m)
577
		}
578

579
		if int64(pc) > p.Pc {
580
			ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, pc, p)
581
		}
582
		for int64(pc) != p.Pc {
583
			// emit 0xe1a00000 (MOVW R0, R0)
584
			bp[0] = 0x00
585
			bp = bp[1:]
586

587
			bp[0] = 0x00
588
			bp = bp[1:]
589
			bp[0] = 0xa0
590
			bp = bp[1:]
591
			bp[0] = 0xe1
592
			bp = bp[1:]
593
			pc += 4
594
		}
595

596
		for i := 0; i < m/4; i++ {
597
			v = int(out[i])
598
			bp[0] = byte(v)
599
			bp = bp[1:]
600
			bp[0] = byte(v >> 8)
601
			bp = bp[1:]
602
			bp[0] = byte(v >> 16)
603
			bp = bp[1:]
604
			bp[0] = byte(v >> 24)
605
			bp = bp[1:]
606
		}
607

608
		pc += 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.
621
func (c *ctxt5) checkpool(p *obj.Prog, nextpc int32) bool {
622
	poolLast := nextpc
623
	poolLast += 4                      // the AB instruction to jump around the pool
624
	poolLast += int32(c.pool.size) - 4 // the offset of the last pool entry
625

626
	refPC := int32(c.pool.start) // PC of the first pool reference
627

628
	v := poolLast - refPC - 8 // 12-bit PC-relative offset (see omvl)
629

630
	if c.pool.size >= 0xff0 || immaddr(v) == 0 {
631
		return c.flushpool(p, 1, 0)
632
	} else if p.Link == nil {
633
		return c.flushpool(p, 2, 0)
634
	}
635
	return false
636
}
637

638
func (c *ctxt5) flushpool(p *obj.Prog, skip int, force int) bool {
639
	if c.blitrl != nil {
640
		if skip != 0 {
641
			if false && skip == 1 {
642
				fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start)
643
			}
644
			q := c.newprog()
645
			q.As = AB
646
			q.To.Type = obj.TYPE_BRANCH
647
			q.To.SetTarget(p.Link)
648
			q.Link = c.blitrl
649
			q.Pos = p.Pos
650
			c.blitrl = q
651
		} else if force == 0 && (p.Pc+int64(c.pool.size)-int64(c.pool.start) < 2048) {
652
			return 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.
658
		for q := c.blitrl; q != nil; q = q.Link {
659
			q.Pos = p.Pos
660
		}
661

662
		c.elitrl.Link = p.Link
663
		p.Link = c.blitrl
664

665
		c.blitrl = nil /* BUG: should refer back to values until out-of-range */
666
		c.elitrl = nil
667
		c.pool.size = 0
668
		c.pool.start = 0
669
		c.pool.extra = 0
670
		return true
671
	}
672

673
	return false
674
}
675

676
func (c *ctxt5) addpool(p *obj.Prog, a *obj.Addr) {
677
	t := c.newprog()
678
	t.As = AWORD
679

680
	switch c.aclass(a) {
681
	default:
682
		t.To.Offset = a.Offset
683
		t.To.Sym = a.Sym
684
		t.To.Type = a.Type
685
		t.To.Name = a.Name
686

687
		if c.ctxt.Flag_shared && t.To.Sym != nil {
688
			t.Rel = p
689
		}
690

691
	case C_SROREG,
692
		C_LOREG,
693
		C_ROREG,
694
		C_FOREG,
695
		C_SOREG,
696
		C_HOREG,
697
		C_FAUTO,
698
		C_SAUTO,
699
		C_LAUTO,
700
		C_LACON:
701
		t.To.Type = obj.TYPE_CONST
702
		t.To.Offset = c.instoffset
703
	}
704

705
	if t.Rel == nil {
706
		for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
707
			if q.Rel == nil && q.To == t.To {
708
				p.Pool = q
709
				return
710
			}
711
		}
712
	}
713

714
	q := c.newprog()
715
	*q = *t
716
	q.Pc = int64(c.pool.size)
717

718
	if c.blitrl == nil {
719
		c.blitrl = q
720
		c.pool.start = uint32(p.Pc)
721
	} else {
722
		c.elitrl.Link = q
723
	}
724
	c.elitrl = q
725
	c.pool.size += 4
726

727
	// Store the link to the pool entry in Pool.
728
	p.Pool = q
729
}
730

731
func (c *ctxt5) regoff(a *obj.Addr) int32 {
732
	c.instoffset = 0
733
	c.aclass(a)
734
	return int32(c.instoffset)
735
}
736

737
func immrot(v uint32) int32 {
738
	for i := 0; i < 16; i++ {
739
		if v&^0xff == 0 {
740
			return int32(uint32(int32(i)<<8) | v | 1<<25)
741
		}
742
		v = v<<2 | v>>30
743
	}
744

745
	return 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.
751
func immrot2a(v uint32) (uint32, uint32) {
752
	for i := uint(1); i < 32; i++ {
753
		m := uint32(1<<i - 1)
754
		if x, y := immrot(v&m), immrot(v&^m); x != 0 && y != 0 {
755
			return uint32(x), uint32(y)
756
		}
757
	}
758
	// TODO: handle some more cases, like where
759
	// the wraparound from the rotate could help.
760
	return 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.
766
func immrot2s(v uint32) (uint32, uint32) {
767
	if immrot(v) != 0 {
768
		return 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
772
	var i uint32
773
	for i = 2; i < 32; i += 2 {
774
		if v&(1<<i-1) != 0 {
775
			break
776
		}
777
	}
778
	// i must be <= 24, then adjust i just above lower 8 effective bits of v
779
	i += 6
780
	// let x = {the complement of lower 8 effective bits, trailing 00}, y = x + v
781
	x := 1<<i - v&(1<<i-1)
782
	y := v + x
783
	if y, x = uint32(immrot(y)), uint32(immrot(x)); y != 0 && x != 0 {
784
		return y, x
785
	}
786
	return 0, 0
787
}
788

789
func immaddr(v int32) int32 {
790
	if v >= 0 && v <= 0xfff {
791
		return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */
792
	}
793
	if v >= -0xfff && v < 0 {
794
		return -v&0xfff | 1<<24 /* pre indexing */
795
	}
796
	return 0
797
}
798

799
func immfloat(v int32) bool {
800
	return v&0xC03 == 0 /* offset will fit in floating-point load/store */
801
}
802

803
func immhalf(v int32) bool {
804
	if v >= 0 && v <= 0xff {
805
		return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */
806
	}
807
	if v >= -0xff && v < 0 {
808
		return -v&0xff|1<<24 != 0 /* pre indexing */
809
	}
810
	return false
811
}
812

813
func (c *ctxt5) aclass(a *obj.Addr) int {
814
	switch a.Type {
815
	case obj.TYPE_NONE:
816
		return C_NONE
817

818
	case obj.TYPE_REG:
819
		c.instoffset = 0
820
		if REG_R0 <= a.Reg && a.Reg <= REG_R15 {
821
			return C_REG
822
		}
823
		if REG_F0 <= a.Reg && a.Reg <= REG_F15 {
824
			return C_FREG
825
		}
826
		if a.Reg == REG_FPSR || a.Reg == REG_FPCR {
827
			return C_FCR
828
		}
829
		if a.Reg == REG_CPSR || a.Reg == REG_SPSR {
830
			return C_PSR
831
		}
832
		if a.Reg >= REG_SPECIAL {
833
			return C_SPR
834
		}
835
		return C_GOK
836

837
	case obj.TYPE_REGREG:
838
		return C_REGREG
839

840
	case obj.TYPE_REGREG2:
841
		return C_REGREG2
842

843
	case obj.TYPE_REGLIST:
844
		return C_REGLIST
845

846
	case obj.TYPE_SHIFT:
847
		if a.Reg == 0 {
848
			// register shift R>>i
849
			return C_SHIFT
850
		} else {
851
			// memory address with shifted offset R>>i(R)
852
			return C_SHIFTADDR
853
		}
854

855
	case obj.TYPE_MEM:
856
		switch a.Name {
857
		case obj.NAME_EXTERN,
858
			obj.NAME_GOTREF,
859
			obj.NAME_STATIC:
860
			if a.Sym == nil || a.Sym.Name == "" {
861
				fmt.Printf("null sym external\n")
862
				return C_GOK
863
			}
864

865
			c.instoffset = 0 // s.b. unused but just in case
866
			if a.Sym.Type == objabi.STLSBSS {
867
				if c.ctxt.Flag_shared {
868
					return C_TLS_IE
869
				} else {
870
					return C_TLS_LE
871
				}
872
			}
873

874
			return C_ADDR
875

876
		case obj.NAME_AUTO:
877
			if a.Reg == REGSP {
878
				// unset base register for better printing, since
879
				// a.Offset is still relative to pseudo-SP.
880
				a.Reg = obj.REG_NONE
881
			}
882
			c.instoffset = c.autosize + a.Offset
883
			if t := immaddr(int32(c.instoffset)); t != 0 {
884
				if immhalf(int32(c.instoffset)) {
885
					if immfloat(t) {
886
						return C_HFAUTO
887
					}
888
					return C_HAUTO
889
				}
890

891
				if immfloat(t) {
892
					return C_FAUTO
893
				}
894
				return C_SAUTO
895
			}
896

897
			return C_LAUTO
898

899
		case obj.NAME_PARAM:
900
			if a.Reg == REGSP {
901
				// unset base register for better printing, since
902
				// a.Offset is still relative to pseudo-FP.
903
				a.Reg = obj.REG_NONE
904
			}
905
			c.instoffset = c.autosize + a.Offset + 4
906
			if t := immaddr(int32(c.instoffset)); t != 0 {
907
				if immhalf(int32(c.instoffset)) {
908
					if immfloat(t) {
909
						return C_HFAUTO
910
					}
911
					return C_HAUTO
912
				}
913

914
				if immfloat(t) {
915
					return C_FAUTO
916
				}
917
				return C_SAUTO
918
			}
919

920
			return C_LAUTO
921

922
		case obj.NAME_NONE:
923
			c.instoffset = a.Offset
924
			if t := immaddr(int32(c.instoffset)); t != 0 {
925
				if immhalf(int32(c.instoffset)) { /* n.b. that it will also satisfy immrot */
926
					if immfloat(t) {
927
						return C_HFOREG
928
					}
929
					return C_HOREG
930
				}
931

932
				if immfloat(t) {
933
					return C_FOREG /* n.b. that it will also satisfy immrot */
934
				}
935
				if immrot(uint32(c.instoffset)) != 0 {
936
					return C_SROREG
937
				}
938
				if immhalf(int32(c.instoffset)) {
939
					return C_HOREG
940
				}
941
				return C_SOREG
942
			}
943

944
			if immrot(uint32(c.instoffset)) != 0 {
945
				return C_ROREG
946
			}
947
			return C_LOREG
948
		}
949

950
		return C_GOK
951

952
	case obj.TYPE_FCONST:
953
		if c.chipzero5(a.Val.(float64)) >= 0 {
954
			return C_ZFCON
955
		}
956
		if c.chipfloat5(a.Val.(float64)) >= 0 {
957
			return C_SFCON
958
		}
959
		return C_LFCON
960

961
	case obj.TYPE_TEXTSIZE:
962
		return C_TEXTSIZE
963

964
	case obj.TYPE_CONST,
965
		obj.TYPE_ADDR:
966
		switch a.Name {
967
		case obj.NAME_NONE:
968
			c.instoffset = a.Offset
969
			if a.Reg != 0 {
970
				return c.aconsize()
971
			}
972

973
			if immrot(uint32(c.instoffset)) != 0 {
974
				return C_RCON
975
			}
976
			if immrot(^uint32(c.instoffset)) != 0 {
977
				return C_NCON
978
			}
979
			if uint32(c.instoffset) <= 0xffff && objabi.GOARM == 7 {
980
				return C_SCON
981
			}
982
			if x, y := immrot2a(uint32(c.instoffset)); x != 0 && y != 0 {
983
				return C_RCON2A
984
			}
985
			if y, x := immrot2s(uint32(c.instoffset)); x != 0 && y != 0 {
986
				return C_RCON2S
987
			}
988
			return C_LCON
989

990
		case obj.NAME_EXTERN,
991
			obj.NAME_GOTREF,
992
			obj.NAME_STATIC:
993
			s := a.Sym
994
			if s == nil {
995
				break
996
			}
997
			c.instoffset = 0 // s.b. unused but just in case
998
			return C_LCONADDR
999

1000
		case obj.NAME_AUTO:
1001
			if a.Reg == REGSP {
1002
				// unset base register for better printing, since
1003
				// a.Offset is still relative to pseudo-SP.
1004
				a.Reg = obj.REG_NONE
1005
			}
1006
			c.instoffset = c.autosize + a.Offset
1007
			return c.aconsize()
1008

1009
		case obj.NAME_PARAM:
1010
			if a.Reg == REGSP {
1011
				// unset base register for better printing, since
1012
				// a.Offset is still relative to pseudo-FP.
1013
				a.Reg = obj.REG_NONE
1014
			}
1015
			c.instoffset = c.autosize + a.Offset + 4
1016
			return c.aconsize()
1017
		}
1018

1019
		return C_GOK
1020

1021
	case obj.TYPE_BRANCH:
1022
		return C_SBRA
1023
	}
1024

1025
	return C_GOK
1026
}
1027

1028
func (c *ctxt5) aconsize() int {
1029
	if immrot(uint32(c.instoffset)) != 0 {
1030
		return C_RACON
1031
	}
1032
	if immrot(uint32(-c.instoffset)) != 0 {
1033
		return C_RACON
1034
	}
1035
	return C_LACON
1036
}
1037

1038
func (c *ctxt5) oplook(p *obj.Prog) *Optab {
1039
	a1 := int(p.Optab)
1040
	if a1 != 0 {
1041
		return &optab[a1-1]
1042
	}
1043
	a1 = int(p.From.Class)
1044
	if a1 == 0 {
1045
		a1 = c.aclass(&p.From) + 1
1046
		p.From.Class = int8(a1)
1047
	}
1048

1049
	a1--
1050
	a3 := int(p.To.Class)
1051
	if a3 == 0 {
1052
		a3 = c.aclass(&p.To) + 1
1053
		p.To.Class = int8(a3)
1054
	}
1055

1056
	a3--
1057
	a2 := C_NONE
1058
	if p.Reg != 0 {
1059
		switch {
1060
		case REG_F0 <= p.Reg && p.Reg <= REG_F15:
1061
			a2 = C_FREG
1062
		case REG_R0 <= p.Reg && p.Reg <= REG_R15:
1063
			a2 = C_REG
1064
		default:
1065
			c.ctxt.Diag("invalid register in %v", p)
1066
		}
1067
	}
1068

1069
	// check illegal base register
1070
	switch a1 {
1071
	case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR:
1072
		if p.From.Reg < REG_R0 || REG_R15 < p.From.Reg {
1073
			c.ctxt.Diag("illegal base register: %v", p)
1074
		}
1075
	default:
1076
	}
1077
	switch a3 {
1078
	case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR:
1079
		if p.To.Reg < REG_R0 || REG_R15 < p.To.Reg {
1080
			c.ctxt.Diag("illegal base register: %v", p)
1081
		}
1082
	default:
1083
	}
1084

1085
	// If current instruction has a .S suffix (flags update),
1086
	// we must use the constant pool instead of splitting it.
1087
	if (a1 == C_RCON2A || a1 == C_RCON2S) && p.Scond&C_SBIT != 0 {
1088
		a1 = C_LCON
1089
	}
1090
	if (a3 == C_RCON2A || a3 == C_RCON2S) && p.Scond&C_SBIT != 0 {
1091
		a3 = C_LCON
1092
	}
1093

1094
	if false { /*debug['O']*/
1095
		fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3))
1096
		fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
1097
	}
1098

1099
	ops := oprange[p.As&obj.AMask]
1100
	c1 := &xcmp[a1]
1101
	c3 := &xcmp[a3]
1102
	for i := range ops {
1103
		op := &ops[i]
1104
		if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] {
1105
			p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
1106
			checkSuffix(c, p, op)
1107
			return op
1108
		}
1109
	}
1110

1111
	c.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)
1112
	if ops == nil {
1113
		ops = optab
1114
	}
1115
	return &ops[0]
1116
}
1117

1118
func cmp(a int, b int) bool {
1119
	if a == b {
1120
		return true
1121
	}
1122
	switch a {
1123
	case C_LCON:
1124
		if b == C_RCON || b == C_NCON || b == C_SCON || b == C_RCON2A || b == C_RCON2S {
1125
			return true
1126
		}
1127

1128
	case C_LACON:
1129
		if b == C_RACON {
1130
			return true
1131
		}
1132

1133
	case C_LFCON:
1134
		if b == C_ZFCON || b == C_SFCON {
1135
			return true
1136
		}
1137

1138
	case C_HFAUTO:
1139
		return b == C_HAUTO || b == C_FAUTO
1140

1141
	case C_FAUTO, C_HAUTO:
1142
		return b == C_HFAUTO
1143

1144
	case C_SAUTO:
1145
		return cmp(C_HFAUTO, b)
1146

1147
	case C_LAUTO:
1148
		return cmp(C_SAUTO, b)
1149

1150
	case C_HFOREG:
1151
		return b == C_HOREG || b == C_FOREG
1152

1153
	case C_FOREG, C_HOREG:
1154
		return b == C_HFOREG
1155

1156
	case C_SROREG:
1157
		return cmp(C_SOREG, b) || cmp(C_ROREG, b)
1158

1159
	case C_SOREG, C_ROREG:
1160
		return b == C_SROREG || cmp(C_HFOREG, b)
1161

1162
	case C_LOREG:
1163
		return cmp(C_SROREG, b)
1164

1165
	case C_LBRA:
1166
		if b == C_SBRA {
1167
			return true
1168
		}
1169

1170
	case C_HREG:
1171
		return cmp(C_SP, b) || cmp(C_PC, b)
1172
	}
1173

1174
	return false
1175
}
1176

1177
type ocmp []Optab
1178

1179
func (x ocmp) Len() int {
1180
	return len(x)
1181
}
1182

1183
func (x ocmp) Swap(i, j int) {
1184
	x[i], x[j] = x[j], x[i]
1185
}
1186

1187
func (x ocmp) Less(i, j int) bool {
1188
	p1 := &x[i]
1189
	p2 := &x[j]
1190
	n := int(p1.as) - int(p2.as)
1191
	if n != 0 {
1192
		return n < 0
1193
	}
1194
	n = int(p1.a1) - int(p2.a1)
1195
	if n != 0 {
1196
		return n < 0
1197
	}
1198
	n = int(p1.a2) - int(p2.a2)
1199
	if n != 0 {
1200
		return n < 0
1201
	}
1202
	n = int(p1.a3) - int(p2.a3)
1203
	if n != 0 {
1204
		return n < 0
1205
	}
1206
	return false
1207
}
1208

1209
func opset(a, b0 obj.As) {
1210
	oprange[a&obj.AMask] = oprange[b0]
1211
}
1212

1213
func buildop(ctxt *obj.Link) {
1214
	if 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.
1218
		return
1219
	}
1220

1221
	deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal)
1222

1223
	symdiv = ctxt.Lookup("runtime._div")
1224
	symdivu = ctxt.Lookup("runtime._divu")
1225
	symmod = ctxt.Lookup("runtime._mod")
1226
	symmodu = ctxt.Lookup("runtime._modu")
1227

1228
	var n int
1229

1230
	for i := 0; i < C_GOK; i++ {
1231
		for n = 0; n < C_GOK; n++ {
1232
			if cmp(n, i) {
1233
				xcmp[i][n] = true
1234
			}
1235
		}
1236
	}
1237
	for n = 0; optab[n].as != obj.AXXX; n++ {
1238
		if optab[n].flag&LPCREL != 0 {
1239
			if ctxt.Flag_shared {
1240
				optab[n].size += int8(optab[n].pcrelsiz)
1241
			} else {
1242
				optab[n].flag &^= LPCREL
1243
			}
1244
		}
1245
	}
1246

1247
	sort.Sort(ocmp(optab[:n]))
1248
	for i := 0; i < n; i++ {
1249
		r := optab[i].as
1250
		r0 := r & obj.AMask
1251
		start := i
1252
		for optab[i].as == r {
1253
			i++
1254
		}
1255
		oprange[r0] = optab[start:i]
1256
		i--
1257

1258
		switch r {
1259
		default:
1260
			ctxt.Diag("unknown op in build: %v", r)
1261
			ctxt.DiagFlush()
1262
			log.Fatalf("bad code")
1263

1264
		case AADD:
1265
			opset(ASUB, r0)
1266
			opset(ARSB, r0)
1267
			opset(AADC, r0)
1268
			opset(ASBC, r0)
1269
			opset(ARSC, r0)
1270

1271
		case AORR:
1272
			opset(AEOR, r0)
1273
			opset(ABIC, r0)
1274

1275
		case ACMP:
1276
			opset(ATEQ, r0)
1277
			opset(ACMN, r0)
1278
			opset(ATST, r0)
1279

1280
		case AMVN:
1281
			break
1282

1283
		case ABEQ:
1284
			opset(ABNE, r0)
1285
			opset(ABCS, r0)
1286
			opset(ABHS, r0)
1287
			opset(ABCC, r0)
1288
			opset(ABLO, r0)
1289
			opset(ABMI, r0)
1290
			opset(ABPL, r0)
1291
			opset(ABVS, r0)
1292
			opset(ABVC, r0)
1293
			opset(ABHI, r0)
1294
			opset(ABLS, r0)
1295
			opset(ABGE, r0)
1296
			opset(ABLT, r0)
1297
			opset(ABGT, r0)
1298
			opset(ABLE, r0)
1299

1300
		case ASLL:
1301
			opset(ASRL, r0)
1302
			opset(ASRA, r0)
1303

1304
		case AMUL:
1305
			opset(AMULU, r0)
1306

1307
		case ADIV:
1308
			opset(AMOD, r0)
1309
			opset(AMODU, r0)
1310
			opset(ADIVU, r0)
1311

1312
		case ADIVHW:
1313
			opset(ADIVUHW, r0)
1314

1315
		case AMOVW,
1316
			AMOVB,
1317
			AMOVBS,
1318
			AMOVBU,
1319
			AMOVH,
1320
			AMOVHS,
1321
			AMOVHU:
1322
			break
1323

1324
		case ASWPW:
1325
			opset(ASWPBU, r0)
1326

1327
		case AB,
1328
			ABL,
1329
			ABX,
1330
			ABXRET,
1331
			obj.ADUFFZERO,
1332
			obj.ADUFFCOPY,
1333
			ASWI,
1334
			AWORD,
1335
			AMOVM,
1336
			ARFE,
1337
			obj.ATEXT:
1338
			break
1339

1340
		case AADDF:
1341
			opset(AADDD, r0)
1342
			opset(ASUBF, r0)
1343
			opset(ASUBD, r0)
1344
			opset(AMULF, r0)
1345
			opset(AMULD, r0)
1346
			opset(ANMULF, r0)
1347
			opset(ANMULD, r0)
1348
			opset(AMULAF, r0)
1349
			opset(AMULAD, r0)
1350
			opset(AMULSF, r0)
1351
			opset(AMULSD, r0)
1352
			opset(ANMULAF, r0)
1353
			opset(ANMULAD, r0)
1354
			opset(ANMULSF, r0)
1355
			opset(ANMULSD, r0)
1356
			opset(AFMULAF, r0)
1357
			opset(AFMULAD, r0)
1358
			opset(AFMULSF, r0)
1359
			opset(AFMULSD, r0)
1360
			opset(AFNMULAF, r0)
1361
			opset(AFNMULAD, r0)
1362
			opset(AFNMULSF, r0)
1363
			opset(AFNMULSD, r0)
1364
			opset(ADIVF, r0)
1365
			opset(ADIVD, r0)
1366

1367
		case ANEGF:
1368
			opset(ANEGD, r0)
1369
			opset(ASQRTF, r0)
1370
			opset(ASQRTD, r0)
1371
			opset(AMOVFD, r0)
1372
			opset(AMOVDF, r0)
1373
			opset(AABSF, r0)
1374
			opset(AABSD, r0)
1375

1376
		case ACMPF:
1377
			opset(ACMPD, r0)
1378

1379
		case AMOVF:
1380
			opset(AMOVD, r0)
1381

1382
		case AMOVFW:
1383
			opset(AMOVDW, r0)
1384

1385
		case AMOVWF:
1386
			opset(AMOVWD, r0)
1387

1388
		case AMULL:
1389
			opset(AMULAL, r0)
1390
			opset(AMULLU, r0)
1391
			opset(AMULALU, r0)
1392

1393
		case AMULWT:
1394
			opset(AMULWB, r0)
1395
			opset(AMULBB, r0)
1396
			opset(AMMUL, r0)
1397

1398
		case AMULAWT:
1399
			opset(AMULAWB, r0)
1400
			opset(AMULABB, r0)
1401
			opset(AMULS, r0)
1402
			opset(AMMULA, r0)
1403
			opset(AMMULS, r0)
1404

1405
		case ABFX:
1406
			opset(ABFXU, r0)
1407
			opset(ABFC, r0)
1408
			opset(ABFI, r0)
1409

1410
		case ACLZ:
1411
			opset(AREV, r0)
1412
			opset(AREV16, r0)
1413
			opset(AREVSH, r0)
1414
			opset(ARBIT, r0)
1415

1416
		case AXTAB:
1417
			opset(AXTAH, r0)
1418
			opset(AXTABU, r0)
1419
			opset(AXTAHU, r0)
1420

1421
		case ALDREX,
1422
			ASTREX,
1423
			ALDREXD,
1424
			ASTREXD,
1425
			ADMB,
1426
			APLD,
1427
			AAND,
1428
			AMULA,
1429
			obj.AUNDEF,
1430
			obj.AFUNCDATA,
1431
			obj.APCDATA,
1432
			obj.ANOP:
1433
			break
1434
		}
1435
	}
1436
}
1437

1438
func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) {
1439
	c.printp = p
1440
	o1 := uint32(0)
1441
	o2 := uint32(0)
1442
	o3 := uint32(0)
1443
	o4 := uint32(0)
1444
	o5 := uint32(0)
1445
	o6 := uint32(0)
1446
	if false { /*debug['P']*/
1447
		fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
1448
	}
1449
	switch o.type_ {
1450
	default:
1451
		c.ctxt.Diag("%v: unknown asm %d", p, o.type_)
1452

1453
	case 0: /* pseudo ops */
1454
		if false { /*debug['G']*/
1455
			fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
1456
		}
1457

1458
	case 1: /* op R,[R],R */
1459
		o1 = c.oprrr(p, p.As, int(p.Scond))
1460

1461
		rf := int(p.From.Reg)
1462
		rt := int(p.To.Reg)
1463
		r := int(p.Reg)
1464
		if p.To.Type == obj.TYPE_NONE {
1465
			rt = 0
1466
		}
1467
		if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN {
1468
			r = 0
1469
		} else if r == 0 {
1470
			r = rt
1471
		}
1472
		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1473

1474
	case 2: /* movbu $I,[R],R */
1475
		c.aclass(&p.From)
1476

1477
		o1 = c.oprrr(p, p.As, int(p.Scond))
1478
		o1 |= uint32(immrot(uint32(c.instoffset)))
1479
		rt := int(p.To.Reg)
1480
		r := int(p.Reg)
1481
		if p.To.Type == obj.TYPE_NONE {
1482
			rt = 0
1483
		}
1484
		if p.As == AMOVW || p.As == AMVN {
1485
			r = 0
1486
		} else if r == 0 {
1487
			r = rt
1488
		}
1489
		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1490

1491
	case 106: /* op $I,R,R where I can be decomposed into 2 immediates */
1492
		c.aclass(&p.From)
1493
		r := int(p.Reg)
1494
		rt := int(p.To.Reg)
1495
		if r == 0 {
1496
			r = rt
1497
		}
1498
		x, y := immrot2a(uint32(c.instoffset))
1499
		var as2 obj.As
1500
		switch p.As {
1501
		case AADD, ASUB, AORR, AEOR, ABIC:
1502
			as2 = p.As // ADD, SUB, ORR, EOR, BIC
1503
		case ARSB:
1504
			as2 = AADD // RSB -> RSB/ADD pair
1505
		case AADC:
1506
			as2 = AADD // ADC -> ADC/ADD pair
1507
		case ASBC:
1508
			as2 = ASUB // SBC -> SBC/SUB pair
1509
		case ARSC:
1510
			as2 = AADD // RSC -> RSC/ADD pair
1511
		default:
1512
			c.ctxt.Diag("unknown second op for %v", p)
1513
		}
1514
		o1 = c.oprrr(p, p.As, int(p.Scond))
1515
		o2 = c.oprrr(p, as2, int(p.Scond))
1516
		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1517
		o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12
1518
		o1 |= x
1519
		o2 |= y
1520

1521
	case 107: /* op $I,R,R where I can be decomposed into 2 immediates */
1522
		c.aclass(&p.From)
1523
		r := int(p.Reg)
1524
		rt := int(p.To.Reg)
1525
		if r == 0 {
1526
			r = rt
1527
		}
1528
		y, x := immrot2s(uint32(c.instoffset))
1529
		var as2 obj.As
1530
		switch p.As {
1531
		case AADD:
1532
			as2 = ASUB // ADD -> ADD/SUB pair
1533
		case ASUB:
1534
			as2 = AADD // SUB -> SUB/ADD pair
1535
		case ARSB:
1536
			as2 = ASUB // RSB -> RSB/SUB pair
1537
		case AADC:
1538
			as2 = ASUB // ADC -> ADC/SUB pair
1539
		case ASBC:
1540
			as2 = AADD // SBC -> SBC/ADD pair
1541
		case ARSC:
1542
			as2 = ASUB // RSC -> RSC/SUB pair
1543
		default:
1544
			c.ctxt.Diag("unknown second op for %v", p)
1545
		}
1546
		o1 = c.oprrr(p, p.As, int(p.Scond))
1547
		o2 = c.oprrr(p, as2, int(p.Scond))
1548
		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
1549
		o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12
1550
		o1 |= y
1551
		o2 |= x
1552

1553
	case 3: /* add R<<[IR],[R],R */
1554
		o1 = c.mov(p)
1555

1556
	case 4: /* MOVW $off(R), R -> add $off,[R],R */
1557
		c.aclass(&p.From)
1558
		if c.instoffset < 0 {
1559
			o1 = c.oprrr(p, ASUB, int(p.Scond))
1560
			o1 |= uint32(immrot(uint32(-c.instoffset)))
1561
		} else {
1562
			o1 = c.oprrr(p, AADD, int(p.Scond))
1563
			o1 |= uint32(immrot(uint32(c.instoffset)))
1564
		}
1565
		r := int(p.From.Reg)
1566
		if r == 0 {
1567
			r = int(o.param)
1568
		}
1569
		o1 |= (uint32(r) & 15) << 16
1570
		o1 |= (uint32(p.To.Reg) & 15) << 12
1571

1572
	case 5: /* bra s */
1573
		o1 = c.opbra(p, p.As, int(p.Scond))
1574

1575
		v := int32(-8)
1576
		if p.To.Sym != nil {
1577
			rel := obj.Addrel(c.cursym)
1578
			rel.Off = int32(c.pc)
1579
			rel.Siz = 4
1580
			rel.Sym = p.To.Sym
1581
			v += int32(p.To.Offset)
1582
			rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
1583
			rel.Type = objabi.R_CALLARM
1584
			break
1585
		}
1586

1587
		if p.To.Target() != nil {
1588
			v = int32((p.To.Target().Pc - c.pc) - 8)
1589
		}
1590
		o1 |= (uint32(v) >> 2) & 0xffffff
1591

1592
	case 6: /* b ,O(R) -> add $O,R,PC */
1593
		c.aclass(&p.To)
1594

1595
		o1 = c.oprrr(p, AADD, int(p.Scond))
1596
		o1 |= uint32(immrot(uint32(c.instoffset)))
1597
		o1 |= (uint32(p.To.Reg) & 15) << 16
1598
		o1 |= (REGPC & 15) << 12
1599

1600
	case 7: /* bl (R) -> blx R */
1601
		c.aclass(&p.To)
1602

1603
		if c.instoffset != 0 {
1604
			c.ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, c.instoffset)
1605
		}
1606
		o1 = c.oprrr(p, ABL, int(p.Scond))
1607
		o1 |= (uint32(p.To.Reg) & 15) << 0
1608
		rel := obj.Addrel(c.cursym)
1609
		rel.Off = int32(c.pc)
1610
		rel.Siz = 0
1611
		rel.Type = objabi.R_CALLIND
1612

1613
	case 8: /* sll $c,[R],R -> mov (R<<$c),R */
1614
		c.aclass(&p.From)
1615

1616
		o1 = c.oprrr(p, p.As, int(p.Scond))
1617
		r := int(p.Reg)
1618
		if r == 0 {
1619
			r = int(p.To.Reg)
1620
		}
1621
		o1 |= (uint32(r) & 15) << 0
1622
		o1 |= uint32((c.instoffset & 31) << 7)
1623
		o1 |= (uint32(p.To.Reg) & 15) << 12
1624

1625
	case 9: /* sll R,[R],R -> mov (R<<R),R */
1626
		o1 = c.oprrr(p, p.As, int(p.Scond))
1627

1628
		r := int(p.Reg)
1629
		if r == 0 {
1630
			r = int(p.To.Reg)
1631
		}
1632
		o1 |= (uint32(r) & 15) << 0
1633
		o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4
1634
		o1 |= (uint32(p.To.Reg) & 15) << 12
1635

1636
	case 10: /* swi [$con] */
1637
		o1 = c.oprrr(p, p.As, int(p.Scond))
1638

1639
		if p.To.Type != obj.TYPE_NONE {
1640
			c.aclass(&p.To)
1641
			o1 |= uint32(c.instoffset & 0xffffff)
1642
		}
1643

1644
	case 11: /* word */
1645
		c.aclass(&p.To)
1646

1647
		o1 = uint32(c.instoffset)
1648
		if p.To.Sym != nil {
1649
			// This case happens with words generated
1650
			// in the PC stream as part of the literal pool (c.pool).
1651
			rel := obj.Addrel(c.cursym)
1652

1653
			rel.Off = int32(c.pc)
1654
			rel.Siz = 4
1655
			rel.Sym = p.To.Sym
1656
			rel.Add = p.To.Offset
1657

1658
			if c.ctxt.Flag_shared {
1659
				if p.To.Name == obj.NAME_GOTREF {
1660
					rel.Type = objabi.R_GOTPCREL
1661
				} else {
1662
					rel.Type = objabi.R_PCREL
1663
				}
1664
				rel.Add += c.pc - p.Rel.Pc - 8
1665
			} else {
1666
				rel.Type = objabi.R_ADDR
1667
			}
1668
			o1 = 0
1669
		}
1670

1671
	case 12: /* movw $lcon, reg */
1672
		if o.a1 == C_SCON {
1673
			o1 = c.omvs(p, &p.From, int(p.To.Reg))
1674
		} else if p.As == AMVN {
1675
			o1 = c.omvr(p, &p.From, int(p.To.Reg))
1676
		} else {
1677
			o1 = c.omvl(p, &p.From, int(p.To.Reg))
1678
		}
1679

1680
		if o.flag&LPCREL != 0 {
1681
			o2 = c.oprrr(p, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
1682
		}
1683

1684
	case 13: /* op $lcon, [R], R */
1685
		if o.a1 == C_SCON {
1686
			o1 = c.omvs(p, &p.From, REGTMP)
1687
		} else {
1688
			o1 = c.omvl(p, &p.From, REGTMP)
1689
		}
1690

1691
		if o1 == 0 {
1692
			break
1693
		}
1694
		o2 = c.oprrr(p, p.As, int(p.Scond))
1695
		o2 |= REGTMP & 15
1696
		r := int(p.Reg)
1697
		if p.As == AMVN {
1698
			r = 0
1699
		} else if r == 0 {
1700
			r = int(p.To.Reg)
1701
		}
1702
		o2 |= (uint32(r) & 15) << 16
1703
		if p.To.Type != obj.TYPE_NONE {
1704
			o2 |= (uint32(p.To.Reg) & 15) << 12
1705
		}
1706

1707
	case 14: /* movb/movbu/movh/movhu R,R */
1708
		o1 = c.oprrr(p, ASLL, int(p.Scond))
1709

1710
		if p.As == AMOVBU || p.As == AMOVHU {
1711
			o2 = c.oprrr(p, ASRL, int(p.Scond))
1712
		} else {
1713
			o2 = c.oprrr(p, ASRA, int(p.Scond))
1714
		}
1715

1716
		r := int(p.To.Reg)
1717
		o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12
1718
		o2 |= uint32(r)&15 | (uint32(r)&15)<<12
1719
		if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
1720
			o1 |= 24 << 7
1721
			o2 |= 24 << 7
1722
		} else {
1723
			o1 |= 16 << 7
1724
			o2 |= 16 << 7
1725
		}
1726

1727
	case 15: /* mul r,[r,]r */
1728
		o1 = c.oprrr(p, p.As, int(p.Scond))
1729

1730
		rf := int(p.From.Reg)
1731
		rt := int(p.To.Reg)
1732
		r := int(p.Reg)
1733
		if r == 0 {
1734
			r = rt
1735
		}
1736

1737
		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
1738

1739
	case 16: /* div r,[r,]r */
1740
		o1 = 0xf << 28
1741

1742
		o2 = 0
1743

1744
	case 17:
1745
		o1 = c.oprrr(p, p.As, int(p.Scond))
1746
		rf := int(p.From.Reg)
1747
		rt := int(p.To.Reg)
1748
		rt2 := int(p.To.Offset)
1749
		r := int(p.Reg)
1750
		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
1751

1752
	case 18: /* BFX/BFXU/BFC/BFI */
1753
		o1 = c.oprrr(p, p.As, int(p.Scond))
1754
		rt := int(p.To.Reg)
1755
		r := int(p.Reg)
1756
		if r == 0 {
1757
			r = rt
1758
		} else if p.As == ABFC { // only "BFC $width, $lsb, Reg" is accepted, p.Reg must be 0
1759
			c.ctxt.Diag("illegal combination: %v", p)
1760
		}
1761
		if p.GetFrom3() == nil || p.GetFrom3().Type != obj.TYPE_CONST {
1762
			c.ctxt.Diag("%v: missing or wrong LSB", p)
1763
			break
1764
		}
1765
		lsb := p.GetFrom3().Offset
1766
		width := p.From.Offset
1767
		if lsb < 0 || lsb > 31 || width <= 0 || (lsb+width) > 32 {
1768
			c.ctxt.Diag("%v: wrong width or LSB", p)
1769
		}
1770
		switch p.As {
1771
		case ABFX, ABFXU: // (width-1) is encoded
1772
			o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(width-1)<<16
1773
		case ABFC, ABFI: // MSB is encoded
1774
			o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(lsb+width-1)<<16
1775
		default:
1776
			c.ctxt.Diag("illegal combination: %v", p)
1777
		}
1778

1779
	case 20: /* mov/movb/movbu R,O(R) */
1780
		c.aclass(&p.To)
1781

1782
		r := int(p.To.Reg)
1783
		if r == 0 {
1784
			r = int(o.param)
1785
		}
1786
		o1 = c.osr(p.As, int(p.From.Reg), int32(c.instoffset), r, int(p.Scond))
1787

1788
	case 21: /* mov/movbu O(R),R -> lr */
1789
		c.aclass(&p.From)
1790

1791
		r := int(p.From.Reg)
1792
		if r == 0 {
1793
			r = int(o.param)
1794
		}
1795
		o1 = c.olr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond))
1796
		if p.As != AMOVW {
1797
			o1 |= 1 << 22
1798
		}
1799

1800
	case 22: /* XTAB R@>i, [R], R */
1801
		o1 = c.oprrr(p, p.As, int(p.Scond))
1802
		switch p.From.Offset &^ 0xf {
1803
		// only 0/8/16/24 bits rotation is accepted
1804
		case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7:
1805
			o1 |= uint32(p.From.Offset) & 0xc0f
1806
		default:
1807
			c.ctxt.Diag("illegal shift: %v", p)
1808
		}
1809
		rt := p.To.Reg
1810
		r := p.Reg
1811
		if r == 0 {
1812
			r = rt
1813
		}
1814
		o1 |= (uint32(rt)&15)<<12 | (uint32(r)&15)<<16
1815

1816
	case 23: /* MOVW/MOVB/MOVH R@>i, R */
1817
		switch p.As {
1818
		case AMOVW:
1819
			o1 = c.mov(p)
1820
		case AMOVBU, AMOVBS, AMOVB, AMOVHU, AMOVHS, AMOVH:
1821
			o1 = c.movxt(p)
1822
		default:
1823
			c.ctxt.Diag("illegal combination: %v", p)
1824
		}
1825

1826
	case 30: /* mov/movb/movbu R,L(R) */
1827
		o1 = c.omvl(p, &p.To, REGTMP)
1828

1829
		if o1 == 0 {
1830
			break
1831
		}
1832
		r := int(p.To.Reg)
1833
		if r == 0 {
1834
			r = int(o.param)
1835
		}
1836
		o2 = c.osrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond))
1837
		if p.As != AMOVW {
1838
			o2 |= 1 << 22
1839
		}
1840

1841
	case 31: /* mov/movbu L(R),R -> lr[b] */
1842
		o1 = c.omvl(p, &p.From, REGTMP)
1843

1844
		if o1 == 0 {
1845
			break
1846
		}
1847
		r := int(p.From.Reg)
1848
		if r == 0 {
1849
			r = int(o.param)
1850
		}
1851
		o2 = c.olrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond))
1852
		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
1853
			o2 |= 1 << 22
1854
		}
1855

1856
	case 34: /* mov $lacon,R */
1857
		o1 = c.omvl(p, &p.From, REGTMP)
1858

1859
		if o1 == 0 {
1860
			break
1861
		}
1862

1863
		o2 = c.oprrr(p, AADD, int(p.Scond))
1864
		o2 |= REGTMP & 15
1865
		r := int(p.From.Reg)
1866
		if r == 0 {
1867
			r = int(o.param)
1868
		}
1869
		o2 |= (uint32(r) & 15) << 16
1870
		if p.To.Type != obj.TYPE_NONE {
1871
			o2 |= (uint32(p.To.Reg) & 15) << 12
1872
		}
1873

1874
	case 35: /* mov PSR,R */
1875
		o1 = 2<<23 | 0xf<<16 | 0<<0
1876

1877
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1878
		o1 |= (uint32(p.From.Reg) & 1) << 22
1879
		o1 |= (uint32(p.To.Reg) & 15) << 12
1880

1881
	case 36: /* mov R,PSR */
1882
		o1 = 2<<23 | 0x2cf<<12 | 0<<4
1883

1884
		if p.Scond&C_FBIT != 0 {
1885
			o1 ^= 0x010 << 12
1886
		}
1887
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1888
		o1 |= (uint32(p.To.Reg) & 1) << 22
1889
		o1 |= (uint32(p.From.Reg) & 15) << 0
1890

1891
	case 37: /* mov $con,PSR */
1892
		c.aclass(&p.From)
1893

1894
		o1 = 2<<23 | 0x2cf<<12 | 0<<4
1895
		if p.Scond&C_FBIT != 0 {
1896
			o1 ^= 0x010 << 12
1897
		}
1898
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1899
		o1 |= uint32(immrot(uint32(c.instoffset)))
1900
		o1 |= (uint32(p.To.Reg) & 1) << 22
1901
		o1 |= (uint32(p.From.Reg) & 15) << 0
1902

1903
	case 38, 39:
1904
		switch o.type_ {
1905
		case 38: /* movm $con,oreg -> stm */
1906
			o1 = 0x4 << 25
1907

1908
			o1 |= uint32(p.From.Offset & 0xffff)
1909
			o1 |= (uint32(p.To.Reg) & 15) << 16
1910
			c.aclass(&p.To)
1911

1912
		case 39: /* movm oreg,$con -> ldm */
1913
			o1 = 0x4<<25 | 1<<20
1914

1915
			o1 |= uint32(p.To.Offset & 0xffff)
1916
			o1 |= (uint32(p.From.Reg) & 15) << 16
1917
			c.aclass(&p.From)
1918
		}
1919

1920
		if c.instoffset != 0 {
1921
			c.ctxt.Diag("offset must be zero in MOVM; %v", p)
1922
		}
1923
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1924
		if p.Scond&C_PBIT != 0 {
1925
			o1 |= 1 << 24
1926
		}
1927
		if p.Scond&C_UBIT != 0 {
1928
			o1 |= 1 << 23
1929
		}
1930
		if p.Scond&C_WBIT != 0 {
1931
			o1 |= 1 << 21
1932
		}
1933

1934
	case 40: /* swp oreg,reg,reg */
1935
		c.aclass(&p.From)
1936

1937
		if c.instoffset != 0 {
1938
			c.ctxt.Diag("offset must be zero in SWP")
1939
		}
1940
		o1 = 0x2<<23 | 0x9<<4
1941
		if p.As != ASWPW {
1942
			o1 |= 1 << 22
1943
		}
1944
		o1 |= (uint32(p.From.Reg) & 15) << 16
1945
		o1 |= (uint32(p.Reg) & 15) << 0
1946
		o1 |= (uint32(p.To.Reg) & 15) << 12
1947
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
1948

1949
	case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
1950
		o1 = 0xe8fd8000
1951

1952
	case 50: /* floating point store */
1953
		v := c.regoff(&p.To)
1954

1955
		r := int(p.To.Reg)
1956
		if r == 0 {
1957
			r = int(o.param)
1958
		}
1959
		o1 = c.ofsr(p.As, int(p.From.Reg), v, r, int(p.Scond), p)
1960

1961
	case 51: /* floating point load */
1962
		v := c.regoff(&p.From)
1963

1964
		r := int(p.From.Reg)
1965
		if r == 0 {
1966
			r = int(o.param)
1967
		}
1968
		o1 = c.ofsr(p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
1969

1970
	case 52: /* floating point store, int32 offset UGLY */
1971
		o1 = c.omvl(p, &p.To, REGTMP)
1972

1973
		if o1 == 0 {
1974
			break
1975
		}
1976
		r := int(p.To.Reg)
1977
		if r == 0 {
1978
			r = int(o.param)
1979
		}
1980
		o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
1981
		o3 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
1982

1983
	case 53: /* floating point load, int32 offset UGLY */
1984
		o1 = c.omvl(p, &p.From, REGTMP)
1985

1986
		if o1 == 0 {
1987
			break
1988
		}
1989
		r := int(p.From.Reg)
1990
		if r == 0 {
1991
			r = int(o.param)
1992
		}
1993
		o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
1994
		o3 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
1995

1996
	case 54: /* floating point arith */
1997
		o1 = c.oprrr(p, p.As, int(p.Scond))
1998

1999
		rf := int(p.From.Reg)
2000
		rt := int(p.To.Reg)
2001
		r := int(p.Reg)
2002
		if r == 0 {
2003
			switch p.As {
2004
			case AMULAD, AMULAF, AMULSF, AMULSD, ANMULAF, ANMULAD, ANMULSF, ANMULSD,
2005
				AFMULAD, AFMULAF, AFMULSF, AFMULSD, AFNMULAF, AFNMULAD, AFNMULSF, AFNMULSD:
2006
				c.ctxt.Diag("illegal combination: %v", p)
2007
			default:
2008
				r = rt
2009
			}
2010
		}
2011

2012
		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
2013

2014
	case 55: /* negf freg, freg */
2015
		o1 = c.oprrr(p, p.As, int(p.Scond))
2016

2017
		rf := int(p.From.Reg)
2018
		rt := int(p.To.Reg)
2019

2020
		o1 |= (uint32(rf)&15)<<0 | (uint32(rt)&15)<<12
2021

2022
	case 56: /* move to FP[CS]R */
2023
		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xee1<<16 | 0xa1<<4
2024

2025
		o1 |= (uint32(p.From.Reg) & 15) << 12
2026

2027
	case 57: /* move from FP[CS]R */
2028
		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xef1<<16 | 0xa1<<4
2029

2030
		o1 |= (uint32(p.To.Reg) & 15) << 12
2031

2032
	case 58: /* movbu R,R */
2033
		o1 = c.oprrr(p, AAND, int(p.Scond))
2034

2035
		o1 |= uint32(immrot(0xff))
2036
		rt := int(p.To.Reg)
2037
		r := int(p.From.Reg)
2038
		if p.To.Type == obj.TYPE_NONE {
2039
			rt = 0
2040
		}
2041
		if r == 0 {
2042
			r = rt
2043
		}
2044
		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
2045

2046
	case 59: /* movw/bu R<<I(R),R -> ldr indexed */
2047
		if p.From.Reg == 0 {
2048
			c.ctxt.Diag("source operand is not a memory address: %v", p)
2049
			break
2050
		}
2051
		if p.From.Offset&(1<<4) != 0 {
2052
			c.ctxt.Diag("bad shift in LDR")
2053
			break
2054
		}
2055
		o1 = c.olrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
2056
		if p.As == AMOVBU {
2057
			o1 |= 1 << 22
2058
		}
2059

2060
	case 60: /* movb R(R),R -> ldrsb indexed */
2061
		if p.From.Reg == 0 {
2062
			c.ctxt.Diag("source operand is not a memory address: %v", p)
2063
			break
2064
		}
2065
		if p.From.Offset&(^0xf) != 0 {
2066
			c.ctxt.Diag("bad shift: %v", p)
2067
			break
2068
		}
2069
		o1 = c.olhrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
2070
		switch p.As {
2071
		case AMOVB, AMOVBS:
2072
			o1 ^= 1<<5 | 1<<6
2073
		case AMOVH, AMOVHS:
2074
			o1 ^= 1 << 6
2075
		default:
2076
		}
2077
		if p.Scond&C_UBIT != 0 {
2078
			o1 &^= 1 << 23
2079
		}
2080

2081
	case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
2082
		if p.To.Reg == 0 {
2083
			c.ctxt.Diag("MOV to shifter operand")
2084
		}
2085
		o1 = c.osrr(int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
2086
		if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
2087
			o1 |= 1 << 22
2088
		}
2089

2090
	case 62: /* MOVH/MOVHS/MOVHU Reg, Reg<<0(Reg) -> strh */
2091
		if p.To.Reg == 0 {
2092
			c.ctxt.Diag("MOV to shifter operand")
2093
		}
2094
		if p.To.Offset&(^0xf) != 0 {
2095
			c.ctxt.Diag("bad shift: %v", p)
2096
		}
2097
		o1 = c.olhrr(int(p.To.Offset), int(p.To.Reg), int(p.From.Reg), int(p.Scond))
2098
		o1 ^= 1 << 20
2099
		if p.Scond&C_UBIT != 0 {
2100
			o1 &^= 1 << 23
2101
		}
2102

2103
		/* reloc ops */
2104
	case 64: /* mov/movb/movbu R,addr */
2105
		o1 = c.omvl(p, &p.To, REGTMP)
2106

2107
		if o1 == 0 {
2108
			break
2109
		}
2110
		o2 = c.osr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond))
2111
		if o.flag&LPCREL != 0 {
2112
			o3 = o2
2113
			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2114
		}
2115

2116
	case 65: /* mov/movbu addr,R */
2117
		o1 = c.omvl(p, &p.From, REGTMP)
2118

2119
		if o1 == 0 {
2120
			break
2121
		}
2122
		o2 = c.olr(0, REGTMP, int(p.To.Reg), int(p.Scond))
2123
		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
2124
			o2 |= 1 << 22
2125
		}
2126
		if o.flag&LPCREL != 0 {
2127
			o3 = o2
2128
			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2129
		}
2130

2131
	case 101: /* movw tlsvar,R, local exec*/
2132
		o1 = c.omvl(p, &p.From, int(p.To.Reg))
2133

2134
	case 102: /* movw tlsvar,R, initial exec*/
2135
		o1 = c.omvl(p, &p.From, int(p.To.Reg))
2136
		o2 = c.olrr(int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond))
2137

2138
	case 103: /* word tlsvar, local exec */
2139
		if p.To.Sym == nil {
2140
			c.ctxt.Diag("nil sym in tls %v", p)
2141
		}
2142
		if p.To.Offset != 0 {
2143
			c.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.
2147
		rel := obj.Addrel(c.cursym)
2148

2149
		rel.Off = int32(c.pc)
2150
		rel.Siz = 4
2151
		rel.Sym = p.To.Sym
2152
		rel.Type = objabi.R_TLS_LE
2153
		o1 = 0
2154

2155
	case 104: /* word tlsvar, initial exec */
2156
		if p.To.Sym == nil {
2157
			c.ctxt.Diag("nil sym in tls %v", p)
2158
		}
2159
		if p.To.Offset != 0 {
2160
			c.ctxt.Diag("offset against tls var in %v", p)
2161
		}
2162
		rel := obj.Addrel(c.cursym)
2163
		rel.Off = int32(c.pc)
2164
		rel.Siz = 4
2165
		rel.Sym = p.To.Sym
2166
		rel.Type = objabi.R_TLS_IE
2167
		rel.Add = c.pc - p.Rel.Pc - 8 - int64(rel.Siz)
2168

2169
	case 68: /* floating point store -> ADDR */
2170
		o1 = c.omvl(p, &p.To, REGTMP)
2171

2172
		if o1 == 0 {
2173
			break
2174
		}
2175
		o2 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
2176
		if o.flag&LPCREL != 0 {
2177
			o3 = o2
2178
			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2179
		}
2180

2181
	case 69: /* floating point load <- ADDR */
2182
		o1 = c.omvl(p, &p.From, REGTMP)
2183

2184
		if o1 == 0 {
2185
			break
2186
		}
2187
		o2 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
2188
		if o.flag&LPCREL != 0 {
2189
			o3 = o2
2190
			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2191
		}
2192

2193
		/* ArmV4 ops: */
2194
	case 70: /* movh/movhu R,O(R) -> strh */
2195
		c.aclass(&p.To)
2196

2197
		r := int(p.To.Reg)
2198
		if r == 0 {
2199
			r = int(o.param)
2200
		}
2201
		o1 = c.oshr(int(p.From.Reg), int32(c.instoffset), r, int(p.Scond))
2202

2203
	case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
2204
		c.aclass(&p.From)
2205

2206
		r := int(p.From.Reg)
2207
		if r == 0 {
2208
			r = int(o.param)
2209
		}
2210
		o1 = c.olhr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond))
2211
		if p.As == AMOVB || p.As == AMOVBS {
2212
			o1 ^= 1<<5 | 1<<6
2213
		} else if p.As == AMOVH || p.As == AMOVHS {
2214
			o1 ^= (1 << 6)
2215
		}
2216

2217
	case 72: /* movh/movhu R,L(R) -> strh */
2218
		o1 = c.omvl(p, &p.To, REGTMP)
2219

2220
		if o1 == 0 {
2221
			break
2222
		}
2223
		r := int(p.To.Reg)
2224
		if r == 0 {
2225
			r = int(o.param)
2226
		}
2227
		o2 = c.oshrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond))
2228

2229
	case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
2230
		o1 = c.omvl(p, &p.From, REGTMP)
2231

2232
		if o1 == 0 {
2233
			break
2234
		}
2235
		r := int(p.From.Reg)
2236
		if r == 0 {
2237
			r = int(o.param)
2238
		}
2239
		o2 = c.olhrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond))
2240
		if p.As == AMOVB || p.As == AMOVBS {
2241
			o2 ^= 1<<5 | 1<<6
2242
		} else if p.As == AMOVH || p.As == AMOVHS {
2243
			o2 ^= (1 << 6)
2244
		}
2245

2246
	case 74: /* bx $I */
2247
		c.ctxt.Diag("ABX $I")
2248

2249
	case 75: /* bx O(R) */
2250
		c.aclass(&p.To)
2251

2252
		if c.instoffset != 0 {
2253
			c.ctxt.Diag("non-zero offset in ABX")
2254
		}
2255

2256
		/*
2257
			o1 = 	c.oprrr(p, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12);	// mov PC, LR
2258
			o2 = (((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
2261
		o1 = c.oprrr(p, AADD, int(p.Scond))
2262

2263
		o1 |= uint32(immrot(uint32(c.instoffset)))
2264
		o1 |= (uint32(p.To.Reg) & 15) << 16
2265
		o1 |= (REGTMP & 15) << 12
2266
		o2 = c.oprrr(p, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
2267
		o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15            // BX Rtmp
2268

2269
	case 76: /* bx O(R) when returning from fn*/
2270
		c.ctxt.Diag("ABXRET")
2271

2272
	case 77: /* ldrex oreg,reg */
2273
		c.aclass(&p.From)
2274

2275
		if c.instoffset != 0 {
2276
			c.ctxt.Diag("offset must be zero in LDREX")
2277
		}
2278
		o1 = 0x19<<20 | 0xf9f
2279
		o1 |= (uint32(p.From.Reg) & 15) << 16
2280
		o1 |= (uint32(p.To.Reg) & 15) << 12
2281
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2282

2283
	case 78: /* strex reg,oreg,reg */
2284
		c.aclass(&p.From)
2285

2286
		if c.instoffset != 0 {
2287
			c.ctxt.Diag("offset must be zero in STREX")
2288
		}
2289
		if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg {
2290
			c.ctxt.Diag("cannot use same register as both source and destination: %v", p)
2291
		}
2292
		o1 = 0x18<<20 | 0xf90
2293
		o1 |= (uint32(p.From.Reg) & 15) << 16
2294
		o1 |= (uint32(p.Reg) & 15) << 0
2295
		o1 |= (uint32(p.To.Reg) & 15) << 12
2296
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2297

2298
	case 80: /* fmov zfcon,freg */
2299
		if p.As == AMOVD {
2300
			o1 = 0xeeb00b00 // VMOV imm 64
2301
			o2 = c.oprrr(p, ASUBD, int(p.Scond))
2302
		} else {
2303
			o1 = 0x0eb00a00 // VMOV imm 32
2304
			o2 = c.oprrr(p, ASUBF, int(p.Scond))
2305
		}
2306

2307
		v := int32(0x70) // 1.0
2308
		r := (int(p.To.Reg) & 15) << 0
2309

2310
		// movf $1.0, r
2311
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2312

2313
		o1 |= (uint32(r) & 15) << 12
2314
		o1 |= (uint32(v) & 0xf) << 0
2315
		o1 |= (uint32(v) & 0xf0) << 12
2316

2317
		// subf r,r,r
2318
		o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12
2319

2320
	case 81: /* fmov sfcon,freg */
2321
		o1 = 0x0eb00a00 // VMOV imm 32
2322
		if p.As == AMOVD {
2323
			o1 = 0xeeb00b00 // VMOV imm 64
2324
		}
2325
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2326
		o1 |= (uint32(p.To.Reg) & 15) << 12
2327
		v := int32(c.chipfloat5(p.From.Val.(float64)))
2328
		o1 |= (uint32(v) & 0xf) << 0
2329
		o1 |= (uint32(v) & 0xf0) << 12
2330

2331
	case 82: /* fcmp freg,freg, */
2332
		o1 = c.oprrr(p, p.As, int(p.Scond))
2333

2334
		o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0
2335
		o2 = 0x0ef1fa10 // VMRS R15
2336
		o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2337

2338
	case 83: /* fcmp freg,, */
2339
		o1 = c.oprrr(p, p.As, int(p.Scond))
2340

2341
		o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16
2342
		o2 = 0x0ef1fa10 // VMRS R15
2343
		o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2344

2345
	case 84: /* movfw freg,freg - truncate float-to-fix */
2346
		o1 = c.oprrr(p, p.As, int(p.Scond))
2347

2348
		o1 |= (uint32(p.From.Reg) & 15) << 0
2349
		o1 |= (uint32(p.To.Reg) & 15) << 12
2350

2351
	case 85: /* movwf freg,freg - fix-to-float */
2352
		o1 = c.oprrr(p, p.As, int(p.Scond))
2353

2354
		o1 |= (uint32(p.From.Reg) & 15) << 0
2355
		o1 |= (uint32(p.To.Reg) & 15) << 12
2356

2357
		// macro for movfw freg,FTMP; movw FTMP,reg
2358
	case 86: /* movfw freg,reg - truncate float-to-fix */
2359
		o1 = c.oprrr(p, p.As, int(p.Scond))
2360

2361
		o1 |= (uint32(p.From.Reg) & 15) << 0
2362
		o1 |= (FREGTMP & 15) << 12
2363
		o2 = c.oprrr(p, -AMOVFW, int(p.Scond))
2364
		o2 |= (FREGTMP & 15) << 16
2365
		o2 |= (uint32(p.To.Reg) & 15) << 12
2366

2367
		// macro for movw reg,FTMP; movwf FTMP,freg
2368
	case 87: /* movwf reg,freg - fix-to-float */
2369
		o1 = c.oprrr(p, -AMOVWF, int(p.Scond))
2370

2371
		o1 |= (uint32(p.From.Reg) & 15) << 12
2372
		o1 |= (FREGTMP & 15) << 16
2373
		o2 = c.oprrr(p, p.As, int(p.Scond))
2374
		o2 |= (FREGTMP & 15) << 0
2375
		o2 |= (uint32(p.To.Reg) & 15) << 12
2376

2377
	case 88: /* movw reg,freg  */
2378
		o1 = c.oprrr(p, -AMOVWF, int(p.Scond))
2379

2380
		o1 |= (uint32(p.From.Reg) & 15) << 12
2381
		o1 |= (uint32(p.To.Reg) & 15) << 16
2382

2383
	case 89: /* movw freg,reg  */
2384
		o1 = c.oprrr(p, -AMOVFW, int(p.Scond))
2385

2386
		o1 |= (uint32(p.From.Reg) & 15) << 16
2387
		o1 |= (uint32(p.To.Reg) & 15) << 12
2388

2389
	case 91: /* ldrexd oreg,reg */
2390
		c.aclass(&p.From)
2391

2392
		if c.instoffset != 0 {
2393
			c.ctxt.Diag("offset must be zero in LDREX")
2394
		}
2395
		o1 = 0x1b<<20 | 0xf9f
2396
		o1 |= (uint32(p.From.Reg) & 15) << 16
2397
		o1 |= (uint32(p.To.Reg) & 15) << 12
2398
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2399

2400
	case 92: /* strexd reg,oreg,reg */
2401
		c.aclass(&p.From)
2402

2403
		if c.instoffset != 0 {
2404
			c.ctxt.Diag("offset must be zero in STREX")
2405
		}
2406
		if p.Reg&1 != 0 {
2407
			c.ctxt.Diag("source register must be even in STREXD: %v", p)
2408
		}
2409
		if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg || p.To.Reg == p.Reg+1 {
2410
			c.ctxt.Diag("cannot use same register as both source and destination: %v", p)
2411
		}
2412
		o1 = 0x1a<<20 | 0xf90
2413
		o1 |= (uint32(p.From.Reg) & 15) << 16
2414
		o1 |= (uint32(p.Reg) & 15) << 0
2415
		o1 |= (uint32(p.To.Reg) & 15) << 12
2416
		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2417

2418
	case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
2419
		o1 = c.omvl(p, &p.From, REGTMP)
2420

2421
		if o1 == 0 {
2422
			break
2423
		}
2424
		o2 = c.olhr(0, REGTMP, int(p.To.Reg), int(p.Scond))
2425
		if p.As == AMOVB || p.As == AMOVBS {
2426
			o2 ^= 1<<5 | 1<<6
2427
		} else if p.As == AMOVH || p.As == AMOVHS {
2428
			o2 ^= (1 << 6)
2429
		}
2430
		if o.flag&LPCREL != 0 {
2431
			o3 = o2
2432
			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2433
		}
2434

2435
	case 94: /* movh/movhu R,addr -> strh */
2436
		o1 = c.omvl(p, &p.To, REGTMP)
2437

2438
		if o1 == 0 {
2439
			break
2440
		}
2441
		o2 = c.oshr(int(p.From.Reg), 0, REGTMP, int(p.Scond))
2442
		if o.flag&LPCREL != 0 {
2443
			o3 = o2
2444
			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
2445
		}
2446

2447
	case 95: /* PLD off(reg) */
2448
		o1 = 0xf5d0f000
2449

2450
		o1 |= (uint32(p.From.Reg) & 15) << 16
2451
		if p.From.Offset < 0 {
2452
			o1 &^= (1 << 23)
2453
			o1 |= uint32((-p.From.Offset) & 0xfff)
2454
		} else {
2455
			o1 |= 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.
2463
	case 96: /* UNDEF */
2464
		o1 = 0xf7fabcfd
2465

2466
	case 97: /* CLZ Rm, Rd */
2467
		o1 = c.oprrr(p, p.As, int(p.Scond))
2468

2469
		o1 |= (uint32(p.To.Reg) & 15) << 12
2470
		o1 |= (uint32(p.From.Reg) & 15) << 0
2471

2472
	case 98: /* MULW{T,B} Rs, Rm, Rd */
2473
		o1 = c.oprrr(p, p.As, int(p.Scond))
2474

2475
		o1 |= (uint32(p.To.Reg) & 15) << 16
2476
		o1 |= (uint32(p.From.Reg) & 15) << 8
2477
		o1 |= (uint32(p.Reg) & 15) << 0
2478

2479
	case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
2480
		o1 = c.oprrr(p, p.As, int(p.Scond))
2481

2482
		o1 |= (uint32(p.To.Reg) & 15) << 16
2483
		o1 |= (uint32(p.From.Reg) & 15) << 8
2484
		o1 |= (uint32(p.Reg) & 15) << 0
2485
		o1 |= uint32((p.To.Offset & 15) << 12)
2486

2487
	case 105: /* divhw r,[r,]r */
2488
		o1 = c.oprrr(p, p.As, int(p.Scond))
2489
		rf := int(p.From.Reg)
2490
		rt := int(p.To.Reg)
2491
		r := int(p.Reg)
2492
		if r == 0 {
2493
			r = rt
2494
		}
2495
		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
2496

2497
	case 110: /* dmb [mbop | $con] */
2498
		o1 = 0xf57ff050
2499
		mbop := uint32(0)
2500

2501
		switch c.aclass(&p.From) {
2502
		case C_SPR:
2503
			for _, f := range mbOp {
2504
				if f.reg == p.From.Reg {
2505
					mbop = f.enc
2506
					break
2507
				}
2508
			}
2509
		case C_RCON:
2510
			for _, f := range mbOp {
2511
				enc := uint32(c.instoffset)
2512
				if f.enc == enc {
2513
					mbop = enc
2514
					break
2515
				}
2516
			}
2517
		case C_NONE:
2518
			mbop = 0xf
2519
		}
2520

2521
		if mbop == 0 {
2522
			c.ctxt.Diag("illegal mb option:\n%v", p)
2523
		}
2524
		o1 |= mbop
2525
	}
2526

2527
	out[0] = o1
2528
	out[1] = o2
2529
	out[2] = o3
2530
	out[3] = o4
2531
	out[4] = o5
2532
	out[5] = o6
2533
}
2534

2535
func (c *ctxt5) movxt(p *obj.Prog) uint32 {
2536
	o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
2537
	switch p.As {
2538
	case AMOVB, AMOVBS:
2539
		o1 |= 0x6af<<16 | 0x7<<4
2540
	case AMOVH, AMOVHS:
2541
		o1 |= 0x6bf<<16 | 0x7<<4
2542
	case AMOVBU:
2543
		o1 |= 0x6ef<<16 | 0x7<<4
2544
	case AMOVHU:
2545
		o1 |= 0x6ff<<16 | 0x7<<4
2546
	default:
2547
		c.ctxt.Diag("illegal combination: %v", p)
2548
	}
2549
	switch p.From.Offset &^ 0xf {
2550
	// only 0/8/16/24 bits rotation is accepted
2551
	case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7:
2552
		o1 |= uint32(p.From.Offset) & 0xc0f
2553
	default:
2554
		c.ctxt.Diag("illegal shift: %v", p)
2555
	}
2556
	o1 |= (uint32(p.To.Reg) & 15) << 12
2557
	return o1
2558
}
2559

2560
func (c *ctxt5) mov(p *obj.Prog) uint32 {
2561
	c.aclass(&p.From)
2562
	o1 := c.oprrr(p, p.As, int(p.Scond))
2563
	o1 |= uint32(p.From.Offset)
2564
	rt := int(p.To.Reg)
2565
	if p.To.Type == obj.TYPE_NONE {
2566
		rt = 0
2567
	}
2568
	r := int(p.Reg)
2569
	if p.As == AMOVW || p.As == AMVN {
2570
		r = 0
2571
	} else if r == 0 {
2572
		r = rt
2573
	}
2574
	o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
2575
	return o1
2576
}
2577

2578
func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 {
2579
	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2580
	if sc&C_SBIT != 0 {
2581
		o |= 1 << 20
2582
	}
2583
	switch a {
2584
	case ADIVHW:
2585
		return o | 0x71<<20 | 0xf<<12 | 0x1<<4
2586
	case ADIVUHW:
2587
		return o | 0x73<<20 | 0xf<<12 | 0x1<<4
2588
	case AMMUL:
2589
		return o | 0x75<<20 | 0xf<<12 | 0x1<<4
2590
	case AMULS:
2591
		return o | 0x6<<20 | 0x9<<4
2592
	case AMMULA:
2593
		return o | 0x75<<20 | 0x1<<4
2594
	case AMMULS:
2595
		return o | 0x75<<20 | 0xd<<4
2596
	case AMULU, AMUL:
2597
		return o | 0x0<<21 | 0x9<<4
2598
	case AMULA:
2599
		return o | 0x1<<21 | 0x9<<4
2600
	case AMULLU:
2601
		return o | 0x4<<21 | 0x9<<4
2602
	case AMULL:
2603
		return o | 0x6<<21 | 0x9<<4
2604
	case AMULALU:
2605
		return o | 0x5<<21 | 0x9<<4
2606
	case AMULAL:
2607
		return o | 0x7<<21 | 0x9<<4
2608
	case AAND:
2609
		return o | 0x0<<21
2610
	case AEOR:
2611
		return o | 0x1<<21
2612
	case ASUB:
2613
		return o | 0x2<<21
2614
	case ARSB:
2615
		return o | 0x3<<21
2616
	case AADD:
2617
		return o | 0x4<<21
2618
	case AADC:
2619
		return o | 0x5<<21
2620
	case ASBC:
2621
		return o | 0x6<<21
2622
	case ARSC:
2623
		return o | 0x7<<21
2624
	case ATST:
2625
		return o | 0x8<<21 | 1<<20
2626
	case ATEQ:
2627
		return o | 0x9<<21 | 1<<20
2628
	case ACMP:
2629
		return o | 0xa<<21 | 1<<20
2630
	case ACMN:
2631
		return o | 0xb<<21 | 1<<20
2632
	case AORR:
2633
		return o | 0xc<<21
2634

2635
	case AMOVB, AMOVH, AMOVW:
2636
		if sc&(C_PBIT|C_WBIT) != 0 {
2637
			c.ctxt.Diag("invalid .P/.W suffix: %v", p)
2638
		}
2639
		return o | 0xd<<21
2640
	case ABIC:
2641
		return o | 0xe<<21
2642
	case AMVN:
2643
		return o | 0xf<<21
2644
	case ASLL:
2645
		return o | 0xd<<21 | 0<<5
2646
	case ASRL:
2647
		return o | 0xd<<21 | 1<<5
2648
	case ASRA:
2649
		return o | 0xd<<21 | 2<<5
2650
	case ASWI:
2651
		return o | 0xf<<24
2652

2653
	case AADDD:
2654
		return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4
2655
	case AADDF:
2656
		return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4
2657
	case ASUBD:
2658
		return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4
2659
	case ASUBF:
2660
		return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4
2661
	case AMULD:
2662
		return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4
2663
	case AMULF:
2664
		return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4
2665
	case ANMULD:
2666
		return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0x4<<4
2667
	case ANMULF:
2668
		return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0x4<<4
2669
	case AMULAD:
2670
		return o | 0xe<<24 | 0xb<<8
2671
	case AMULAF:
2672
		return o | 0xe<<24 | 0xa<<8
2673
	case AMULSD:
2674
		return o | 0xe<<24 | 0xb<<8 | 0x4<<4
2675
	case AMULSF:
2676
		return o | 0xe<<24 | 0xa<<8 | 0x4<<4
2677
	case ANMULAD:
2678
		return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 0x4<<4
2679
	case ANMULAF:
2680
		return o | 0xe<<24 | 0x1<<20 | 0xa<<8 | 0x4<<4
2681
	case ANMULSD:
2682
		return o | 0xe<<24 | 0x1<<20 | 0xb<<8
2683
	case ANMULSF:
2684
		return o | 0xe<<24 | 0x1<<20 | 0xa<<8
2685
	case AFMULAD:
2686
		return o | 0xe<<24 | 0xa<<20 | 0xb<<8
2687
	case AFMULAF:
2688
		return o | 0xe<<24 | 0xa<<20 | 0xa<<8
2689
	case AFMULSD:
2690
		return o | 0xe<<24 | 0xa<<20 | 0xb<<8 | 0x4<<4
2691
	case AFMULSF:
2692
		return o | 0xe<<24 | 0xa<<20 | 0xa<<8 | 0x4<<4
2693
	case AFNMULAD:
2694
		return o | 0xe<<24 | 0x9<<20 | 0xb<<8 | 0x4<<4
2695
	case AFNMULAF:
2696
		return o | 0xe<<24 | 0x9<<20 | 0xa<<8 | 0x4<<4
2697
	case AFNMULSD:
2698
		return o | 0xe<<24 | 0x9<<20 | 0xb<<8
2699
	case AFNMULSF:
2700
		return o | 0xe<<24 | 0x9<<20 | 0xa<<8
2701
	case ADIVD:
2702
		return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4
2703
	case ADIVF:
2704
		return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4
2705
	case ASQRTD:
2706
		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4
2707
	case ASQRTF:
2708
		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4
2709
	case AABSD:
2710
		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
2711
	case AABSF:
2712
		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
2713
	case ANEGD:
2714
		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4
2715
	case ANEGF:
2716
		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4
2717
	case ACMPD:
2718
		return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
2719
	case ACMPF:
2720
		return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4
2721

2722
	case AMOVF:
2723
		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4
2724
	case AMOVD:
2725
		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4
2726

2727
	case AMOVDF:
2728
		return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof
2729
	case AMOVFD:
2730
		return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof
2731

2732
	case AMOVWF:
2733
		if sc&C_UBIT == 0 {
2734
			o |= 1 << 7 /* signed */
2735
		}
2736
		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double
2737

2738
	case AMOVWD:
2739
		if sc&C_UBIT == 0 {
2740
			o |= 1 << 7 /* signed */
2741
		}
2742
		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double
2743

2744
	case AMOVFW:
2745
		if sc&C_UBIT == 0 {
2746
			o |= 1 << 16 /* signed */
2747
		}
2748
		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc
2749

2750
	case AMOVDW:
2751
		if sc&C_UBIT == 0 {
2752
			o |= 1 << 16 /* signed */
2753
		}
2754
		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc
2755

2756
	case -AMOVWF: // copy WtoF
2757
		return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
2758

2759
	case -AMOVFW: // copy FtoW
2760
		return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
2761

2762
	case -ACMP: // cmp imm
2763
		return o | 0x3<<24 | 0x5<<20
2764

2765
	case ABFX:
2766
		return o | 0x3d<<21 | 0x5<<4
2767

2768
	case ABFXU:
2769
		return o | 0x3f<<21 | 0x5<<4
2770

2771
	case ABFC:
2772
		return o | 0x3e<<21 | 0x1f
2773

2774
	case ABFI:
2775
		return o | 0x3e<<21 | 0x1<<4
2776

2777
	case AXTAB:
2778
		return o | 0x6a<<20 | 0x7<<4
2779

2780
	case AXTAH:
2781
		return o | 0x6b<<20 | 0x7<<4
2782

2783
	case AXTABU:
2784
		return o | 0x6e<<20 | 0x7<<4
2785

2786
	case AXTAHU:
2787
		return o | 0x6f<<20 | 0x7<<4
2788

2789
		// CLZ doesn't support .nil
2790
	case ACLZ:
2791
		return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
2792

2793
	case AREV:
2794
		return o&(0xf<<28) | 0x6bf<<16 | 0xf3<<4
2795

2796
	case AREV16:
2797
		return o&(0xf<<28) | 0x6bf<<16 | 0xfb<<4
2798

2799
	case AREVSH:
2800
		return o&(0xf<<28) | 0x6ff<<16 | 0xfb<<4
2801

2802
	case ARBIT:
2803
		return o&(0xf<<28) | 0x6ff<<16 | 0xf3<<4
2804

2805
	case AMULWT:
2806
		return o&(0xf<<28) | 0x12<<20 | 0xe<<4
2807

2808
	case AMULWB:
2809
		return o&(0xf<<28) | 0x12<<20 | 0xa<<4
2810

2811
	case AMULBB:
2812
		return o&(0xf<<28) | 0x16<<20 | 0x8<<4
2813

2814
	case AMULAWT:
2815
		return o&(0xf<<28) | 0x12<<20 | 0xc<<4
2816

2817
	case AMULAWB:
2818
		return o&(0xf<<28) | 0x12<<20 | 0x8<<4
2819

2820
	case AMULABB:
2821
		return o&(0xf<<28) | 0x10<<20 | 0x8<<4
2822

2823
	case ABL: // BLX REG
2824
		return o&(0xf<<28) | 0x12fff3<<4
2825
	}
2826

2827
	c.ctxt.Diag("%v: bad rrr %d", p, a)
2828
	return 0
2829
}
2830

2831
func (c *ctxt5) opbra(p *obj.Prog, a obj.As, sc int) uint32 {
2832
	sc &= C_SCOND
2833
	sc ^= C_SCOND_XOR
2834
	if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
2835
		return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
2836
	}
2837
	if sc != 0xe {
2838
		c.ctxt.Diag("%v: .COND on bcond instruction", p)
2839
	}
2840
	switch a {
2841
	case ABEQ:
2842
		return 0x0<<28 | 0x5<<25
2843
	case ABNE:
2844
		return 0x1<<28 | 0x5<<25
2845
	case ABCS:
2846
		return 0x2<<28 | 0x5<<25
2847
	case ABHS:
2848
		return 0x2<<28 | 0x5<<25
2849
	case ABCC:
2850
		return 0x3<<28 | 0x5<<25
2851
	case ABLO:
2852
		return 0x3<<28 | 0x5<<25
2853
	case ABMI:
2854
		return 0x4<<28 | 0x5<<25
2855
	case ABPL:
2856
		return 0x5<<28 | 0x5<<25
2857
	case ABVS:
2858
		return 0x6<<28 | 0x5<<25
2859
	case ABVC:
2860
		return 0x7<<28 | 0x5<<25
2861
	case ABHI:
2862
		return 0x8<<28 | 0x5<<25
2863
	case ABLS:
2864
		return 0x9<<28 | 0x5<<25
2865
	case ABGE:
2866
		return 0xa<<28 | 0x5<<25
2867
	case ABLT:
2868
		return 0xb<<28 | 0x5<<25
2869
	case ABGT:
2870
		return 0xc<<28 | 0x5<<25
2871
	case ABLE:
2872
		return 0xd<<28 | 0x5<<25
2873
	case AB:
2874
		return 0xe<<28 | 0x5<<25
2875
	}
2876

2877
	c.ctxt.Diag("%v: bad bra %v", p, a)
2878
	return 0
2879
}
2880

2881
func (c *ctxt5) olr(v int32, b int, r int, sc int) uint32 {
2882
	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2883
	if sc&C_PBIT == 0 {
2884
		o |= 1 << 24
2885
	}
2886
	if sc&C_UBIT == 0 {
2887
		o |= 1 << 23
2888
	}
2889
	if sc&C_WBIT != 0 {
2890
		o |= 1 << 21
2891
	}
2892
	o |= 1<<26 | 1<<20
2893
	if v < 0 {
2894
		if sc&C_UBIT != 0 {
2895
			c.ctxt.Diag(".U on neg offset")
2896
		}
2897
		v = -v
2898
		o ^= 1 << 23
2899
	}
2900

2901
	if v >= 1<<12 || v < 0 {
2902
		c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp)
2903
	}
2904
	o |= uint32(v)
2905
	o |= (uint32(b) & 15) << 16
2906
	o |= (uint32(r) & 15) << 12
2907
	return o
2908
}
2909

2910
func (c *ctxt5) olhr(v int32, b int, r int, sc int) uint32 {
2911
	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2912
	if sc&C_PBIT == 0 {
2913
		o |= 1 << 24
2914
	}
2915
	if sc&C_WBIT != 0 {
2916
		o |= 1 << 21
2917
	}
2918
	o |= 1<<23 | 1<<20 | 0xb<<4
2919
	if v < 0 {
2920
		v = -v
2921
		o ^= 1 << 23
2922
	}
2923

2924
	if v >= 1<<8 || v < 0 {
2925
		c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp)
2926
	}
2927
	o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
2928
	o |= (uint32(b) & 15) << 16
2929
	o |= (uint32(r) & 15) << 12
2930
	return o
2931
}
2932

2933
func (c *ctxt5) osr(a obj.As, r int, v int32, b int, sc int) uint32 {
2934
	o := c.olr(v, b, r, sc) ^ (1 << 20)
2935
	if a != AMOVW {
2936
		o |= 1 << 22
2937
	}
2938
	return o
2939
}
2940

2941
func (c *ctxt5) oshr(r int, v int32, b int, sc int) uint32 {
2942
	o := c.olhr(v, b, r, sc) ^ (1 << 20)
2943
	return o
2944
}
2945

2946
func (c *ctxt5) osrr(r int, i int, b int, sc int) uint32 {
2947
	return c.olr(int32(i), b, r, sc) ^ (1<<25 | 1<<20)
2948
}
2949

2950
func (c *ctxt5) oshrr(r int, i int, b int, sc int) uint32 {
2951
	return c.olhr(int32(i), b, r, sc) ^ (1<<22 | 1<<20)
2952
}
2953

2954
func (c *ctxt5) olrr(i int, b int, r int, sc int) uint32 {
2955
	return c.olr(int32(i), b, r, sc) ^ (1 << 25)
2956
}
2957

2958
func (c *ctxt5) olhrr(i int, b int, r int, sc int) uint32 {
2959
	return c.olhr(int32(i), b, r, sc) ^ (1 << 22)
2960
}
2961

2962
func (c *ctxt5) ofsr(a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
2963
	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
2964
	if sc&C_PBIT == 0 {
2965
		o |= 1 << 24
2966
	}
2967
	if sc&C_WBIT != 0 {
2968
		o |= 1 << 21
2969
	}
2970
	o |= 6<<25 | 1<<24 | 1<<23 | 10<<8
2971
	if v < 0 {
2972
		v = -v
2973
		o ^= 1 << 23
2974
	}
2975

2976
	if v&3 != 0 {
2977
		c.ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
2978
	} else if v >= 1<<10 || v < 0 {
2979
		c.ctxt.Diag("literal span too large: %d\n%v", v, p)
2980
	}
2981
	o |= (uint32(v) >> 2) & 0xFF
2982
	o |= (uint32(b) & 15) << 16
2983
	o |= (uint32(r) & 15) << 12
2984

2985
	switch a {
2986
	default:
2987
		c.ctxt.Diag("bad fst %v", a)
2988
		fallthrough
2989

2990
	case AMOVD:
2991
		o |= 1 << 8
2992
		fallthrough
2993

2994
	case AMOVF:
2995
		break
2996
	}
2997

2998
	return o
2999
}
3000

3001
// MOVW $"lower 16-bit", Reg
3002
func (c *ctxt5) omvs(p *obj.Prog, a *obj.Addr, dr int) uint32 {
3003
	o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
3004
	o1 |= 0x30 << 20
3005
	o1 |= (uint32(dr) & 15) << 12
3006
	o1 |= uint32(a.Offset) & 0x0fff
3007
	o1 |= (uint32(a.Offset) & 0xf000) << 4
3008
	return o1
3009
}
3010

3011
// MVN $C_NCON, Reg -> MOVW $C_RCON, Reg
3012
func (c *ctxt5) omvr(p *obj.Prog, a *obj.Addr, dr int) uint32 {
3013
	o1 := c.oprrr(p, AMOVW, int(p.Scond))
3014
	o1 |= (uint32(dr) & 15) << 12
3015
	v := immrot(^uint32(a.Offset))
3016
	if v == 0 {
3017
		c.ctxt.Diag("%v: missing literal", p)
3018
		return 0
3019
	}
3020
	o1 |= uint32(v)
3021
	return o1
3022
}
3023

3024
func (c *ctxt5) omvl(p *obj.Prog, a *obj.Addr, dr int) uint32 {
3025
	var o1 uint32
3026
	if p.Pool == nil {
3027
		c.aclass(a)
3028
		v := immrot(^uint32(c.instoffset))
3029
		if v == 0 {
3030
			c.ctxt.Diag("%v: missing literal", p)
3031
			return 0
3032
		}
3033

3034
		o1 = c.oprrr(p, AMVN, int(p.Scond)&C_SCOND)
3035
		o1 |= uint32(v)
3036
		o1 |= (uint32(dr) & 15) << 12
3037
	} else {
3038
		v := int32(p.Pool.Pc - p.Pc - 8)
3039
		o1 = c.olr(v, REGPC, dr, int(p.Scond)&C_SCOND)
3040
	}
3041

3042
	return o1
3043
}
3044

3045
func (c *ctxt5) chipzero5(e float64) int {
3046
	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
3047
	if objabi.GOARM < 7 || math.Float64bits(e) != 0 {
3048
		return -1
3049
	}
3050
	return 0
3051
}
3052

3053
func (c *ctxt5) chipfloat5(e float64) int {
3054
	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
3055
	if objabi.GOARM < 7 {
3056
		return -1
3057
	}
3058

3059
	ei := math.Float64bits(e)
3060
	l := uint32(ei)
3061
	h := uint32(ei >> 32)
3062

3063
	if l != 0 || h&0xffff != 0 {
3064
		return -1
3065
	}
3066
	h1 := h & 0x7fc00000
3067
	if h1 != 0x40000000 && h1 != 0x3fc00000 {
3068
		return -1
3069
	}
3070
	n := 0
3071

3072
	// sign bit (a)
3073
	if h&0x80000000 != 0 {
3074
		n |= 1 << 7
3075
	}
3076

3077
	// exp sign bit (b)
3078
	if h1 == 0x3fc00000 {
3079
		n |= 1 << 6
3080
	}
3081

3082
	// rest of exp and mantissa (cd-efgh)
3083
	n |= int((h >> 16) & 0x3f)
3084

3085
	//print("match %.8lux %.8lux %d\n", l, h, n);
3086
	return n
3087
}
3088

3089
func nocache(p *obj.Prog) {
3090
	p.Optab = 0
3091
	p.From.Class = 0
3092
	if p.GetFrom3() != nil {
3093
		p.GetFrom3().Class = 0
3094
	}
3095
	p.To.Class = 0
3096
}
3097

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.