shithub: riscv

Download patch

ref: 8483799d4a0f80e38edfb83f1772af840cafe637
parent: 7f8bd359548ce61cad5011e44075d21e83d56314
author: Jacob Moody <[email protected]>
date: Mon Apr 1 01:20:20 EDT 2024

9c/9l/libmach: handle 64 bit constants

* Add a handful of 64 bit classifications to 9l, along with instruction generation for each.
* 9c should avoid generating immediate instructions for 64 constants.
* libmach should know about 9l's generation to present a better disassembly.
* libmach now properly displays MOVD for moves between registers on 64 bit.

--- a/sys/src/cmd/9c/cgen.c
+++ b/sys/src/cmd/9c/cgen.c
@@ -1,5 +1,15 @@
 #include "gc.h"
 
+static int
+isim32(vlong v)
+{
+	if((v & 0xffffffff80000000) == 0xffffffff80000000) // 32-bit negative
+		return 1;
+	if((v & 0xffffffff00000000) == 0) // 32-bit positive
+		return 1;
+	return 0;	
+}
+
 void
 cgen(Node *n, Node *nn)
 {
@@ -148,7 +158,7 @@
 		 * immediate operands
 		 */
 		if(nn != Z)
-		if(r->op == OCONST)
+		if(r->op == OCONST && isim32(r->vconst))
 		if(!typefd[n->type->etype]) {
 			cgen(l, nn);
 			if(r->vconst == 0)
@@ -203,7 +213,7 @@
 	case OASOR:
 		if(l->op == OBIT)
 			goto asbitop;
-		if(r->op == OCONST)
+		if(r->op == OCONST && isim32(r->vconst))
 		if(!typefd[r->type->etype])
 		if(!typefd[n->type->etype]) {
 			if(l->addable < INDEXED)
--- a/sys/src/cmd/9l/asmout.c
+++ b/sys/src/cmd/9l/asmout.c
@@ -138,6 +138,21 @@
 		return LOP_IRR(OP_ORIS, r, REGZERO, v);
 	return AOP_IRR(OP_ADDIS, r, REGZERO, v);
 }
+
+static ulong
+rotateleft32(Prog *p, int as, int from, int to)
+{
+	ulong o;
+	uchar mask[2];
+
+	maskgen64(p, mask, 0xFFFFFFFFULL<<32);
+	if(mask[1] != (63-32))
+		diag("invalid mask for shift: %llux (shift %d)\n%P", 0xFFFFFFFFULL<<32, 32, p);
+	o = AOP_RRR(opirr(as), from, to, (32&0x1F));
+	o |= (mask[0]&31L)<<6 | 1<<1;
+	assert((mask[0] & 0x20) == 0);
+	return o;
+}
 	
 int
 asmout(Prog *p, Optab *o, int aflag)
@@ -949,6 +964,35 @@
 			reloc(&p->from, p->pc, 1);
 		break;
 
+	/* 64 bit constant operations */
+
+	case 77: /* mov $vucon,r */
+		d = vregoff(&p->from); 
+		o1 = loadu32(p->to.reg, d>>32);
+		o2 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, d>>32);
+		o3 = rotateleft32(p, ARLDMI, p->to.reg, p->to.reg);
+		break;
+
+	case 78: /* mov $vcon,r */
+		d = vregoff(&p->from); 
+		o1 = loadu32(p->to.reg, d);
+		o2 = loadu32(REGTMP, d>>32);
+		o3 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, (long)d);
+		o4 = LOP_IRR(OP_ORI, REGTMP, REGTMP, d>>32);
+		o5 = rotateleft32(p, ARLDMI, REGTMP, p->to.reg);
+		break;
+
+	case 79: /* mov $vulcon,r */
+		d = vregoff(&p->from);
+		o1 = LOP_IRR(OP_ORI, p->to.reg, REGZERO, d>>32);
+		o2 = rotateleft32(p, ARLDMI, p->to.reg, p->to.reg);
+		break;
+
+	case 80: /* mov $vuucon,r */
+		d = vregoff(&p->from); 
+		o1 = loadu32(p->to.reg, d>>32);
+		o2 = rotateleft32(p, ARLDMI, p->to.reg, p->to.reg);
+		break;
 	}
 	if(aflag)
 		return o1;
