1 #include "l.h"
2
3 #define COMPREG(r) ((r & ~0x7) == 0x8)
4 #define COP_CR(op,rs,rd)\
5 (op | (rs)<<2 | (rd)<<7)
6 #define COP_CI(op,rd,i)\
7 (op | (rd)<<7 | ((i)&0x20)<<7 | ((i)&0x1F)<<2)
8 #define COP_CIW(op,rd,i)\
9 (op | (rd)<<2 | (i)<<5)
10 #define COP_CJ(op,i)\
11 (op | (i)<<2)
12 #define COP_CB(op,rs,i)\
13 (op | (rs)<<7 | ((i)&0x1f)<<2 | ((i)&0xE0)<<5)
14 #define COP_CL(op,rs,rd,i)\
15 (op | (rs)<<7 | (rd)<<2 | ((i)&0x7)<<4 | ((i)&0x38)<<7)
16 #define COP_CSS(op,rs,i)\
17 (op | (rs)<<2 | ((i)&0x3F)<<7)
18 #define COP_CS(op,rs2,rs1,i)\
19 (op | (rs2)<<2 | (rs1)<<7 | ((i)&0x7)<<4 | ((i)&0x38)<<7)
20
21 static int
immbits(int v,char * permute)22 immbits(int v, char *permute)
23 {
24 int r, i, c;
25
26 r = 0;
27 for(i = 0; (c = *permute++) != 0; i++)
28 r |= ((v>>c) & 0x01) << i;
29 return r;
30 }
31
32 long
asmcjmp(int a,Prog * p,int first)33 asmcjmp(int a, Prog *p, int first)
34 {
35 long v;
36
37 if(p->cond == P)
38 v = 0;
39 else
40 v = (p->cond->pc - p->pc);
41 if(first || ((v&0x01) == 0 && v >= -0x800 && v < 0x800))
42 return COP_CJ(a, immbits(v, "\5\1\2\3\7\6\12\10\11\4\13"));
43 return 0;
44 }
45
46 int
asmcbz(int a,Prog * p,int first)47 asmcbz(int a, Prog *p, int first)
48 {
49 long v;
50 int r;
51
52 r = p->reg;
53 if(r == REGZERO || r == NREG)
54 r = p->from.reg;
55 else if(p->from.reg != REGZERO)
56 return 0;
57 if(!COMPREG(r))
58 return 0;
59 if(p->cond == P)
60 v = 0;
61 else
62 v = (p->cond->pc - p->pc);
63 if(first || ((v&0x01) == 0 && v >= -0x100 && v < 0x100))
64 return COP_CB(a, r&0x7, immbits(v, "\5\1\2\6\7\3\4\10"));
65 return 0;
66 }
67
68 int
asmcload(Prog * p,int a,uint len,uint maxoff)69 asmcload(Prog *p, int a, uint len, uint maxoff)
70 {
71 int v;
72 int r;
73
74 v = regoff(&p->from);
75 if((v & (len-1)) != 0 || v < 0)
76 return 0;
77 r = classreg(&p->from);
78 if(COMPREG(r) && COMPREG(p->to.reg)){
79 if(v < maxoff){
80 v |= (v>>5) & ~0x1;
81 return COP_CL(a, r&0x7, p->to.reg&0x7, v);
82 }
83 }else if(r == REGSP){
84 if(v < 2*maxoff){
85 v |= (v>>6);
86 return COP_CI(a | 0x2, p->to.reg, v);
87 }
88 }
89 return 0;
90 }
91
92 int
asmcstore(Prog * p,int a,uint len,uint maxoff)93 asmcstore(Prog *p, int a, uint len, uint maxoff)
94 {
95 int v;
96 int r;
97
98 v = regoff(&p->to);
99 if((v & (len-1)) != 0 || v < 0)
100 return 0;
101 r = classreg(&p->to);
102 if(COMPREG(r) && COMPREG(p->from.reg)){
103 if(v < maxoff){
104 v |= (v>>5) & ~0x1;
105 return COP_CS(a, p->from.reg&0x7, r&0x7, v);
106 }
107 }else if(r == REGSP){
108 if(v < 2*maxoff){
109 v |= (v>>6);
110 return COP_CSS(a | 0x2, (p->from.reg&0x1F), v);
111 }
112 }
113 return 0;
114 }
115
116 int
asmcompressed(Prog * p,Optab * o,int r,int first)117 asmcompressed(Prog *p, Optab *o, int r, int first)
118 {
119 long v;
120 int a;
121
122 switch(o->ctype){
123 case 1: /* C.ADD */
124 if(p->from.reg != REGZERO && p->to.reg != REGZERO && r == p->to.reg)
125 return COP_CR(0x9002, p->from.reg, r);
126 break;
127 case 2: /* C.MV */
128 if(p->from.type != D_REG)
129 diag("compress MOVW R,R doesn't apply\n%P", p);
130 if(p->to.reg != REGZERO){
131 if(p->from.type == D_REG && p->from.reg != REGZERO)
132 return COP_CR(0x8002, p->from.reg, p->to.reg);
133 else
134 return COP_CI(0x4001, p->to.reg, 0);
135 }
136 break;
137 case 3: /* C.JALR */
138 if(r == REGLINK && p->to.reg != REGZERO && p->to.offset == 0)
139 return COP_CR(0x9002, 0, p->to.reg);
140 break;
141 case 4: /* C.JR */
142 if(p->to.reg != REGZERO &&p->to.offset == 0)
143 return COP_CR(0x8002, 0, p->to.reg);
144 break;
145 case 5: /* C.AND C.OR C.SUB C.XOR */
146 if(r == p->to.reg && COMPREG(p->from.reg) && COMPREG(p->to.reg)){
147 v = 0x8C01;
148 switch(o->as){
149 case AXOR:
150 v |= 1<<5;
151 break;
152 case AOR:
153 v |= 2<<5;
154 break;
155 case AAND:
156 v |= 3<<5;
157 break;
158 }
159 return COP_CR(v, p->from.reg&0x7, p->to.reg&0x7);
160 }
161 break;
162 case 6: /* C.LI */
163 v = p->from.offset;
164 if(p->to.reg != REGZERO && v >= -0x20 && v < 0x20){
165 return COP_CI(0x4001, p->to.reg, v);
166 }
167 break;
168 case 7: /* C.LUI */
169 v = p->from.offset;
170 if((v&0xFFF) != 0)
171 return 0;
172 v >>= 12;
173 if(p->to.reg != REGZERO && p->to.reg != REGSP && v >= -0x20 && v < 0x20)
174 return COP_CI(0x6001, p->to.reg, v);
175 break;
176 case 8: /* C.SLLI */
177 v = p->from.offset;
178 if((v & 0x20) != 0 && thechar == 'i')
179 break;
180 if(r == p->to.reg && r != REGZERO && v != 0 && (v & ~0x3F) == 0)
181 return COP_CI(0x0002, p->to.reg, v);
182 break;
183 case 9: /* C.SRAI C.SRLI */
184 v = p->from.offset;
185 if((v & 0x20) != 0 && thechar == 'i')
186 break;
187 a = (o->as == ASRA) << 10;
188 if(r == p->to.reg && COMPREG(r) && v != 0 && (v & ~0x3F) == 0)
189 return COP_CI(0x8001 | a, r&0x7, v);
190 break;
191 case 10: /* C.ADDI C.ADDI16SP C.ADDI4SPN C.NOP */
192 v = p->from.offset;
193 if(r == p->to.reg && r != REGZERO && v != 0 && v >= -0x20 && v < 0x20)
194 return COP_CI(0x0001, p->to.reg, v);
195 if(r == p->to.reg && r == REGSP && v != 0 && (v&0xF) == 0 && v >= -0x200 && v < 0x200)
196 return COP_CI(0x6001, REGSP, immbits(v, "\5\7\10\6\4\11"));
197 if(r == REGSP && COMPREG(p->to.reg) && (v&0x3) == 0 && v > 0 && v < 0x400)
198 return COP_CIW(0x0000, p->to.reg&0x7, immbits(v, "\3\2\6\7\10\11\4\5"));
199 if(r == p->to.reg && r == REGZERO && v == 0)
200 return COP_CI(0x0001, 0, 0);
201 break;
202 case 11: /* C.JAL (rv32) */
203 if(thechar != 'i')
204 break;
205 if(r == REGLINK)
206 return asmcjmp(0x2001, p, first);
207 break;
208 case 12: /* C.J */
209 return asmcjmp(0xA001, p, first);
210 break;
211 case 13: /* C.ANDI */
212 v = p->from.offset;
213 if(r == p->to.reg && COMPREG(r) && v >= -0x20 && v < 0x20)
214 return COP_CI(0x8801, r&0x7, v);
215 break;
216 case 14: /* C.BEQZ */
217 return asmcbz(0xC001, p, first);
218 case 15: /* C.BNEZ */
219 return asmcbz(0xE001, p, first);
220 case 16: /* C.LW C.LWSP */
221 return asmcload(p, 0x4000, 4, 0x80);
222 case 17: /* C.FLW, C.FLWSP (rv32) */
223 if(thechar != 'i')
224 break;
225 return asmcload(p, 0x6000, 4, 0x80);
226 case 18: /* C.FLD, C.FLDSP */
227 return asmcload(p, 0x2000, 8, 0x100);
228 case 19: /* C.SW C.SWSP */
229 return asmcstore(p, 0xC000, 4, 0x80);
230 case 20: /* C.FSW, C.FSWSP (rv32) */
231 if(thechar != 'i')
232 break;
233 return asmcstore(p, 0xE000, 4, 0x80);
234 case 21: /* C.FSD, C.FSDSP */
235 return asmcstore(p, 0xA000, 8, 0x100);
236 case 22: /* C.ADDW C.SUBW (rv64) */
237 if(thechar != 'j')
238 break;
239 if(r == p->to.reg && COMPREG(p->from.reg) && COMPREG(p->to.reg)){
240 v = 0x9C01;
241 switch(o->as){
242 case AADDW:
243 v |= 1<<5;
244 break;
245 }
246 return COP_CR(v, p->from.reg&0x7, p->to.reg&0x7);
247 }
248 break;
249 case 23: /* C.ADDIW (rv64) */
250 if(thechar != 'j')
251 break;
252 v = p->from.offset;
253 if(p->as == AMOVW){
254 v = 0;
255 r = p->from.reg;
256 }
257 if(r == p->to.reg && r != REGZERO && v >= -0x20 && v < 0x20)
258 return COP_CI(0x2001, p->to.reg, v);
259 break;
260 case 24: /* C.LD (rv64) */
261 if(thechar != 'j')
262 break;
263 return asmcload(p, 0x6000, 8, 0x100);
264 case 25: /* C.SD (rv64) */
265 if(thechar != 'j')
266 break;
267 return asmcstore(p, 0xE000, 8, 0x100);
268 }
269 return 0;
270 }
271