Index: uspace/app/pcc/arch/sparc64/local.c
===================================================================
--- uspace/app/pcc/arch/sparc64/local.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/sparc64/local.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass1.h"
+
+NODE *
+clocal(NODE *p)
+{
+	struct symtab *sp;
+	int op;
+	NODE *r, *l;
+
+	op = p->n_op;
+	sp = p->n_sp;
+	l  = p->n_left;
+	r  = p->n_right;
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal in: %p, %s\n", p, copst(op));
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	switch (op) {
+
+	case NAME:
+		if (sp->sclass == PARAM || sp->sclass == AUTO) {
+			/*
+			 * Use a fake structure reference to
+			 * write out frame pointer offsets.
+			 */
+			l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+			l->n_lval = 0;
+			l->n_rval = FP;
+			r = p;
+			p = stref(block(STREF, l, r, 0, 0, 0));
+		}
+		break;
+	case PCONV: /* Remove what PCONVs we can. */
+		if (l->n_op == SCONV)
+			break;
+
+		if (l->n_op == ICON || (ISPTR(p->n_type) && ISPTR(l->n_type))) {
+			l->n_type = p->n_type;
+			l->n_qual = p->n_qual;
+			l->n_df = p->n_df;
+			l->n_ap = p->n_ap;
+			nfree(p);
+			p = l;
+		}
+		break;
+
+	case SCONV:
+        /* Remove redundant conversions. */
+		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+		    btattr[p->n_type].atypsz == btattr[l->n_type].atypsz &&
+		    p->n_type != FLOAT && p->n_type != DOUBLE &&
+		    l->n_type != FLOAT && l->n_type != DOUBLE &&
+		    l->n_type != DOUBLE && p->n_type != LDOUBLE) {
+			if (l->n_op == NAME || l->n_op == UMUL ||
+			    l->n_op == TEMP) {
+				l->n_type = p->n_type;
+				nfree(p);
+				p = l;
+				break;
+			}
+		}
+
+        /* Convert floating point to int before to char or short. */
+        if ((l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)
+            && (DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT)) {
+            p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+            p->n_left->n_type = INT;
+            break;
+        }
+
+        /* Transform constants now. */
+		if (l->n_op != ICON)
+			break;
+
+		if (ISPTR(p->n_type)) {
+			l->n_type = p->n_type;
+			nfree(p);
+			p = l;
+			break;
+		}
+
+		switch (p->n_type) {
+		case BOOL:      l->n_lval = (l->n_lval != 0); break;
+		case CHAR:      l->n_lval = (char)l->n_lval; break;
+		case UCHAR:     l->n_lval = l->n_lval & 0377; break;
+		case SHORT:     l->n_lval = (short)l->n_lval; break;
+		case USHORT:    l->n_lval = l->n_lval & 0177777; break;
+		case UNSIGNED:  l->n_lval = l->n_lval & 0xffffffff; break;
+		case INT:       l->n_lval = (int)l->n_lval; break;
+		case ULONG:
+		case ULONGLONG: l->n_lval = l->n_lval; break;
+		case LONG:
+		case LONGLONG:	l->n_lval = (long long)l->n_lval; break;
+		case FLOAT:
+		case DOUBLE:
+		case LDOUBLE:
+			l->n_op = FCON;
+			l->n_dcon = l->n_lval;
+			break;
+		case VOID:
+			break;
+		default:
+			cerror("sconv type unknown %d", p->n_type);
+		}
+
+		l->n_type = p->n_type;
+		nfree(p);
+		p = l;
+		break;
+
+	case PMCONV:
+	case PVCONV:
+		if (r->n_op != ICON)
+			cerror("converting bad type");
+		nfree(p);
+		p = buildtree(op == PMCONV ? MUL : DIV, l, r);
+		break;
+
+	case FORCE:
+		/* Put attached value into the return register. */
+		p->n_op = ASSIGN;
+		p->n_right = p->n_left;
+		p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
+		p->n_left->n_rval = RETREG_PRE(p->n_type);
+		break;
+	}
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal out: %p, %s\n", p, copst(op));
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	return p;
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+
+	if (p->n_op != FCON)
+		return;
+
+	sp = tmpalloc(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->slevel = 1;
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, btattr[p->n_type].atypsz, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
+}
+
+int
+andable(NODE *p)
+{
+	return 1;
+}
+
+void
+cendarg()
+{
+	autooff = AUTOINIT;
+}
+
+int
+cisreg(TWORD t)
+{
+	/* SPARCv9 registers are all 64-bits wide. */
+	return 1;
+}
+
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *ap)
+{
+	return bcon(off / SZCHAR);
+}
+
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+}
+
+void
+instring(struct symtab *sp)
+{
+	char *s, *str;
+
+	defloc(sp);
+	str = sp->sname;
+
+	printf("\t.ascii \"");
+	for (s = str; *s != 0; ) {
+		if (*s++ == '\\')
+			esccon(&s);
+		if (s - str > 60) {
+			fwrite(str, 1, s - str, stdout);
+			printf("\"\n\t.ascii \"");
+			str = s;
+		}
+	}
+	fwrite(str, 1, s - str, stdout);
+	printf("\\0\"\n");
+}
+
+void
+zbits(OFFSZ off, int fsz)
+{
+}
+
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+}
+
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+	TWORD t;
+	struct symtab *sp;
+	union { float f; double d; int i; long long l; } u;
+
+	t = p->n_type;
+	sp = p->n_sp;
+
+	if (ISPTR(t))
+		t = LONGLONG;
+
+	if (p->n_op != ICON && p->n_op != FCON)
+		cerror("ninval: not a constant");
+	if (p->n_op == ICON && sp != NULL && DEUNSIGN(t) != LONGLONG)
+		cerror("ninval: not constant");
+
+	switch (t) {
+		case CHAR:
+		case UCHAR:
+			printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+			break;
+		case SHORT:
+		case USHORT:
+			printf("\t.half %d\n", (int)p->n_lval &0xffff);
+			break;
+		case BOOL:
+			p->n_lval = (p->n_lval != 0); /* FALLTHROUGH */
+		case INT:
+		case UNSIGNED:
+			printf("\t.long " CONFMT "\n", p->n_lval);
+			break;
+		case LONG:
+		case ULONG:
+		case LONGLONG:
+		case ULONGLONG:
+			printf("\t.xword %lld", p->n_lval);
+			if (sp != 0) {
+				if (sp->sclass == STATIC && sp->slevel > 0)
+					printf("+" LABFMT, sp->soffset);
+				else
+					printf("+%s", sp->soname ?
+					    sp->soname : exname(sp->sname));
+			}
+			printf("\n");
+			break;
+		case FLOAT:
+			u.f = (float)p->n_dcon;
+			printf("\t.long %d\n", u.i);
+			break;
+		case DOUBLE:
+			u.d = (double)p->n_dcon;
+			printf("\t.xword %lld\n", u.l);
+			break;
+	}
+}
+
+char *
+exname(char *p)
+{
+	return p ? p : "";
+}
+
+TWORD
+ctype(TWORD type)
+{
+	return type;
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+void
+defzero(struct symtab *sp)
+{
+	int off = (tsize(sp->stype, sp->sdf, sp->sap) + SZCHAR - 1) / SZCHAR;
+	printf("\t.comm ");
+	if (sp->slevel == 0)
+		printf("%s,%d\n", sp->soname ? sp->soname : exname(sp->sname), off);
+	else
+		printf(LABFMT ",%d\n", sp->soffset, off);
+}
+
+int
+mypragma(char *str)
+{
+	return 0;
+}
+
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
+