--- a/sys/src/cmd/9l/cnam.c
+++ b/sys/src/cmd/9l/cnam.c
@@ -11,6 +11,10 @@
 	"ADDCON",
 	"ANDCON",
 	"LCON",
+	"VULCON",
+	"VUUCON",
+	"VUCON",
+	"VCON",
 	"SACON",
 	"SECON",
 	"LACON",
--- a/sys/src/cmd/9l/l.h
+++ b/sys/src/cmd/9l/l.h
@@ -140,7 +140,11 @@
 	C_UCON,		/* low 16 bits 0 */
 	C_ADDCON,	/* -0x8000 <= v < 0 */
 	C_ANDCON,	/* 0 < v <= 0xFFFF */
-	C_LCON,		/* other */
+	C_LCON,		/* 32 bit */
+	C_VULCON,	/* 64 bit, low 32 bits 0, top 16 bits zero */
+	C_VUUCON,	/* 64 bit, low 32 bits 0, top 16 bits only */
+	C_VUCON,	/* 64 bit, low 32 bits 0 */
+	C_VCON,		/* 64 bit */
 	C_SACON,
 	C_SECON,
 	C_LACON,
--- a/sys/src/cmd/9l/optab.c
+++ b/sys/src/cmd/9l/optab.c
@@ -92,9 +92,9 @@
 	{ ASRAD,	C_SCON,	C_REG, C_NONE, 	C_REG,		56, 4, 0 },
 	{ ASRAD,	C_SCON,	C_NONE, C_NONE, 	C_REG,		56, 4, 0 },
 
-	{ ARLWMI,	C_SCON, C_REG, C_LCON, 	C_REG,		62, 4, 0 },
-	{ ARLWMI,	C_REG,	C_REG, C_LCON, 	C_REG,		63, 4, 0 },
-	{ ARLDMI,	C_SCON,	C_REG, C_LCON,	C_REG,		30, 4, 0 },
+	{ ARLWMI,	C_SCON, C_REG, C_VCON, 	C_REG,		62, 4, 0 },
+	{ ARLWMI,	C_REG,	C_REG, C_VCON, 	C_REG,		63, 4, 0 },
+	{ ARLDMI,	C_SCON,	C_REG, C_VCON,	C_REG,		30, 4, 0 },
 
 	{ ARLDC,	C_SCON,	C_REG, C_LCON,	C_REG,		29, 4, 0 },
 	{ ARLDCL,	C_SCON,	C_REG, C_LCON,	C_REG,		29, 4, 0 },
@@ -223,9 +223,13 @@
 	{ AMOVWZ,	C_LACON,C_NONE, C_NONE, 	C_REG,		26, 8, REGSP },
 	{ AMOVWZ,	C_ADDCON,C_NONE, C_NONE, C_REG,		 3, 4, REGZERO },
 
-	/* load unsigned/long constants (TO DO: check) */
+	/* load unsigned/long/vlong constants */
 	{ AMOVD,	C_UCON, C_NONE, C_NONE,  C_REG,		3, 4, REGZERO },
 	{ AMOVD,	C_LCON,	C_NONE, C_NONE, 	C_REG,		19, 8, 0 },
+	{ AMOVD,	C_VUCON, C_NONE, C_NONE, C_REG, 77, 12, 0 },
+	{ AMOVD,	C_VULCON, C_NONE, C_NONE, C_REG, 79, 8, 0 },
+	{ AMOVD,	C_VUUCON, C_NONE, C_NONE, C_REG, 80, 8, 0 },
+	{ AMOVD,	C_VCON, C_NONE, C_NONE,  C_REG, 78, 20, 0 },
 	{ AMOVW,	C_UCON, C_NONE, C_NONE,  C_REG,		3, 4, REGZERO },
 	{ AMOVW,	C_LCON,	C_NONE, C_NONE, 	C_REG,		19, 8, 0 },
 	{ AMOVWZ,	C_UCON, C_NONE, C_NONE,  C_REG,		3, 4, REGZERO },
--- a/sys/src/cmd/9l/span.c
+++ b/sys/src/cmd/9l/span.c
@@ -266,13 +266,33 @@
 					return C_ANDCON;
 				if((instoffset & 0xffff) == 0 && isuint32(instoffset))	/* && (instoffset & (1<<31)) == 0) */
 					return C_UCON;
