shithub: riscv

Download patch

ref: ea0f58090923bd7e435c4f48eb751854a4292b9a
parent: bc610a1b1c32f6e2e9b034217bb3ce9a7defa739
author: cinap_lenrek <[email protected]>
date: Sat Jan 26 13:03:45 EST 2013

add arm vfp support to compiler and linker (from sources)

--- a/sys/man/1/2l
+++ b/sys/man/1/2l
@@ -102,6 +102,9 @@
 .L _traceout
 at function exits.
 .TP
+.B -f
+(ARM only) Generate VFP hardware floating point instructions.
+.TP
 .B -s
 Strip the symbol tables from the output file.
 .TP
--- a/sys/src/cmd/5c/txt.c
+++ b/sys/src/cmd/5c/txt.c
@@ -721,8 +721,13 @@
 			regfree(&nod1);
 			p1 = p;
 			regalloc(&nod, t, Z);
-			gins(AMOVF, nodfconst(2147483648.), &nod);
-			gins(AADDF, &nod, t);
+			if(tt == TFLOAT) {
+				gins(AMOVF, nodfconst(2147483648.), &nod);
+				gins(AADDF, &nod, t);
+			} else {
+				gins(AMOVD, nodfconst(2147483648.), &nod);
+				gins(AADDD, &nod, t);
+			}
 			regfree(&nod);
 			patch(p1, pc);
 			return;
@@ -1056,7 +1061,8 @@
 		nextpc();
 		p->as = a;
 		naddr(f1, &p->from);
-		if(a == ACMP && f1->op == OCONST && p->from.offset < 0 && p->from.offset != -p->from.offset) {
+		if(a == ACMP && f1->op == OCONST && p->from.offset < 0 &&
+		    p->from.offset != 0x80000000) {
 			p->as = ACMN;
 			p->from.offset = -p->from.offset;
 		}
--- a/sys/src/cmd/5l/asm.c
+++ b/sys/src/cmd/5l/asm.c
@@ -483,12 +483,12 @@
 		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
 			if(p->as == ATEXT)
 				curtext = p;
-			if(debug['L'])
+			if(debug['V'])
 				Bprint(&bso, "%6lux %P\n",
 					p->pc, p);
 			continue;
 		}
