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