plan9fox/sys/src/cmd/dtracy/cgen.c
2019-01-20 03:07:10 +00:00

314 lines
6.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <u.h>
#include <libc.h>
#include <dtracy.h>
#include <bio.h>
#include "dat.h"
#include "fns.h"
u16int regsused = 1;
u32int cbuf[256];
int ncbuf;
int labtab[256];
int nlab;
static void
emit(u32int x)
{
assert(ncbuf < nelem(cbuf));
cbuf[ncbuf++] = x;
}
static int
regalloc(void)
{
u16int v;
int n;
if(regsused == 0xffff){
error("out of registers");
return 0;
}
v = regsused + 1 & ~regsused;
regsused ^= v;
n = 0;
if((u8int)v == 0) {v >>= 8; n += 8;}
if((v & 0xf) == 0) {v >>= 4; n += 4;}
if((v & 3) == 0) {v >>= 2; n += 2;}
return n + (v >> 1);
}
static void
regfree(int n)
{
assert((regsused & 1<<n) != 0);
assert(n != 0);
regsused &= ~(1<<n);
}
static int
popcount(u64int s)
{
s = (s & 0x5555555555555555ULL) + (s >> 1 & 0x5555555555555555ULL);
s = (s & 0x3333333333333333ULL) + (s >> 2 & 0x3333333333333333ULL);
s = (s & 0x0F0F0F0F0F0F0F0FULL) + (s >> 4 & 0x0F0F0F0F0F0F0F0FULL);
s = (s & 0x00FF00FF00FF00FFULL) + (s >> 8 & 0x00FF00FF00FF00FFULL);
s = (s & 0x0000FFFF0000FFFFULL) + (s >> 16 & 0x0000FFFF0000FFFFULL);
return (u32int)s + (u32int)(s >> 32);
}
static int
constenc(s64int val)
{
int i, r;
s64int x;
r = 0;
do{
i = popcount(val ^ val - 1) - 1;
x = val << 54 - i >> 54;
if(r == 0){
r = regalloc();
emit(DTE_LDI << 24 | (x & 0x3ff) << 14 | i << 8 | r);
}else
emit(DTE_XORI << 24 | (x & 0x3ff) << 14 | i << 8 | r);
val ^= x << i;
}while(val != 0);
return r;
}
static int egen(Node *);
static void
condgen(Node *n, int invert, int truelab)
{
int r1, r2, l1, op;
if(n->type != OBIN) goto other;
switch(n->op){
case OPEQ: op = DTE_BEQ; goto cmp;
case OPNE: op = DTE_BNE; goto cmp;
case OPLT: op = DTE_BLT; goto cmp;
case OPLE: op = DTE_BLE;
cmp:
r1 = egen(n->n1);
r2 = egen(n->n2);
if(invert)
emit(DTE(op ^ 1, r2, r1, truelab));
else
emit(DTE(op, r1, r2, truelab));
regfree(r1);
regfree(r2);
break;
case OPLOR:
case OPLAND:
if(invert ^ n->op == OPLOR){
condgen(n->n1, invert, truelab);
condgen(n->n2, invert, truelab);
}else{
l1 = nlab++;
condgen(n->n1, !invert, l1);
condgen(n->n2, invert, truelab);
labtab[l1] = ncbuf;
}
break;
default:
other:
r1 = egen(n);
emit(DTE(DTE_BNE ^ invert, r1, 0, truelab));
regfree(r1);
break;
}
}
static int
condvgen(Node *n, int invert)
{
int r, l1, l2, op;
if(n->type == OLNOT)
return condvgen(n->n1, !invert);
if(n->type != OBIN) goto other;
switch(n->op){
case OPEQ: op = DTE_SEQ; goto cmp;
case OPNE: op = DTE_SNE; goto cmp;
case OPLT: op = DTE_SLT; goto cmp;
case OPLE: op = DTE_SLE;
cmp:
if(invert)
return egen(node(OBIN, op ^ 1, n->n2, n->n1));
return egen(n);
case OPLOR:
case OPLAND:
if(invert ^ n->op == OPLOR){
l1 = nlab++;
l2 = nlab++;
condgen(n->n1, invert, l1);
r = condvgen(n->n2, invert);
emit(DTE(DTE_BEQ, 0, 0, l2));
labtab[l1] = ncbuf;
emit(DTE(DTE_LDI, 0, 1<<6, r));
labtab[l2] = ncbuf;
return r;
}else{
l1 = nlab++;
l2 = nlab++;
condgen(n->n1, !invert, l1);
r = condvgen(n->n2, invert);
emit(DTE(DTE_BEQ, 0, 0, l2));
labtab[l1] = ncbuf;
emit(DTE(DTE_LDI, 0, 0<<6, r));
labtab[l2] = ncbuf;
return r;
}
default:
other:
r = egen(n);
emit(DTE(DTE_SNE ^ invert, r, 0, r));
return r;
}
}
static int
egen(Node *n)
{
int r1, r2, rt, l1, l2, op;
switch(/*nodetype*/n->type){
case ONUM:
return constenc(n->num);
case OSYM:
switch(n->sym->type){
case SYMVAR:
rt = regalloc();
emit(DTE(DTE_LDV, n->sym->idx, rt, 0));
return rt;
default: sysfatal("egen: unknown symbol type %d", n->sym->type); return 0;
}
case OBIN:
switch(/*oper*/n->op){
case OPLAND:
case OPLOR:
return condvgen(n, 0);
case OPADD: op = DTE_ADD; break;
case OPSUB: op = DTE_SUB; break;
case OPMUL: op = DTE_MUL; break;
case OPDIV: op = n->typ->sign ? DTE_SDIV : DTE_UDIV; break;
case OPMOD: op = n->typ->sign ? DTE_SMOD : DTE_UMOD; break;
case OPAND: op = DTE_AND; break;
case OPOR: op = DTE_OR; break;
case OPXOR: op = DTE_XOR; break;
case OPLSH: op = DTE_LSL; break;
case OPRSH: op = n->typ->sign ? DTE_ASR : DTE_LSR; break;
case OPEQ: op = DTE_SEQ; break;
case OPNE: op = DTE_SNE; break;
case OPLT: op = DTE_SLT; break;
case OPLE: op = DTE_SLE; break;
case OPXNOR: op = DTE_XNOR; break;
default: sysfatal("egen: unknown op %d", n->op); return 0;
}
r1 = egen(n->n1);
r2 = egen(n->n2);
regfree(r1);
regfree(r2);
rt = regalloc();
emit(DTE(op, r1, r2, rt));
return rt;
case OTERN:
l1 = nlab++;
l2 = nlab++;
condgen(n->n1, 1, l1);
r1 = egen(n->n2);
emit(DTE(DTE_BEQ, 0, 0, l2));
labtab[l1] = ncbuf;
r2 = egen(n->n3);
if(r1 != r2)
emit(DTE(DTE_OR, 0, r2, r1));
labtab[l2] = ncbuf;
return r1;
case OLNOT:
return condvgen(n, 0);
case OCAST:
switch(n->typ->type){
case TYPINT:
r1 = egen(n->n1);
emit(DTE(n->typ->sign ? DTE_SXT : DTE_ZXT, r1, n->typ->size * 8, r1));
return r1;
case TYPSTRING:
return egen(n->n1);
default:
sysfatal("egen: don't know how to cast %τ to %τ", n->n1->typ, n->typ);
}
case ORECORD:
case OSTR:
default: sysfatal("egen: unknown type %α", n->type); return 0;
}
}
DTExpr *
codegen(Node *n)
{
int r, i, t;
DTExpr *ep;
regsused = 1;
ncbuf = 0;
nlab = 0;
r = egen(n);
emit(DTE(DTE_RET, r, 0, 0));
for(i = 0; i < ncbuf; i++)
if((cbuf[i] >> 24 & 0xf0) == 0x30){
t = labtab[cbuf[i] & 0xff];
assert((uint)(t - i - 1) < 0x100);
cbuf[i] = cbuf[i] & 0xffffff00 | t - i - 1;
}
ep = emalloc(sizeof(DTExpr) + ncbuf * sizeof(u32int));
ep->n = ncbuf;
ep->b = (void *)(ep + 1);
memcpy(ep->b, cbuf, ncbuf * sizeof(u32int));
return ep;
}
Node *
tracegen(Node *n, DTActGr *g, int *recoff)
{
switch(/*nodetype*/n->type){
case OSYM:
case ONUM:
case OSTR:
break;
case OBIN:
n->n1 = tracegen(n->n1, g, recoff);
n->n2 = tracegen(n->n2, g, recoff);
break;
case OLNOT:
n->n1 = tracegen(n->n1, g, recoff);
break;
case OTERN:
n->n1 = tracegen(n->n1, g, recoff);
n->n2 = tracegen(n->n2, g, recoff);
n->n3 = tracegen(n->n3, g, recoff);
break;
case OCAST:
n->n1 = tracegen(n->n1, g, recoff);
break;
case ORECORD:
switch(n->typ->type){
case TYPINT:
actgradd(g, (DTAct){ACTTRACE, codegen(n->n1), n->typ->size, noagg});
break;
case TYPSTRING:
actgradd(g, (DTAct){ACTTRACESTR, codegen(n->n1), n->typ->size, noagg});
break;
default:
sysfatal("tracegen: don't know how to record %τ", n->typ);
}
n->num = *recoff;
*recoff += n->typ->size;
return n;
default: sysfatal("tracegen: unknown type %α", n->type); return nil;
}
return n;
}