16ff6d951SJohn Birrell /*
26ff6d951SJohn Birrell  * CDDL HEADER START
36ff6d951SJohn Birrell  *
46ff6d951SJohn Birrell  * The contents of this file are subject to the terms of the
56ff6d951SJohn Birrell  * Common Development and Distribution License, Version 1.0 only
66ff6d951SJohn Birrell  * (the "License").  You may not use this file except in compliance
76ff6d951SJohn Birrell  * with the License.
86ff6d951SJohn Birrell  *
96ff6d951SJohn Birrell  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
106ff6d951SJohn Birrell  * or http://www.opensolaris.org/os/licensing.
116ff6d951SJohn Birrell  * See the License for the specific language governing permissions
126ff6d951SJohn Birrell  * and limitations under the License.
136ff6d951SJohn Birrell  *
146ff6d951SJohn Birrell  * When distributing Covered Code, include this CDDL HEADER in each
156ff6d951SJohn Birrell  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
166ff6d951SJohn Birrell  * If applicable, add the following below this CDDL HEADER, with the
176ff6d951SJohn Birrell  * fields enclosed by brackets "[]" replaced with your own identifying
186ff6d951SJohn Birrell  * information: Portions Copyright [yyyy] [name of copyright owner]
196ff6d951SJohn Birrell  *
206ff6d951SJohn Birrell  * CDDL HEADER END
216ff6d951SJohn Birrell  */
22ba6cafe2SMark Johnston 
236ff6d951SJohn Birrell /*
246ff6d951SJohn Birrell  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
256ff6d951SJohn Birrell  * Use is subject to license terms.
266ff6d951SJohn Birrell  */
276ff6d951SJohn Birrell 
28ba6cafe2SMark Johnston /*
29ba6cafe2SMark Johnston  * Copyright (c) 2012 by Delphix. All rights reserved.
30ba6cafe2SMark Johnston  */
316ff6d951SJohn Birrell 
326ff6d951SJohn Birrell #include <sys/types.h>
336ff6d951SJohn Birrell #include <sys/sysmacros.h>
346ff6d951SJohn Birrell #include <sys/isa_defs.h>
356ff6d951SJohn Birrell 
366ff6d951SJohn Birrell #include <strings.h>
376ff6d951SJohn Birrell #include <stdlib.h>
386ff6d951SJohn Birrell #include <setjmp.h>
396ff6d951SJohn Birrell #include <assert.h>
406ff6d951SJohn Birrell #include <errno.h>
416ff6d951SJohn Birrell 
426ff6d951SJohn Birrell #include <dt_impl.h>
436ff6d951SJohn Birrell #include <dt_grammar.h>
446ff6d951SJohn Birrell #include <dt_parser.h>
456ff6d951SJohn Birrell #include <dt_provider.h>
466ff6d951SJohn Birrell 
476ff6d951SJohn Birrell static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *);
486ff6d951SJohn Birrell 
496ff6d951SJohn Birrell static dt_irnode_t *
dt_cg_node_alloc(uint_t label,dif_instr_t instr)506ff6d951SJohn Birrell dt_cg_node_alloc(uint_t label, dif_instr_t instr)
516ff6d951SJohn Birrell {
526ff6d951SJohn Birrell 	dt_irnode_t *dip = malloc(sizeof (dt_irnode_t));
536ff6d951SJohn Birrell 
546ff6d951SJohn Birrell 	if (dip == NULL)
556ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
566ff6d951SJohn Birrell 
576ff6d951SJohn Birrell 	dip->di_label = label;
586ff6d951SJohn Birrell 	dip->di_instr = instr;
596ff6d951SJohn Birrell 	dip->di_extern = NULL;
606ff6d951SJohn Birrell 	dip->di_next = NULL;
616ff6d951SJohn Birrell 
626ff6d951SJohn Birrell 	return (dip);
636ff6d951SJohn Birrell }
646ff6d951SJohn Birrell 
656ff6d951SJohn Birrell /*
666ff6d951SJohn Birrell  * Code generator wrapper function for ctf_member_info.  If we are given a
676ff6d951SJohn Birrell  * reference to a forward declaration tag, search the entire type space for
686ff6d951SJohn Birrell  * the actual definition and then call ctf_member_info on the result.
696ff6d951SJohn Birrell  */
706ff6d951SJohn Birrell static ctf_file_t *
dt_cg_membinfo(ctf_file_t * fp,ctf_id_t type,const char * s,ctf_membinfo_t * mp)716ff6d951SJohn Birrell dt_cg_membinfo(ctf_file_t *fp, ctf_id_t type, const char *s, ctf_membinfo_t *mp)
726ff6d951SJohn Birrell {
736ff6d951SJohn Birrell 	while (ctf_type_kind(fp, type) == CTF_K_FORWARD) {
746ff6d951SJohn Birrell 		char n[DT_TYPE_NAMELEN];
756ff6d951SJohn Birrell 		dtrace_typeinfo_t dtt;
766ff6d951SJohn Birrell 
776ff6d951SJohn Birrell 		if (ctf_type_name(fp, type, n, sizeof (n)) == NULL ||
786ff6d951SJohn Birrell 		    dt_type_lookup(n, &dtt) == -1 || (
796ff6d951SJohn Birrell 		    dtt.dtt_ctfp == fp && dtt.dtt_type == type))
806ff6d951SJohn Birrell 			break; /* unable to improve our position */
816ff6d951SJohn Birrell 
826ff6d951SJohn Birrell 		fp = dtt.dtt_ctfp;
836ff6d951SJohn Birrell 		type = ctf_type_resolve(fp, dtt.dtt_type);
846ff6d951SJohn Birrell 	}
856ff6d951SJohn Birrell 
866ff6d951SJohn Birrell 	if (ctf_member_info(fp, type, s, mp) == CTF_ERR)
876ff6d951SJohn Birrell 		return (NULL); /* ctf_errno is set for us */
886ff6d951SJohn Birrell 
896ff6d951SJohn Birrell 	return (fp);
906ff6d951SJohn Birrell }
916ff6d951SJohn Birrell 
926ff6d951SJohn Birrell static void
dt_cg_xsetx(dt_irlist_t * dlp,dt_ident_t * idp,uint_t lbl,int reg,uint64_t x)936ff6d951SJohn Birrell dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x)
946ff6d951SJohn Birrell {
956ff6d951SJohn Birrell 	int flag = idp != NULL ? DT_INT_PRIVATE : DT_INT_SHARED;
966ff6d951SJohn Birrell 	int intoff = dt_inttab_insert(yypcb->pcb_inttab, x, flag);
976ff6d951SJohn Birrell 	dif_instr_t instr = DIF_INSTR_SETX((uint_t)intoff, reg);
986ff6d951SJohn Birrell 
996ff6d951SJohn Birrell 	if (intoff == -1)
1006ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
1016ff6d951SJohn Birrell 
1026ff6d951SJohn Birrell 	if (intoff > DIF_INTOFF_MAX)
1036ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_INT2BIG);
1046ff6d951SJohn Birrell 
1056ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl, instr));
1066ff6d951SJohn Birrell 
1076ff6d951SJohn Birrell 	if (idp != NULL)
1086ff6d951SJohn Birrell 		dlp->dl_last->di_extern = idp;
1096ff6d951SJohn Birrell }
1106ff6d951SJohn Birrell 
1116ff6d951SJohn Birrell static void
dt_cg_setx(dt_irlist_t * dlp,int reg,uint64_t x)1126ff6d951SJohn Birrell dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x)
1136ff6d951SJohn Birrell {
1146ff6d951SJohn Birrell 	dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x);
1156ff6d951SJohn Birrell }
1166ff6d951SJohn Birrell 
1176ff6d951SJohn Birrell /*
1186ff6d951SJohn Birrell  * When loading bit-fields, we want to convert a byte count in the range
1196ff6d951SJohn Birrell  * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc).  The clp2() function
1206ff6d951SJohn Birrell  * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.
1216ff6d951SJohn Birrell  */
1226ff6d951SJohn Birrell static size_t
clp2(size_t x)1236ff6d951SJohn Birrell clp2(size_t x)
1246ff6d951SJohn Birrell {
1256ff6d951SJohn Birrell 	x--;
1266ff6d951SJohn Birrell 
1276ff6d951SJohn Birrell 	x |= (x >> 1);
1286ff6d951SJohn Birrell 	x |= (x >> 2);
1296ff6d951SJohn Birrell 	x |= (x >> 4);
1306ff6d951SJohn Birrell 	x |= (x >> 8);
1316ff6d951SJohn Birrell 	x |= (x >> 16);
1326ff6d951SJohn Birrell 
1336ff6d951SJohn Birrell 	return (x + 1);
1346ff6d951SJohn Birrell }
1356ff6d951SJohn Birrell 
1366ff6d951SJohn Birrell /*
1376ff6d951SJohn Birrell  * Lookup the correct load opcode to use for the specified node and CTF type.
1386ff6d951SJohn Birrell  * We determine the size and convert it to a 3-bit index.  Our lookup table
1396ff6d951SJohn Birrell  * is constructed to use a 5-bit index, consisting of the 3-bit size 0-7, a
1406ff6d951SJohn Birrell  * bit for the sign, and a bit for userland address.  For example, a 4-byte
1416ff6d951SJohn Birrell  * signed load from userland would be at the following table index:
1426ff6d951SJohn Birrell  * user=1 sign=1 size=4 => binary index 11011 = decimal index 27
1436ff6d951SJohn Birrell  */
1446ff6d951SJohn Birrell static uint_t
dt_cg_load(dt_node_t * dnp,ctf_file_t * ctfp,ctf_id_t type)1456ff6d951SJohn Birrell dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)
1466ff6d951SJohn Birrell {
1476ff6d951SJohn Birrell 	static const uint_t ops[] = {
1486ff6d951SJohn Birrell 		DIF_OP_LDUB,	DIF_OP_LDUH,	0,	DIF_OP_LDUW,
1496ff6d951SJohn Birrell 		0,		0,		0,	DIF_OP_LDX,
1506ff6d951SJohn Birrell 		DIF_OP_LDSB,	DIF_OP_LDSH,	0,	DIF_OP_LDSW,
1516ff6d951SJohn Birrell 		0,		0,		0,	DIF_OP_LDX,
1526ff6d951SJohn Birrell 		DIF_OP_ULDUB,	DIF_OP_ULDUH,	0,	DIF_OP_ULDUW,
1536ff6d951SJohn Birrell 		0,		0,		0,	DIF_OP_ULDX,
1546ff6d951SJohn Birrell 		DIF_OP_ULDSB,	DIF_OP_ULDSH,	0,	DIF_OP_ULDSW,
1556ff6d951SJohn Birrell 		0,		0,		0,	DIF_OP_ULDX,
1566ff6d951SJohn Birrell 	};
1576ff6d951SJohn Birrell 
1586ff6d951SJohn Birrell 	ctf_encoding_t e;
1596ff6d951SJohn Birrell 	ssize_t size;
1606ff6d951SJohn Birrell 
1616ff6d951SJohn Birrell 	/*
1626ff6d951SJohn Birrell 	 * If we're loading a bit-field, the size of our load is found by
1636ff6d951SJohn Birrell 	 * rounding cte_bits up to a byte boundary and then finding the
1646ff6d951SJohn Birrell 	 * nearest power of two to this value (see clp2(), above).
1656ff6d951SJohn Birrell 	 */
1666ff6d951SJohn Birrell 	if ((dnp->dn_flags & DT_NF_BITFIELD) &&
1676ff6d951SJohn Birrell 	    ctf_type_encoding(ctfp, type, &e) != CTF_ERR)
1686ff6d951SJohn Birrell 		size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);
1696ff6d951SJohn Birrell 	else
1706ff6d951SJohn Birrell 		size = ctf_type_size(ctfp, type);
1716ff6d951SJohn Birrell 
1726ff6d951SJohn Birrell 	if (size < 1 || size > 8 || (size & (size - 1)) != 0) {
1736ff6d951SJohn Birrell 		xyerror(D_UNKNOWN, "internal error -- cg cannot load "
1746ff6d951SJohn Birrell 		    "size %ld when passed by value\n", (long)size);
1756ff6d951SJohn Birrell 	}
1766ff6d951SJohn Birrell 
1776ff6d951SJohn Birrell 	size--; /* convert size to 3-bit index */
1786ff6d951SJohn Birrell 
1796ff6d951SJohn Birrell 	if (dnp->dn_flags & DT_NF_SIGNED)
1806ff6d951SJohn Birrell 		size |= 0x08;
1816ff6d951SJohn Birrell 	if (dnp->dn_flags & DT_NF_USERLAND)
1826ff6d951SJohn Birrell 		size |= 0x10;
1836ff6d951SJohn Birrell 
1846ff6d951SJohn Birrell 	return (ops[size]);
1856ff6d951SJohn Birrell }
1866ff6d951SJohn Birrell 
1876ff6d951SJohn Birrell static void
dt_cg_ptrsize(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op,int dreg)1886ff6d951SJohn Birrell dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
1896ff6d951SJohn Birrell     uint_t op, int dreg)
1906ff6d951SJohn Birrell {
1916ff6d951SJohn Birrell 	ctf_file_t *ctfp = dnp->dn_ctfp;
1926ff6d951SJohn Birrell 	ctf_arinfo_t r;
1936ff6d951SJohn Birrell 	dif_instr_t instr;
1946ff6d951SJohn Birrell 	ctf_id_t type;
1956ff6d951SJohn Birrell 	uint_t kind;
1966ff6d951SJohn Birrell 	ssize_t size;
1976ff6d951SJohn Birrell 	int sreg;
1986ff6d951SJohn Birrell 
1996ff6d951SJohn Birrell 	type = ctf_type_resolve(ctfp, dnp->dn_type);
2006ff6d951SJohn Birrell 	kind = ctf_type_kind(ctfp, type);
2016ff6d951SJohn Birrell 	assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY);
2026ff6d951SJohn Birrell 
2036ff6d951SJohn Birrell 	if (kind == CTF_K_ARRAY) {
2046ff6d951SJohn Birrell 		if (ctf_array_info(ctfp, type, &r) != 0) {
2056ff6d951SJohn Birrell 			yypcb->pcb_hdl->dt_ctferr = ctf_errno(ctfp);
2066ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
2076ff6d951SJohn Birrell 		}
2086ff6d951SJohn Birrell 		type = r.ctr_contents;
2096ff6d951SJohn Birrell 	} else
2106ff6d951SJohn Birrell 		type = ctf_type_reference(ctfp, type);
2116ff6d951SJohn Birrell 
2126ff6d951SJohn Birrell 	if ((size = ctf_type_size(ctfp, type)) == 1)
2136ff6d951SJohn Birrell 		return; /* multiply or divide by one can be omitted */
2146ff6d951SJohn Birrell 
215ba6cafe2SMark Johnston 	sreg = dt_regset_alloc(drp);
2166ff6d951SJohn Birrell 	dt_cg_setx(dlp, sreg, size);
2176ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(op, dreg, sreg, dreg);
2186ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2196ff6d951SJohn Birrell 	dt_regset_free(drp, sreg);
2206ff6d951SJohn Birrell }
2216ff6d951SJohn Birrell 
2226ff6d951SJohn Birrell /*
2236ff6d951SJohn Birrell  * If the result of a "." or "->" operation is a bit-field, we use this routine
2246ff6d951SJohn Birrell  * to generate an epilogue to the load instruction that extracts the value.  In
2256ff6d951SJohn Birrell  * the diagrams below the "ld??" is the load instruction that is generated to
2266ff6d951SJohn Birrell  * load the containing word that is generating prior to calling this function.
2276ff6d951SJohn Birrell  *
2286ff6d951SJohn Birrell  * Epilogue for unsigned fields:	Epilogue for signed fields:
2296ff6d951SJohn Birrell  *
2306ff6d951SJohn Birrell  * ldu?	[r1], r1			lds? [r1], r1
2316ff6d951SJohn Birrell  * setx	USHIFT, r2			setx 64 - SSHIFT, r2
2326ff6d951SJohn Birrell  * srl	r1, r2, r1			sll  r1, r2, r1
2336ff6d951SJohn Birrell  * setx	(1 << bits) - 1, r2		setx 64 - bits, r2
2346ff6d951SJohn Birrell  * and	r1, r2, r1			sra  r1, r2, r1
2356ff6d951SJohn Birrell  *
2366ff6d951SJohn Birrell  * The *SHIFT constants above changes value depending on the endian-ness of our
2376ff6d951SJohn Birrell  * target architecture.  Refer to the comments below for more details.
2386ff6d951SJohn Birrell  */
2396ff6d951SJohn Birrell static void
dt_cg_field_get(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,ctf_file_t * fp,const ctf_membinfo_t * mp)2406ff6d951SJohn Birrell dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
2416ff6d951SJohn Birrell     ctf_file_t *fp, const ctf_membinfo_t *mp)
2426ff6d951SJohn Birrell {
2436ff6d951SJohn Birrell 	ctf_encoding_t e;
2446ff6d951SJohn Birrell 	dif_instr_t instr;
2456ff6d951SJohn Birrell 	uint64_t shift;
2466ff6d951SJohn Birrell 	int r1, r2;
2476ff6d951SJohn Birrell 
2486ff6d951SJohn Birrell 	if (ctf_type_encoding(fp, mp->ctm_type, &e) != 0 || e.cte_bits > 64) {
2496ff6d951SJohn Birrell 		xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "
2506ff6d951SJohn Birrell 		    "bits %u\n", mp->ctm_offset, mp->ctm_type, e.cte_bits);
2516ff6d951SJohn Birrell 	}
2526ff6d951SJohn Birrell 
2536ff6d951SJohn Birrell 	assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT);
2546ff6d951SJohn Birrell 	r1 = dnp->dn_left->dn_reg;
255ba6cafe2SMark Johnston 	r2 = dt_regset_alloc(drp);
2566ff6d951SJohn Birrell 
2576ff6d951SJohn Birrell 	/*
2586ff6d951SJohn Birrell 	 * On little-endian architectures, ctm_offset counts from the right so
2596ff6d951SJohn Birrell 	 * ctm_offset % NBBY itself is the amount we want to shift right to
2606ff6d951SJohn Birrell 	 * move the value bits to the little end of the register to mask them.
2616ff6d951SJohn Birrell 	 * On big-endian architectures, ctm_offset counts from the left so we
2626ff6d951SJohn Birrell 	 * must subtract (ctm_offset % NBBY + cte_bits) from the size in bits
2636ff6d951SJohn Birrell 	 * we used for the load.  The size of our load in turn is found by
2646ff6d951SJohn Birrell 	 * rounding cte_bits up to a byte boundary and then finding the
2656ff6d951SJohn Birrell 	 * nearest power of two to this value (see clp2(), above).  These
2666ff6d951SJohn Birrell 	 * properties are used to compute shift as USHIFT or SSHIFT, below.
2676ff6d951SJohn Birrell 	 */
2686ff6d951SJohn Birrell 	if (dnp->dn_flags & DT_NF_SIGNED) {
26918737969SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN
2706ff6d951SJohn Birrell 		shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
2716ff6d951SJohn Birrell 		    mp->ctm_offset % NBBY;
2726ff6d951SJohn Birrell #else
2736ff6d951SJohn Birrell 		shift = mp->ctm_offset % NBBY + e.cte_bits;
2746ff6d951SJohn Birrell #endif
2756ff6d951SJohn Birrell 		dt_cg_setx(dlp, r2, 64 - shift);
2766ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_SLL, r1, r2, r1);
2776ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2786ff6d951SJohn Birrell 
2796ff6d951SJohn Birrell 		dt_cg_setx(dlp, r2, 64 - e.cte_bits);
2806ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_SRA, r1, r2, r1);
2816ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2826ff6d951SJohn Birrell 	} else {
28318737969SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN
2846ff6d951SJohn Birrell 		shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
2856ff6d951SJohn Birrell 		    (mp->ctm_offset % NBBY + e.cte_bits);
2866ff6d951SJohn Birrell #else
2876ff6d951SJohn Birrell 		shift = mp->ctm_offset % NBBY;
2886ff6d951SJohn Birrell #endif
2896ff6d951SJohn Birrell 		dt_cg_setx(dlp, r2, shift);
2906ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_SRL, r1, r2, r1);
2916ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2926ff6d951SJohn Birrell 
2936ff6d951SJohn Birrell 		dt_cg_setx(dlp, r2, (1ULL << e.cte_bits) - 1);
2946ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);
2956ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2966ff6d951SJohn Birrell 	}
2976ff6d951SJohn Birrell 
2986ff6d951SJohn Birrell 	dt_regset_free(drp, r2);
2996ff6d951SJohn Birrell }
3006ff6d951SJohn Birrell 
3016ff6d951SJohn Birrell /*
3026ff6d951SJohn Birrell  * If the destination of a store operation is a bit-field, we use this routine
3036ff6d951SJohn Birrell  * to generate a prologue to the store instruction that loads the surrounding
3046ff6d951SJohn Birrell  * bits, clears the destination field, and ORs in the new value of the field.
3056ff6d951SJohn Birrell  * In the diagram below the "st?" is the store instruction that is generated to
3066ff6d951SJohn Birrell  * store the containing word that is generating after calling this function.
3076ff6d951SJohn Birrell  *
3086ff6d951SJohn Birrell  * ld	[dst->dn_reg], r1
3096ff6d951SJohn Birrell  * setx	~(((1 << cte_bits) - 1) << (ctm_offset % NBBY)), r2
3106ff6d951SJohn Birrell  * and	r1, r2, r1
3116ff6d951SJohn Birrell  *
3126ff6d951SJohn Birrell  * setx	(1 << cte_bits) - 1, r2
3136ff6d951SJohn Birrell  * and	src->dn_reg, r2, r2
3146ff6d951SJohn Birrell  * setx ctm_offset % NBBY, r3
3156ff6d951SJohn Birrell  * sll	r2, r3, r2
3166ff6d951SJohn Birrell  *
3176ff6d951SJohn Birrell  * or	r1, r2, r1
3186ff6d951SJohn Birrell  * st?	r1, [dst->dn_reg]
3196ff6d951SJohn Birrell  *
3206ff6d951SJohn Birrell  * This routine allocates a new register to hold the value to be stored and
3216ff6d951SJohn Birrell  * returns it.  The caller is responsible for freeing this register later.
3226ff6d951SJohn Birrell  */
3236ff6d951SJohn Birrell static int
dt_cg_field_set(dt_node_t * src,dt_irlist_t * dlp,dt_regset_t * drp,dt_node_t * dst)3246ff6d951SJohn Birrell dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp,
3256ff6d951SJohn Birrell     dt_regset_t *drp, dt_node_t *dst)
3266ff6d951SJohn Birrell {
3276ff6d951SJohn Birrell 	uint64_t cmask, fmask, shift;
3286ff6d951SJohn Birrell 	dif_instr_t instr;
3296ff6d951SJohn Birrell 	int r1, r2, r3;
3306ff6d951SJohn Birrell 
3316ff6d951SJohn Birrell 	ctf_membinfo_t m;
3326ff6d951SJohn Birrell 	ctf_encoding_t e;
3336ff6d951SJohn Birrell 	ctf_file_t *fp, *ofp;
3346ff6d951SJohn Birrell 	ctf_id_t type;
3356ff6d951SJohn Birrell 
3366ff6d951SJohn Birrell 	assert(dst->dn_op == DT_TOK_PTR || dst->dn_op == DT_TOK_DOT);
3376ff6d951SJohn Birrell 	assert(dst->dn_right->dn_kind == DT_NODE_IDENT);
3386ff6d951SJohn Birrell 
3396ff6d951SJohn Birrell 	fp = dst->dn_left->dn_ctfp;
3406ff6d951SJohn Birrell 	type = ctf_type_resolve(fp, dst->dn_left->dn_type);
3416ff6d951SJohn Birrell 
3426ff6d951SJohn Birrell 	if (dst->dn_op == DT_TOK_PTR) {
3436ff6d951SJohn Birrell 		type = ctf_type_reference(fp, type);
3446ff6d951SJohn Birrell 		type = ctf_type_resolve(fp, type);
3456ff6d951SJohn Birrell 	}
3466ff6d951SJohn Birrell 
3476ff6d951SJohn Birrell 	if ((fp = dt_cg_membinfo(ofp = fp, type,
3486ff6d951SJohn Birrell 	    dst->dn_right->dn_string, &m)) == NULL) {
3496ff6d951SJohn Birrell 		yypcb->pcb_hdl->dt_ctferr = ctf_errno(ofp);
3506ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
3516ff6d951SJohn Birrell 	}
3526ff6d951SJohn Birrell 
3536ff6d951SJohn Birrell 	if (ctf_type_encoding(fp, m.ctm_type, &e) != 0 || e.cte_bits > 64) {
3546ff6d951SJohn Birrell 		xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "
3556ff6d951SJohn Birrell 		    "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits);
3566ff6d951SJohn Birrell 	}
3576ff6d951SJohn Birrell 
358ba6cafe2SMark Johnston 	r1 = dt_regset_alloc(drp);
359ba6cafe2SMark Johnston 	r2 = dt_regset_alloc(drp);
360ba6cafe2SMark Johnston 	r3 = dt_regset_alloc(drp);
3616ff6d951SJohn Birrell 
3626ff6d951SJohn Birrell 	/*
3636ff6d951SJohn Birrell 	 * Compute shifts and masks.  We need to compute "shift" as the amount
3646ff6d951SJohn Birrell 	 * we need to shift left to position our field in the containing word.
3656ff6d951SJohn Birrell 	 * Refer to the comments in dt_cg_field_get(), above, for more info.
3666ff6d951SJohn Birrell 	 * We then compute fmask as the mask that truncates the value in the
3676ff6d951SJohn Birrell 	 * input register to width cte_bits, and cmask as the mask used to
3686ff6d951SJohn Birrell 	 * pass through the containing bits and zero the field bits.
3696ff6d951SJohn Birrell 	 */
37018737969SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN
3716ff6d951SJohn Birrell 	shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
3726ff6d951SJohn Birrell 	    (m.ctm_offset % NBBY + e.cte_bits);
3736ff6d951SJohn Birrell #else
3746ff6d951SJohn Birrell 	shift = m.ctm_offset % NBBY;
3756ff6d951SJohn Birrell #endif
3766ff6d951SJohn Birrell 	fmask = (1ULL << e.cte_bits) - 1;
3776ff6d951SJohn Birrell 	cmask = ~(fmask << shift);
3786ff6d951SJohn Birrell 
3796ff6d951SJohn Birrell 	instr = DIF_INSTR_LOAD(
3806ff6d951SJohn Birrell 	    dt_cg_load(dst, fp, m.ctm_type), dst->dn_reg, r1);
3816ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3826ff6d951SJohn Birrell 
3836ff6d951SJohn Birrell 	dt_cg_setx(dlp, r2, cmask);
3846ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);
3856ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3866ff6d951SJohn Birrell 
3876ff6d951SJohn Birrell 	dt_cg_setx(dlp, r2, fmask);
3886ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_AND, src->dn_reg, r2, r2);
3896ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3906ff6d951SJohn Birrell 
3916ff6d951SJohn Birrell 	dt_cg_setx(dlp, r3, shift);
3926ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_SLL, r2, r3, r2);
3936ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3946ff6d951SJohn Birrell 
3956ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_OR, r1, r2, r1);
3966ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3976ff6d951SJohn Birrell 
3986ff6d951SJohn Birrell 	dt_regset_free(drp, r3);
3996ff6d951SJohn Birrell 	dt_regset_free(drp, r2);
4006ff6d951SJohn Birrell 
4016ff6d951SJohn Birrell 	return (r1);
4026ff6d951SJohn Birrell }
4036ff6d951SJohn Birrell 
4046ff6d951SJohn Birrell static void
dt_cg_store(dt_node_t * src,dt_irlist_t * dlp,dt_regset_t * drp,dt_node_t * dst)4056ff6d951SJohn Birrell dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
4066ff6d951SJohn Birrell {
4076ff6d951SJohn Birrell 	ctf_encoding_t e;
4086ff6d951SJohn Birrell 	dif_instr_t instr;
4096ff6d951SJohn Birrell 	size_t size;
4106ff6d951SJohn Birrell 	int reg;
4116ff6d951SJohn Birrell 
4126ff6d951SJohn Birrell 	/*
4136ff6d951SJohn Birrell 	 * If we're loading a bit-field, the size of our store is found by
4146ff6d951SJohn Birrell 	 * rounding dst's cte_bits up to a byte boundary and then finding the
4156ff6d951SJohn Birrell 	 * nearest power of two to this value (see clp2(), above).
4166ff6d951SJohn Birrell 	 */
4176ff6d951SJohn Birrell 	if ((dst->dn_flags & DT_NF_BITFIELD) &&
4186ff6d951SJohn Birrell 	    ctf_type_encoding(dst->dn_ctfp, dst->dn_type, &e) != CTF_ERR)
4196ff6d951SJohn Birrell 		size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);
4206ff6d951SJohn Birrell 	else
4216ff6d951SJohn Birrell 		size = dt_node_type_size(src);
4226ff6d951SJohn Birrell 
4236ff6d951SJohn Birrell 	if (src->dn_flags & DT_NF_REF) {
424ba6cafe2SMark Johnston 		reg = dt_regset_alloc(drp);
4256ff6d951SJohn Birrell 		dt_cg_setx(dlp, reg, size);
4266ff6d951SJohn Birrell 		instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg);
4276ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4286ff6d951SJohn Birrell 		dt_regset_free(drp, reg);
4296ff6d951SJohn Birrell 	} else {
4306ff6d951SJohn Birrell 		if (dst->dn_flags & DT_NF_BITFIELD)
4316ff6d951SJohn Birrell 			reg = dt_cg_field_set(src, dlp, drp, dst);
4326ff6d951SJohn Birrell 		else
4336ff6d951SJohn Birrell 			reg = src->dn_reg;
4346ff6d951SJohn Birrell 
4356ff6d951SJohn Birrell 		switch (size) {
4366ff6d951SJohn Birrell 		case 1:
4376ff6d951SJohn Birrell 			instr = DIF_INSTR_STORE(DIF_OP_STB, reg, dst->dn_reg);
4386ff6d951SJohn Birrell 			break;
4396ff6d951SJohn Birrell 		case 2:
4406ff6d951SJohn Birrell 			instr = DIF_INSTR_STORE(DIF_OP_STH, reg, dst->dn_reg);
4416ff6d951SJohn Birrell 			break;
4426ff6d951SJohn Birrell 		case 4:
4436ff6d951SJohn Birrell 			instr = DIF_INSTR_STORE(DIF_OP_STW, reg, dst->dn_reg);
4446ff6d951SJohn Birrell 			break;
4456ff6d951SJohn Birrell 		case 8:
4466ff6d951SJohn Birrell 			instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg);
4476ff6d951SJohn Birrell 			break;
4486ff6d951SJohn Birrell 		default:
4496ff6d951SJohn Birrell 			xyerror(D_UNKNOWN, "internal error -- cg cannot store "
4506ff6d951SJohn Birrell 			    "size %lu when passed by value\n", (ulong_t)size);
4516ff6d951SJohn Birrell 		}
4526ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4536ff6d951SJohn Birrell 
4546ff6d951SJohn Birrell 		if (dst->dn_flags & DT_NF_BITFIELD)
4556ff6d951SJohn Birrell 			dt_regset_free(drp, reg);
4566ff6d951SJohn Birrell 	}
4576ff6d951SJohn Birrell }
4586ff6d951SJohn Birrell 
4596ff6d951SJohn Birrell /*
4606ff6d951SJohn Birrell  * Generate code for a typecast or for argument promotion from the type of the
4616ff6d951SJohn Birrell  * actual to the type of the formal.  We need to generate code for casts when
4626ff6d951SJohn Birrell  * a scalar type is being narrowed or changing signed-ness.  We first shift the
4636ff6d951SJohn Birrell  * desired bits high (losing excess bits if narrowing) and then shift them down
4646ff6d951SJohn Birrell  * using logical shift (unsigned result) or arithmetic shift (signed result).
4656ff6d951SJohn Birrell  */
4666ff6d951SJohn Birrell static void
dt_cg_typecast(const dt_node_t * src,const dt_node_t * dst,dt_irlist_t * dlp,dt_regset_t * drp)4676ff6d951SJohn Birrell dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
4686ff6d951SJohn Birrell     dt_irlist_t *dlp, dt_regset_t *drp)
4696ff6d951SJohn Birrell {
4706ff6d951SJohn Birrell 	size_t srcsize = dt_node_type_size(src);
4716ff6d951SJohn Birrell 	size_t dstsize = dt_node_type_size(dst);
4726ff6d951SJohn Birrell 
4736ff6d951SJohn Birrell 	dif_instr_t instr;
474ba6cafe2SMark Johnston 	int rg;
4756ff6d951SJohn Birrell 
476ba6cafe2SMark Johnston 	if (!dt_node_is_scalar(dst))
477ba6cafe2SMark Johnston 		return; /* not a scalar */
478ba6cafe2SMark Johnston 	if (dstsize == srcsize &&
479ba6cafe2SMark Johnston 	    ((src->dn_flags ^ dst->dn_flags) & DT_NF_SIGNED) != 0)
480ba6cafe2SMark Johnston 		return; /* not narrowing or changing signed-ness */
481ba6cafe2SMark Johnston 	if (dstsize > srcsize && (src->dn_flags & DT_NF_SIGNED) == 0)
482ba6cafe2SMark Johnston 		return; /* nothing to do in this case */
4836ff6d951SJohn Birrell 
484ba6cafe2SMark Johnston 	rg = dt_regset_alloc(drp);
4856ff6d951SJohn Birrell 
486ba6cafe2SMark Johnston 	if (dstsize > srcsize) {
487ba6cafe2SMark Johnston 		int n = sizeof (uint64_t) * NBBY - srcsize * NBBY;
488ba6cafe2SMark Johnston 		int s = (dstsize - srcsize) * NBBY;
4896ff6d951SJohn Birrell 
490ba6cafe2SMark Johnston 		dt_cg_setx(dlp, rg, n);
491ba6cafe2SMark Johnston 
492ba6cafe2SMark Johnston 		instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
493ba6cafe2SMark Johnston 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
494ba6cafe2SMark Johnston 
495ba6cafe2SMark Johnston 		if ((dst->dn_flags & DT_NF_SIGNED) || n == s) {
496ba6cafe2SMark Johnston 			instr = DIF_INSTR_FMT(DIF_OP_SRA,
497ba6cafe2SMark Johnston 			    dst->dn_reg, rg, dst->dn_reg);
498ba6cafe2SMark Johnston 			dt_irlist_append(dlp,
499ba6cafe2SMark Johnston 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
500ba6cafe2SMark Johnston 		} else {
501ba6cafe2SMark Johnston 			dt_cg_setx(dlp, rg, s);
502ba6cafe2SMark Johnston 			instr = DIF_INSTR_FMT(DIF_OP_SRA,
503ba6cafe2SMark Johnston 			    dst->dn_reg, rg, dst->dn_reg);
504ba6cafe2SMark Johnston 			dt_irlist_append(dlp,
505ba6cafe2SMark Johnston 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
506ba6cafe2SMark Johnston 			dt_cg_setx(dlp, rg, n - s);
507ba6cafe2SMark Johnston 			instr = DIF_INSTR_FMT(DIF_OP_SRL,
508ba6cafe2SMark Johnston 			    dst->dn_reg, rg, dst->dn_reg);
509ba6cafe2SMark Johnston 			dt_irlist_append(dlp,
510ba6cafe2SMark Johnston 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
511ba6cafe2SMark Johnston 		}
512ba6cafe2SMark Johnston 	} else if (dstsize != sizeof (uint64_t)) {
513ba6cafe2SMark Johnston 		int n = sizeof (uint64_t) * NBBY - dstsize * NBBY;
514ba6cafe2SMark Johnston 
515ba6cafe2SMark Johnston 		dt_cg_setx(dlp, rg, n);
516ba6cafe2SMark Johnston 
517ba6cafe2SMark Johnston 		instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
5186ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
5196ff6d951SJohn Birrell 
5206ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ?
521ba6cafe2SMark Johnston 		    DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, rg, dst->dn_reg);
52203836978SPedro F. Giffuni 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
52303836978SPedro F. Giffuni 	}
524ba6cafe2SMark Johnston 
525ba6cafe2SMark Johnston 	dt_regset_free(drp, rg);
5266ff6d951SJohn Birrell }
5276ff6d951SJohn Birrell 
5286ff6d951SJohn Birrell /*
5296ff6d951SJohn Birrell  * Generate code to push the specified argument list on to the tuple stack.
5306ff6d951SJohn Birrell  * We use this routine for handling subroutine calls and associative arrays.
5316ff6d951SJohn Birrell  * We must first generate code for all subexpressions before loading the stack
5326ff6d951SJohn Birrell  * because any subexpression could itself require the use of the tuple stack.
5336ff6d951SJohn Birrell  * This holds a number of registers equal to the number of arguments, but this
5346ff6d951SJohn Birrell  * is not a huge problem because the number of arguments can't exceed the
5356ff6d951SJohn Birrell  * number of tuple register stack elements anyway.  At most one extra register
5366ff6d951SJohn Birrell  * is required (either by dt_cg_typecast() or for dtdt_size, below).  This
5376ff6d951SJohn Birrell  * implies that a DIF implementation should offer a number of general purpose
5386ff6d951SJohn Birrell  * registers at least one greater than the number of tuple registers.
5396ff6d951SJohn Birrell  */
5406ff6d951SJohn Birrell static void
dt_cg_arglist(dt_ident_t * idp,dt_node_t * args,dt_irlist_t * dlp,dt_regset_t * drp)5416ff6d951SJohn Birrell dt_cg_arglist(dt_ident_t *idp, dt_node_t *args,
5426ff6d951SJohn Birrell     dt_irlist_t *dlp, dt_regset_t *drp)
5436ff6d951SJohn Birrell {
5446ff6d951SJohn Birrell 	const dt_idsig_t *isp = idp->di_data;
5456ff6d951SJohn Birrell 	dt_node_t *dnp;
5466ff6d951SJohn Birrell 	int i = 0;
5476ff6d951SJohn Birrell 
5486ff6d951SJohn Birrell 	for (dnp = args; dnp != NULL; dnp = dnp->dn_list)
5496ff6d951SJohn Birrell 		dt_cg_node(dnp, dlp, drp);
5506ff6d951SJohn Birrell 
551ba6cafe2SMark Johnston 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
5526ff6d951SJohn Birrell 
5536ff6d951SJohn Birrell 	for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) {
5546ff6d951SJohn Birrell 		dtrace_diftype_t t;
5556ff6d951SJohn Birrell 		dif_instr_t instr;
5566ff6d951SJohn Birrell 		uint_t op;
5576ff6d951SJohn Birrell 		int reg;
5586ff6d951SJohn Birrell 
5596ff6d951SJohn Birrell 		dt_node_diftype(yypcb->pcb_hdl, dnp, &t);
5606ff6d951SJohn Birrell 
5616ff6d951SJohn Birrell 		isp->dis_args[i].dn_reg = dnp->dn_reg; /* re-use register */
5626ff6d951SJohn Birrell 		dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp);
5636ff6d951SJohn Birrell 		isp->dis_args[i].dn_reg = -1;
5646ff6d951SJohn Birrell 
565ba6cafe2SMark Johnston 		if (t.dtdt_flags & DIF_TF_BYREF) {
5666ff6d951SJohn Birrell 			op = DIF_OP_PUSHTR;
56703836978SPedro F. Giffuni 			if (t.dtdt_size != 0) {
568ba6cafe2SMark Johnston 				reg = dt_regset_alloc(drp);
56903836978SPedro F. Giffuni 				dt_cg_setx(dlp, reg, t.dtdt_size);
570ba6cafe2SMark Johnston 			} else {
571ddd5b8e9SPedro F. Giffuni 				reg = DIF_REG_R0;
572ba6cafe2SMark Johnston 			}
573ba6cafe2SMark Johnston 		} else {
574ba6cafe2SMark Johnston 			op = DIF_OP_PUSHTV;
575ba6cafe2SMark Johnston 			reg = DIF_REG_R0;
576ba6cafe2SMark Johnston 		}
5776ff6d951SJohn Birrell 
5786ff6d951SJohn Birrell 		instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg);
5796ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
5806ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_reg);
5816ff6d951SJohn Birrell 
5826ff6d951SJohn Birrell 		if (reg != DIF_REG_R0)
5836ff6d951SJohn Birrell 			dt_regset_free(drp, reg);
5846ff6d951SJohn Birrell 	}
5856ff6d951SJohn Birrell 
5866ff6d951SJohn Birrell 	if (i > yypcb->pcb_hdl->dt_conf.dtc_diftupregs)
5876ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG);
5886ff6d951SJohn Birrell }
5896ff6d951SJohn Birrell 
5906ff6d951SJohn Birrell static void
dt_cg_arithmetic_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op)5916ff6d951SJohn Birrell dt_cg_arithmetic_op(dt_node_t *dnp, dt_irlist_t *dlp,
5926ff6d951SJohn Birrell     dt_regset_t *drp, uint_t op)
5936ff6d951SJohn Birrell {
5946ff6d951SJohn Birrell 	int is_ptr_op = (dnp->dn_op == DT_TOK_ADD || dnp->dn_op == DT_TOK_SUB ||
5956ff6d951SJohn Birrell 	    dnp->dn_op == DT_TOK_ADD_EQ || dnp->dn_op == DT_TOK_SUB_EQ);
5966ff6d951SJohn Birrell 
5976ff6d951SJohn Birrell 	int lp_is_ptr = dt_node_is_pointer(dnp->dn_left);
5986ff6d951SJohn Birrell 	int rp_is_ptr = dt_node_is_pointer(dnp->dn_right);
5996ff6d951SJohn Birrell 
6006ff6d951SJohn Birrell 	dif_instr_t instr;
6016ff6d951SJohn Birrell 
6026ff6d951SJohn Birrell 	if (lp_is_ptr && rp_is_ptr) {
6036ff6d951SJohn Birrell 		assert(dnp->dn_op == DT_TOK_SUB);
6046ff6d951SJohn Birrell 		is_ptr_op = 0;
6056ff6d951SJohn Birrell 	}
6066ff6d951SJohn Birrell 
6076ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
6086ff6d951SJohn Birrell 	if (is_ptr_op && rp_is_ptr)
6096ff6d951SJohn Birrell 		dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_left->dn_reg);
6106ff6d951SJohn Birrell 
6116ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
6126ff6d951SJohn Birrell 	if (is_ptr_op && lp_is_ptr)
6136ff6d951SJohn Birrell 		dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_right->dn_reg);
6146ff6d951SJohn Birrell 
6156ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(op, dnp->dn_left->dn_reg,
6166ff6d951SJohn Birrell 	    dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);
6176ff6d951SJohn Birrell 
6186ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
6196ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_right->dn_reg);
6206ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_left->dn_reg;
6216ff6d951SJohn Birrell 
6226ff6d951SJohn Birrell 	if (lp_is_ptr && rp_is_ptr)
6236ff6d951SJohn Birrell 		dt_cg_ptrsize(dnp->dn_right,
6246ff6d951SJohn Birrell 		    dlp, drp, DIF_OP_UDIV, dnp->dn_reg);
6256ff6d951SJohn Birrell }
6266ff6d951SJohn Birrell 
6276ff6d951SJohn Birrell static uint_t
dt_cg_stvar(const dt_ident_t * idp)6286ff6d951SJohn Birrell dt_cg_stvar(const dt_ident_t *idp)
6296ff6d951SJohn Birrell {
6306ff6d951SJohn Birrell 	static const uint_t aops[] = { DIF_OP_STGAA, DIF_OP_STTAA, DIF_OP_NOP };
6316ff6d951SJohn Birrell 	static const uint_t sops[] = { DIF_OP_STGS, DIF_OP_STTS, DIF_OP_STLS };
6326ff6d951SJohn Birrell 
6336ff6d951SJohn Birrell 	uint_t i = (((idp->di_flags & DT_IDFLG_LOCAL) != 0) << 1) |
6346ff6d951SJohn Birrell 	    ((idp->di_flags & DT_IDFLG_TLS) != 0);
6356ff6d951SJohn Birrell 
6366ff6d951SJohn Birrell 	return (idp->di_kind == DT_IDENT_ARRAY ? aops[i] : sops[i]);
6376ff6d951SJohn Birrell }
6386ff6d951SJohn Birrell 
6396ff6d951SJohn Birrell static void
dt_cg_prearith_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op)6406ff6d951SJohn Birrell dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
6416ff6d951SJohn Birrell {
6426ff6d951SJohn Birrell 	ctf_file_t *ctfp = dnp->dn_ctfp;
6436ff6d951SJohn Birrell 	dif_instr_t instr;
6446ff6d951SJohn Birrell 	ctf_id_t type;
6456ff6d951SJohn Birrell 	ssize_t size = 1;
6466ff6d951SJohn Birrell 	int reg;
6476ff6d951SJohn Birrell 
6486ff6d951SJohn Birrell 	if (dt_node_is_pointer(dnp)) {
6496ff6d951SJohn Birrell 		type = ctf_type_resolve(ctfp, dnp->dn_type);
6506ff6d951SJohn Birrell 		assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);
6516ff6d951SJohn Birrell 		size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));
6526ff6d951SJohn Birrell 	}
6536ff6d951SJohn Birrell 
6546ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_child, dlp, drp);
6556ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_child->dn_reg;
6566ff6d951SJohn Birrell 
657ba6cafe2SMark Johnston 	reg = dt_regset_alloc(drp);
6586ff6d951SJohn Birrell 	dt_cg_setx(dlp, reg, size);
6596ff6d951SJohn Birrell 
6606ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg);
6616ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
6626ff6d951SJohn Birrell 	dt_regset_free(drp, reg);
6636ff6d951SJohn Birrell 
6646ff6d951SJohn Birrell 	/*
6656ff6d951SJohn Birrell 	 * If we are modifying a variable, generate an stv instruction from
6666ff6d951SJohn Birrell 	 * the variable specified by the identifier.  If we are storing to a
6676ff6d951SJohn Birrell 	 * memory address, generate code again for the left-hand side using
6686ff6d951SJohn Birrell 	 * DT_NF_REF to get the address, and then generate a store to it.
6696ff6d951SJohn Birrell 	 * In both paths, we store the value in dnp->dn_reg (the new value).
6706ff6d951SJohn Birrell 	 */
6716ff6d951SJohn Birrell 	if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
6726ff6d951SJohn Birrell 		dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
6736ff6d951SJohn Birrell 
6746ff6d951SJohn Birrell 		idp->di_flags |= DT_IDFLG_DIFW;
6756ff6d951SJohn Birrell 		instr = DIF_INSTR_STV(dt_cg_stvar(idp),
6766ff6d951SJohn Birrell 		    idp->di_id, dnp->dn_reg);
6776ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
6786ff6d951SJohn Birrell 	} else {
6796ff6d951SJohn Birrell 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
6806ff6d951SJohn Birrell 
6816ff6d951SJohn Birrell 		assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
6826ff6d951SJohn Birrell 		assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
6836ff6d951SJohn Birrell 
6846ff6d951SJohn Birrell 		dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
6856ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
6866ff6d951SJohn Birrell 
6876ff6d951SJohn Birrell 		dt_cg_store(dnp, dlp, drp, dnp->dn_child);
6886ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_child->dn_reg);
6896ff6d951SJohn Birrell 
6906ff6d951SJohn Birrell 		dnp->dn_left->dn_flags &= ~DT_NF_REF;
6916ff6d951SJohn Birrell 		dnp->dn_left->dn_flags |= rbit;
6926ff6d951SJohn Birrell 	}
6936ff6d951SJohn Birrell }
6946ff6d951SJohn Birrell 
6956ff6d951SJohn Birrell static void
dt_cg_postarith_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op)6966ff6d951SJohn Birrell dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,
6976ff6d951SJohn Birrell     dt_regset_t *drp, uint_t op)
6986ff6d951SJohn Birrell {
6996ff6d951SJohn Birrell 	ctf_file_t *ctfp = dnp->dn_ctfp;
7006ff6d951SJohn Birrell 	dif_instr_t instr;
7016ff6d951SJohn Birrell 	ctf_id_t type;
7026ff6d951SJohn Birrell 	ssize_t size = 1;
7036ff6d951SJohn Birrell 	int nreg;
7046ff6d951SJohn Birrell 
7056ff6d951SJohn Birrell 	if (dt_node_is_pointer(dnp)) {
7066ff6d951SJohn Birrell 		type = ctf_type_resolve(ctfp, dnp->dn_type);
7076ff6d951SJohn Birrell 		assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);
7086ff6d951SJohn Birrell 		size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));
7096ff6d951SJohn Birrell 	}
7106ff6d951SJohn Birrell 
7116ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_child, dlp, drp);
7126ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_child->dn_reg;
7136ff6d951SJohn Birrell 
714ba6cafe2SMark Johnston 	nreg = dt_regset_alloc(drp);
7156ff6d951SJohn Birrell 	dt_cg_setx(dlp, nreg, size);
7166ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg);
7176ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7186ff6d951SJohn Birrell 
7196ff6d951SJohn Birrell 	/*
7206ff6d951SJohn Birrell 	 * If we are modifying a variable, generate an stv instruction from
7216ff6d951SJohn Birrell 	 * the variable specified by the identifier.  If we are storing to a
7226ff6d951SJohn Birrell 	 * memory address, generate code again for the left-hand side using
7236ff6d951SJohn Birrell 	 * DT_NF_REF to get the address, and then generate a store to it.
7246ff6d951SJohn Birrell 	 * In both paths, we store the value from 'nreg' (the new value).
7256ff6d951SJohn Birrell 	 */
7266ff6d951SJohn Birrell 	if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
7276ff6d951SJohn Birrell 		dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
7286ff6d951SJohn Birrell 
7296ff6d951SJohn Birrell 		idp->di_flags |= DT_IDFLG_DIFW;
7306ff6d951SJohn Birrell 		instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, nreg);
7316ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7326ff6d951SJohn Birrell 	} else {
7336ff6d951SJohn Birrell 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
7346ff6d951SJohn Birrell 		int oreg = dnp->dn_reg;
7356ff6d951SJohn Birrell 
7366ff6d951SJohn Birrell 		assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
7376ff6d951SJohn Birrell 		assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
7386ff6d951SJohn Birrell 
7396ff6d951SJohn Birrell 		dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
7406ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
7416ff6d951SJohn Birrell 
7426ff6d951SJohn Birrell 		dnp->dn_reg = nreg;
7436ff6d951SJohn Birrell 		dt_cg_store(dnp, dlp, drp, dnp->dn_child);
7446ff6d951SJohn Birrell 		dnp->dn_reg = oreg;
7456ff6d951SJohn Birrell 
7466ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_child->dn_reg);
7476ff6d951SJohn Birrell 		dnp->dn_left->dn_flags &= ~DT_NF_REF;
7486ff6d951SJohn Birrell 		dnp->dn_left->dn_flags |= rbit;
7496ff6d951SJohn Birrell 	}
7506ff6d951SJohn Birrell 
7516ff6d951SJohn Birrell 	dt_regset_free(drp, nreg);
7526ff6d951SJohn Birrell }
7536ff6d951SJohn Birrell 
7546ff6d951SJohn Birrell /*
7556ff6d951SJohn Birrell  * Determine if we should perform signed or unsigned comparison for an OP2.
7566ff6d951SJohn Birrell  * If both operands are of arithmetic type, perform the usual arithmetic
7576ff6d951SJohn Birrell  * conversions to determine the common real type for comparison [ISOC 6.5.8.3].
7586ff6d951SJohn Birrell  */
7596ff6d951SJohn Birrell static int
dt_cg_compare_signed(dt_node_t * dnp)7606ff6d951SJohn Birrell dt_cg_compare_signed(dt_node_t *dnp)
7616ff6d951SJohn Birrell {
7626ff6d951SJohn Birrell 	dt_node_t dn;
7636ff6d951SJohn Birrell 
7646ff6d951SJohn Birrell 	if (dt_node_is_string(dnp->dn_left) ||
7656ff6d951SJohn Birrell 	    dt_node_is_string(dnp->dn_right))
7666ff6d951SJohn Birrell 		return (1); /* strings always compare signed */
7676ff6d951SJohn Birrell 	else if (!dt_node_is_arith(dnp->dn_left) ||
7686ff6d951SJohn Birrell 	    !dt_node_is_arith(dnp->dn_right))
7696ff6d951SJohn Birrell 		return (0); /* non-arithmetic types always compare unsigned */
7706ff6d951SJohn Birrell 
7716ff6d951SJohn Birrell 	bzero(&dn, sizeof (dn));
7726ff6d951SJohn Birrell 	dt_node_promote(dnp->dn_left, dnp->dn_right, &dn);
7736ff6d951SJohn Birrell 	return (dn.dn_flags & DT_NF_SIGNED);
7746ff6d951SJohn Birrell }
7756ff6d951SJohn Birrell 
7766ff6d951SJohn Birrell static void
dt_cg_compare_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op)7776ff6d951SJohn Birrell dt_cg_compare_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
7786ff6d951SJohn Birrell {
7796ff6d951SJohn Birrell 	uint_t lbl_true = dt_irlist_label(dlp);
7806ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
7816ff6d951SJohn Birrell 
7826ff6d951SJohn Birrell 	dif_instr_t instr;
7836ff6d951SJohn Birrell 	uint_t opc;
7846ff6d951SJohn Birrell 
7856ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
7866ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
7876ff6d951SJohn Birrell 
7886ff6d951SJohn Birrell 	if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right))
7896ff6d951SJohn Birrell 		opc = DIF_OP_SCMP;
7906ff6d951SJohn Birrell 	else
7916ff6d951SJohn Birrell 		opc = DIF_OP_CMP;
7926ff6d951SJohn Birrell 
7936ff6d951SJohn Birrell 	instr = DIF_INSTR_CMP(opc, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg);
7946ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7956ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_right->dn_reg);
7966ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_left->dn_reg;
7976ff6d951SJohn Birrell 
7986ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(op, lbl_true);
7996ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8006ff6d951SJohn Birrell 
8016ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
8026ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8036ff6d951SJohn Birrell 
8046ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
8056ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8066ff6d951SJohn Birrell 
8076ff6d951SJohn Birrell 	dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);
8086ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
8096ff6d951SJohn Birrell }
8106ff6d951SJohn Birrell 
8116ff6d951SJohn Birrell /*
8126ff6d951SJohn Birrell  * Code generation for the ternary op requires some trickery with the assembler
8136ff6d951SJohn Birrell  * in order to conserve registers.  We generate code for dn_expr and dn_left
8146ff6d951SJohn Birrell  * and free their registers so they do not have be consumed across codegen for
8156ff6d951SJohn Birrell  * dn_right.  We insert a dummy MOV at the end of dn_left into the destination
8166ff6d951SJohn Birrell  * register, which is not yet known because we haven't done dn_right yet, and
8176ff6d951SJohn Birrell  * save the pointer to this instruction node.  We then generate code for
8186ff6d951SJohn Birrell  * dn_right and use its register as our output.  Finally, we reach back and
8196ff6d951SJohn Birrell  * patch the instruction for dn_left to move its output into this register.
8206ff6d951SJohn Birrell  */
8216ff6d951SJohn Birrell static void
dt_cg_ternary_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)8226ff6d951SJohn Birrell dt_cg_ternary_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
8236ff6d951SJohn Birrell {
8246ff6d951SJohn Birrell 	uint_t lbl_false = dt_irlist_label(dlp);
8256ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
8266ff6d951SJohn Birrell 
8276ff6d951SJohn Birrell 	dif_instr_t instr;
8286ff6d951SJohn Birrell 	dt_irnode_t *dip;
8296ff6d951SJohn Birrell 
8306ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_expr, dlp, drp);
8316ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_expr->dn_reg);
8326ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8336ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_expr->dn_reg);
8346ff6d951SJohn Birrell 
8356ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
8366ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8376ff6d951SJohn Birrell 
8386ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
8396ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, DIF_REG_R0);
8406ff6d951SJohn Birrell 	dip = dt_cg_node_alloc(DT_LBL_NONE, instr); /* save dip for below */
8416ff6d951SJohn Birrell 	dt_irlist_append(dlp, dip);
8426ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_left->dn_reg);
8436ff6d951SJohn Birrell 
8446ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
8456ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8466ff6d951SJohn Birrell 
8476ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, DIF_INSTR_NOP));
8486ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
8496ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_right->dn_reg;
8506ff6d951SJohn Birrell 
8516ff6d951SJohn Birrell 	/*
8526ff6d951SJohn Birrell 	 * Now that dn_reg is assigned, reach back and patch the correct MOV
8536ff6d951SJohn Birrell 	 * instruction into the tail of dn_left.  We know dn_reg was unused
8546ff6d951SJohn Birrell 	 * at that point because otherwise dn_right couldn't have allocated it.
8556ff6d951SJohn Birrell 	 */
8566ff6d951SJohn Birrell 	dip->di_instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, dnp->dn_reg);
8576ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
8586ff6d951SJohn Birrell }
8596ff6d951SJohn Birrell 
8606ff6d951SJohn Birrell static void
dt_cg_logical_and(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)8616ff6d951SJohn Birrell dt_cg_logical_and(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
8626ff6d951SJohn Birrell {
8636ff6d951SJohn Birrell 	uint_t lbl_false = dt_irlist_label(dlp);
8646ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
8656ff6d951SJohn Birrell 
8666ff6d951SJohn Birrell 	dif_instr_t instr;
8676ff6d951SJohn Birrell 
8686ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
8696ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
8706ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8716ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_left->dn_reg);
8726ff6d951SJohn Birrell 
8736ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
8746ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8756ff6d951SJohn Birrell 
8766ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
8776ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
8786ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8796ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_right->dn_reg;
8806ff6d951SJohn Birrell 
8816ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
8826ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8836ff6d951SJohn Birrell 
8846ff6d951SJohn Birrell 	dt_cg_setx(dlp, dnp->dn_reg, 1);
8856ff6d951SJohn Birrell 
8866ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
8876ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8886ff6d951SJohn Birrell 
8896ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
8906ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));
8916ff6d951SJohn Birrell 
8926ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
8936ff6d951SJohn Birrell }
8946ff6d951SJohn Birrell 
8956ff6d951SJohn Birrell static void
dt_cg_logical_xor(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)8966ff6d951SJohn Birrell dt_cg_logical_xor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
8976ff6d951SJohn Birrell {
8986ff6d951SJohn Birrell 	uint_t lbl_next = dt_irlist_label(dlp);
8996ff6d951SJohn Birrell 	uint_t lbl_tail = dt_irlist_label(dlp);
9006ff6d951SJohn Birrell 
9016ff6d951SJohn Birrell 	dif_instr_t instr;
9026ff6d951SJohn Birrell 
9036ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
9046ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
9056ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9066ff6d951SJohn Birrell 
9076ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_next);
9086ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9096ff6d951SJohn Birrell 	dt_cg_setx(dlp, dnp->dn_left->dn_reg, 1);
9106ff6d951SJohn Birrell 
9116ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_next, DIF_INSTR_NOP));
9126ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
9136ff6d951SJohn Birrell 
9146ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
9156ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9166ff6d951SJohn Birrell 
9176ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_tail);
9186ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9196ff6d951SJohn Birrell 	dt_cg_setx(dlp, dnp->dn_right->dn_reg, 1);
9206ff6d951SJohn Birrell 
9216ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_XOR, dnp->dn_left->dn_reg,
9226ff6d951SJohn Birrell 	    dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);
9236ff6d951SJohn Birrell 
9246ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_tail, instr));
9256ff6d951SJohn Birrell 
9266ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_right->dn_reg);
9276ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_left->dn_reg;
9286ff6d951SJohn Birrell }
9296ff6d951SJohn Birrell 
9306ff6d951SJohn Birrell static void
dt_cg_logical_or(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)9316ff6d951SJohn Birrell dt_cg_logical_or(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9326ff6d951SJohn Birrell {
9336ff6d951SJohn Birrell 	uint_t lbl_true = dt_irlist_label(dlp);
9346ff6d951SJohn Birrell 	uint_t lbl_false = dt_irlist_label(dlp);
9356ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
9366ff6d951SJohn Birrell 
9376ff6d951SJohn Birrell 	dif_instr_t instr;
9386ff6d951SJohn Birrell 
9396ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
9406ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
9416ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9426ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_left->dn_reg);
9436ff6d951SJohn Birrell 
9446ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BNE, lbl_true);
9456ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9466ff6d951SJohn Birrell 
9476ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
9486ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
9496ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9506ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_right->dn_reg;
9516ff6d951SJohn Birrell 
9526ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
9536ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9546ff6d951SJohn Birrell 
9556ff6d951SJohn Birrell 	dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);
9566ff6d951SJohn Birrell 
9576ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
9586ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9596ff6d951SJohn Birrell 
9606ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
9616ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));
9626ff6d951SJohn Birrell 
9636ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
9646ff6d951SJohn Birrell }
9656ff6d951SJohn Birrell 
9666ff6d951SJohn Birrell static void
dt_cg_logical_neg(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)9676ff6d951SJohn Birrell dt_cg_logical_neg(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9686ff6d951SJohn Birrell {
9696ff6d951SJohn Birrell 	uint_t lbl_zero = dt_irlist_label(dlp);
9706ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
9716ff6d951SJohn Birrell 
9726ff6d951SJohn Birrell 	dif_instr_t instr;
9736ff6d951SJohn Birrell 
9746ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_child, dlp, drp);
9756ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_child->dn_reg;
9766ff6d951SJohn Birrell 
9776ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_reg);
9786ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9796ff6d951SJohn Birrell 
9806ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_zero);
9816ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9826ff6d951SJohn Birrell 
9836ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
9846ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9856ff6d951SJohn Birrell 
9866ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
9876ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9886ff6d951SJohn Birrell 
9896ff6d951SJohn Birrell 	dt_cg_xsetx(dlp, NULL, lbl_zero, dnp->dn_reg, 1);
9906ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
9916ff6d951SJohn Birrell }
9926ff6d951SJohn Birrell 
9936ff6d951SJohn Birrell static void
dt_cg_asgn_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)9946ff6d951SJohn Birrell dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9956ff6d951SJohn Birrell {
9966ff6d951SJohn Birrell 	dif_instr_t instr;
9976ff6d951SJohn Birrell 	dt_ident_t *idp;
9986ff6d951SJohn Birrell 
9996ff6d951SJohn Birrell 	/*
10006ff6d951SJohn Birrell 	 * If we are performing a structure assignment of a translated type,
10016ff6d951SJohn Birrell 	 * we must instantiate all members and create a snapshot of the object
10026ff6d951SJohn Birrell 	 * in scratch space.  We allocs a chunk of memory, generate code for
10036ff6d951SJohn Birrell 	 * each member, and then set dnp->dn_reg to the scratch object address.
10046ff6d951SJohn Birrell 	 */
10056ff6d951SJohn Birrell 	if ((idp = dt_node_resolve(dnp->dn_right, DT_IDENT_XLSOU)) != NULL) {
10066ff6d951SJohn Birrell 		ctf_membinfo_t ctm;
10076ff6d951SJohn Birrell 		dt_xlator_t *dxp = idp->di_data;
10086ff6d951SJohn Birrell 		dt_node_t *mnp, dn, mn;
10096ff6d951SJohn Birrell 		int r1, r2;
10106ff6d951SJohn Birrell 
10116ff6d951SJohn Birrell 		/*
10126ff6d951SJohn Birrell 		 * Create two fake dt_node_t's representing operator "." and a
10136ff6d951SJohn Birrell 		 * right-hand identifier child node.  These will be repeatedly
10146ff6d951SJohn Birrell 		 * modified according to each instantiated member so that we
10156ff6d951SJohn Birrell 		 * can pass them to dt_cg_store() and effect a member store.
10166ff6d951SJohn Birrell 		 */
10176ff6d951SJohn Birrell 		bzero(&dn, sizeof (dt_node_t));
10186ff6d951SJohn Birrell 		dn.dn_kind = DT_NODE_OP2;
10196ff6d951SJohn Birrell 		dn.dn_op = DT_TOK_DOT;
10206ff6d951SJohn Birrell 		dn.dn_left = dnp;
10216ff6d951SJohn Birrell 		dn.dn_right = &mn;
10226ff6d951SJohn Birrell 
10236ff6d951SJohn Birrell 		bzero(&mn, sizeof (dt_node_t));
10246ff6d951SJohn Birrell 		mn.dn_kind = DT_NODE_IDENT;
10256ff6d951SJohn Birrell 		mn.dn_op = DT_TOK_IDENT;
10266ff6d951SJohn Birrell 
10276ff6d951SJohn Birrell 		/*
10286ff6d951SJohn Birrell 		 * Allocate a register for our scratch data pointer.  First we
10296ff6d951SJohn Birrell 		 * set it to the size of our data structure, and then replace
10306ff6d951SJohn Birrell 		 * it with the result of an allocs of the specified size.
10316ff6d951SJohn Birrell 		 */
1032ba6cafe2SMark Johnston 		r1 = dt_regset_alloc(drp);
10336ff6d951SJohn Birrell 		dt_cg_setx(dlp, r1,
10346ff6d951SJohn Birrell 		    ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base));
10356ff6d951SJohn Birrell 
10366ff6d951SJohn Birrell 		instr = DIF_INSTR_ALLOCS(r1, r1);
10376ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
10386ff6d951SJohn Birrell 
10396ff6d951SJohn Birrell 		/*
10406ff6d951SJohn Birrell 		 * When dt_cg_asgn_op() is called, we have already generated
10416ff6d951SJohn Birrell 		 * code for dnp->dn_right, which is the translator input.  We
10426ff6d951SJohn Birrell 		 * now associate this register with the translator's input
10436ff6d951SJohn Birrell 		 * identifier so it can be referenced during our member loop.
10446ff6d951SJohn Birrell 		 */
10456ff6d951SJohn Birrell 		dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
10466ff6d951SJohn Birrell 		dxp->dx_ident->di_id = dnp->dn_right->dn_reg;
10476ff6d951SJohn Birrell 
10486ff6d951SJohn Birrell 		for (mnp = dxp->dx_members; mnp != NULL; mnp = mnp->dn_list) {
10496ff6d951SJohn Birrell 			/*
10506ff6d951SJohn Birrell 			 * Generate code for the translator member expression,
10516ff6d951SJohn Birrell 			 * and then cast the result to the member type.
10526ff6d951SJohn Birrell 			 */
10536ff6d951SJohn Birrell 			dt_cg_node(mnp->dn_membexpr, dlp, drp);
10546ff6d951SJohn Birrell 			mnp->dn_reg = mnp->dn_membexpr->dn_reg;
10556ff6d951SJohn Birrell 			dt_cg_typecast(mnp->dn_membexpr, mnp, dlp, drp);
10566ff6d951SJohn Birrell 
10576ff6d951SJohn Birrell 			/*
10586ff6d951SJohn Birrell 			 * Ask CTF for the offset of the member so we can store
10596ff6d951SJohn Birrell 			 * to the appropriate offset.  This call has already
10606ff6d951SJohn Birrell 			 * been done once by the parser, so it should succeed.
10616ff6d951SJohn Birrell 			 */
10626ff6d951SJohn Birrell 			if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_base,
10636ff6d951SJohn Birrell 			    mnp->dn_membname, &ctm) == CTF_ERR) {
10646ff6d951SJohn Birrell 				yypcb->pcb_hdl->dt_ctferr =
10656ff6d951SJohn Birrell 				    ctf_errno(dxp->dx_dst_ctfp);
10666ff6d951SJohn Birrell 				longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
10676ff6d951SJohn Birrell 			}
10686ff6d951SJohn Birrell 
10696ff6d951SJohn Birrell 			/*
10706ff6d951SJohn Birrell 			 * If the destination member is at offset 0, store the
10716ff6d951SJohn Birrell 			 * result directly to r1 (the scratch buffer address).
10726ff6d951SJohn Birrell 			 * Otherwise allocate another temporary for the offset
10736ff6d951SJohn Birrell 			 * and add r1 to it before storing the result.
10746ff6d951SJohn Birrell 			 */
10756ff6d951SJohn Birrell 			if (ctm.ctm_offset != 0) {
1076ba6cafe2SMark Johnston 				r2 = dt_regset_alloc(drp);
10776ff6d951SJohn Birrell 
10786ff6d951SJohn Birrell 				/*
10796ff6d951SJohn Birrell 				 * Add the member offset rounded down to the
10806ff6d951SJohn Birrell 				 * nearest byte.  If the offset was not aligned
10816ff6d951SJohn Birrell 				 * on a byte boundary, this member is a bit-
10826ff6d951SJohn Birrell 				 * field and dt_cg_store() will handle masking.
10836ff6d951SJohn Birrell 				 */
10846ff6d951SJohn Birrell 				dt_cg_setx(dlp, r2, ctm.ctm_offset / NBBY);
10856ff6d951SJohn Birrell 				instr = DIF_INSTR_FMT(DIF_OP_ADD, r1, r2, r2);
10866ff6d951SJohn Birrell 				dt_irlist_append(dlp,
10876ff6d951SJohn Birrell 				    dt_cg_node_alloc(DT_LBL_NONE, instr));
10886ff6d951SJohn Birrell 
10896ff6d951SJohn Birrell 				dt_node_type_propagate(mnp, &dn);
10906ff6d951SJohn Birrell 				dn.dn_right->dn_string = mnp->dn_membname;
10916ff6d951SJohn Birrell 				dn.dn_reg = r2;
10926ff6d951SJohn Birrell 
10936ff6d951SJohn Birrell 				dt_cg_store(mnp, dlp, drp, &dn);
10946ff6d951SJohn Birrell 				dt_regset_free(drp, r2);
10956ff6d951SJohn Birrell 
10966ff6d951SJohn Birrell 			} else {
10976ff6d951SJohn Birrell 				dt_node_type_propagate(mnp, &dn);
10986ff6d951SJohn Birrell 				dn.dn_right->dn_string = mnp->dn_membname;
10996ff6d951SJohn Birrell 				dn.dn_reg = r1;
11006ff6d951SJohn Birrell 
11016ff6d951SJohn Birrell 				dt_cg_store(mnp, dlp, drp, &dn);
11026ff6d951SJohn Birrell 			}
11036ff6d951SJohn Birrell 
11046ff6d951SJohn Birrell 			dt_regset_free(drp, mnp->dn_reg);
11056ff6d951SJohn Birrell 		}
11066ff6d951SJohn Birrell 
11076ff6d951SJohn Birrell 		dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
11086ff6d951SJohn Birrell 		dxp->dx_ident->di_id = 0;
11096ff6d951SJohn Birrell 
11106ff6d951SJohn Birrell 		if (dnp->dn_right->dn_reg != -1)
11116ff6d951SJohn Birrell 			dt_regset_free(drp, dnp->dn_right->dn_reg);
11126ff6d951SJohn Birrell 
11136ff6d951SJohn Birrell 		assert(dnp->dn_reg == dnp->dn_right->dn_reg);
11146ff6d951SJohn Birrell 		dnp->dn_reg = r1;
11156ff6d951SJohn Birrell 	}
11166ff6d951SJohn Birrell 
11176ff6d951SJohn Birrell 	/*
11186ff6d951SJohn Birrell 	 * If we are storing to a variable, generate an stv instruction from
11196ff6d951SJohn Birrell 	 * the variable specified by the identifier.  If we are storing to a
11206ff6d951SJohn Birrell 	 * memory address, generate code again for the left-hand side using
11216ff6d951SJohn Birrell 	 * DT_NF_REF to get the address, and then generate a store to it.
11226ff6d951SJohn Birrell 	 * In both paths, we assume dnp->dn_reg already has the new value.
11236ff6d951SJohn Birrell 	 */
11246ff6d951SJohn Birrell 	if (dnp->dn_left->dn_kind == DT_NODE_VAR) {
11256ff6d951SJohn Birrell 		idp = dt_ident_resolve(dnp->dn_left->dn_ident);
11266ff6d951SJohn Birrell 
11276ff6d951SJohn Birrell 		if (idp->di_kind == DT_IDENT_ARRAY)
11286ff6d951SJohn Birrell 			dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp);
11296ff6d951SJohn Birrell 
11306ff6d951SJohn Birrell 		idp->di_flags |= DT_IDFLG_DIFW;
11316ff6d951SJohn Birrell 		instr = DIF_INSTR_STV(dt_cg_stvar(idp),
11326ff6d951SJohn Birrell 		    idp->di_id, dnp->dn_reg);
11336ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11346ff6d951SJohn Birrell 	} else {
11356ff6d951SJohn Birrell 		uint_t rbit = dnp->dn_left->dn_flags & DT_NF_REF;
11366ff6d951SJohn Birrell 
11376ff6d951SJohn Birrell 		assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE);
11386ff6d951SJohn Birrell 		assert(dnp->dn_left->dn_flags & DT_NF_LVALUE);
11396ff6d951SJohn Birrell 
11406ff6d951SJohn Birrell 		dnp->dn_left->dn_flags |= DT_NF_REF; /* force pass-by-ref */
11416ff6d951SJohn Birrell 
11426ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_left, dlp, drp);
11436ff6d951SJohn Birrell 		dt_cg_store(dnp, dlp, drp, dnp->dn_left);
11446ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_left->dn_reg);
11456ff6d951SJohn Birrell 
11466ff6d951SJohn Birrell 		dnp->dn_left->dn_flags &= ~DT_NF_REF;
11476ff6d951SJohn Birrell 		dnp->dn_left->dn_flags |= rbit;
11486ff6d951SJohn Birrell 	}
11496ff6d951SJohn Birrell }
11506ff6d951SJohn Birrell 
11516ff6d951SJohn Birrell static void
dt_cg_assoc_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)11526ff6d951SJohn Birrell dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
11536ff6d951SJohn Birrell {
11546ff6d951SJohn Birrell 	dif_instr_t instr;
11556ff6d951SJohn Birrell 	uint_t op;
11566ff6d951SJohn Birrell 
11576ff6d951SJohn Birrell 	assert(dnp->dn_kind == DT_NODE_VAR);
11586ff6d951SJohn Birrell 	assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL));
11596ff6d951SJohn Birrell 	assert(dnp->dn_args != NULL);
11606ff6d951SJohn Birrell 
11616ff6d951SJohn Birrell 	dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
11626ff6d951SJohn Birrell 
1163ba6cafe2SMark Johnston 	dnp->dn_reg = dt_regset_alloc(drp);
11646ff6d951SJohn Birrell 
11656ff6d951SJohn Birrell 	if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
11666ff6d951SJohn Birrell 		op = DIF_OP_LDTAA;
11676ff6d951SJohn Birrell 	else
11686ff6d951SJohn Birrell 		op = DIF_OP_LDGAA;
11696ff6d951SJohn Birrell 
11706ff6d951SJohn Birrell 	dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;
11716ff6d951SJohn Birrell 	instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);
11726ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11736ff6d951SJohn Birrell 
11746ff6d951SJohn Birrell 	/*
11756ff6d951SJohn Birrell 	 * If the associative array is a pass-by-reference type, then we are
11766ff6d951SJohn Birrell 	 * loading its value as a pointer to either load or store through it.
11776ff6d951SJohn Birrell 	 * The array element in question may not have been faulted in yet, in
11786ff6d951SJohn Birrell 	 * which case DIF_OP_LD*AA will return zero.  We append an epilogue
11796ff6d951SJohn Birrell 	 * of instructions similar to the following:
11806ff6d951SJohn Birrell 	 *
11816ff6d951SJohn Birrell 	 *	  ld?aa	 id, %r1	! base ld?aa instruction above
11826ff6d951SJohn Birrell 	 *	  tst	 %r1		! start of epilogue
11836ff6d951SJohn Birrell 	 *   +--- bne	 label
11846ff6d951SJohn Birrell 	 *   |    setx	 size, %r1
11856ff6d951SJohn Birrell 	 *   |    allocs %r1, %r1
11866ff6d951SJohn Birrell 	 *   |    st?aa	 id, %r1
11876ff6d951SJohn Birrell 	 *   |    ld?aa	 id, %r1
11886ff6d951SJohn Birrell 	 *   v
11896ff6d951SJohn Birrell 	 * label: < rest of code >
11906ff6d951SJohn Birrell 	 *
11916ff6d951SJohn Birrell 	 * The idea is that we allocs a zero-filled chunk of scratch space and
11926ff6d951SJohn Birrell 	 * do a DIF_OP_ST*AA to fault in and initialize the array element, and
11936ff6d951SJohn Birrell 	 * then reload it to get the faulted-in address of the new variable
11946ff6d951SJohn Birrell 	 * storage.  This isn't cheap, but pass-by-ref associative array values
11956ff6d951SJohn Birrell 	 * are (thus far) uncommon and the allocs cost only occurs once.  If
11966ff6d951SJohn Birrell 	 * this path becomes important to DTrace users, we can improve things
11976ff6d951SJohn Birrell 	 * by adding a new DIF opcode to fault in associative array elements.
11986ff6d951SJohn Birrell 	 */
11996ff6d951SJohn Birrell 	if (dnp->dn_flags & DT_NF_REF) {
12006ff6d951SJohn Birrell 		uint_t stvop = op == DIF_OP_LDTAA ? DIF_OP_STTAA : DIF_OP_STGAA;
12016ff6d951SJohn Birrell 		uint_t label = dt_irlist_label(dlp);
12026ff6d951SJohn Birrell 
12036ff6d951SJohn Birrell 		instr = DIF_INSTR_TST(dnp->dn_reg);
12046ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12056ff6d951SJohn Birrell 
12066ff6d951SJohn Birrell 		instr = DIF_INSTR_BRANCH(DIF_OP_BNE, label);
12076ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12086ff6d951SJohn Birrell 
12096ff6d951SJohn Birrell 		dt_cg_setx(dlp, dnp->dn_reg, dt_node_type_size(dnp));
12106ff6d951SJohn Birrell 		instr = DIF_INSTR_ALLOCS(dnp->dn_reg, dnp->dn_reg);
12116ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12126ff6d951SJohn Birrell 
12136ff6d951SJohn Birrell 		dnp->dn_ident->di_flags |= DT_IDFLG_DIFW;
12146ff6d951SJohn Birrell 		instr = DIF_INSTR_STV(stvop, dnp->dn_ident->di_id, dnp->dn_reg);
12156ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12166ff6d951SJohn Birrell 
12176ff6d951SJohn Birrell 		instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);
12186ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12196ff6d951SJohn Birrell 
12206ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(label, DIF_INSTR_NOP));
12216ff6d951SJohn Birrell 	}
12226ff6d951SJohn Birrell }
12236ff6d951SJohn Birrell 
12246ff6d951SJohn Birrell static void
dt_cg_array_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)12256ff6d951SJohn Birrell dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
12266ff6d951SJohn Birrell {
12276ff6d951SJohn Birrell 	dt_probe_t *prp = yypcb->pcb_probe;
12286ff6d951SJohn Birrell 	uintmax_t saved = dnp->dn_args->dn_value;
12296ff6d951SJohn Birrell 	dt_ident_t *idp = dnp->dn_ident;
12306ff6d951SJohn Birrell 
12316ff6d951SJohn Birrell 	dif_instr_t instr;
12326ff6d951SJohn Birrell 	uint_t op;
12336ff6d951SJohn Birrell 	size_t size;
12346ff6d951SJohn Birrell 	int reg, n;
12356ff6d951SJohn Birrell 
12366ff6d951SJohn Birrell 	assert(dnp->dn_kind == DT_NODE_VAR);
12376ff6d951SJohn Birrell 	assert(!(idp->di_flags & DT_IDFLG_LOCAL));
12386ff6d951SJohn Birrell 
12396ff6d951SJohn Birrell 	assert(dnp->dn_args->dn_kind == DT_NODE_INT);
12406ff6d951SJohn Birrell 	assert(dnp->dn_args->dn_list == NULL);
12416ff6d951SJohn Birrell 
12426ff6d951SJohn Birrell 	/*
12436ff6d951SJohn Birrell 	 * If this is a reference in the args[] array, temporarily modify the
12446ff6d951SJohn Birrell 	 * array index according to the static argument mapping (if any),
12456ff6d951SJohn Birrell 	 * unless the argument reference is provided by a dynamic translator.
12466ff6d951SJohn Birrell 	 * If we're using a dynamic translator for args[], then just set dn_reg
12476ff6d951SJohn Birrell 	 * to an invalid reg and return: DIF_OP_XLARG will fetch the arg later.
12486ff6d951SJohn Birrell 	 */
12496ff6d951SJohn Birrell 	if (idp->di_id == DIF_VAR_ARGS) {
12506ff6d951SJohn Birrell 		if ((idp->di_kind == DT_IDENT_XLPTR ||
12516ff6d951SJohn Birrell 		    idp->di_kind == DT_IDENT_XLSOU) &&
12526ff6d951SJohn Birrell 		    dt_xlator_dynamic(idp->di_data)) {
12536ff6d951SJohn Birrell 			dnp->dn_reg = -1;
12546ff6d951SJohn Birrell 			return;
12556ff6d951SJohn Birrell 		}
12566ff6d951SJohn Birrell 		dnp->dn_args->dn_value = prp->pr_mapping[saved];
12576ff6d951SJohn Birrell 	}
12586ff6d951SJohn Birrell 
12596ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_args, dlp, drp);
12606ff6d951SJohn Birrell 	dnp->dn_args->dn_value = saved;
12616ff6d951SJohn Birrell 
12626ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_args->dn_reg;
12636ff6d951SJohn Birrell 
12646ff6d951SJohn Birrell 	if (idp->di_flags & DT_IDFLG_TLS)
12656ff6d951SJohn Birrell 		op = DIF_OP_LDTA;
12666ff6d951SJohn Birrell 	else
12676ff6d951SJohn Birrell 		op = DIF_OP_LDGA;
12686ff6d951SJohn Birrell 
12696ff6d951SJohn Birrell 	idp->di_flags |= DT_IDFLG_DIFR;
12706ff6d951SJohn Birrell 
12716ff6d951SJohn Birrell 	instr = DIF_INSTR_LDA(op, idp->di_id,
12726ff6d951SJohn Birrell 	    dnp->dn_args->dn_reg, dnp->dn_reg);
12736ff6d951SJohn Birrell 
12746ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12756ff6d951SJohn Birrell 
12766ff6d951SJohn Birrell 	/*
12776ff6d951SJohn Birrell 	 * If this is a reference to the args[] array, we need to take the
12786ff6d951SJohn Birrell 	 * additional step of explicitly eliminating any bits larger than the
12796ff6d951SJohn Birrell 	 * type size: the DIF interpreter in the kernel will always give us
12806ff6d951SJohn Birrell 	 * the raw (64-bit) argument value, and any bits larger than the type
12816ff6d951SJohn Birrell 	 * size may be junk.  As a practical matter, this arises only on 64-bit
12826ff6d951SJohn Birrell 	 * architectures and only when the argument index is larger than the
12836ff6d951SJohn Birrell 	 * number of arguments passed directly to DTrace: if a 8-, 16- or
12846ff6d951SJohn Birrell 	 * 32-bit argument must be retrieved from the stack, it is possible
12856ff6d951SJohn Birrell 	 * (and it some cases, likely) that the upper bits will be garbage.
12866ff6d951SJohn Birrell 	 */
12876ff6d951SJohn Birrell 	if (idp->di_id != DIF_VAR_ARGS || !dt_node_is_scalar(dnp))
12886ff6d951SJohn Birrell 		return;
12896ff6d951SJohn Birrell 
12906ff6d951SJohn Birrell 	if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t))
12916ff6d951SJohn Birrell 		return;
12926ff6d951SJohn Birrell 
1293ba6cafe2SMark Johnston 	reg = dt_regset_alloc(drp);
12946ff6d951SJohn Birrell 	assert(size < sizeof (uint64_t));
12956ff6d951SJohn Birrell 	n = sizeof (uint64_t) * NBBY - size * NBBY;
12966ff6d951SJohn Birrell 
12976ff6d951SJohn Birrell 	dt_cg_setx(dlp, reg, n);
12986ff6d951SJohn Birrell 
12996ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_SLL, dnp->dn_reg, reg, dnp->dn_reg);
13006ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
13016ff6d951SJohn Birrell 
13026ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT((dnp->dn_flags & DT_NF_SIGNED) ?
13036ff6d951SJohn Birrell 	    DIF_OP_SRA : DIF_OP_SRL, dnp->dn_reg, reg, dnp->dn_reg);
13046ff6d951SJohn Birrell 
13056ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
13066ff6d951SJohn Birrell 	dt_regset_free(drp, reg);
13076ff6d951SJohn Birrell }
13086ff6d951SJohn Birrell 
13096ff6d951SJohn Birrell /*
13106ff6d951SJohn Birrell  * Generate code for an inlined variable reference.  Inlines can be used to
13116ff6d951SJohn Birrell  * define either scalar or associative array substitutions.  For scalars, we
13126ff6d951SJohn Birrell  * simply generate code for the parse tree saved in the identifier's din_root,
13136ff6d951SJohn Birrell  * and then cast the resulting expression to the inline's declaration type.
13146ff6d951SJohn Birrell  * For arrays, we take the input parameter subtrees from dnp->dn_args and
13156ff6d951SJohn Birrell  * temporarily store them in the din_root of each din_argv[i] identifier,
13166ff6d951SJohn Birrell  * which are themselves inlines and were set up for us by the parser.  The
13176ff6d951SJohn Birrell  * result is that any reference to the inlined parameter inside the top-level
13186ff6d951SJohn Birrell  * din_root will turn into a recursive call to dt_cg_inline() for a scalar
13196ff6d951SJohn Birrell  * inline whose din_root will refer to the subtree pointed to by the argument.
13206ff6d951SJohn Birrell  */
13216ff6d951SJohn Birrell static void
dt_cg_inline(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)13226ff6d951SJohn Birrell dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
13236ff6d951SJohn Birrell {
13246ff6d951SJohn Birrell 	dt_ident_t *idp = dnp->dn_ident;
13256ff6d951SJohn Birrell 	dt_idnode_t *inp = idp->di_iarg;
13266ff6d951SJohn Birrell 
13276ff6d951SJohn Birrell 	dt_idnode_t *pinp;
13286ff6d951SJohn Birrell 	dt_node_t *pnp;
13296ff6d951SJohn Birrell 	int i;
13306ff6d951SJohn Birrell 
13316ff6d951SJohn Birrell 	assert(idp->di_flags & DT_IDFLG_INLINE);
13326ff6d951SJohn Birrell 	assert(idp->di_ops == &dt_idops_inline);
13336ff6d951SJohn Birrell 
13346ff6d951SJohn Birrell 	if (idp->di_kind == DT_IDENT_ARRAY) {
13356ff6d951SJohn Birrell 		for (i = 0, pnp = dnp->dn_args;
13366ff6d951SJohn Birrell 		    pnp != NULL; pnp = pnp->dn_list, i++) {
13376ff6d951SJohn Birrell 			if (inp->din_argv[i] != NULL) {
13386ff6d951SJohn Birrell 				pinp = inp->din_argv[i]->di_iarg;
13396ff6d951SJohn Birrell 				pinp->din_root = pnp;
13406ff6d951SJohn Birrell 			}
13416ff6d951SJohn Birrell 		}
13426ff6d951SJohn Birrell 	}
13436ff6d951SJohn Birrell 
13446ff6d951SJohn Birrell 	dt_cg_node(inp->din_root, dlp, drp);
13456ff6d951SJohn Birrell 	dnp->dn_reg = inp->din_root->dn_reg;
13466ff6d951SJohn Birrell 	dt_cg_typecast(inp->din_root, dnp, dlp, drp);
13476ff6d951SJohn Birrell 
13486ff6d951SJohn Birrell 	if (idp->di_kind == DT_IDENT_ARRAY) {
13496ff6d951SJohn Birrell 		for (i = 0; i < inp->din_argc; i++) {
13506ff6d951SJohn Birrell 			pinp = inp->din_argv[i]->di_iarg;
13516ff6d951SJohn Birrell 			pinp->din_root = NULL;
13526ff6d951SJohn Birrell 		}
13536ff6d951SJohn Birrell 	}
13546ff6d951SJohn Birrell }
13556ff6d951SJohn Birrell 
1356a98ff317SPedro F. Giffuni typedef struct dt_xlmemb {
1357a98ff317SPedro F. Giffuni 	dt_ident_t *dtxl_idp;		/* translated ident */
1358a98ff317SPedro F. Giffuni 	dt_irlist_t *dtxl_dlp;		/* instruction list */
1359a98ff317SPedro F. Giffuni 	dt_regset_t *dtxl_drp;		/* register set */
1360a98ff317SPedro F. Giffuni 	int dtxl_sreg;			/* location of the translation input */
1361a98ff317SPedro F. Giffuni 	int dtxl_dreg;			/* location of our allocated buffer */
1362a98ff317SPedro F. Giffuni } dt_xlmemb_t;
1363a98ff317SPedro F. Giffuni 
1364a98ff317SPedro F. Giffuni /*ARGSUSED*/
1365a98ff317SPedro F. Giffuni static int
dt_cg_xlate_member(const char * name,ctf_id_t type,ulong_t off,void * arg)1366a98ff317SPedro F. Giffuni dt_cg_xlate_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
1367a98ff317SPedro F. Giffuni {
1368a98ff317SPedro F. Giffuni 	dt_xlmemb_t *dx = arg;
1369a98ff317SPedro F. Giffuni 	dt_ident_t *idp = dx->dtxl_idp;
1370a98ff317SPedro F. Giffuni 	dt_irlist_t *dlp = dx->dtxl_dlp;
1371a98ff317SPedro F. Giffuni 	dt_regset_t *drp = dx->dtxl_drp;
1372a98ff317SPedro F. Giffuni 
1373a98ff317SPedro F. Giffuni 	dt_node_t *mnp;
1374a98ff317SPedro F. Giffuni 	dt_xlator_t *dxp;
1375a98ff317SPedro F. Giffuni 
1376a98ff317SPedro F. Giffuni 	int reg, treg;
1377a98ff317SPedro F. Giffuni 	uint32_t instr;
1378a98ff317SPedro F. Giffuni 	size_t size;
1379a98ff317SPedro F. Giffuni 
1380a98ff317SPedro F. Giffuni 	/* Generate code for the translation. */
1381a98ff317SPedro F. Giffuni 	dxp = idp->di_data;
1382a98ff317SPedro F. Giffuni 	mnp = dt_xlator_member(dxp, name);
1383a98ff317SPedro F. Giffuni 
1384a98ff317SPedro F. Giffuni 	/* If there's no translator for the given member, skip it. */
1385a98ff317SPedro F. Giffuni 	if (mnp == NULL)
1386a98ff317SPedro F. Giffuni 		return (0);
1387a98ff317SPedro F. Giffuni 
1388a98ff317SPedro F. Giffuni 	dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
1389a98ff317SPedro F. Giffuni 	dxp->dx_ident->di_id = dx->dtxl_sreg;
1390a98ff317SPedro F. Giffuni 
1391a98ff317SPedro F. Giffuni 	dt_cg_node(mnp->dn_membexpr, dlp, drp);
1392a98ff317SPedro F. Giffuni 
1393a98ff317SPedro F. Giffuni 	dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
1394a98ff317SPedro F. Giffuni 	dxp->dx_ident->di_id = 0;
1395a98ff317SPedro F. Giffuni 
1396a98ff317SPedro F. Giffuni 	treg = mnp->dn_membexpr->dn_reg;
1397a98ff317SPedro F. Giffuni 
1398a98ff317SPedro F. Giffuni 	/* Compute the offset into our buffer and store the result there. */
1399a98ff317SPedro F. Giffuni 	reg = dt_regset_alloc(drp);
1400a98ff317SPedro F. Giffuni 
1401a98ff317SPedro F. Giffuni 	dt_cg_setx(dlp, reg, off / NBBY);
1402a98ff317SPedro F. Giffuni 	instr = DIF_INSTR_FMT(DIF_OP_ADD, dx->dtxl_dreg, reg, reg);
1403a98ff317SPedro F. Giffuni 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1404a98ff317SPedro F. Giffuni 
1405a98ff317SPedro F. Giffuni 	size = ctf_type_size(mnp->dn_membexpr->dn_ctfp,
1406a98ff317SPedro F. Giffuni 	    mnp->dn_membexpr->dn_type);
1407a98ff317SPedro F. Giffuni 	if (dt_node_is_scalar(mnp->dn_membexpr)) {
1408a98ff317SPedro F. Giffuni 		/*
1409a98ff317SPedro F. Giffuni 		 * Copying scalars is simple.
1410a98ff317SPedro F. Giffuni 		 */
1411a98ff317SPedro F. Giffuni 		switch (size) {
1412a98ff317SPedro F. Giffuni 		case 1:
1413a98ff317SPedro F. Giffuni 			instr = DIF_INSTR_STORE(DIF_OP_STB, treg, reg);
1414a98ff317SPedro F. Giffuni 			break;
1415a98ff317SPedro F. Giffuni 		case 2:
1416a98ff317SPedro F. Giffuni 			instr = DIF_INSTR_STORE(DIF_OP_STH, treg, reg);
1417a98ff317SPedro F. Giffuni 			break;
1418a98ff317SPedro F. Giffuni 		case 4:
1419a98ff317SPedro F. Giffuni 			instr = DIF_INSTR_STORE(DIF_OP_STW, treg, reg);
1420a98ff317SPedro F. Giffuni 			break;
1421a98ff317SPedro F. Giffuni 		case 8:
1422a98ff317SPedro F. Giffuni 			instr = DIF_INSTR_STORE(DIF_OP_STX, treg, reg);
1423a98ff317SPedro F. Giffuni 			break;
1424a98ff317SPedro F. Giffuni 		default:
1425a98ff317SPedro F. Giffuni 			xyerror(D_UNKNOWN, "internal error -- unexpected "
1426a98ff317SPedro F. Giffuni 			    "size: %lu\n", (ulong_t)size);
1427a98ff317SPedro F. Giffuni 		}
1428a98ff317SPedro F. Giffuni 
1429a98ff317SPedro F. Giffuni 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1430a98ff317SPedro F. Giffuni 
1431a98ff317SPedro F. Giffuni 	} else if (dt_node_is_string(mnp->dn_membexpr)) {
1432a98ff317SPedro F. Giffuni 		int szreg;
1433a98ff317SPedro F. Giffuni 
1434a98ff317SPedro F. Giffuni 		/*
1435a98ff317SPedro F. Giffuni 		 * Use the copys instruction for strings.
1436a98ff317SPedro F. Giffuni 		 */
1437a98ff317SPedro F. Giffuni 		szreg = dt_regset_alloc(drp);
1438a98ff317SPedro F. Giffuni 		dt_cg_setx(dlp, szreg, size);
1439a98ff317SPedro F. Giffuni 		instr = DIF_INSTR_COPYS(treg, szreg, reg);
1440a98ff317SPedro F. Giffuni 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1441a98ff317SPedro F. Giffuni 		dt_regset_free(drp, szreg);
1442a98ff317SPedro F. Giffuni 	} else {
1443a98ff317SPedro F. Giffuni 		int szreg;
1444a98ff317SPedro F. Giffuni 
1445a98ff317SPedro F. Giffuni 		/*
1446a98ff317SPedro F. Giffuni 		 * If it's anything else then we'll just bcopy it.
1447a98ff317SPedro F. Giffuni 		 */
1448a98ff317SPedro F. Giffuni 		szreg = dt_regset_alloc(drp);
1449a98ff317SPedro F. Giffuni 		dt_cg_setx(dlp, szreg, size);
1450a98ff317SPedro F. Giffuni 		dt_irlist_append(dlp,
1451a98ff317SPedro F. Giffuni 		    dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
1452a98ff317SPedro F. Giffuni 		instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
1453a98ff317SPedro F. Giffuni 		    DIF_REG_R0, treg);
1454a98ff317SPedro F. Giffuni 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1455a98ff317SPedro F. Giffuni 		instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
1456a98ff317SPedro F. Giffuni 		    DIF_REG_R0, reg);
1457a98ff317SPedro F. Giffuni 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1458a98ff317SPedro F. Giffuni 		instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
1459a98ff317SPedro F. Giffuni 		    DIF_REG_R0, szreg);
1460a98ff317SPedro F. Giffuni 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1461a98ff317SPedro F. Giffuni 		instr = DIF_INSTR_CALL(DIF_SUBR_BCOPY, szreg);
1462a98ff317SPedro F. Giffuni 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1463a98ff317SPedro F. Giffuni 		dt_regset_free(drp, szreg);
1464a98ff317SPedro F. Giffuni 	}
1465a98ff317SPedro F. Giffuni 
1466a98ff317SPedro F. Giffuni 	dt_regset_free(drp, reg);
1467a98ff317SPedro F. Giffuni 	dt_regset_free(drp, treg);
1468a98ff317SPedro F. Giffuni 
1469a98ff317SPedro F. Giffuni 	return (0);
1470a98ff317SPedro F. Giffuni }
1471a98ff317SPedro F. Giffuni 
1472a98ff317SPedro F. Giffuni /*
1473a98ff317SPedro F. Giffuni  * If we're expanding a translated type, we create an appropriately sized
1474a98ff317SPedro F. Giffuni  * buffer with alloca() and then translate each member into it.
1475a98ff317SPedro F. Giffuni  */
1476a98ff317SPedro F. Giffuni static int
dt_cg_xlate_expand(dt_node_t * dnp,dt_ident_t * idp,dt_irlist_t * dlp,dt_regset_t * drp)1477a98ff317SPedro F. Giffuni dt_cg_xlate_expand(dt_node_t *dnp, dt_ident_t *idp, dt_irlist_t *dlp,
1478a98ff317SPedro F. Giffuni     dt_regset_t *drp)
1479a98ff317SPedro F. Giffuni {
1480a98ff317SPedro F. Giffuni 	dt_xlmemb_t dlm;
1481a98ff317SPedro F. Giffuni 	uint32_t instr;
1482a98ff317SPedro F. Giffuni 	int dreg;
1483a98ff317SPedro F. Giffuni 	size_t size;
1484a98ff317SPedro F. Giffuni 
1485a98ff317SPedro F. Giffuni 	dreg = dt_regset_alloc(drp);
1486a98ff317SPedro F. Giffuni 	size = ctf_type_size(dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type);
1487a98ff317SPedro F. Giffuni 
1488a98ff317SPedro F. Giffuni 	/* Call alloca() to create the buffer. */
1489a98ff317SPedro F. Giffuni 	dt_cg_setx(dlp, dreg, size);
1490a98ff317SPedro F. Giffuni 
1491a98ff317SPedro F. Giffuni 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
1492a98ff317SPedro F. Giffuni 
1493a98ff317SPedro F. Giffuni 	instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, DIF_REG_R0, dreg);
1494a98ff317SPedro F. Giffuni 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1495a98ff317SPedro F. Giffuni 
1496a98ff317SPedro F. Giffuni 	instr = DIF_INSTR_CALL(DIF_SUBR_ALLOCA, dreg);
1497a98ff317SPedro F. Giffuni 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1498a98ff317SPedro F. Giffuni 
1499a98ff317SPedro F. Giffuni 	/* Generate the translation for each member. */
1500a98ff317SPedro F. Giffuni 	dlm.dtxl_idp = idp;
1501a98ff317SPedro F. Giffuni 	dlm.dtxl_dlp = dlp;
1502a98ff317SPedro F. Giffuni 	dlm.dtxl_drp = drp;
1503a98ff317SPedro F. Giffuni 	dlm.dtxl_sreg = dnp->dn_reg;
1504a98ff317SPedro F. Giffuni 	dlm.dtxl_dreg = dreg;
1505a98ff317SPedro F. Giffuni 	(void) ctf_member_iter(dnp->dn_ident->di_ctfp,
1506a98ff317SPedro F. Giffuni 	    dnp->dn_ident->di_type, dt_cg_xlate_member,
1507a98ff317SPedro F. Giffuni 	    &dlm);
1508a98ff317SPedro F. Giffuni 
1509a98ff317SPedro F. Giffuni 	return (dreg);
1510a98ff317SPedro F. Giffuni }
1511a98ff317SPedro F. Giffuni 
151218737969SJohn Birrell static void
dt_cg_node(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)15136ff6d951SJohn Birrell dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
15146ff6d951SJohn Birrell {
15156ff6d951SJohn Birrell 	ctf_file_t *ctfp = dnp->dn_ctfp;
15166ff6d951SJohn Birrell 	ctf_file_t *octfp;
15176ff6d951SJohn Birrell 	ctf_membinfo_t m;
15186ff6d951SJohn Birrell 	ctf_id_t type;
15196ff6d951SJohn Birrell 
15206ff6d951SJohn Birrell 	dif_instr_t instr;
15216ff6d951SJohn Birrell 	dt_ident_t *idp;
15226ff6d951SJohn Birrell 	ssize_t stroff;
15236ff6d951SJohn Birrell 	uint_t op;
15246ff6d951SJohn Birrell 
15256ff6d951SJohn Birrell 	switch (dnp->dn_op) {
15266ff6d951SJohn Birrell 	case DT_TOK_COMMA:
15276ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_left, dlp, drp);
15286ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_left->dn_reg);
15296ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_right, dlp, drp);
15306ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_right->dn_reg;
15316ff6d951SJohn Birrell 		break;
15326ff6d951SJohn Birrell 
15336ff6d951SJohn Birrell 	case DT_TOK_ASGN:
15346ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_right, dlp, drp);
15356ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_right->dn_reg;
15366ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15376ff6d951SJohn Birrell 		break;
15386ff6d951SJohn Birrell 
15396ff6d951SJohn Birrell 	case DT_TOK_ADD_EQ:
15406ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);
15416ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15426ff6d951SJohn Birrell 		break;
15436ff6d951SJohn Birrell 
15446ff6d951SJohn Birrell 	case DT_TOK_SUB_EQ:
15456ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);
15466ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15476ff6d951SJohn Birrell 		break;
15486ff6d951SJohn Birrell 
15496ff6d951SJohn Birrell 	case DT_TOK_MUL_EQ:
15506ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);
15516ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15526ff6d951SJohn Birrell 		break;
15536ff6d951SJohn Birrell 
15546ff6d951SJohn Birrell 	case DT_TOK_DIV_EQ:
15556ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
15566ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);
15576ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15586ff6d951SJohn Birrell 		break;
15596ff6d951SJohn Birrell 
15606ff6d951SJohn Birrell 	case DT_TOK_MOD_EQ:
15616ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
15626ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);
15636ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15646ff6d951SJohn Birrell 		break;
15656ff6d951SJohn Birrell 
15666ff6d951SJohn Birrell 	case DT_TOK_AND_EQ:
15676ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);
15686ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15696ff6d951SJohn Birrell 		break;
15706ff6d951SJohn Birrell 
15716ff6d951SJohn Birrell 	case DT_TOK_XOR_EQ:
15726ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);
15736ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15746ff6d951SJohn Birrell 		break;
15756ff6d951SJohn Birrell 
15766ff6d951SJohn Birrell 	case DT_TOK_OR_EQ:
15776ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);
15786ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15796ff6d951SJohn Birrell 		break;
15806ff6d951SJohn Birrell 
15816ff6d951SJohn Birrell 	case DT_TOK_LSH_EQ:
15826ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);
15836ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15846ff6d951SJohn Birrell 		break;
15856ff6d951SJohn Birrell 
15866ff6d951SJohn Birrell 	case DT_TOK_RSH_EQ:
15876ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
15886ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);
15896ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
15906ff6d951SJohn Birrell 		break;
15916ff6d951SJohn Birrell 
15926ff6d951SJohn Birrell 	case DT_TOK_QUESTION:
15936ff6d951SJohn Birrell 		dt_cg_ternary_op(dnp, dlp, drp);
15946ff6d951SJohn Birrell 		break;
15956ff6d951SJohn Birrell 
15966ff6d951SJohn Birrell 	case DT_TOK_LOR:
15976ff6d951SJohn Birrell 		dt_cg_logical_or(dnp, dlp, drp);
15986ff6d951SJohn Birrell 		break;
15996ff6d951SJohn Birrell 
16006ff6d951SJohn Birrell 	case DT_TOK_LXOR:
16016ff6d951SJohn Birrell 		dt_cg_logical_xor(dnp, dlp, drp);
16026ff6d951SJohn Birrell 		break;
16036ff6d951SJohn Birrell 
16046ff6d951SJohn Birrell 	case DT_TOK_LAND:
16056ff6d951SJohn Birrell 		dt_cg_logical_and(dnp, dlp, drp);
16066ff6d951SJohn Birrell 		break;
16076ff6d951SJohn Birrell 
16086ff6d951SJohn Birrell 	case DT_TOK_BOR:
16096ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);
16106ff6d951SJohn Birrell 		break;
16116ff6d951SJohn Birrell 
16126ff6d951SJohn Birrell 	case DT_TOK_XOR:
16136ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);
16146ff6d951SJohn Birrell 		break;
16156ff6d951SJohn Birrell 
16166ff6d951SJohn Birrell 	case DT_TOK_BAND:
16176ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);
16186ff6d951SJohn Birrell 		break;
16196ff6d951SJohn Birrell 
16206ff6d951SJohn Birrell 	case DT_TOK_EQU:
16216ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BE);
16226ff6d951SJohn Birrell 		break;
16236ff6d951SJohn Birrell 
16246ff6d951SJohn Birrell 	case DT_TOK_NEQ:
16256ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BNE);
16266ff6d951SJohn Birrell 		break;
16276ff6d951SJohn Birrell 
16286ff6d951SJohn Birrell 	case DT_TOK_LT:
16296ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp,
16306ff6d951SJohn Birrell 		    dt_cg_compare_signed(dnp) ? DIF_OP_BL : DIF_OP_BLU);
16316ff6d951SJohn Birrell 		break;
16326ff6d951SJohn Birrell 
16336ff6d951SJohn Birrell 	case DT_TOK_LE:
16346ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp,
16356ff6d951SJohn Birrell 		    dt_cg_compare_signed(dnp) ? DIF_OP_BLE : DIF_OP_BLEU);
16366ff6d951SJohn Birrell 		break;
16376ff6d951SJohn Birrell 
16386ff6d951SJohn Birrell 	case DT_TOK_GT:
16396ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp,
16406ff6d951SJohn Birrell 		    dt_cg_compare_signed(dnp) ? DIF_OP_BG : DIF_OP_BGU);
16416ff6d951SJohn Birrell 		break;
16426ff6d951SJohn Birrell 
16436ff6d951SJohn Birrell 	case DT_TOK_GE:
16446ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp,
16456ff6d951SJohn Birrell 		    dt_cg_compare_signed(dnp) ? DIF_OP_BGE : DIF_OP_BGEU);
16466ff6d951SJohn Birrell 		break;
16476ff6d951SJohn Birrell 
16486ff6d951SJohn Birrell 	case DT_TOK_LSH:
16496ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);
16506ff6d951SJohn Birrell 		break;
16516ff6d951SJohn Birrell 
16526ff6d951SJohn Birrell 	case DT_TOK_RSH:
16536ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
16546ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);
16556ff6d951SJohn Birrell 		break;
16566ff6d951SJohn Birrell 
16576ff6d951SJohn Birrell 	case DT_TOK_ADD:
16586ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);
16596ff6d951SJohn Birrell 		break;
16606ff6d951SJohn Birrell 
16616ff6d951SJohn Birrell 	case DT_TOK_SUB:
16626ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);
16636ff6d951SJohn Birrell 		break;
16646ff6d951SJohn Birrell 
16656ff6d951SJohn Birrell 	case DT_TOK_MUL:
16666ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);
16676ff6d951SJohn Birrell 		break;
16686ff6d951SJohn Birrell 
16696ff6d951SJohn Birrell 	case DT_TOK_DIV:
16706ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
16716ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);
16726ff6d951SJohn Birrell 		break;
16736ff6d951SJohn Birrell 
16746ff6d951SJohn Birrell 	case DT_TOK_MOD:
16756ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
16766ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);
16776ff6d951SJohn Birrell 		break;
16786ff6d951SJohn Birrell 
16796ff6d951SJohn Birrell 	case DT_TOK_LNEG:
16806ff6d951SJohn Birrell 		dt_cg_logical_neg(dnp, dlp, drp);
16816ff6d951SJohn Birrell 		break;
16826ff6d951SJohn Birrell 
16836ff6d951SJohn Birrell 	case DT_TOK_BNEG:
16846ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
16856ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
16866ff6d951SJohn Birrell 		instr = DIF_INSTR_NOT(dnp->dn_reg, dnp->dn_reg);
16876ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
16886ff6d951SJohn Birrell 		break;
16896ff6d951SJohn Birrell 
16906ff6d951SJohn Birrell 	case DT_TOK_PREINC:
16916ff6d951SJohn Birrell 		dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_ADD);
16926ff6d951SJohn Birrell 		break;
16936ff6d951SJohn Birrell 
16946ff6d951SJohn Birrell 	case DT_TOK_POSTINC:
16956ff6d951SJohn Birrell 		dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_ADD);
16966ff6d951SJohn Birrell 		break;
16976ff6d951SJohn Birrell 
16986ff6d951SJohn Birrell 	case DT_TOK_PREDEC:
16996ff6d951SJohn Birrell 		dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_SUB);
17006ff6d951SJohn Birrell 		break;
17016ff6d951SJohn Birrell 
17026ff6d951SJohn Birrell 	case DT_TOK_POSTDEC:
17036ff6d951SJohn Birrell 		dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_SUB);
17046ff6d951SJohn Birrell 		break;
17056ff6d951SJohn Birrell 
17066ff6d951SJohn Birrell 	case DT_TOK_IPOS:
17076ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
17086ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
17096ff6d951SJohn Birrell 		break;
17106ff6d951SJohn Birrell 
17116ff6d951SJohn Birrell 	case DT_TOK_INEG:
17126ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
17136ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
17146ff6d951SJohn Birrell 
17156ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_SUB, DIF_REG_R0,
17166ff6d951SJohn Birrell 		    dnp->dn_reg, dnp->dn_reg);
17176ff6d951SJohn Birrell 
17186ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
17196ff6d951SJohn Birrell 		break;
17206ff6d951SJohn Birrell 
17216ff6d951SJohn Birrell 	case DT_TOK_DEREF:
17226ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
17236ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
17246ff6d951SJohn Birrell 
1725a98ff317SPedro F. Giffuni 		if (dt_node_is_dynamic(dnp->dn_child)) {
1726a98ff317SPedro F. Giffuni 			int reg;
1727a98ff317SPedro F. Giffuni 			idp = dt_node_resolve(dnp->dn_child, DT_IDENT_XLPTR);
1728a98ff317SPedro F. Giffuni 			assert(idp != NULL);
1729a98ff317SPedro F. Giffuni 			reg = dt_cg_xlate_expand(dnp, idp, dlp, drp);
1730a98ff317SPedro F. Giffuni 
1731a98ff317SPedro F. Giffuni 			dt_regset_free(drp, dnp->dn_child->dn_reg);
1732a98ff317SPedro F. Giffuni 			dnp->dn_reg = reg;
1733a98ff317SPedro F. Giffuni 
1734a98ff317SPedro F. Giffuni 		} else if (!(dnp->dn_flags & DT_NF_REF)) {
17356ff6d951SJohn Birrell 			uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
17366ff6d951SJohn Birrell 
17376ff6d951SJohn Birrell 			/*
17386ff6d951SJohn Birrell 			 * Save and restore DT_NF_USERLAND across dt_cg_load():
17396ff6d951SJohn Birrell 			 * we need the sign bit from dnp and the user bit from
17406ff6d951SJohn Birrell 			 * dnp->dn_child in order to get the proper opcode.
17416ff6d951SJohn Birrell 			 */
17426ff6d951SJohn Birrell 			dnp->dn_flags |=
17436ff6d951SJohn Birrell 			    (dnp->dn_child->dn_flags & DT_NF_USERLAND);
17446ff6d951SJohn Birrell 
17456ff6d951SJohn Birrell 			instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,
17466ff6d951SJohn Birrell 			    dnp->dn_type), dnp->dn_reg, dnp->dn_reg);
17476ff6d951SJohn Birrell 
17486ff6d951SJohn Birrell 			dnp->dn_flags &= ~DT_NF_USERLAND;
17496ff6d951SJohn Birrell 			dnp->dn_flags |= ubit;
17506ff6d951SJohn Birrell 
17516ff6d951SJohn Birrell 			dt_irlist_append(dlp,
17526ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
17536ff6d951SJohn Birrell 		}
17546ff6d951SJohn Birrell 		break;
17556ff6d951SJohn Birrell 
17566ff6d951SJohn Birrell 	case DT_TOK_ADDROF: {
17576ff6d951SJohn Birrell 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
17586ff6d951SJohn Birrell 
17596ff6d951SJohn Birrell 		dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
17606ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
17616ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
17626ff6d951SJohn Birrell 
17636ff6d951SJohn Birrell 		dnp->dn_child->dn_flags &= ~DT_NF_REF;
17646ff6d951SJohn Birrell 		dnp->dn_child->dn_flags |= rbit;
17656ff6d951SJohn Birrell 		break;
17666ff6d951SJohn Birrell 	}
17676ff6d951SJohn Birrell 
17686ff6d951SJohn Birrell 	case DT_TOK_SIZEOF: {
17696ff6d951SJohn Birrell 		size_t size = dt_node_sizeof(dnp->dn_child);
1770ba6cafe2SMark Johnston 		dnp->dn_reg = dt_regset_alloc(drp);
17716ff6d951SJohn Birrell 		assert(size != 0);
17726ff6d951SJohn Birrell 		dt_cg_setx(dlp, dnp->dn_reg, size);
17736ff6d951SJohn Birrell 		break;
17746ff6d951SJohn Birrell 	}
17756ff6d951SJohn Birrell 
17766ff6d951SJohn Birrell 	case DT_TOK_STRINGOF:
17776ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
17786ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
17796ff6d951SJohn Birrell 		break;
17806ff6d951SJohn Birrell 
17816ff6d951SJohn Birrell 	case DT_TOK_XLATE:
17826ff6d951SJohn Birrell 		/*
17836ff6d951SJohn Birrell 		 * An xlate operator appears in either an XLATOR, indicating a
17846ff6d951SJohn Birrell 		 * reference to a dynamic translator, or an OP2, indicating
17856ff6d951SJohn Birrell 		 * use of the xlate operator in the user's program.  For the
17866ff6d951SJohn Birrell 		 * dynamic case, generate an xlate opcode with a reference to
17876ff6d951SJohn Birrell 		 * the corresponding member, pre-computed for us in dn_members.
17886ff6d951SJohn Birrell 		 */
17896ff6d951SJohn Birrell 		if (dnp->dn_kind == DT_NODE_XLATOR) {
17906ff6d951SJohn Birrell 			dt_xlator_t *dxp = dnp->dn_xlator;
17916ff6d951SJohn Birrell 
17926ff6d951SJohn Birrell 			assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG);
17936ff6d951SJohn Birrell 			assert(dxp->dx_ident->di_id != 0);
17946ff6d951SJohn Birrell 
1795ba6cafe2SMark Johnston 			dnp->dn_reg = dt_regset_alloc(drp);
17966ff6d951SJohn Birrell 
17976ff6d951SJohn Birrell 			if (dxp->dx_arg == -1) {
17986ff6d951SJohn Birrell 				instr = DIF_INSTR_MOV(
17996ff6d951SJohn Birrell 				    dxp->dx_ident->di_id, dnp->dn_reg);
18006ff6d951SJohn Birrell 				dt_irlist_append(dlp,
18016ff6d951SJohn Birrell 				    dt_cg_node_alloc(DT_LBL_NONE, instr));
18026ff6d951SJohn Birrell 				op = DIF_OP_XLATE;
18036ff6d951SJohn Birrell 			} else
18046ff6d951SJohn Birrell 				op = DIF_OP_XLARG;
18056ff6d951SJohn Birrell 
18066ff6d951SJohn Birrell 			instr = DIF_INSTR_XLATE(op, 0, dnp->dn_reg);
18076ff6d951SJohn Birrell 			dt_irlist_append(dlp,
18086ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
18096ff6d951SJohn Birrell 
18106ff6d951SJohn Birrell 			dlp->dl_last->di_extern = dnp->dn_xmember;
18116ff6d951SJohn Birrell 			break;
18126ff6d951SJohn Birrell 		}
18136ff6d951SJohn Birrell 
18146ff6d951SJohn Birrell 		assert(dnp->dn_kind == DT_NODE_OP2);
18156ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_right, dlp, drp);
18166ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_right->dn_reg;
18176ff6d951SJohn Birrell 		break;
18186ff6d951SJohn Birrell 
18196ff6d951SJohn Birrell 	case DT_TOK_LPAR:
18206ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_right, dlp, drp);
18216ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_right->dn_reg;
18226ff6d951SJohn Birrell 		dt_cg_typecast(dnp->dn_right, dnp, dlp, drp);
18236ff6d951SJohn Birrell 		break;
18246ff6d951SJohn Birrell 
18256ff6d951SJohn Birrell 	case DT_TOK_PTR:
18266ff6d951SJohn Birrell 	case DT_TOK_DOT:
18276ff6d951SJohn Birrell 		assert(dnp->dn_right->dn_kind == DT_NODE_IDENT);
18286ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_left, dlp, drp);
18296ff6d951SJohn Birrell 
18306ff6d951SJohn Birrell 		/*
18316ff6d951SJohn Birrell 		 * If the left-hand side of PTR or DOT is a dynamic variable,
18326ff6d951SJohn Birrell 		 * we expect it to be the output of a D translator.   In this
18336ff6d951SJohn Birrell 		 * case, we look up the parse tree corresponding to the member
18346ff6d951SJohn Birrell 		 * that is being accessed and run the code generator over it.
18356ff6d951SJohn Birrell 		 * We then cast the result as if by the assignment operator.
18366ff6d951SJohn Birrell 		 */
18376ff6d951SJohn Birrell 		if ((idp = dt_node_resolve(
18386ff6d951SJohn Birrell 		    dnp->dn_left, DT_IDENT_XLSOU)) != NULL ||
18396ff6d951SJohn Birrell 		    (idp = dt_node_resolve(
18406ff6d951SJohn Birrell 		    dnp->dn_left, DT_IDENT_XLPTR)) != NULL) {
18416ff6d951SJohn Birrell 
18426ff6d951SJohn Birrell 			dt_xlator_t *dxp;
18436ff6d951SJohn Birrell 			dt_node_t *mnp;
18446ff6d951SJohn Birrell 
18456ff6d951SJohn Birrell 			dxp = idp->di_data;
18466ff6d951SJohn Birrell 			mnp = dt_xlator_member(dxp, dnp->dn_right->dn_string);
18476ff6d951SJohn Birrell 			assert(mnp != NULL);
18486ff6d951SJohn Birrell 
18496ff6d951SJohn Birrell 			dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
18506ff6d951SJohn Birrell 			dxp->dx_ident->di_id = dnp->dn_left->dn_reg;
18516ff6d951SJohn Birrell 
18526ff6d951SJohn Birrell 			dt_cg_node(mnp->dn_membexpr, dlp, drp);
18536ff6d951SJohn Birrell 			dnp->dn_reg = mnp->dn_membexpr->dn_reg;
18546ff6d951SJohn Birrell 			dt_cg_typecast(mnp->dn_membexpr, dnp, dlp, drp);
18556ff6d951SJohn Birrell 
18566ff6d951SJohn Birrell 			dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
18576ff6d951SJohn Birrell 			dxp->dx_ident->di_id = 0;
18586ff6d951SJohn Birrell 
18596ff6d951SJohn Birrell 			if (dnp->dn_left->dn_reg != -1)
18606ff6d951SJohn Birrell 				dt_regset_free(drp, dnp->dn_left->dn_reg);
18616ff6d951SJohn Birrell 			break;
18626ff6d951SJohn Birrell 		}
18636ff6d951SJohn Birrell 
18646ff6d951SJohn Birrell 		ctfp = dnp->dn_left->dn_ctfp;
18656ff6d951SJohn Birrell 		type = ctf_type_resolve(ctfp, dnp->dn_left->dn_type);
18666ff6d951SJohn Birrell 
18676ff6d951SJohn Birrell 		if (dnp->dn_op == DT_TOK_PTR) {
18686ff6d951SJohn Birrell 			type = ctf_type_reference(ctfp, type);
18696ff6d951SJohn Birrell 			type = ctf_type_resolve(ctfp, type);
18706ff6d951SJohn Birrell 		}
18716ff6d951SJohn Birrell 
18726ff6d951SJohn Birrell 		if ((ctfp = dt_cg_membinfo(octfp = ctfp, type,
18736ff6d951SJohn Birrell 		    dnp->dn_right->dn_string, &m)) == NULL) {
18746ff6d951SJohn Birrell 			yypcb->pcb_hdl->dt_ctferr = ctf_errno(octfp);
18756ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
18766ff6d951SJohn Birrell 		}
18776ff6d951SJohn Birrell 
18786ff6d951SJohn Birrell 		if (m.ctm_offset != 0) {
1879ba6cafe2SMark Johnston 			int reg;
1880ba6cafe2SMark Johnston 
1881ba6cafe2SMark Johnston 			reg = dt_regset_alloc(drp);
18826ff6d951SJohn Birrell 
18836ff6d951SJohn Birrell 			/*
18846ff6d951SJohn Birrell 			 * If the offset is not aligned on a byte boundary, it
18856ff6d951SJohn Birrell 			 * is a bit-field member and we will extract the value
18866ff6d951SJohn Birrell 			 * bits below after we generate the appropriate load.
18876ff6d951SJohn Birrell 			 */
18886ff6d951SJohn Birrell 			dt_cg_setx(dlp, reg, m.ctm_offset / NBBY);
18896ff6d951SJohn Birrell 
18906ff6d951SJohn Birrell 			instr = DIF_INSTR_FMT(DIF_OP_ADD,
18916ff6d951SJohn Birrell 			    dnp->dn_left->dn_reg, reg, dnp->dn_left->dn_reg);
18926ff6d951SJohn Birrell 
18936ff6d951SJohn Birrell 			dt_irlist_append(dlp,
18946ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
18956ff6d951SJohn Birrell 			dt_regset_free(drp, reg);
18966ff6d951SJohn Birrell 		}
18976ff6d951SJohn Birrell 
18986ff6d951SJohn Birrell 		if (!(dnp->dn_flags & DT_NF_REF)) {
18996ff6d951SJohn Birrell 			uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
19006ff6d951SJohn Birrell 
19016ff6d951SJohn Birrell 			/*
19026ff6d951SJohn Birrell 			 * Save and restore DT_NF_USERLAND across dt_cg_load():
19036ff6d951SJohn Birrell 			 * we need the sign bit from dnp and the user bit from
19046ff6d951SJohn Birrell 			 * dnp->dn_left in order to get the proper opcode.
19056ff6d951SJohn Birrell 			 */
19066ff6d951SJohn Birrell 			dnp->dn_flags |=
19076ff6d951SJohn Birrell 			    (dnp->dn_left->dn_flags & DT_NF_USERLAND);
19086ff6d951SJohn Birrell 
19096ff6d951SJohn Birrell 			instr = DIF_INSTR_LOAD(dt_cg_load(dnp,
19106ff6d951SJohn Birrell 			    ctfp, m.ctm_type), dnp->dn_left->dn_reg,
19116ff6d951SJohn Birrell 			    dnp->dn_left->dn_reg);
19126ff6d951SJohn Birrell 
19136ff6d951SJohn Birrell 			dnp->dn_flags &= ~DT_NF_USERLAND;
19146ff6d951SJohn Birrell 			dnp->dn_flags |= ubit;
19156ff6d951SJohn Birrell 
19166ff6d951SJohn Birrell 			dt_irlist_append(dlp,
19176ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
19186ff6d951SJohn Birrell 
19196ff6d951SJohn Birrell 			if (dnp->dn_flags & DT_NF_BITFIELD)
19206ff6d951SJohn Birrell 				dt_cg_field_get(dnp, dlp, drp, ctfp, &m);
19216ff6d951SJohn Birrell 		}
19226ff6d951SJohn Birrell 
19236ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_left->dn_reg;
19246ff6d951SJohn Birrell 		break;
19256ff6d951SJohn Birrell 
19266ff6d951SJohn Birrell 	case DT_TOK_STRING:
1927ba6cafe2SMark Johnston 		dnp->dn_reg = dt_regset_alloc(drp);
19286ff6d951SJohn Birrell 
19296ff6d951SJohn Birrell 		assert(dnp->dn_kind == DT_NODE_STRING);
19306ff6d951SJohn Birrell 		stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string);
19316ff6d951SJohn Birrell 
19326ff6d951SJohn Birrell 		if (stroff == -1L)
19336ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
19346ff6d951SJohn Birrell 		if (stroff > DIF_STROFF_MAX)
19356ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG);
19366ff6d951SJohn Birrell 
19376ff6d951SJohn Birrell 		instr = DIF_INSTR_SETS((ulong_t)stroff, dnp->dn_reg);
19386ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
19396ff6d951SJohn Birrell 		break;
19406ff6d951SJohn Birrell 
19416ff6d951SJohn Birrell 	case DT_TOK_IDENT:
19426ff6d951SJohn Birrell 		/*
19436ff6d951SJohn Birrell 		 * If the specified identifier is a variable on which we have
19446ff6d951SJohn Birrell 		 * set the code generator register flag, then this variable
19456ff6d951SJohn Birrell 		 * has already had code generated for it and saved in di_id.
19466ff6d951SJohn Birrell 		 * Allocate a new register and copy the existing value to it.
19476ff6d951SJohn Birrell 		 */
19486ff6d951SJohn Birrell 		if (dnp->dn_kind == DT_NODE_VAR &&
19496ff6d951SJohn Birrell 		    (dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) {
1950ba6cafe2SMark Johnston 			dnp->dn_reg = dt_regset_alloc(drp);
19516ff6d951SJohn Birrell 			instr = DIF_INSTR_MOV(dnp->dn_ident->di_id,
19526ff6d951SJohn Birrell 			    dnp->dn_reg);
19536ff6d951SJohn Birrell 			dt_irlist_append(dlp,
19546ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
19556ff6d951SJohn Birrell 			break;
19566ff6d951SJohn Birrell 		}
19576ff6d951SJohn Birrell 
19586ff6d951SJohn Birrell 		/*
19596ff6d951SJohn Birrell 		 * Identifiers can represent function calls, variable refs, or
19606ff6d951SJohn Birrell 		 * symbols.  First we check for inlined variables, and handle
19616ff6d951SJohn Birrell 		 * them by generating code for the inline parse tree.
19626ff6d951SJohn Birrell 		 */
19636ff6d951SJohn Birrell 		if (dnp->dn_kind == DT_NODE_VAR &&
19646ff6d951SJohn Birrell 		    (dnp->dn_ident->di_flags & DT_IDFLG_INLINE)) {
19656ff6d951SJohn Birrell 			dt_cg_inline(dnp, dlp, drp);
19666ff6d951SJohn Birrell 			break;
19676ff6d951SJohn Birrell 		}
19686ff6d951SJohn Birrell 
19696ff6d951SJohn Birrell 		switch (dnp->dn_kind) {
197018737969SJohn Birrell 		case DT_NODE_FUNC: {
19716ff6d951SJohn Birrell 			if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) {
19726ff6d951SJohn Birrell 				dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be "
19736ff6d951SJohn Birrell 				    "called from a D expression (D program "
19746ff6d951SJohn Birrell 				    "context required)\n",
19756ff6d951SJohn Birrell 				    dt_idkind_name(idp->di_kind), idp->di_name);
19766ff6d951SJohn Birrell 			}
19776ff6d951SJohn Birrell 
19786ff6d951SJohn Birrell 			dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
19796ff6d951SJohn Birrell 
1980ba6cafe2SMark Johnston 			dnp->dn_reg = dt_regset_alloc(drp);
1981ba6cafe2SMark Johnston 			instr = DIF_INSTR_CALL(dnp->dn_ident->di_id,
1982ba6cafe2SMark Johnston 			    dnp->dn_reg);
19836ff6d951SJohn Birrell 
19846ff6d951SJohn Birrell 			dt_irlist_append(dlp,
19856ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
19866ff6d951SJohn Birrell 
19876ff6d951SJohn Birrell 			break;
198818737969SJohn Birrell 		}
19896ff6d951SJohn Birrell 
19906ff6d951SJohn Birrell 		case DT_NODE_VAR:
19916ff6d951SJohn Birrell 			if (dnp->dn_ident->di_kind == DT_IDENT_XLSOU ||
19926ff6d951SJohn Birrell 			    dnp->dn_ident->di_kind == DT_IDENT_XLPTR) {
19936ff6d951SJohn Birrell 				/*
19946ff6d951SJohn Birrell 				 * This can only happen if we have translated
19956ff6d951SJohn Birrell 				 * args[].  See dt_idcook_args() for details.
19966ff6d951SJohn Birrell 				 */
19976ff6d951SJohn Birrell 				assert(dnp->dn_ident->di_id == DIF_VAR_ARGS);
19986ff6d951SJohn Birrell 				dt_cg_array_op(dnp, dlp, drp);
19996ff6d951SJohn Birrell 				break;
20006ff6d951SJohn Birrell 			}
20016ff6d951SJohn Birrell 
20026ff6d951SJohn Birrell 			if (dnp->dn_ident->di_kind == DT_IDENT_ARRAY) {
20036ff6d951SJohn Birrell 				if (dnp->dn_ident->di_id > DIF_VAR_ARRAY_MAX)
20046ff6d951SJohn Birrell 					dt_cg_assoc_op(dnp, dlp, drp);
20056ff6d951SJohn Birrell 				else
20066ff6d951SJohn Birrell 					dt_cg_array_op(dnp, dlp, drp);
20076ff6d951SJohn Birrell 				break;
20086ff6d951SJohn Birrell 			}
20096ff6d951SJohn Birrell 
2010ba6cafe2SMark Johnston 			dnp->dn_reg = dt_regset_alloc(drp);
20116ff6d951SJohn Birrell 
20126ff6d951SJohn Birrell 			if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)
20136ff6d951SJohn Birrell 				op = DIF_OP_LDLS;
20146ff6d951SJohn Birrell 			else if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
20156ff6d951SJohn Birrell 				op = DIF_OP_LDTS;
20166ff6d951SJohn Birrell 			else
20176ff6d951SJohn Birrell 				op = DIF_OP_LDGS;
20186ff6d951SJohn Birrell 
20196ff6d951SJohn Birrell 			dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;
20206ff6d951SJohn Birrell 
20216ff6d951SJohn Birrell 			instr = DIF_INSTR_LDV(op,
20226ff6d951SJohn Birrell 			    dnp->dn_ident->di_id, dnp->dn_reg);
20236ff6d951SJohn Birrell 
20246ff6d951SJohn Birrell 			dt_irlist_append(dlp,
20256ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
20266ff6d951SJohn Birrell 			break;
20276ff6d951SJohn Birrell 
20286ff6d951SJohn Birrell 		case DT_NODE_SYM: {
20296ff6d951SJohn Birrell 			dtrace_hdl_t *dtp = yypcb->pcb_hdl;
20306ff6d951SJohn Birrell 			dtrace_syminfo_t *sip = dnp->dn_ident->di_data;
20316ff6d951SJohn Birrell 			GElf_Sym sym;
20326ff6d951SJohn Birrell 
20336ff6d951SJohn Birrell 			if (dtrace_lookup_by_name(dtp,
20346ff6d951SJohn Birrell 			    sip->dts_object, sip->dts_name, &sym, NULL) == -1) {
20356ff6d951SJohn Birrell 				xyerror(D_UNKNOWN, "cg failed for symbol %s`%s:"
20366ff6d951SJohn Birrell 				    " %s\n", sip->dts_object, sip->dts_name,
20376ff6d951SJohn Birrell 				    dtrace_errmsg(dtp, dtrace_errno(dtp)));
20386ff6d951SJohn Birrell 			}
20396ff6d951SJohn Birrell 
2040ba6cafe2SMark Johnston 			dnp->dn_reg = dt_regset_alloc(drp);
20416ff6d951SJohn Birrell 			dt_cg_xsetx(dlp, dnp->dn_ident,
20426ff6d951SJohn Birrell 			    DT_LBL_NONE, dnp->dn_reg, sym.st_value);
20436ff6d951SJohn Birrell 
20446ff6d951SJohn Birrell 			if (!(dnp->dn_flags & DT_NF_REF)) {
20456ff6d951SJohn Birrell 				instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,
20466ff6d951SJohn Birrell 				    dnp->dn_type), dnp->dn_reg, dnp->dn_reg);
20476ff6d951SJohn Birrell 				dt_irlist_append(dlp,
20486ff6d951SJohn Birrell 				    dt_cg_node_alloc(DT_LBL_NONE, instr));
20496ff6d951SJohn Birrell 			}
20506ff6d951SJohn Birrell 			break;
20516ff6d951SJohn Birrell 		}
20526ff6d951SJohn Birrell 
20536ff6d951SJohn Birrell 		default:
20546ff6d951SJohn Birrell 			xyerror(D_UNKNOWN, "internal error -- node type %u is "
20556ff6d951SJohn Birrell 			    "not valid for an identifier\n", dnp->dn_kind);
20566ff6d951SJohn Birrell 		}
20576ff6d951SJohn Birrell 		break;
20586ff6d951SJohn Birrell 
20596ff6d951SJohn Birrell 	case DT_TOK_INT:
2060ba6cafe2SMark Johnston 		dnp->dn_reg = dt_regset_alloc(drp);
20616ff6d951SJohn Birrell 		dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value);
20626ff6d951SJohn Birrell 		break;
20636ff6d951SJohn Birrell 
20646ff6d951SJohn Birrell 	default:
20656ff6d951SJohn Birrell 		xyerror(D_UNKNOWN, "internal error -- token type %u is not a "
20666ff6d951SJohn Birrell 		    "valid D compilation token\n", dnp->dn_op);
20676ff6d951SJohn Birrell 	}
20686ff6d951SJohn Birrell }
20696ff6d951SJohn Birrell 
20706ff6d951SJohn Birrell void
dt_cg(dt_pcb_t * pcb,dt_node_t * dnp)20716ff6d951SJohn Birrell dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
20726ff6d951SJohn Birrell {
20736ff6d951SJohn Birrell 	dif_instr_t instr;
20746ff6d951SJohn Birrell 	dt_xlator_t *dxp;
2075ba6cafe2SMark Johnston 	dt_ident_t *idp;
20766ff6d951SJohn Birrell 
20776ff6d951SJohn Birrell 	if (pcb->pcb_regs == NULL && (pcb->pcb_regs =
20786ff6d951SJohn Birrell 	    dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL)
20796ff6d951SJohn Birrell 		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
20806ff6d951SJohn Birrell 
20816ff6d951SJohn Birrell 	dt_regset_reset(pcb->pcb_regs);
20826ff6d951SJohn Birrell 	(void) dt_regset_alloc(pcb->pcb_regs); /* allocate %r0 */
20836ff6d951SJohn Birrell 
20846ff6d951SJohn Birrell 	if (pcb->pcb_inttab != NULL)
20856ff6d951SJohn Birrell 		dt_inttab_destroy(pcb->pcb_inttab);
20866ff6d951SJohn Birrell 
20876ff6d951SJohn Birrell 	if ((pcb->pcb_inttab = dt_inttab_create(yypcb->pcb_hdl)) == NULL)
20886ff6d951SJohn Birrell 		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
20896ff6d951SJohn Birrell 
20906ff6d951SJohn Birrell 	if (pcb->pcb_strtab != NULL)
20916ff6d951SJohn Birrell 		dt_strtab_destroy(pcb->pcb_strtab);
20926ff6d951SJohn Birrell 
20936ff6d951SJohn Birrell 	if ((pcb->pcb_strtab = dt_strtab_create(BUFSIZ)) == NULL)
20946ff6d951SJohn Birrell 		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
20956ff6d951SJohn Birrell 
20966ff6d951SJohn Birrell 	dt_irlist_destroy(&pcb->pcb_ir);
20976ff6d951SJohn Birrell 	dt_irlist_create(&pcb->pcb_ir);
20986ff6d951SJohn Birrell 
20996ff6d951SJohn Birrell 	assert(pcb->pcb_dret == NULL);
21006ff6d951SJohn Birrell 	pcb->pcb_dret = dnp;
21016ff6d951SJohn Birrell 
2102ba6cafe2SMark Johnston 	if (dt_node_resolve(dnp, DT_IDENT_XLPTR) != NULL) {
21036ff6d951SJohn Birrell 		dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result "
2104ba6cafe2SMark Johnston 		    "of a translated pointer\n");
21056ff6d951SJohn Birrell 	}
21066ff6d951SJohn Birrell 
21076ff6d951SJohn Birrell 	/*
21086ff6d951SJohn Birrell 	 * If we're generating code for a translator body, assign the input
21096ff6d951SJohn Birrell 	 * parameter to the first available register (i.e. caller passes %r1).
21106ff6d951SJohn Birrell 	 */
21116ff6d951SJohn Birrell 	if (dnp->dn_kind == DT_NODE_MEMBER) {
21126ff6d951SJohn Birrell 		dxp = dnp->dn_membxlator;
21136ff6d951SJohn Birrell 		dnp = dnp->dn_membexpr;
21146ff6d951SJohn Birrell 
21156ff6d951SJohn Birrell 		dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
21166ff6d951SJohn Birrell 		dxp->dx_ident->di_id = dt_regset_alloc(pcb->pcb_regs);
21176ff6d951SJohn Birrell 	}
21186ff6d951SJohn Birrell 
21196ff6d951SJohn Birrell 	dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs);
2120ba6cafe2SMark Johnston 
2121a98ff317SPedro F. Giffuni 	if ((idp = dt_node_resolve(dnp, DT_IDENT_XLSOU)) != NULL) {
2122a98ff317SPedro F. Giffuni 		int reg = dt_cg_xlate_expand(dnp, idp,
2123a98ff317SPedro F. Giffuni 		    &pcb->pcb_ir, pcb->pcb_regs);
2124a98ff317SPedro F. Giffuni 		dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
2125a98ff317SPedro F. Giffuni 		dnp->dn_reg = reg;
2126a98ff317SPedro F. Giffuni 	}
2127a98ff317SPedro F. Giffuni 
21286ff6d951SJohn Birrell 	instr = DIF_INSTR_RET(dnp->dn_reg);
21296ff6d951SJohn Birrell 	dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
21306ff6d951SJohn Birrell 	dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr));
21316ff6d951SJohn Birrell 
21326ff6d951SJohn Birrell 	if (dnp->dn_kind == DT_NODE_MEMBER) {
21336ff6d951SJohn Birrell 		dt_regset_free(pcb->pcb_regs, dxp->dx_ident->di_id);
21346ff6d951SJohn Birrell 		dxp->dx_ident->di_id = 0;
21356ff6d951SJohn Birrell 		dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
21366ff6d951SJohn Birrell 	}
2137ba6cafe2SMark Johnston 
2138ba6cafe2SMark Johnston 	dt_regset_free(pcb->pcb_regs, 0);
2139ba6cafe2SMark Johnston 	dt_regset_assert_free(pcb->pcb_regs);
21406ff6d951SJohn Birrell }
2141