-				return C_LCON;
+				if((instoffset & 0xffffffff00000000) == 0) // 32-bit positive 
+					return C_LCON;
+				if((instoffset & 0xffffffff) == 0){
+					if((instoffset & 0xffff000000000000ull) == 0)
+						return C_VULCON;
+					if((instoffset & 0x0000ffff00000000ull) == 0)
+						return C_VUUCON;
+					return C_VUCON;
+				}
+				return C_VCON;
 			}
 			if(instoffset >= -0x8000)
 				return C_ADDCON;
 			if((instoffset & 0xffff) == 0 && isint32(instoffset))
 				return C_UCON;
-			return C_LCON;
+			if((instoffset & 0xffffffff80000000) == 0xffffffff80000000) // 32-bit negative
+				return C_LCON;
+			if((instoffset & 0xffffffff00000000) == 0) // 32-bit positive 
+				return C_LCON;
+			if((instoffset & 0xffffffff) == 0){
+				if((instoffset & 0xffff000000000000ull) == 0)
+					return C_VULCON;
+				if((instoffset & 0x0000ffff00000000ull) == 0)
+					return C_VUUCON;
+				return C_VUCON;
+			}
+			return C_VCON;
 
 		case D_EXTERN:
 		case D_STATIC:
@@ -398,6 +418,10 @@
 	if(a == b)
 		return 1;
 	switch(a) {
+	case C_VCON:
+		if(b == C_VUCON || b == C_LCON || b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON)
+			return 1;
+		break;
 	case C_LCON:
 		if(b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON)
 			return 1;
--- a/sys/src/libmach/qdb.c
+++ b/sys/src/libmach/qdb.c
@@ -147,8 +147,7 @@
 	uchar	imm;		/* bits 16-19 */
 	ushort	xo;		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
 	uvlong	imm64;
-	long w0;
-	long w1;
+	long	w[5];		/* full context of a combined pseudo instruction */
 	uchar	pop;		/* op of second half of prefixed instruction */
 	uvlong	addr;		/* pc of instruction */
 	short	target;
@@ -241,7 +240,7 @@
 		i->imm64 <<= 16;
 	else if(i->op == 25 || i->op == 27 || i->op == 29)
 		i->imm64 = (uvlong)(i->uimm<<16);
-	i->w0 = w;
+	i->w[0] = w;
 	i->target = -1;
 	i->addr = pc;
 	i->size = 1;
@@ -252,26 +251,62 @@
 mkinstr(uvlong pc, Instr *i)
 {
 	Instr x;
+	Instr sf[3];
 	ulong w;
+	int j;
 
 	if(decode(pc, i) < 0)
 		return -1;
 	/*
-	 * combine ADDIS/ORI (CAU/ORIL) into MOVW
-	 * also ORIS/ORIL for unsigned in 64-bit mode
+	 * Linker has to break out larger constants into multiple instructions.
+	 * Combine them back together into one MOV.
+	 * 15 is addis, 25 is oris, 24 is ori.
 	 */
-	if((i->op == 15 || i->op == 25) && i->ra==0) {
+	if((i->op == 15 && i->ra == 0) || (i->op == 25 && i->rs == 0) || (i->op == 24 && i->rs == 0)) {
 		if(decode(pc+4, &x) < 0)
-			return -1;
-		if(x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
+			return 1;
+
+		/* very specific worst case 64 bit load */
+		if(x.rd == 31 && (x.op == 15 && x.ra == 0) || (x.op == 25 && x.rs == 0)){
+			for(j = 0; j < nelem(sf); j++)
+				if(decode(pc + 4*(j+2), sf+j) < 0)
+					goto Next;
+			if(sf[0].op == 24 && sf[0].rs == sf[0].ra && sf[0].ra == i->rd)
+			if(sf[1].op == 24 && sf[1].rs == sf[1].ra && sf[1].ra == 31)
+			if(sf[2].ra == (i->rs == 0 ? i->ra : i ->rs))
+			if(sf[2].op == 30 && IBF(sf[2].w[0], 27, 30) == 7)
+			if(sf[2].xsh == 32 && IBF(sf[2].w[0], 21, 26) == 0){
+				i->size = 5;
+				i->imm64 = (i->imm64&0xFFFF0000) | ((sf[0].imm64&0xFFFF));
+				i->imm64 |= ((x.imm64&0xFFFF0000)<<32) | ((sf[1].imm64&0xFFFF)<<32);
+			}
+			return 1;
+		}
+
+Next:
+		if(i->op != 24 && x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
 			i->imm64 |= (x.imm64 & 0xFFFF);
 			if(i->op != 15)
 				i->imm64 &= 0xFFFFFFFFUL;
-			i->w1 = x.w0;
+			i->w[1] = x.w[0];
 			i->target = x.rd;
 			i->size++;
-			return 1;
+			if(decode(pc+8, &x) < 0)
+				return 1;
 		}
+
+		/* 64 bit constant mov with lower 32 zero */
+		if(x.ra == (i->rs == 0 ? i->ra : i ->rs))
+		if(x.op == 30 && IBF(x.w[0], 27, 30) == 7)
+		if(x.xsh == 32 && IBF(x.w[0], 21, 26) == 0){
+			i->imm64 <<= 32;
+			if(i->size == 2)
+				i->w[2] = x.w[0];
+			else
+				i->w[1] = x.w[0];
+			i->size++;
+		}
+		return 1;
 	}
 
 	/* ISA3.1+ prefixed instructions */
@@ -278,8 +313,8 @@
 	if(i->op == 1){
 		if(get4(mymap, pc+4, &w) < 0)
 			return -1;
-		i->w1 = w;
-		i->pop = IBF(i->w1, 0, 5);
+		i->w[1] = w;
+		i->pop = IBF(i->w[1], 0, 5);
 		i->size++;
 	}
 	return 1;
@@ -398,9 +433,9 @@
 addi(Opcode *o, Instr *i)
 {
 	if (i->op==14 && i->ra == 0)
-		format("MOVW", i, "%i,R%d");
+		format("MOV%N", i, "%i,R%d");
 	else if (i->ra == REGSB) {
-		bprint(i, "MOVW\t$");
+		format("MOV%N\t$", i, nil);
 		address(i);
 		bprint(i, ",R%d", i->rd);
 	} else if(i->op==14 && i->simm < 0) {
@@ -417,22 +452,23 @@
 static void
 addis(Opcode *o, Instr *i)
 {
-	long v;
+	vlong v;
 
 	v = i->imm64;
-	if (i->op==15 && i->ra == 0)
-		bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
-	else if (i->op==15 && i->ra == REGSB) {
-		bprint(i, "MOVW\t$");
+	if (i->op==15 && i->ra == 0){
+		format("MOV%N\t", i, nil);
+		bprint(i, "$%llux,R%d", v, i->rd);
+	} else if (i->op==15 && i->ra == REGSB) {
+		format("MOV%N\t$", i, nil);
 		address(i);
 		bprint(i, ",R%d", i->rd);
 	} else if(i->op==15 && v < 0) {
-		bprint(i, "SUB\t$%ld,R%d", -v, i->ra);
+		bprint(i, "SUB\t$%lld,R%d", -v, i->ra);
 		if(i->rd != i->ra)
 			bprint(i, ",R%d", i->rd);
 	} else {
 		format(o->mnemonic, i, nil);
-		bprint(i, "\t$%ld,R%d", v, i->ra);
+		bprint(i, "\t$%lld,R%d", v, i->ra);
 		if(i->rd != i->ra)
 			bprint(i, ",R%d", i->rd);
 	}
@@ -683,10 +719,12 @@
 		if (i->rs == 0 && i->ra == 0 && i->rb == 0)
 			format("NOP", i, nil);
 		else if (i->rs == i->rb)
-			format("MOVW", i, "R%b,R%a");
+			format("MOV%N", i, "R%b,R%a");
 		else
 			and(o, i);
-	} else
+	} else if(i->op == 24 && i->rs == 0)
+		format("MOV%N", i, "$%B,R%a");
+	else
 		and(o, i);
 }
 
@@ -693,8 +731,13 @@
 static void
 shifted(Opcode *o, Instr *i)
 {
+	if (i->op == 25 && i->rs == 0){
+		format("MOV%N\t", i, nil);
+		bprint(i, "$%llux,R%d", i->imm64, i->ra);
+		return;
+	}
 	format(o->mnemonic, i, nil);
-	bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
+	bprint(i, "\t$%llux,", i->imm64);
 	if (i->rs == i->ra)
 		bprint(i, "R%d", i->ra);
 	else
@@ -851,7 +894,7 @@
 	long l;
 	char buf[16];
 
-	l = ((IBF(i->w0, 11, 15)<<11) | (IBF(i->w0, 16, 25)<<1) | (i->rc))<<16;
+	l = ((IBF(i->w[0], 11, 15)<<11) | (IBF(i->w[0], 16, 25)<<1) | (i->rc))<<16;
 	snprint(buf, sizeof buf, "$%ld,PC,R%%d", l);
 	format(o->mnemonic, i, buf);
 }
@@ -859,7 +902,7 @@
 static void
 vsldbi(Opcode *o, Instr *i)
 {
-	switch(IBF(i->w0, 21, 22)){
+	switch(IBF(i->w[0], 21, 22)){
 	case 1:
 		format("vsrdbi", i, o->ken);
 		break;
@@ -1014,16 +1057,16 @@
 	for(p = popcodes; p->mnemonic != nil; p++){
 		if(i->pop != p->op2)
 			continue;
-		if((i->w0 & p->xomask1) != p->xo1)
+		if((i->w[0] & p->xomask1) != p->xo1)
 			continue;
-		if((i->w1 & p->xomask2) != p->xo2)
+		if((i->w[1] & p->xomask2) != p->xo2)
 			continue;
 		format(p->mnemonic, i, nil);
 		return;
 	}
-	if((i->w0 & XXM1) == 3<<24)
+	if((i->w[0] & XXM1) == 3<<24)
 		format("NOP", i, nil);
-	else if((i->w0 & XXM4) == 0){
+	else if((i->w[0] & XXM4) == 0){
 		if((i->pop & ~1) == 25<<1)
 			format("plxv", i, nil);
 		else if((i->pop & ~1) == 27<<1)
@@ -1178,18 +1221,21 @@
 
 	{19,	0,	ALL,	"MOVFL",	gen,	"%S,%D"},
 	{63,	64,	ALL,	"MOVCRFS",	gen,	"%S,%D"},
-	{31,	512,	ALL,	"MOVW",		gen,	"XER,%D"},
-	{31,	19,	ALL,	"MOVW",		gen,	"CR,R%d"},
+	{31,	19,	ALL,	"MOV%N",	gen,	"CR,R%d"},
 
-	{63,	583,	ALL,	"MOVW%C",	gen,	"FPSCR, F%d"},	/* mffs */
-	{31,	83,	ALL,	"MOVW",		gen,	"MSR,R%d"},
-	{31,	339,	ALL,	"MOVW",		gen,	"%P,R%d"},
-	{31,	595,	ALL,	"MOVW",		gen,	"SEG(%a),R%d"},
-	{31,	659,	ALL,	"MOVW",		gen,	"SEG(R%b),R%d"},
-	{31,	323,	ALL,	"MOVW",		gen,	"DCR(%Q),R%d"},
-	{31,	451,	ALL,	"MOVW",		gen,	"R%s,DCR(%Q)"},
-	{31,	259,	ALL,	"MOVW",		gen,	"DCR(R%a),R%d"},
-	{31,	387,	ALL,	"MOVW",		gen,	"R%s,DCR(R%a)"},
+	{31,	512,	ALL,	"MOVW",		gen,	"XER,%D"}, 	/* deprecated */
+	{31,	595,	ALL,	"MOVW",		gen,	"SEG(%a),R%d"},	/* deprecated */
+	{31,	659,	ALL,	"MOVW",		gen,	"SEG(R%b),R%d"},/* deprecated */
+	{31,	323,	ALL,	"MOVW",		gen,	"DCR(%Q),R%d"},	/* deprecated */
+	{31,	451,	ALL,	"MOVW",		gen,	"R%s,DCR(%Q)"},	/* deprecated */
+	{31,	259,	ALL,	"MOVW",		gen,	"DCR(R%a),R%d"},/* deprecated */
+	{31,	387,	ALL,	"MOVW",		gen,	"R%s,DCR(R%a)"},/* deprecated */
+	{31,	210,	ALL,	"MOVW",		gen,	"R%s,SEG(%a)"},	/* deprecated */
+	{31,	242,	ALL,	"MOVW",		gen,	"R%s,SEG(R%b)"},/* deprecated */
+
+	{63,	583,	ALL,	"MOV%N%C",	gen,	"FPSCR, F%d"},	/* mffs */
+	{31,	83,	ALL,	"MOV%N",	gen,	"MSR,R%d"},
+	{31,	339,	ALL,	"MOV%N",	gen,	"%P,R%d"},
 	{31,	144,	ALL,	"MOVFL",	gen,	"R%s,%m,CR"},
 	{63,	70,	ALL,	"MTFSB0%C",	gencc,	"%D"},
 	{63,	38,	ALL,	"MTFSB1%C",	gencc,	"%D"},
@@ -1197,9 +1243,7 @@
 	{63,	134,	ALL,	"MOVFL%C",	gencc,	"%K,%D"},
 	{31,	146,	ALL,	"MOVW",		gen,	"R%s,MSR"},
 	{31,	178,	ALL,	"MOVD",		gen,	"R%s,MSR"},
-	{31,	467,	ALL,	"MOVW",		gen,	"R%s,%P"},
-	{31,	210,	ALL,	"MOVW",		gen,	"R%s,SEG(%a)"},
-	{31,	242,	ALL,	"MOVW",		gen,	"R%s,SEG(R%b)"},
+	{31,	467,	ALL,	"MOV%N",	gen,	"R%s,%P"},
 
 	{31,	7,	ALL,	"MOVBE",	vldx,	0},
 	{31,	39,	ALL,	"MOVHE",	vldx,	0},
@@ -1263,7 +1307,7 @@
 	{31,	124,	ALL,	"NOR%C",	gencc,	il3},
 	{31,	444,	ALL,	"OR%C",		or,	il3},
 	{31,	412,	ALL,	"ORN%C",	or,	il3},
-	{24,	0,	0,	"OR",		and,	"%I,R%d,R%a"},
+	{24,	0,	0,	"OR",		or,	"%I,R%d,R%a"},
 	{25,	0,	0,	"OR",		shifted, 0},
 
 	{19,	50,	ALL,	"RFI",		gen,	0},
@@ -2301,6 +2345,10 @@
 			bprint(i, "%d", i->frc);
 			break;
 
+		case 'B':
+			bprint(i, "%llx", i->imm64);
+			break;
+
 		case 'd':
 		case 's':
 			bprint(i, "%d", i->rd);
@@ -2325,7 +2373,7 @@
 			break;
 
 		case 'E':
-			switch(IBF(i->w0,27,30)){	/* low bit is top bit of shift in rldiX cases */
+			switch(IBF(i->w[0],27,30)){	/* low bit is top bit of shift in rldiX cases */
 			case 8:	i->mb = i->xmbe; i->me = 63; break;	/* rldcl */
 			case 9:	i->mb = 0; i->me = i->xmbe; break;	/* rldcr */
 			case 4: case 5:
@@ -2399,6 +2447,10 @@
 			bprint(i, "%d", i->nb==0? 32: i->nb);	/* eg, pg 10-103 */
 			break;
 
+		case 'N':
+			bprint(i, "%c", asstype==APOWER64 ? 'D' : 'W');
+			break;
+
 		case 'P':
 			n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
 			for(s=0; sprname[s].name; s++)
@@ -2438,7 +2490,7 @@
 			break;
 
 		case 'w':
-			bprint(i, "[%lux]", i->w0);
+			bprint(i, "[%lux]", i->w[0]);
 			break;
 
 		case 'W':
@@ -2490,7 +2542,7 @@
 				format(o->mnemonic, &i, o->ken);
 			return i.size*4;
 		}
-	bprint(&i, "unknown %lux", i.w0);
+	bprint(&i, "unknown %lux", i.w[0]);
 	return i.size*4;
 }
 
@@ -2505,6 +2557,7 @@
 powerdas(Map *map, uvlong pc, char *buf, int n)
 {
 	Instr instr;
+	int i;
 
 	mymap = map;
 	memset(&instr, 0, sizeof(instr));
@@ -2512,11 +2565,10 @@
 	instr.end = buf+n-1;
 	if (mkinstr(pc, &instr) < 0)
 		return -1;
-	if (instr.end-instr.curr > 8)
-		instr.curr = _hexify(instr.curr, instr.w0, 7);
-	if (instr.end-instr.curr > 9 && instr.size == 2) {
-		*instr.curr++ = ' ';
-		instr.curr = _hexify(instr.curr, instr.w1, 7);
+	for(i = 0; instr.end-instr.curr > 8+1 && i < instr.size; i++){
+		if(i != 0)
+			*instr.curr++ = ' ';
+		instr.curr = _hexify(instr.curr, instr.w[i], 7);
 	}
 	*instr.curr = 0;
 	return instr.size*4;