xref: /inferno-os/utils/il/compress.c (revision 871e0f01ca6cdef953c81d1a5018d90fbd01838a)
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
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
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
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
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
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
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