qbe

Internal scc patchset buffer for QBE
Log | Files | Refs | README | LICENSE

isel.c (5684B)


      1 #include "all.h"
      2 
      3 enum Imm {
      4 	Iother,
      5 	Iplo12,
      6 	Iphi12,
      7 	Iplo24,
      8 	Inlo12,
      9 	Inhi12,
     10 	Inlo24
     11 };
     12 
     13 static enum Imm
     14 imm(Con *c, int k, int64_t *pn)
     15 {
     16 	int64_t n;
     17 	int i;
     18 
     19 	if (c->type != CBits)
     20 		return Iother;
     21 	n = c->bits.i;
     22 	if (k == Kw)
     23 		n = (int32_t)n;
     24 	i = Iplo12;
     25 	if (n < 0) {
     26 		i = Inlo12;
     27 		n = -n;
     28 	}
     29 	*pn = n;
     30 	if ((n & 0x000fff) == n)
     31 		return i;
     32 	if ((n & 0xfff000) == n)
     33 		return i + 1;
     34 	if ((n & 0xffffff) == n)
     35 		return i + 2;
     36 	return Iother;
     37 }
     38 
     39 int
     40 arm64_logimm(uint64_t x, int k)
     41 {
     42 	uint64_t n;
     43 
     44 	if (k == Kw)
     45 		x = (x & 0xffffffff) | x << 32;
     46 	if (x & 1)
     47 		x = ~x;
     48 	if (x == 0)
     49 		return 0;
     50 	if (x == 0xaaaaaaaaaaaaaaaa)
     51 		return 1;
     52 	n = x & 0xf;
     53 	if (0x1111111111111111 * n == x)
     54 		goto Check;
     55 	n = x & 0xff;
     56 	if (0x0101010101010101 * n == x)
     57 		goto Check;
     58 	n = x & 0xffff;
     59 	if (0x0001000100010001 * n == x)
     60 		goto Check;
     61 	n = x & 0xffffffff;
     62 	if (0x0000000100000001 * n == x)
     63 		goto Check;
     64 	n = x;
     65 Check:
     66 	return (n & (n + (n & -n))) == 0;
     67 }
     68 
     69 static void
     70 fixarg(Ref *pr, int k, int phi, Fn *fn)
     71 {
     72 	char buf[32];
     73 	Con *c, cc;
     74 	Ref r0, r1, r2, r3;
     75 	int s, n;
     76 
     77 	r0 = *pr;
     78 	switch (rtype(r0)) {
     79 	case RCon:
     80 		c = &fn->con[r0.val];
     81 		if (T.apple
     82 		&& c->type == CAddr
     83 		&& c->sym.type == SThr) {
     84 			r1 = newtmp("isel", Kl, fn);
     85 			*pr = r1;
     86 			if (c->bits.i) {
     87 				r2 = newtmp("isel", Kl, fn);
     88 				cc = (Con){.type = CBits};
     89 				cc.bits.i = c->bits.i;
     90 				r3 = newcon(&cc, fn);
     91 				emit(Oadd, Kl, r1, r2, r3);
     92 				r1 = r2;
     93 			}
     94 			emit(Ocopy, Kl, r1, TMP(R0), R);
     95 			r1 = newtmp("isel", Kl, fn);
     96 			r2 = newtmp("isel", Kl, fn);
     97 			emit(Ocall, 0, R, r1, CALL(33));
     98 			emit(Ocopy, Kl, TMP(R0), r2, R);
     99 			emit(Oload, Kl, r1, r2, R);
    100 			cc = *c;
    101 			cc.bits.i = 0;
    102 			r3 = newcon(&cc, fn);
    103 			emit(Ocopy, Kl, r2, r3, R);
    104 			break;
    105 		}
    106 		if (KBASE(k) == 0 && phi)
    107 			return;
    108 		r1 = newtmp("isel", k, fn);
    109 		if (KBASE(k) == 0) {
    110 			emit(Ocopy, k, r1, r0, R);
    111 		} else {
    112 			n = stashbits(&c->bits, KWIDE(k) ? 8 : 4);
    113 			vgrow(&fn->con, ++fn->ncon);
    114 			c = &fn->con[fn->ncon-1];
    115 			sprintf(buf, "\"%sfp%d\"", T.asloc, n);
    116 			*c = (Con){.type = CAddr};
    117 			c->sym.id = intern(buf);
    118 			r2 = newtmp("isel", Kl, fn);
    119 			emit(Oload, k, r1, r2, R);
    120 			emit(Ocopy, Kl, r2, CON(c-fn->con), R);
    121 		}
    122 		*pr = r1;
    123 		break;
    124 	case RTmp:
    125 		s = fn->tmp[r0.val].slot;
    126 		if (s == -1)
    127 			break;
    128 		r1 = newtmp("isel", Kl, fn);
    129 		emit(Oaddr, Kl, r1, SLOT(s), R);
    130 		*pr = r1;
    131 		break;
    132 	}
    133 }
    134 
    135 static int
    136 selcmp(Ref arg[2], int k, Fn *fn)
    137 {
    138 	Ref r, *iarg;
    139 	Con *c;
    140 	int swap, cmp, fix;
    141 	int64_t n;
    142 
    143 	if (KBASE(k) == 1) {
    144 		emit(Oafcmp, k, R, arg[0], arg[1]);
    145 		iarg = curi->arg;
    146 		fixarg(&iarg[0], k, 0, fn);
    147 		fixarg(&iarg[1], k, 0, fn);
    148 		return 0;
    149 	}
    150 	swap = rtype(arg[0]) == RCon;
    151 	if (swap) {
    152 		r = arg[1];
    153 		arg[1] = arg[0];
    154 		arg[0] = r;
    155 	}
    156 	fix = 1;
    157 	cmp = Oacmp;
    158 	r = arg[1];
    159 	if (rtype(r) == RCon) {
    160 		c = &fn->con[r.val];
    161 		switch (imm(c, k, &n)) {
    162 		default:
    163 			break;
    164 		case Iplo12:
    165 		case Iphi12:
    166 			fix = 0;
    167 			break;
    168 		case Inlo12:
    169 		case Inhi12:
    170 			cmp = Oacmn;
    171 			r = getcon(n, fn);
    172 			fix = 0;
    173 			break;
    174 		}
    175 	}
    176 	emit(cmp, k, R, arg[0], r);
    177 	iarg = curi->arg;
    178 	fixarg(&iarg[0], k, 0, fn);
    179 	if (fix)
    180 		fixarg(&iarg[1], k, 0, fn);
    181 	return swap;
    182 }
    183 
    184 static int
    185 callable(Ref r, Fn *fn)
    186 {
    187 	Con *c;
    188 
    189 	if (rtype(r) == RTmp)
    190 		return 1;
    191 	if (rtype(r) == RCon) {
    192 		c = &fn->con[r.val];
    193 		if (c->type == CAddr)
    194 		if (c->bits.i == 0)
    195 			return 1;
    196 	}
    197 	return 0;
    198 }
    199 
    200 static void
    201 sel(Ins i, Fn *fn)
    202 {
    203 	Ref *iarg;
    204 	Ins *i0;
    205 	int ck, cc;
    206 
    207 	if (INRANGE(i.op, Oalloc, Oalloc1)) {
    208 		i0 = curi - 1;
    209 		salloc(i.to, i.arg[0], fn);
    210 		fixarg(&i0->arg[0], Kl, 0, fn);
    211 		return;
    212 	}
    213 	if (iscmp(i.op, &ck, &cc)) {
    214 		emit(Oflag, i.cls, i.to, R, R);
    215 		i0 = curi;
    216 		if (selcmp(i.arg, ck, fn))
    217 			i0->op += cmpop(cc);
    218 		else
    219 			i0->op += cc;
    220 		return;
    221 	}
    222 	if (i.op == Ocall)
    223 	if (callable(i.arg[0], fn)) {
    224 		emiti(i);
    225 		return;
    226 	}
    227 	if (i.op != Onop) {
    228 		emiti(i);
    229 		iarg = curi->arg; /* fixarg() can change curi */
    230 		fixarg(&iarg[0], argcls(&i, 0), 0, fn);
    231 		fixarg(&iarg[1], argcls(&i, 1), 0, fn);
    232 	}
    233 }
    234 
    235 static void
    236 seljmp(Blk *b, Fn *fn)
    237 {
    238 	Ref r;
    239 	Ins *i, *ir;
    240 	int ck, cc, use;
    241 
    242 	if (b->jmp.type == Jret0
    243 	|| b->jmp.type == Jjmp
    244 	|| b->jmp.type == Jhlt)
    245 		return;
    246 	assert(b->jmp.type == Jjnz);
    247 	r = b->jmp.arg;
    248 	use = -1;
    249 	b->jmp.arg = R;
    250 	ir = 0;
    251 	i = &b->ins[b->nins];
    252 	while (i > b->ins)
    253 		if (req((--i)->to, r)) {
    254 			use = fn->tmp[r.val].nuse;
    255 			ir = i;
    256 			break;
    257 		}
    258 	if (ir && use == 1
    259 	&& iscmp(ir->op, &ck, &cc)) {
    260 		if (selcmp(ir->arg, ck, fn))
    261 			cc = cmpop(cc);
    262 		b->jmp.type = Jjf + cc;
    263 		*ir = (Ins){.op = Onop};
    264 	}
    265 	else {
    266 		selcmp((Ref[]){r, CON_Z}, Kw, fn);
    267 		b->jmp.type = Jjfine;
    268 	}
    269 }
    270 
    271 void
    272 arm64_isel(Fn *fn)
    273 {
    274 	Blk *b, **sb;
    275 	Ins *i;
    276 	Phi *p;
    277 	uint n, al;
    278 	int64_t sz;
    279 
    280 	/* assign slots to fast allocs */
    281 	b = fn->start;
    282 	/* specific to NAlign == 3 */ /* or change n=4 and sz /= 4 below */
    283 	for (al=Oalloc, n=4; al<=Oalloc1; al++, n*=2)
    284 		for (i=b->ins; i<&b->ins[b->nins]; i++)
    285 			if (i->op == al) {
    286 				if (rtype(i->arg[0]) != RCon)
    287 					break;
    288 				sz = fn->con[i->arg[0].val].bits.i;
    289 				if (sz < 0 || sz >= INT_MAX-15)
    290 					err("invalid alloc size %"PRId64, sz);
    291 				sz = (sz + n-1) & -n;
    292 				sz /= 4;
    293 				fn->tmp[i->to.val].slot = fn->slot;
    294 				fn->slot += sz;
    295 				*i = (Ins){.op = Onop};
    296 			}
    297 
    298 	for (b=fn->start; b; b=b->link) {
    299 		curi = &insb[NIns];
    300 		for (sb=(Blk*[3]){b->s1, b->s2, 0}; *sb; sb++)
    301 			for (p=(*sb)->phi; p; p=p->link) {
    302 				for (n=0; p->blk[n] != b; n++)
    303 					assert(n+1 < p->narg);
    304 				fixarg(&p->arg[n], p->cls, 1, fn);
    305 			}
    306 		seljmp(b, fn);
    307 		for (i=&b->ins[b->nins]; i!=b->ins;)
    308 			sel(*--i, fn);
    309 		b->nins = &insb[NIns] - curi;
    310 		idup(&b->ins, curi, b->nins);
    311 	}
    312 
    313 	if (debug['I']) {
    314 		fprintf(stderr, "\n> After instruction selection:\n");
    315 		printfn(fn, stderr);
    316 	}
    317 }