@@ -31,8 +31,43 @@ var RISCV64DWARFRegisters = map[int16]int16{}
31
31
32
32
func buildop (ctxt * obj.Link ) {}
33
33
34
+ // progedit is called individually for each *obj.Prog. It normalizes instruction
35
+ // formats and eliminates as many pseudo-instructions as possible.
34
36
func progedit (ctxt * obj.Link , p * obj.Prog , newprog obj.ProgAlloc ) {
35
- // TODO(jsing): Implement.
37
+
38
+ // Expand binary instructions to ternary ones.
39
+ if p .Reg == 0 {
40
+ switch p .As {
41
+ case AADDI , ASLTI , ASLTIU , AANDI , AORI , AXORI , ASLLI , ASRLI , ASRAI ,
42
+ AADD , AAND , AOR , AXOR , ASLL , ASRL , ASUB , ASRA :
43
+ p .Reg = p .To .Reg
44
+ }
45
+ }
46
+
47
+ // Rewrite instructions with constant operands to refer to the immediate
48
+ // form of the instruction.
49
+ if p .From .Type == obj .TYPE_CONST {
50
+ switch p .As {
51
+ case AADD :
52
+ p .As = AADDI
53
+ case ASLT :
54
+ p .As = ASLTI
55
+ case ASLTU :
56
+ p .As = ASLTIU
57
+ case AAND :
58
+ p .As = AANDI
59
+ case AOR :
60
+ p .As = AORI
61
+ case AXOR :
62
+ p .As = AXORI
63
+ case ASLL :
64
+ p .As = ASLLI
65
+ case ASRL :
66
+ p .As = ASRLI
67
+ case ASRA :
68
+ p .As = ASRAI
69
+ }
70
+ }
36
71
}
37
72
38
73
// setPCs sets the Pc field in all instructions reachable from p.
@@ -83,6 +118,103 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
83
118
}
84
119
}
85
120
121
+ func regVal (r , min , max int16 ) uint32 {
122
+ if r < min || r > max {
123
+ panic (fmt .Sprintf ("register out of range, want %d < %d < %d" , min , r , max ))
124
+ }
125
+ return uint32 (r - min )
126
+ }
127
+
128
+ // regI returns an integer register.
129
+ func regI (r int16 ) uint32 {
130
+ return regVal (r , REG_X0 , REG_X31 )
131
+ }
132
+
133
+ // regAddr extracts a register from an Addr.
134
+ func regAddr (a obj.Addr , min , max int16 ) uint32 {
135
+ if a .Type != obj .TYPE_REG {
136
+ panic (fmt .Sprintf ("ill typed: %+v" , a ))
137
+ }
138
+ return regVal (a .Reg , min , max )
139
+ }
140
+
141
+ // regIAddr extracts the integer register from an Addr.
142
+ func regIAddr (a obj.Addr ) uint32 {
143
+ return regAddr (a , REG_X0 , REG_X31 )
144
+ }
145
+
146
+ // immFits reports whether immediate value x fits in nbits bits as a
147
+ // signed integer.
148
+ func immFits (x int64 , nbits uint ) bool {
149
+ nbits --
150
+ var min int64 = - 1 << nbits
151
+ var max int64 = 1 << nbits - 1
152
+ return min <= x && x <= max
153
+ }
154
+
155
+ // immI extracts the integer literal of the specified size from an Addr.
156
+ func immI (a obj.Addr , nbits uint ) uint32 {
157
+ if a .Type != obj .TYPE_CONST {
158
+ panic (fmt .Sprintf ("ill typed: %+v" , a ))
159
+ }
160
+ if ! immFits (a .Offset , nbits ) {
161
+ panic (fmt .Sprintf ("immediate %d in %v cannot fit in %d bits" , a .Offset , a , nbits ))
162
+ }
163
+ return uint32 (a .Offset )
164
+ }
165
+
166
+ func wantImm (p * obj.Prog , pos string , a obj.Addr , nbits uint ) {
167
+ if a .Type != obj .TYPE_CONST {
168
+ p .Ctxt .Diag ("%v\t expected immediate in %s position but got %s" , p , pos , obj .Dconv (p , & a ))
169
+ return
170
+ }
171
+ if ! immFits (a .Offset , nbits ) {
172
+ p .Ctxt .Diag ("%v\t immediate in %s position cannot be larger than %d bits but got %d" , p , pos , nbits , a .Offset )
173
+ }
174
+ }
175
+
176
+ func wantReg (p * obj.Prog , pos string , descr string , r , min , max int16 ) {
177
+ if r < min || r > max {
178
+ p .Ctxt .Diag ("%v\t expected %s register in %s position but got non-%s register %s" , p , descr , pos , descr , regName (int (r )))
179
+ }
180
+ }
181
+
182
+ // wantIntReg checks that r is an integer register.
183
+ func wantIntReg (p * obj.Prog , pos string , r int16 ) {
184
+ wantReg (p , pos , "integer" , r , REG_X0 , REG_X31 )
185
+ }
186
+
187
+ func wantRegAddr (p * obj.Prog , pos string , a * obj.Addr , descr string , min int16 , max int16 ) {
188
+ if a == nil {
189
+ p .Ctxt .Diag ("%v\t expected register in %s position but got nothing" , p , pos )
190
+ return
191
+ }
192
+ if a .Type != obj .TYPE_REG {
193
+ p .Ctxt .Diag ("%v\t expected register in %s position but got %s" , p , pos , obj .Dconv (p , a ))
194
+ return
195
+ }
196
+ if a .Reg < min || a .Reg > max {
197
+ p .Ctxt .Diag ("%v\t expected %s register in %s position but got non-%s register %s" , p , descr , pos , descr , obj .Dconv (p , a ))
198
+ }
199
+ }
200
+
201
+ // wantIntRegAddr checks that a contains an integer register.
202
+ func wantIntRegAddr (p * obj.Prog , pos string , a * obj.Addr ) {
203
+ wantRegAddr (p , pos , a , "integer" , REG_X0 , REG_X31 )
204
+ }
205
+
206
+ func validateRIII (p * obj.Prog ) {
207
+ wantIntRegAddr (p , "from" , & p .From )
208
+ wantIntReg (p , "reg" , p .Reg )
209
+ wantIntRegAddr (p , "to" , & p .To )
210
+ }
211
+
212
+ func validateII (p * obj.Prog ) {
213
+ wantImm (p , "from" , p .From , 12 )
214
+ wantIntReg (p , "reg" , p .Reg )
215
+ wantIntRegAddr (p , "to" , & p .To )
216
+ }
217
+
86
218
func validateRaw (p * obj.Prog ) {
87
219
// Treat the raw value specially as a 32-bit unsigned integer.
88
220
// Nobody wants to enter negative machine code.
@@ -96,6 +228,42 @@ func validateRaw(p *obj.Prog) {
96
228
}
97
229
}
98
230
231
+ // encodeR encodes an R-type RISC-V instruction.
232
+ func encodeR (p * obj.Prog , rs1 uint32 , rs2 uint32 , rd uint32 ) uint32 {
233
+ ins := encode (p .As )
234
+ if ins == nil {
235
+ panic ("encodeR: could not encode instruction" )
236
+ }
237
+ if ins .rs2 != 0 && rs2 != 0 {
238
+ panic ("encodeR: instruction uses rs2, but rs2 was nonzero" )
239
+ }
240
+
241
+ // Use Scond for the floating-point rounding mode override.
242
+ // TODO(sorear): Is there a more appropriate way to handle opcode extension bits like this?
243
+ return ins .funct7 << 25 | ins .rs2 << 20 | rs2 << 20 | rs1 << 15 | ins .funct3 << 12 | uint32 (p .Scond )<< 12 | rd << 7 | ins .opcode
244
+ }
245
+
246
+ func encodeRIII (p * obj.Prog ) uint32 {
247
+ return encodeR (p , regI (p .Reg ), regIAddr (p .From ), regIAddr (p .To ))
248
+ }
249
+
250
+ // encodeI encodes an I-type RISC-V instruction.
251
+ func encodeI (p * obj.Prog , rd uint32 ) uint32 {
252
+ imm := immI (p .From , 12 )
253
+ rs1 := regI (p .Reg )
254
+ ins := encode (p .As )
255
+ if ins == nil {
256
+ panic ("encodeI: could not encode instruction" )
257
+ }
258
+ imm |= uint32 (ins .csr )
259
+ return imm << 20 | rs1 << 15 | ins .funct3 << 12 | rd << 7 | ins .opcode
260
+ }
261
+
262
+ func encodeII (p * obj.Prog ) uint32 {
263
+ return encodeI (p , regIAddr (p .To ))
264
+ }
265
+
266
+ // encodeRaw encodes a raw instruction value.
99
267
func encodeRaw (p * obj.Prog ) uint32 {
100
268
// Treat the raw value specially as a 32-bit unsigned integer.
101
269
// Nobody wants to enter negative machine code.
@@ -116,6 +284,22 @@ type encoding struct {
116
284
}
117
285
118
286
var (
287
+ // Encodings have the following naming convention:
288
+ //
289
+ // 1. the instruction encoding (R/I/S/SB/U/UJ), in lowercase
290
+ // 2. zero or more register operand identifiers (I = integer
291
+ // register, F = float register), in uppercase
292
+ // 3. the word "Encoding"
293
+ //
294
+ // For example, rIIIEncoding indicates an R-type instruction with two
295
+ // integer register inputs and an integer register output; sFEncoding
296
+ // indicates an S-type instruction with rs2 being a float register.
297
+
298
+ rIIIEncoding = encoding {encode : encodeRIII , validate : validateRIII , length : 4 }
299
+
300
+ iIEncoding = encoding {encode : encodeII , validate : validateII , length : 4 }
301
+
302
+ // rawEncoding encodes a raw instruction byte sequence.
119
303
rawEncoding = encoding {encode : encodeRaw , validate : validateRaw , length : 4 }
120
304
121
305
// pseudoOpEncoding panics if encoding is attempted, but does no validation.
@@ -131,6 +315,29 @@ var (
131
315
var encodingForAs = [ALAST & obj .AMask ]encoding {
132
316
// TODO(jsing): Implement remaining instructions.
133
317
318
+ // Unprivileged ISA
319
+
320
+ // 2.4: Integer Computational Instructions
321
+ AADDI & obj .AMask : iIEncoding ,
322
+ ASLTI & obj .AMask : iIEncoding ,
323
+ ASLTIU & obj .AMask : iIEncoding ,
324
+ AANDI & obj .AMask : iIEncoding ,
325
+ AORI & obj .AMask : iIEncoding ,
326
+ AXORI & obj .AMask : iIEncoding ,
327
+ ASLLI & obj .AMask : iIEncoding ,
328
+ ASRLI & obj .AMask : iIEncoding ,
329
+ ASRAI & obj .AMask : iIEncoding ,
330
+ AADD & obj .AMask : rIIIEncoding ,
331
+ ASLT & obj .AMask : rIIIEncoding ,
332
+ ASLTU & obj .AMask : rIIIEncoding ,
333
+ AAND & obj .AMask : rIIIEncoding ,
334
+ AOR & obj .AMask : rIIIEncoding ,
335
+ AXOR & obj .AMask : rIIIEncoding ,
336
+ ASLL & obj .AMask : rIIIEncoding ,
337
+ ASRL & obj .AMask : rIIIEncoding ,
338
+ ASUB & obj .AMask : rIIIEncoding ,
339
+ ASRA & obj .AMask : rIIIEncoding ,
340
+
134
341
// Escape hatch
135
342
AWORD & obj .AMask : rawEncoding ,
136
343
0 commit comments