-		if(debug['L'])
+		if(debug['V'])
 			Bprint(&bso, "\t\t%6ld", lcsize);
 		v = (p->pc - oldpc) / MINLC;
 		while(v) {
@@ -496,7 +496,7 @@
 			if(v < 127)
 				s = v;
 			cput(s+128);	/* 129-255 +pc */
-			if(debug['L'])
+			if(debug['V'])
 				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
 			v -= s;
 			lcsize++;
@@ -510,7 +510,7 @@
 			cput(s>>16);
 			cput(s>>8);
 			cput(s);
-			if(debug['L']) {
+			if(debug['V']) {
 				if(s > 0)
 					Bprint(&bso, " lc+%ld(%d,%ld)\n",
 						s, 0, s);
@@ -525,7 +525,7 @@
 		}
 		if(s > 0) {
 			cput(0+s);	/* 1-64 +lc */
-			if(debug['L']) {
+			if(debug['V']) {
 				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
 				Bprint(&bso, "%6lux %P\n",
 					p->pc, p);
@@ -532,7 +532,7 @@
 			}
 		} else {
 			cput(64-s);	/* 65-128 -lc */
-			if(debug['L']) {
+			if(debug['V']) {
 				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
 				Bprint(&bso, "%6lux %P\n",
 					p->pc, p);
@@ -545,7 +545,7 @@
 		cput(s);
 		lcsize++;
 	}
-	if(debug['v'] || debug['L'])
+	if(debug['v'] || debug['V'])
 		Bprint(&bso, "lcsize = %ld\n", lcsize);
 	Bflush(&bso);
 }
@@ -1365,6 +1365,53 @@
 		else if(p->as == AMOVH)
 			o2 ^= (1<<6);
 		break;
+
+	/* VFP ops: */
+	case 74:	/* vfp floating point arith */
+		o1 = opvfprrr(p->as, p->scond);
+		rf = p->from.reg;
+		if(p->from.type == D_FCONST) {
+			diag("invalid floating-point immediate\n%P", p);
+			rf = 0;
+		}
+		rt = p->to.reg;
+		r = p->reg;
+		if(r == NREG)
+			r = rt;
+		o1 |= rt<<12;
+		if(((o1>>20)&0xf) == 0xb)
+			o1 |= rf<<0;
+		else
+			o1 |= r<<16 | rf<<0;
+		break;
+	case 75:	/* vfp floating point compare */
+		o1 = opvfprrr(p->as, p->scond);
+		rf = p->from.reg;
+		if(p->from.type == D_FCONST) {
+			if(p->from.ieee->h != 0 || p->from.ieee->l != 0)
+				diag("invalid floating-point immediate\n%P", p);
+			o1 |= 1<<16;
+			rf = 0;
+		}
+		rt = p->reg;
+		o1 |= rt<<12 | rf<<0;
+		o2 = 0x0ef1fa10;	/* MRS APSR_nzcv, FPSCR */
+		o2 |= (p->scond & C_SCOND) << 28;
+		break;
+	case 76:	/* vfp floating point fix and float */
+		o1 = opvfprrr(p->as, p->scond);
+		rf = p->from.reg;
+		rt = p->to.reg;
+		if(p->from.type == D_REG) {
+			o2 = o1 | rt<<12 | rt<<0;
+			o1 = 0x0e000a10;	/* VMOV F,R */
+			o1 |= (p->scond & C_SCOND) << 28 | rt<<16 | rf<<12;
+		} else {
+			o1 |= FREGTMP<<12 | rf<<0;
+			o2 = 0x0e100a10;	/* VMOV R,F */
+			o2 |= (p->scond & C_SCOND) << 28 | FREGTMP<<16 | rt<<12;
+		}
+		break;
 	}
 
 	if(debug['a'] > 1)
@@ -1494,6 +1541,40 @@
 }
 
 long
+opvfprrr(int a, int sc)
+{
+	long o;
+
+	o = (sc & C_SCOND) << 28;
+	if(sc & (C_SBIT|C_PBIT|C_WBIT))
+		diag(".S/.P/.W on vfp instruction");
+	o |= 0xe<<24;
+	switch(a) {
+	case AMOVWD:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7;
+	case AMOVWF:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7;
+	case AMOVDW:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7;
+	case AMOVFW:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7;
+	case AMOVFD:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7;
+	case AMOVDF:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7;
+	case AMOVF:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7;
+	case AMOVD:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7;
+	case ACMPF:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7;
+	case ACMPD:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7;
+	case AADDF:	return o | 0xa<<8 | 0x3<<20;
+	case AADDD:	return o | 0xb<<8 | 0x3<<20;
+	case ASUBF:	return o | 0xa<<8 | 0x3<<20 | 1<<6;
+	case ASUBD:	return o | 0xb<<8 | 0x3<<20 | 1<<6;
+	case AMULF:	return o | 0xa<<8 | 0x2<<20;
+	case AMULD:	return o | 0xb<<8 | 0x2<<20;
+	case ADIVF:	return o | 0xa<<8 | 0x8<<20;
+	case ADIVD:	return o | 0xb<<8 | 0x8<<20;
+	}
+	diag("bad vfp rrr %d", a);
+	prasm(curp);
+	return 0;
+}
+
+long
 opbra(int a, int sc)
 {
 
@@ -1628,10 +1709,45 @@
 }
 
 long
+ovfpmem(int a, int r, long v, int b, int sc, Prog *p)
+{
+	long o;
+
+	if(sc & (C_SBIT|C_PBIT|C_WBIT))
+		diag(".S/.P/.W on VLDR/VSTR instruction");
+	o = (sc & C_SCOND) << 28;
+	o |= 0xd<<24 | (1<<23);
+	if(v < 0) {
+		v = -v;
+		o ^= 1 << 23;
+	}
+	if(v & 3)
+		diag("odd offset for floating point op: %ld\n%P", v, p);
+	else if(v >= (1<<10))
+		diag("literal span too large: %ld\n%P", v, p);
+	o |= (v>>2) & 0xFF;
+	o |= b << 16;
+	o |= r << 12;
+	switch(a) {
+	default:
+		diag("bad fst %A", a);
+	case AMOVD:
+		o |= 0xb<<8;
+		break;
+	case AMOVF:
+		o |= 0xa<<8;
+		break;
+	}
+	return o;
+}
+
+long
 ofsr(int a, int r, long v, int b, int sc, Prog *p)
 {
 	long o;
 
+	if(vfp)
+		return ovfpmem(a, r, v, b, sc, p);
 	if(sc & C_SBIT)
 		diag(".S on FLDR/FSTR instruction");
 	o = (sc & C_SCOND) << 28;
@@ -1703,6 +1819,8 @@
 	Ieee *p;
 	int n;
 
+	if(vfp)
+		return -1;
 	for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
 		p = &chipfloats[n];
 		if(p->l == e->l && p->h == e->h)
--- a/sys/src/cmd/5l/l.h
+++ b/sys/src/cmd/5l/l.h
@@ -7,7 +7,12 @@
 #define	EXTERN	extern
 #endif
 
+#define	LIBNAMELEN	300
 
+void	addlibpath(char*);
+int	fileexists(char*);
+char*	findlib(char*);
+
 typedef	struct	Adr	Adr;
 typedef	struct	Sym	Sym;
 typedef	struct	Autom	Auto;
@@ -134,6 +139,7 @@
 	LTO		= 1<<1,
 	LPOOL		= 1<<2,
 	V4		= 1<<3,	/* arm v4 arch */
+	VFP		= 1<<4,	/* arm vfpv3 floating point */
 
 	C_NONE		= 0,
 	C_REG,
@@ -269,6 +275,7 @@
 EXTERN	Prog	zprg;
 EXTERN	int	dtype;
 EXTERN	int	armv4;
+EXTERN	int vfp;
 
 EXTERN	int	doexp, dlm;
 EXTERN	int	imports, nimports;
@@ -309,6 +316,7 @@
 int	Sconv(Fmt*);
 int	aclass(Adr*);
 void	addhist(long, int);
+void	addlibpath(char*);
 void	append(Prog*, Prog*);
 void	asmb(void);
 void	asmdyn(void);
@@ -336,7 +344,9 @@
 void	errorexit(void);
 void	exchange(Prog*);
 void	export(void);
+int	fileexists(char*);
 int	find1(long, int);
+char*	findlib(char*);
 void	follow(void);
 void	gethunk(void);
 void	histtoauto(void);
@@ -361,6 +371,7 @@
 long	opirr(int);
 Optab*	oplook(Prog*);
 long	oprrr(int, int);
+long	opvfprrr(int, int);
 long	olr(long, int, int, int);
 long	olhr(long, int, int, int);
 long	olrr(int, int, int, int);
--- a/sys/src/cmd/5l/noop.c
+++ b/sys/src/cmd/5l/noop.c
@@ -302,6 +302,30 @@
 
 			break;
 
+		/*
+		 * 5c code generation for unsigned -> double made the
+		 * unfortunate assumption that single and double floating
+		 * point registers are aliased - true for emulated 7500
+		 * but not for vfp.  Now corrected, but this test is
+		 * insurance against old 5c compiled code in libraries.
+		 */
+		case AMOVWD:
+			if((q = p->link) != P && q->as == ACMP)
+			if((q = q->link) != P && q->as == AMOVF)
+			if((q1 = q->link) != P && q1->as == AADDF)
+			if(q1->to.type == D_FREG && q1->to.reg == p->to.reg) {
+				q1->as = AADDD;
+				q1 = prg();
+				q1->scond = q->scond;
+				q1->line = q->line;
+				q1->as = AMOVFD;
+				q1->from = q->to;
+				q1->to = q1->from;
+				q1->link = q->link;
+				q->link = q1;
+			}
+			break;
+
 		case ADIV:
 		case ADIVU:
 		case AMOD:
--- a/sys/src/cmd/5l/optab.c
+++ b/sys/src/cmd/5l/optab.c
@@ -211,6 +211,14 @@
 	{ ACASE,	C_REG,	C_NONE,	C_NONE,		62, 4, 0 },
 	{ ABCASE,	C_NONE, C_NONE, C_SBRA,		63, 4, 0 },
 
+	{ AADDF,	C_FREG,	C_NONE,	C_FREG,		74, 4, 0, VFP },
+	{ AADDF,	C_FREG,	C_REG,	C_FREG,		74, 4, 0, VFP },
+	{ AMOVF,	C_FREG, C_NONE, C_FREG,		74, 4, 0, VFP },
+	{ ACMPF,	C_FREG,	C_REG,	C_NONE,		75, 8, 0, VFP },
+	{ ACMPF,	C_FCON,	C_REG,	C_NONE,		75, 8, 0, VFP },
+	{ AMOVFW,	C_FREG,	C_NONE,	C_REG,		76, 8, 0, VFP },
+	{ AMOVFW,	C_REG,	C_NONE,	C_FREG,		76, 8, 0, VFP },
+
 	{ AMOVH,	C_REG,	C_NONE,	C_HEXT,		70, 4, REGSB,	V4 },
 	{ AMOVH,	C_REG,	C_NONE, C_HAUTO,	70, 4, REGSP,	V4 },
 	{ AMOVH,	C_REG,	C_NONE,	C_HOREG,	70, 4, 0,	V4 },
--- a/sys/src/cmd/5l/span.c
+++ b/sys/src/cmd/5l/span.c
@@ -639,6 +639,9 @@
 	n = (p2->flag&V4) - (p1->flag&V4);	/* architecture version */
 	if(n)
 		return n;
+	n = (p2->flag&VFP) - (p1->flag&VFP);	/* floating point arch */
+	if(n)
+		return n;
 	n = p1->a1 - p2->a1;
 	if(n)
 		return n;
@@ -657,14 +660,18 @@
 	int i, n, r;
 
 	armv4 = !debug['h'];
+	vfp = debug['f'];
 	for(i=0; i<C_GOK; i++)
 		for(n=0; n<C_GOK; n++)
 			xcmp[i][n] = cmp(n, i);
-	for(n=0; optab[n].as != AXXX; n++)
+	for(n=0; optab[n].as != AXXX; n++) {
+		if((optab[n].flag & VFP) && !vfp)
+			optab[n].as = AXXX;
 		if((optab[n].flag & V4) && !armv4) {
 			optab[n].as = AXXX;
 			break;
 		}
+	}
 	qsort(optab, n, sizeof(optab[0]), ocmp);
 	for(i=0; i<n; i++) {
 		r = optab[i].as;
@@ -679,6 +686,8 @@
 		default:
 			diag("unknown op in build: %A", r);
 			errorexit();
+		case AXXX:
+			break;
 		case AADD:
 			oprange[AAND] = oprange[r];
 			oprange[AEOR] = oprange[r];
--- a/sys/src/libmach/5db.c
+++ b/sys/src/libmach/5db.c
@@ -135,7 +135,7 @@
 int
 armclass(long w)
 {
-	int op, done;
+	int op, done, cp;
 
 	op = (w >> 25) & 0x7;
 	switch(op) {
@@ -220,8 +220,62 @@
 		op = (48+24+4+4+2) + ((w >> 24) & 0x1);
 		break;
 	case 7:	/* coprocessor crap */
+		cp = (w >> 8) & 0xF;
+		if(cp == 10 || cp == 11){	/* vfp */
+			if((w >> 4) & 0x1){
+				/* vfp register transfer */
+				switch((w >> 21) & 0x7){
+				case 0:
+					op = 118 + ((w >> 20) & 0x1);
+					break;
+				case 7:
+					op = 118+2 + ((w >> 20) & 0x1);
+					break;
+				default:
+					op = (48+24+4+4+2+2+4+4);
+					break;
+				}
+				break;
+			}
+			/* vfp data processing */
+			if(((w >> 23) & 0x1) == 0){
+				op = 100 + ((w >> 19) & 0x6) + ((w >> 6) & 0x1);
+				break;
+			}
+			switch(((w >> 19) & 0x6) + ((w >> 6) & 0x1)){
+			case 0:
+				op = 108;
+				break;
+			case 7:
+				if(((w >> 19) & 0x1) == 0)
+					if(((w >> 17) & 0x1) == 0)
+						op = 109 + ((w >> 16) & 0x4) +
+							((w >> 15) & 0x2) +
+							((w >> 7) & 0x1);
+					else if(((w >> 16) & 0x7) == 0x7)
+						op = 117;
+				else
+					switch((w >> 16) & 0x7){
+					case 0:
+					case 4:
+					case 5:
+						op = 117;
+						break;
+					}
+				break;
+			}
+			if(op == 7)
+				op = (48+24+4+4+2+2+4+4);
+			break;
+		}
 		op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
 		break;
+	case 6:	/* vfp load / store */
+		if(((w >> 21) &0x9) == 0x8){
+			op = 122 + ((w >> 20) & 0x1);
+			break;
+		}
+		/* fall through */
 	default:	  
 		op = (48+24+4+4+2+2+4+4);
 		break;
@@ -298,7 +352,7 @@
  * Print value v as name[+offset]
  */
 static int
-gsymoff(char *buf, int n, long v, int space)
+gsymoff(char *buf, int n, ulong v, int space)
 {
 	Symbol s;
 	int r;
@@ -405,6 +459,20 @@
 	format(o->o, i, o->a);
 }
 
+static void
+armvstdi(Opcode *o, Instr *i)
+{
+	ulong v;
+
+	v = (i->w & 0xff) << 2;
+	if(!(i->w & (1<<23)))
+		v = -v;
+	i->imm = v;
+	i->rn = (i->w >> 16) & 0xf;
+	i->rd = (i->w >> 12) & 0xf;
+	format(o->o, i, o->a);
+}
+
 /* arm V4 ld/st halfword, signed byte */
 static void
 armhwby(Opcode *o, Instr *i)
@@ -870,6 +938,40 @@
 
 /* 99 */
 	"RFEV7%P%a",	armbdt, 0,	"(R%n)",
+
+/* 100 */
+	"MLA%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"MLS%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"NMLS%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"NMLA%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"MUL%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"NMUL%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"ADD%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"SUB%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"DIV%f%C",	armdps,	0,	"F%s,F%n,F%d",
+
+/* 109 */
+	"MOV%f%C",	armdps,	0,	"F%s,F%d",
+	"ABS%f%C",	armdps,	0,	"F%s,F%d",
+	"NEG%f%C",	armdps,	0,	"F%s,F%d",
+	"SQRT%f%C",	armdps,	0,	"F%s,F%d",
+	"CMP%f%C",	armdps,	0,	"F%s,F%d",
+	"CMPE%f%C",	armdps,	0,	"F%s,F%d",
+	"CMP%f%C",	armdps,	0,	"$0.0,F%d",
+	"CMPE%f%C",	armdps,	0,	"$0.0,F%d",
+
+/* 117 */
+	"MOV%F%R%C",	armdps, 0,	"F%s,F%d",
+
+/* 118 */
+	"MOVW%C",	armdps, 0,	"R%d,F%n",
+	"MOVW%C",	armdps, 0,	"F%n,R%d",
+	"MOVW%C",	armdps, 0,	"R%d,%x",
+	"MOVW%C",	armdps, 0,	"%x,R%d",
+
+/* 122 */
+	"MOV%f%C",	armvstdi,	0,	"F%d,%I",
+	"MOV%f%C",	armvstdi,	0,	"%I,F%d",
 };
 
 static void
@@ -1011,12 +1113,74 @@
 
 		case 'b':
 			i->curr += symoff(i->curr, i->end-i->curr,
-				i->imm, CTEXT);
+				(ulong)i->imm, CTEXT);
 			break;
 
 		case 'g':
 			i->curr += gsymoff(i->curr, i->end-i->curr,
 				i->imm, CANY);
+			break;
+
+		case 'f':
+			switch((i->w >> 8) & 0xF){
+			case 10:
+				bprint(i, "F");
+				break;
+			case 11:
+				bprint(i, "D");
+				break;
+			}
+			break;
+
+		case 'F':
+			switch(((i->w >> 15) & 0xE) + ((i->w >> 8) & 0x1)){
+			case 0x0:
+				bprint(i, ((i->w >> 7) & 0x1)? "WF" : "WF.U");
+				break;
+			case 0x1:
+				bprint(i, ((i->w >> 7) & 0x1)? "WD" : "WD.U");
+				break;
+			case 0x8:
+				bprint(i, "FW.U");
+				break;
+			case 0x9:
+				bprint(i, "DW.U");
+				break;
+			case 0xA:
+				bprint(i, "FW");
+				break;
+			case 0xB:
+				bprint(i, "DW");
+				break;
+			case 0xE:
+				bprint(i, "FD");
+				break;
+			case 0xF:
+				bprint(i, "DF");
+				break;
+			}
+			break;
+
+		case 'R':
+			if(((i->w >> 7) & 0x1) == 0)
+				bprint(i, "R");
+			break;
+
+		case 'x':
+			switch(i->rn){
+			case 0:
+				bprint(i, "FPSID");
+				break;
+			case 1:
+				bprint(i, "FPSCR");
+				break;
+			case 2:
+				bprint(i, "FPEXC");
+				break;
+			default:
+				bprint(i, "FPS(%d)", i->rn);
+				break;
+			}
 			break;
 
 		case 'r':