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  */
226ff6d951SJohn Birrell /*
236ff6d951SJohn Birrell  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
246ff6d951SJohn Birrell  * Use is subject to license terms.
256ff6d951SJohn Birrell  */
266ff6d951SJohn Birrell 
276ff6d951SJohn Birrell #pragma ident	"%Z%%M%	%I%	%E% SMI"
286ff6d951SJohn Birrell 
296ff6d951SJohn Birrell #include <sys/types.h>
306ff6d951SJohn Birrell #include <sys/sysmacros.h>
316ff6d951SJohn Birrell #include <sys/isa_defs.h>
326ff6d951SJohn Birrell 
336ff6d951SJohn Birrell #include <strings.h>
346ff6d951SJohn Birrell #include <stdlib.h>
356ff6d951SJohn Birrell #include <setjmp.h>
366ff6d951SJohn Birrell #include <assert.h>
376ff6d951SJohn Birrell #include <errno.h>
386ff6d951SJohn Birrell 
396ff6d951SJohn Birrell #include <dt_impl.h>
406ff6d951SJohn Birrell #include <dt_grammar.h>
416ff6d951SJohn Birrell #include <dt_parser.h>
426ff6d951SJohn Birrell #include <dt_provider.h>
436ff6d951SJohn Birrell 
446ff6d951SJohn Birrell static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *);
456ff6d951SJohn Birrell 
466ff6d951SJohn Birrell static dt_irnode_t *
476ff6d951SJohn Birrell dt_cg_node_alloc(uint_t label, dif_instr_t instr)
486ff6d951SJohn Birrell {
496ff6d951SJohn Birrell 	dt_irnode_t *dip = malloc(sizeof (dt_irnode_t));
506ff6d951SJohn Birrell 
516ff6d951SJohn Birrell 	if (dip == NULL)
526ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
536ff6d951SJohn Birrell 
546ff6d951SJohn Birrell 	dip->di_label = label;
556ff6d951SJohn Birrell 	dip->di_instr = instr;
566ff6d951SJohn Birrell 	dip->di_extern = NULL;
576ff6d951SJohn Birrell 	dip->di_next = NULL;
586ff6d951SJohn Birrell 
596ff6d951SJohn Birrell 	return (dip);
606ff6d951SJohn Birrell }
616ff6d951SJohn Birrell 
626ff6d951SJohn Birrell /*
636ff6d951SJohn Birrell  * Code generator wrapper function for ctf_member_info.  If we are given a
646ff6d951SJohn Birrell  * reference to a forward declaration tag, search the entire type space for
656ff6d951SJohn Birrell  * the actual definition and then call ctf_member_info on the result.
666ff6d951SJohn Birrell  */
676ff6d951SJohn Birrell static ctf_file_t *
686ff6d951SJohn Birrell dt_cg_membinfo(ctf_file_t *fp, ctf_id_t type, const char *s, ctf_membinfo_t *mp)
696ff6d951SJohn Birrell {
706ff6d951SJohn Birrell 	while (ctf_type_kind(fp, type) == CTF_K_FORWARD) {
716ff6d951SJohn Birrell 		char n[DT_TYPE_NAMELEN];
726ff6d951SJohn Birrell 		dtrace_typeinfo_t dtt;
736ff6d951SJohn Birrell 
746ff6d951SJohn Birrell 		if (ctf_type_name(fp, type, n, sizeof (n)) == NULL ||
756ff6d951SJohn Birrell 		    dt_type_lookup(n, &dtt) == -1 || (
766ff6d951SJohn Birrell 		    dtt.dtt_ctfp == fp && dtt.dtt_type == type))
776ff6d951SJohn Birrell 			break; /* unable to improve our position */
786ff6d951SJohn Birrell 
796ff6d951SJohn Birrell 		fp = dtt.dtt_ctfp;
806ff6d951SJohn Birrell 		type = ctf_type_resolve(fp, dtt.dtt_type);
816ff6d951SJohn Birrell 	}
826ff6d951SJohn Birrell 
836ff6d951SJohn Birrell 	if (ctf_member_info(fp, type, s, mp) == CTF_ERR)
846ff6d951SJohn Birrell 		return (NULL); /* ctf_errno is set for us */
856ff6d951SJohn Birrell 
866ff6d951SJohn Birrell 	return (fp);
876ff6d951SJohn Birrell }
886ff6d951SJohn Birrell 
896ff6d951SJohn Birrell static void
906ff6d951SJohn Birrell dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x)
916ff6d951SJohn Birrell {
926ff6d951SJohn Birrell 	int flag = idp != NULL ? DT_INT_PRIVATE : DT_INT_SHARED;
936ff6d951SJohn Birrell 	int intoff = dt_inttab_insert(yypcb->pcb_inttab, x, flag);
946ff6d951SJohn Birrell 	dif_instr_t instr = DIF_INSTR_SETX((uint_t)intoff, reg);
956ff6d951SJohn Birrell 
966ff6d951SJohn Birrell 	if (intoff == -1)
976ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
986ff6d951SJohn Birrell 
996ff6d951SJohn Birrell 	if (intoff > DIF_INTOFF_MAX)
1006ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_INT2BIG);
1016ff6d951SJohn Birrell 
1026ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl, instr));
1036ff6d951SJohn Birrell 
1046ff6d951SJohn Birrell 	if (idp != NULL)
1056ff6d951SJohn Birrell 		dlp->dl_last->di_extern = idp;
1066ff6d951SJohn Birrell }
1076ff6d951SJohn Birrell 
1086ff6d951SJohn Birrell static void
1096ff6d951SJohn Birrell dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x)
1106ff6d951SJohn Birrell {
1116ff6d951SJohn Birrell 	dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x);
1126ff6d951SJohn Birrell }
1136ff6d951SJohn Birrell 
1146ff6d951SJohn Birrell /*
1156ff6d951SJohn Birrell  * When loading bit-fields, we want to convert a byte count in the range
1166ff6d951SJohn Birrell  * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc).  The clp2() function
1176ff6d951SJohn Birrell  * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.
1186ff6d951SJohn Birrell  */
1196ff6d951SJohn Birrell static size_t
1206ff6d951SJohn Birrell clp2(size_t x)
1216ff6d951SJohn Birrell {
1226ff6d951SJohn Birrell 	x--;
1236ff6d951SJohn Birrell 
1246ff6d951SJohn Birrell 	x |= (x >> 1);
1256ff6d951SJohn Birrell 	x |= (x >> 2);
1266ff6d951SJohn Birrell 	x |= (x >> 4);
1276ff6d951SJohn Birrell 	x |= (x >> 8);
1286ff6d951SJohn Birrell 	x |= (x >> 16);
1296ff6d951SJohn Birrell 
1306ff6d951SJohn Birrell 	return (x + 1);
1316ff6d951SJohn Birrell }
1326ff6d951SJohn Birrell 
1336ff6d951SJohn Birrell /*
1346ff6d951SJohn Birrell  * Lookup the correct load opcode to use for the specified node and CTF type.
1356ff6d951SJohn Birrell  * We determine the size and convert it to a 3-bit index.  Our lookup table
1366ff6d951SJohn Birrell  * is constructed to use a 5-bit index, consisting of the 3-bit size 0-7, a
1376ff6d951SJohn Birrell  * bit for the sign, and a bit for userland address.  For example, a 4-byte
1386ff6d951SJohn Birrell  * signed load from userland would be at the following table index:
1396ff6d951SJohn Birrell  * user=1 sign=1 size=4 => binary index 11011 = decimal index 27
1406ff6d951SJohn Birrell  */
1416ff6d951SJohn Birrell static uint_t
1426ff6d951SJohn Birrell dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)
1436ff6d951SJohn Birrell {
1446ff6d951SJohn Birrell 	static const uint_t ops[] = {
1456ff6d951SJohn Birrell 		DIF_OP_LDUB,	DIF_OP_LDUH,	0,	DIF_OP_LDUW,
1466ff6d951SJohn Birrell 		0,		0,		0,	DIF_OP_LDX,
1476ff6d951SJohn Birrell 		DIF_OP_LDSB,	DIF_OP_LDSH,	0,	DIF_OP_LDSW,
1486ff6d951SJohn Birrell 		0,		0,		0,	DIF_OP_LDX,
1496ff6d951SJohn Birrell 		DIF_OP_ULDUB,	DIF_OP_ULDUH,	0,	DIF_OP_ULDUW,
1506ff6d951SJohn Birrell 		0,		0,		0,	DIF_OP_ULDX,
1516ff6d951SJohn Birrell 		DIF_OP_ULDSB,	DIF_OP_ULDSH,	0,	DIF_OP_ULDSW,
1526ff6d951SJohn Birrell 		0,		0,		0,	DIF_OP_ULDX,
1536ff6d951SJohn Birrell 	};
1546ff6d951SJohn Birrell 
1556ff6d951SJohn Birrell 	ctf_encoding_t e;
1566ff6d951SJohn Birrell 	ssize_t size;
1576ff6d951SJohn Birrell 
1586ff6d951SJohn Birrell 	/*
1596ff6d951SJohn Birrell 	 * If we're loading a bit-field, the size of our load is found by
1606ff6d951SJohn Birrell 	 * rounding cte_bits up to a byte boundary and then finding the
1616ff6d951SJohn Birrell 	 * nearest power of two to this value (see clp2(), above).
1626ff6d951SJohn Birrell 	 */
1636ff6d951SJohn Birrell 	if ((dnp->dn_flags & DT_NF_BITFIELD) &&
1646ff6d951SJohn Birrell 	    ctf_type_encoding(ctfp, type, &e) != CTF_ERR)
1656ff6d951SJohn Birrell 		size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);
1666ff6d951SJohn Birrell 	else
1676ff6d951SJohn Birrell 		size = ctf_type_size(ctfp, type);
1686ff6d951SJohn Birrell 
1696ff6d951SJohn Birrell 	if (size < 1 || size > 8 || (size & (size - 1)) != 0) {
1706ff6d951SJohn Birrell 		xyerror(D_UNKNOWN, "internal error -- cg cannot load "
1716ff6d951SJohn Birrell 		    "size %ld when passed by value\n", (long)size);
1726ff6d951SJohn Birrell 	}
1736ff6d951SJohn Birrell 
1746ff6d951SJohn Birrell 	size--; /* convert size to 3-bit index */
1756ff6d951SJohn Birrell 
1766ff6d951SJohn Birrell 	if (dnp->dn_flags & DT_NF_SIGNED)
1776ff6d951SJohn Birrell 		size |= 0x08;
1786ff6d951SJohn Birrell 	if (dnp->dn_flags & DT_NF_USERLAND)
1796ff6d951SJohn Birrell 		size |= 0x10;
1806ff6d951SJohn Birrell 
1816ff6d951SJohn Birrell 	return (ops[size]);
1826ff6d951SJohn Birrell }
1836ff6d951SJohn Birrell 
1846ff6d951SJohn Birrell static void
1856ff6d951SJohn Birrell dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
1866ff6d951SJohn Birrell     uint_t op, int dreg)
1876ff6d951SJohn Birrell {
1886ff6d951SJohn Birrell 	ctf_file_t *ctfp = dnp->dn_ctfp;
1896ff6d951SJohn Birrell 	ctf_arinfo_t r;
1906ff6d951SJohn Birrell 	dif_instr_t instr;
1916ff6d951SJohn Birrell 	ctf_id_t type;
1926ff6d951SJohn Birrell 	uint_t kind;
1936ff6d951SJohn Birrell 	ssize_t size;
1946ff6d951SJohn Birrell 	int sreg;
1956ff6d951SJohn Birrell 
1966ff6d951SJohn Birrell 	if ((sreg = dt_regset_alloc(drp)) == -1)
1976ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
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 
2156ff6d951SJohn Birrell 	dt_cg_setx(dlp, sreg, size);
2166ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(op, dreg, sreg, dreg);
2176ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2186ff6d951SJohn Birrell 	dt_regset_free(drp, sreg);
2196ff6d951SJohn Birrell }
2206ff6d951SJohn Birrell 
2216ff6d951SJohn Birrell /*
2226ff6d951SJohn Birrell  * If the result of a "." or "->" operation is a bit-field, we use this routine
2236ff6d951SJohn Birrell  * to generate an epilogue to the load instruction that extracts the value.  In
2246ff6d951SJohn Birrell  * the diagrams below the "ld??" is the load instruction that is generated to
2256ff6d951SJohn Birrell  * load the containing word that is generating prior to calling this function.
2266ff6d951SJohn Birrell  *
2276ff6d951SJohn Birrell  * Epilogue for unsigned fields:	Epilogue for signed fields:
2286ff6d951SJohn Birrell  *
2296ff6d951SJohn Birrell  * ldu?	[r1], r1			lds? [r1], r1
2306ff6d951SJohn Birrell  * setx	USHIFT, r2			setx 64 - SSHIFT, r2
2316ff6d951SJohn Birrell  * srl	r1, r2, r1			sll  r1, r2, r1
2326ff6d951SJohn Birrell  * setx	(1 << bits) - 1, r2		setx 64 - bits, r2
2336ff6d951SJohn Birrell  * and	r1, r2, r1			sra  r1, r2, r1
2346ff6d951SJohn Birrell  *
2356ff6d951SJohn Birrell  * The *SHIFT constants above changes value depending on the endian-ness of our
2366ff6d951SJohn Birrell  * target architecture.  Refer to the comments below for more details.
2376ff6d951SJohn Birrell  */
2386ff6d951SJohn Birrell static void
2396ff6d951SJohn Birrell dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
2406ff6d951SJohn Birrell     ctf_file_t *fp, const ctf_membinfo_t *mp)
2416ff6d951SJohn Birrell {
2426ff6d951SJohn Birrell 	ctf_encoding_t e;
2436ff6d951SJohn Birrell 	dif_instr_t instr;
2446ff6d951SJohn Birrell 	uint64_t shift;
2456ff6d951SJohn Birrell 	int r1, r2;
2466ff6d951SJohn Birrell 
2476ff6d951SJohn Birrell 	if (ctf_type_encoding(fp, mp->ctm_type, &e) != 0 || e.cte_bits > 64) {
2486ff6d951SJohn Birrell 		xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "
2496ff6d951SJohn Birrell 		    "bits %u\n", mp->ctm_offset, mp->ctm_type, e.cte_bits);
2506ff6d951SJohn Birrell 	}
2516ff6d951SJohn Birrell 
2526ff6d951SJohn Birrell 	assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT);
2536ff6d951SJohn Birrell 	r1 = dnp->dn_left->dn_reg;
2546ff6d951SJohn Birrell 
2556ff6d951SJohn Birrell 	if ((r2 = dt_regset_alloc(drp)) == -1)
2566ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
2576ff6d951SJohn Birrell 
2586ff6d951SJohn Birrell 	/*
2596ff6d951SJohn Birrell 	 * On little-endian architectures, ctm_offset counts from the right so
2606ff6d951SJohn Birrell 	 * ctm_offset % NBBY itself is the amount we want to shift right to
2616ff6d951SJohn Birrell 	 * move the value bits to the little end of the register to mask them.
2626ff6d951SJohn Birrell 	 * On big-endian architectures, ctm_offset counts from the left so we
2636ff6d951SJohn Birrell 	 * must subtract (ctm_offset % NBBY + cte_bits) from the size in bits
2646ff6d951SJohn Birrell 	 * we used for the load.  The size of our load in turn is found by
2656ff6d951SJohn Birrell 	 * rounding cte_bits up to a byte boundary and then finding the
2666ff6d951SJohn Birrell 	 * nearest power of two to this value (see clp2(), above).  These
2676ff6d951SJohn Birrell 	 * properties are used to compute shift as USHIFT or SSHIFT, below.
2686ff6d951SJohn Birrell 	 */
2696ff6d951SJohn Birrell 	if (dnp->dn_flags & DT_NF_SIGNED) {
27018737969SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN
2716ff6d951SJohn Birrell 		shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
2726ff6d951SJohn Birrell 		    mp->ctm_offset % NBBY;
2736ff6d951SJohn Birrell #else
2746ff6d951SJohn Birrell 		shift = mp->ctm_offset % NBBY + e.cte_bits;
2756ff6d951SJohn Birrell #endif
2766ff6d951SJohn Birrell 		dt_cg_setx(dlp, r2, 64 - shift);
2776ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_SLL, r1, r2, r1);
2786ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2796ff6d951SJohn Birrell 
2806ff6d951SJohn Birrell 		dt_cg_setx(dlp, r2, 64 - e.cte_bits);
2816ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_SRA, r1, r2, r1);
2826ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2836ff6d951SJohn Birrell 	} else {
28418737969SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN
2856ff6d951SJohn Birrell 		shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
2866ff6d951SJohn Birrell 		    (mp->ctm_offset % NBBY + e.cte_bits);
2876ff6d951SJohn Birrell #else
2886ff6d951SJohn Birrell 		shift = mp->ctm_offset % NBBY;
2896ff6d951SJohn Birrell #endif
2906ff6d951SJohn Birrell 		dt_cg_setx(dlp, r2, shift);
2916ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_SRL, r1, r2, r1);
2926ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2936ff6d951SJohn Birrell 
2946ff6d951SJohn Birrell 		dt_cg_setx(dlp, r2, (1ULL << e.cte_bits) - 1);
2956ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);
2966ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2976ff6d951SJohn Birrell 	}
2986ff6d951SJohn Birrell 
2996ff6d951SJohn Birrell 	dt_regset_free(drp, r2);
3006ff6d951SJohn Birrell }
3016ff6d951SJohn Birrell 
3026ff6d951SJohn Birrell /*
3036ff6d951SJohn Birrell  * If the destination of a store operation is a bit-field, we use this routine
3046ff6d951SJohn Birrell  * to generate a prologue to the store instruction that loads the surrounding
3056ff6d951SJohn Birrell  * bits, clears the destination field, and ORs in the new value of the field.
3066ff6d951SJohn Birrell  * In the diagram below the "st?" is the store instruction that is generated to
3076ff6d951SJohn Birrell  * store the containing word that is generating after calling this function.
3086ff6d951SJohn Birrell  *
3096ff6d951SJohn Birrell  * ld	[dst->dn_reg], r1
3106ff6d951SJohn Birrell  * setx	~(((1 << cte_bits) - 1) << (ctm_offset % NBBY)), r2
3116ff6d951SJohn Birrell  * and	r1, r2, r1
3126ff6d951SJohn Birrell  *
3136ff6d951SJohn Birrell  * setx	(1 << cte_bits) - 1, r2
3146ff6d951SJohn Birrell  * and	src->dn_reg, r2, r2
3156ff6d951SJohn Birrell  * setx ctm_offset % NBBY, r3
3166ff6d951SJohn Birrell  * sll	r2, r3, r2
3176ff6d951SJohn Birrell  *
3186ff6d951SJohn Birrell  * or	r1, r2, r1
3196ff6d951SJohn Birrell  * st?	r1, [dst->dn_reg]
3206ff6d951SJohn Birrell  *
3216ff6d951SJohn Birrell  * This routine allocates a new register to hold the value to be stored and
3226ff6d951SJohn Birrell  * returns it.  The caller is responsible for freeing this register later.
3236ff6d951SJohn Birrell  */
3246ff6d951SJohn Birrell static int
3256ff6d951SJohn Birrell dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp,
3266ff6d951SJohn Birrell     dt_regset_t *drp, dt_node_t *dst)
3276ff6d951SJohn Birrell {
3286ff6d951SJohn Birrell 	uint64_t cmask, fmask, shift;
3296ff6d951SJohn Birrell 	dif_instr_t instr;
3306ff6d951SJohn Birrell 	int r1, r2, r3;
3316ff6d951SJohn Birrell 
3326ff6d951SJohn Birrell 	ctf_membinfo_t m;
3336ff6d951SJohn Birrell 	ctf_encoding_t e;
3346ff6d951SJohn Birrell 	ctf_file_t *fp, *ofp;
3356ff6d951SJohn Birrell 	ctf_id_t type;
3366ff6d951SJohn Birrell 
3376ff6d951SJohn Birrell 	assert(dst->dn_op == DT_TOK_PTR || dst->dn_op == DT_TOK_DOT);
3386ff6d951SJohn Birrell 	assert(dst->dn_right->dn_kind == DT_NODE_IDENT);
3396ff6d951SJohn Birrell 
3406ff6d951SJohn Birrell 	fp = dst->dn_left->dn_ctfp;
3416ff6d951SJohn Birrell 	type = ctf_type_resolve(fp, dst->dn_left->dn_type);
3426ff6d951SJohn Birrell 
3436ff6d951SJohn Birrell 	if (dst->dn_op == DT_TOK_PTR) {
3446ff6d951SJohn Birrell 		type = ctf_type_reference(fp, type);
3456ff6d951SJohn Birrell 		type = ctf_type_resolve(fp, type);
3466ff6d951SJohn Birrell 	}
3476ff6d951SJohn Birrell 
3486ff6d951SJohn Birrell 	if ((fp = dt_cg_membinfo(ofp = fp, type,
3496ff6d951SJohn Birrell 	    dst->dn_right->dn_string, &m)) == NULL) {
3506ff6d951SJohn Birrell 		yypcb->pcb_hdl->dt_ctferr = ctf_errno(ofp);
3516ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
3526ff6d951SJohn Birrell 	}
3536ff6d951SJohn Birrell 
3546ff6d951SJohn Birrell 	if (ctf_type_encoding(fp, m.ctm_type, &e) != 0 || e.cte_bits > 64) {
3556ff6d951SJohn Birrell 		xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "
3566ff6d951SJohn Birrell 		    "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits);
3576ff6d951SJohn Birrell 	}
3586ff6d951SJohn Birrell 
3596ff6d951SJohn Birrell 	if ((r1 = dt_regset_alloc(drp)) == -1 ||
3606ff6d951SJohn Birrell 	    (r2 = dt_regset_alloc(drp)) == -1 ||
3616ff6d951SJohn Birrell 	    (r3 = dt_regset_alloc(drp)) == -1)
3626ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
3636ff6d951SJohn Birrell 
3646ff6d951SJohn Birrell 	/*
3656ff6d951SJohn Birrell 	 * Compute shifts and masks.  We need to compute "shift" as the amount
3666ff6d951SJohn Birrell 	 * we need to shift left to position our field in the containing word.
3676ff6d951SJohn Birrell 	 * Refer to the comments in dt_cg_field_get(), above, for more info.
3686ff6d951SJohn Birrell 	 * We then compute fmask as the mask that truncates the value in the
3696ff6d951SJohn Birrell 	 * input register to width cte_bits, and cmask as the mask used to
3706ff6d951SJohn Birrell 	 * pass through the containing bits and zero the field bits.
3716ff6d951SJohn Birrell 	 */
37218737969SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN
3736ff6d951SJohn Birrell 	shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
3746ff6d951SJohn Birrell 	    (m.ctm_offset % NBBY + e.cte_bits);
3756ff6d951SJohn Birrell #else
3766ff6d951SJohn Birrell 	shift = m.ctm_offset % NBBY;
3776ff6d951SJohn Birrell #endif
3786ff6d951SJohn Birrell 	fmask = (1ULL << e.cte_bits) - 1;
3796ff6d951SJohn Birrell 	cmask = ~(fmask << shift);
3806ff6d951SJohn Birrell 
3816ff6d951SJohn Birrell 	instr = DIF_INSTR_LOAD(
3826ff6d951SJohn Birrell 	    dt_cg_load(dst, fp, m.ctm_type), dst->dn_reg, r1);
3836ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3846ff6d951SJohn Birrell 
3856ff6d951SJohn Birrell 	dt_cg_setx(dlp, r2, cmask);
3866ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);
3876ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3886ff6d951SJohn Birrell 
3896ff6d951SJohn Birrell 	dt_cg_setx(dlp, r2, fmask);
3906ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_AND, src->dn_reg, r2, r2);
3916ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3926ff6d951SJohn Birrell 
3936ff6d951SJohn Birrell 	dt_cg_setx(dlp, r3, shift);
3946ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_SLL, r2, r3, r2);
3956ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3966ff6d951SJohn Birrell 
3976ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_OR, r1, r2, r1);
3986ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3996ff6d951SJohn Birrell 
4006ff6d951SJohn Birrell 	dt_regset_free(drp, r3);
4016ff6d951SJohn Birrell 	dt_regset_free(drp, r2);
4026ff6d951SJohn Birrell 
4036ff6d951SJohn Birrell 	return (r1);
4046ff6d951SJohn Birrell }
4056ff6d951SJohn Birrell 
4066ff6d951SJohn Birrell static void
4076ff6d951SJohn Birrell dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
4086ff6d951SJohn Birrell {
4096ff6d951SJohn Birrell 	ctf_encoding_t e;
4106ff6d951SJohn Birrell 	dif_instr_t instr;
4116ff6d951SJohn Birrell 	size_t size;
4126ff6d951SJohn Birrell 	int reg;
4136ff6d951SJohn Birrell 
4146ff6d951SJohn Birrell 	/*
4156ff6d951SJohn Birrell 	 * If we're loading a bit-field, the size of our store is found by
4166ff6d951SJohn Birrell 	 * rounding dst's cte_bits up to a byte boundary and then finding the
4176ff6d951SJohn Birrell 	 * nearest power of two to this value (see clp2(), above).
4186ff6d951SJohn Birrell 	 */
4196ff6d951SJohn Birrell 	if ((dst->dn_flags & DT_NF_BITFIELD) &&
4206ff6d951SJohn Birrell 	    ctf_type_encoding(dst->dn_ctfp, dst->dn_type, &e) != CTF_ERR)
4216ff6d951SJohn Birrell 		size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);
4226ff6d951SJohn Birrell 	else
4236ff6d951SJohn Birrell 		size = dt_node_type_size(src);
4246ff6d951SJohn Birrell 
4256ff6d951SJohn Birrell 	if (src->dn_flags & DT_NF_REF) {
4266ff6d951SJohn Birrell 		if ((reg = dt_regset_alloc(drp)) == -1)
4276ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
4286ff6d951SJohn Birrell 		dt_cg_setx(dlp, reg, size);
4296ff6d951SJohn Birrell 		instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg);
4306ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4316ff6d951SJohn Birrell 		dt_regset_free(drp, reg);
4326ff6d951SJohn Birrell 	} else {
4336ff6d951SJohn Birrell 		if (dst->dn_flags & DT_NF_BITFIELD)
4346ff6d951SJohn Birrell 			reg = dt_cg_field_set(src, dlp, drp, dst);
4356ff6d951SJohn Birrell 		else
4366ff6d951SJohn Birrell 			reg = src->dn_reg;
4376ff6d951SJohn Birrell 
4386ff6d951SJohn Birrell 		switch (size) {
4396ff6d951SJohn Birrell 		case 1:
4406ff6d951SJohn Birrell 			instr = DIF_INSTR_STORE(DIF_OP_STB, reg, dst->dn_reg);
4416ff6d951SJohn Birrell 			break;
4426ff6d951SJohn Birrell 		case 2:
4436ff6d951SJohn Birrell 			instr = DIF_INSTR_STORE(DIF_OP_STH, reg, dst->dn_reg);
4446ff6d951SJohn Birrell 			break;
4456ff6d951SJohn Birrell 		case 4:
4466ff6d951SJohn Birrell 			instr = DIF_INSTR_STORE(DIF_OP_STW, reg, dst->dn_reg);
4476ff6d951SJohn Birrell 			break;
4486ff6d951SJohn Birrell 		case 8:
4496ff6d951SJohn Birrell 			instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg);
4506ff6d951SJohn Birrell 			break;
4516ff6d951SJohn Birrell 		default:
4526ff6d951SJohn Birrell 			xyerror(D_UNKNOWN, "internal error -- cg cannot store "
4536ff6d951SJohn Birrell 			    "size %lu when passed by value\n", (ulong_t)size);
4546ff6d951SJohn Birrell 		}
4556ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4566ff6d951SJohn Birrell 
4576ff6d951SJohn Birrell 		if (dst->dn_flags & DT_NF_BITFIELD)
4586ff6d951SJohn Birrell 			dt_regset_free(drp, reg);
4596ff6d951SJohn Birrell 	}
4606ff6d951SJohn Birrell }
4616ff6d951SJohn Birrell 
4626ff6d951SJohn Birrell /*
4636ff6d951SJohn Birrell  * Generate code for a typecast or for argument promotion from the type of the
4646ff6d951SJohn Birrell  * actual to the type of the formal.  We need to generate code for casts when
4656ff6d951SJohn Birrell  * a scalar type is being narrowed or changing signed-ness.  We first shift the
4666ff6d951SJohn Birrell  * desired bits high (losing excess bits if narrowing) and then shift them down
4676ff6d951SJohn Birrell  * using logical shift (unsigned result) or arithmetic shift (signed result).
4686ff6d951SJohn Birrell  */
4696ff6d951SJohn Birrell static void
4706ff6d951SJohn Birrell dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
4716ff6d951SJohn Birrell     dt_irlist_t *dlp, dt_regset_t *drp)
4726ff6d951SJohn Birrell {
4736ff6d951SJohn Birrell 	size_t srcsize = dt_node_type_size(src);
4746ff6d951SJohn Birrell 	size_t dstsize = dt_node_type_size(dst);
4756ff6d951SJohn Birrell 
4766ff6d951SJohn Birrell 	dif_instr_t instr;
4776ff6d951SJohn Birrell 	int reg, n;
4786ff6d951SJohn Birrell 
4796ff6d951SJohn Birrell 	if (dt_node_is_scalar(dst) && (dstsize < srcsize ||
4806ff6d951SJohn Birrell 	    (src->dn_flags & DT_NF_SIGNED) ^ (dst->dn_flags & DT_NF_SIGNED))) {
4816ff6d951SJohn Birrell 		if ((reg = dt_regset_alloc(drp)) == -1)
4826ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
4836ff6d951SJohn Birrell 
4846ff6d951SJohn Birrell 		if (dstsize < srcsize)
4856ff6d951SJohn Birrell 			n = sizeof (uint64_t) * NBBY - dstsize * NBBY;
4866ff6d951SJohn Birrell 		else
4876ff6d951SJohn Birrell 			n = sizeof (uint64_t) * NBBY - srcsize * NBBY;
4886ff6d951SJohn Birrell 
4896ff6d951SJohn Birrell 		dt_cg_setx(dlp, reg, n);
4906ff6d951SJohn Birrell 
4916ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_SLL,
4926ff6d951SJohn Birrell 		    src->dn_reg, reg, dst->dn_reg);
4936ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4946ff6d951SJohn Birrell 
4956ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ?
4966ff6d951SJohn Birrell 		    DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, reg, dst->dn_reg);
4976ff6d951SJohn Birrell 
4986ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4996ff6d951SJohn Birrell 		dt_regset_free(drp, reg);
5006ff6d951SJohn Birrell 	}
5016ff6d951SJohn Birrell }
5026ff6d951SJohn Birrell 
5036ff6d951SJohn Birrell /*
5046ff6d951SJohn Birrell  * Generate code to push the specified argument list on to the tuple stack.
5056ff6d951SJohn Birrell  * We use this routine for handling subroutine calls and associative arrays.
5066ff6d951SJohn Birrell  * We must first generate code for all subexpressions before loading the stack
5076ff6d951SJohn Birrell  * because any subexpression could itself require the use of the tuple stack.
5086ff6d951SJohn Birrell  * This holds a number of registers equal to the number of arguments, but this
5096ff6d951SJohn Birrell  * is not a huge problem because the number of arguments can't exceed the
5106ff6d951SJohn Birrell  * number of tuple register stack elements anyway.  At most one extra register
5116ff6d951SJohn Birrell  * is required (either by dt_cg_typecast() or for dtdt_size, below).  This
5126ff6d951SJohn Birrell  * implies that a DIF implementation should offer a number of general purpose
5136ff6d951SJohn Birrell  * registers at least one greater than the number of tuple registers.
5146ff6d951SJohn Birrell  */
5156ff6d951SJohn Birrell static void
5166ff6d951SJohn Birrell dt_cg_arglist(dt_ident_t *idp, dt_node_t *args,
5176ff6d951SJohn Birrell     dt_irlist_t *dlp, dt_regset_t *drp)
5186ff6d951SJohn Birrell {
5196ff6d951SJohn Birrell 	const dt_idsig_t *isp = idp->di_data;
5206ff6d951SJohn Birrell 	dt_node_t *dnp;
5216ff6d951SJohn Birrell 	int i = 0;
5226ff6d951SJohn Birrell 
5236ff6d951SJohn Birrell 	for (dnp = args; dnp != NULL; dnp = dnp->dn_list)
5246ff6d951SJohn Birrell 		dt_cg_node(dnp, dlp, drp);
5256ff6d951SJohn Birrell 
5266ff6d951SJohn Birrell 	dt_irlist_append(dlp,
5276ff6d951SJohn Birrell 	    dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
5286ff6d951SJohn Birrell 
5296ff6d951SJohn Birrell 	for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) {
5306ff6d951SJohn Birrell 		dtrace_diftype_t t;
5316ff6d951SJohn Birrell 		dif_instr_t instr;
5326ff6d951SJohn Birrell 		uint_t op;
5336ff6d951SJohn Birrell 		int reg;
5346ff6d951SJohn Birrell 
5356ff6d951SJohn Birrell 		dt_node_diftype(yypcb->pcb_hdl, dnp, &t);
5366ff6d951SJohn Birrell 
5376ff6d951SJohn Birrell 		isp->dis_args[i].dn_reg = dnp->dn_reg; /* re-use register */
5386ff6d951SJohn Birrell 		dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp);
5396ff6d951SJohn Birrell 		isp->dis_args[i].dn_reg = -1;
5406ff6d951SJohn Birrell 
5416ff6d951SJohn Birrell 		if (t.dtdt_flags & DIF_TF_BYREF)
5426ff6d951SJohn Birrell 			op = DIF_OP_PUSHTR;
5436ff6d951SJohn Birrell 		else
5446ff6d951SJohn Birrell 			op = DIF_OP_PUSHTV;
5456ff6d951SJohn Birrell 
5466ff6d951SJohn Birrell 		if (t.dtdt_size != 0) {
5476ff6d951SJohn Birrell 			if ((reg = dt_regset_alloc(drp)) == -1)
5486ff6d951SJohn Birrell 				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
5496ff6d951SJohn Birrell 			dt_cg_setx(dlp, reg, t.dtdt_size);
5506ff6d951SJohn Birrell 		} else
5516ff6d951SJohn Birrell 			reg = DIF_REG_R0;
5526ff6d951SJohn Birrell 
5536ff6d951SJohn Birrell 		instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg);
5546ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
5556ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_reg);
5566ff6d951SJohn Birrell 
5576ff6d951SJohn Birrell 		if (reg != DIF_REG_R0)
5586ff6d951SJohn Birrell 			dt_regset_free(drp, reg);
5596ff6d951SJohn Birrell 	}
5606ff6d951SJohn Birrell 
5616ff6d951SJohn Birrell 	if (i > yypcb->pcb_hdl->dt_conf.dtc_diftupregs)
5626ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG);
5636ff6d951SJohn Birrell }
5646ff6d951SJohn Birrell 
5656ff6d951SJohn Birrell static void
5666ff6d951SJohn Birrell dt_cg_arithmetic_op(dt_node_t *dnp, dt_irlist_t *dlp,
5676ff6d951SJohn Birrell     dt_regset_t *drp, uint_t op)
5686ff6d951SJohn Birrell {
5696ff6d951SJohn Birrell 	int is_ptr_op = (dnp->dn_op == DT_TOK_ADD || dnp->dn_op == DT_TOK_SUB ||
5706ff6d951SJohn Birrell 	    dnp->dn_op == DT_TOK_ADD_EQ || dnp->dn_op == DT_TOK_SUB_EQ);
5716ff6d951SJohn Birrell 
5726ff6d951SJohn Birrell 	int lp_is_ptr = dt_node_is_pointer(dnp->dn_left);
5736ff6d951SJohn Birrell 	int rp_is_ptr = dt_node_is_pointer(dnp->dn_right);
5746ff6d951SJohn Birrell 
5756ff6d951SJohn Birrell 	dif_instr_t instr;
5766ff6d951SJohn Birrell 
5776ff6d951SJohn Birrell 	if (lp_is_ptr && rp_is_ptr) {
5786ff6d951SJohn Birrell 		assert(dnp->dn_op == DT_TOK_SUB);
5796ff6d951SJohn Birrell 		is_ptr_op = 0;
5806ff6d951SJohn Birrell 	}
5816ff6d951SJohn Birrell 
5826ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
5836ff6d951SJohn Birrell 	if (is_ptr_op && rp_is_ptr)
5846ff6d951SJohn Birrell 		dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_left->dn_reg);
5856ff6d951SJohn Birrell 
5866ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
5876ff6d951SJohn Birrell 	if (is_ptr_op && lp_is_ptr)
5886ff6d951SJohn Birrell 		dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_right->dn_reg);
5896ff6d951SJohn Birrell 
5906ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(op, dnp->dn_left->dn_reg,
5916ff6d951SJohn Birrell 	    dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);
5926ff6d951SJohn Birrell 
5936ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
5946ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_right->dn_reg);
5956ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_left->dn_reg;
5966ff6d951SJohn Birrell 
5976ff6d951SJohn Birrell 	if (lp_is_ptr && rp_is_ptr)
5986ff6d951SJohn Birrell 		dt_cg_ptrsize(dnp->dn_right,
5996ff6d951SJohn Birrell 		    dlp, drp, DIF_OP_UDIV, dnp->dn_reg);
6006ff6d951SJohn Birrell }
6016ff6d951SJohn Birrell 
6026ff6d951SJohn Birrell static uint_t
6036ff6d951SJohn Birrell dt_cg_stvar(const dt_ident_t *idp)
6046ff6d951SJohn Birrell {
6056ff6d951SJohn Birrell 	static const uint_t aops[] = { DIF_OP_STGAA, DIF_OP_STTAA, DIF_OP_NOP };
6066ff6d951SJohn Birrell 	static const uint_t sops[] = { DIF_OP_STGS, DIF_OP_STTS, DIF_OP_STLS };
6076ff6d951SJohn Birrell 
6086ff6d951SJohn Birrell 	uint_t i = (((idp->di_flags & DT_IDFLG_LOCAL) != 0) << 1) |
6096ff6d951SJohn Birrell 	    ((idp->di_flags & DT_IDFLG_TLS) != 0);
6106ff6d951SJohn Birrell 
6116ff6d951SJohn Birrell 	return (idp->di_kind == DT_IDENT_ARRAY ? aops[i] : sops[i]);
6126ff6d951SJohn Birrell }
6136ff6d951SJohn Birrell 
6146ff6d951SJohn Birrell static void
6156ff6d951SJohn Birrell dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
6166ff6d951SJohn Birrell {
6176ff6d951SJohn Birrell 	ctf_file_t *ctfp = dnp->dn_ctfp;
6186ff6d951SJohn Birrell 	dif_instr_t instr;
6196ff6d951SJohn Birrell 	ctf_id_t type;
6206ff6d951SJohn Birrell 	ssize_t size = 1;
6216ff6d951SJohn Birrell 	int reg;
6226ff6d951SJohn Birrell 
6236ff6d951SJohn Birrell 	if (dt_node_is_pointer(dnp)) {
6246ff6d951SJohn Birrell 		type = ctf_type_resolve(ctfp, dnp->dn_type);
6256ff6d951SJohn Birrell 		assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);
6266ff6d951SJohn Birrell 		size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));
6276ff6d951SJohn Birrell 	}
6286ff6d951SJohn Birrell 
6296ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_child, dlp, drp);
6306ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_child->dn_reg;
6316ff6d951SJohn Birrell 
6326ff6d951SJohn Birrell 	if ((reg = dt_regset_alloc(drp)) == -1)
6336ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
6346ff6d951SJohn Birrell 
6356ff6d951SJohn Birrell 	dt_cg_setx(dlp, reg, size);
6366ff6d951SJohn Birrell 
6376ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg);
6386ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
6396ff6d951SJohn Birrell 	dt_regset_free(drp, reg);
6406ff6d951SJohn Birrell 
6416ff6d951SJohn Birrell 	/*
6426ff6d951SJohn Birrell 	 * If we are modifying a variable, generate an stv instruction from
6436ff6d951SJohn Birrell 	 * the variable specified by the identifier.  If we are storing to a
6446ff6d951SJohn Birrell 	 * memory address, generate code again for the left-hand side using
6456ff6d951SJohn Birrell 	 * DT_NF_REF to get the address, and then generate a store to it.
6466ff6d951SJohn Birrell 	 * In both paths, we store the value in dnp->dn_reg (the new value).
6476ff6d951SJohn Birrell 	 */
6486ff6d951SJohn Birrell 	if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
6496ff6d951SJohn Birrell 		dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
6506ff6d951SJohn Birrell 
6516ff6d951SJohn Birrell 		idp->di_flags |= DT_IDFLG_DIFW;
6526ff6d951SJohn Birrell 		instr = DIF_INSTR_STV(dt_cg_stvar(idp),
6536ff6d951SJohn Birrell 		    idp->di_id, dnp->dn_reg);
6546ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
6556ff6d951SJohn Birrell 	} else {
6566ff6d951SJohn Birrell 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
6576ff6d951SJohn Birrell 
6586ff6d951SJohn Birrell 		assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
6596ff6d951SJohn Birrell 		assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
6606ff6d951SJohn Birrell 
6616ff6d951SJohn Birrell 		dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
6626ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
6636ff6d951SJohn Birrell 
6646ff6d951SJohn Birrell 		dt_cg_store(dnp, dlp, drp, dnp->dn_child);
6656ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_child->dn_reg);
6666ff6d951SJohn Birrell 
6676ff6d951SJohn Birrell 		dnp->dn_left->dn_flags &= ~DT_NF_REF;
6686ff6d951SJohn Birrell 		dnp->dn_left->dn_flags |= rbit;
6696ff6d951SJohn Birrell 	}
6706ff6d951SJohn Birrell }
6716ff6d951SJohn Birrell 
6726ff6d951SJohn Birrell static void
6736ff6d951SJohn Birrell dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,
6746ff6d951SJohn Birrell     dt_regset_t *drp, uint_t op)
6756ff6d951SJohn Birrell {
6766ff6d951SJohn Birrell 	ctf_file_t *ctfp = dnp->dn_ctfp;
6776ff6d951SJohn Birrell 	dif_instr_t instr;
6786ff6d951SJohn Birrell 	ctf_id_t type;
6796ff6d951SJohn Birrell 	ssize_t size = 1;
6806ff6d951SJohn Birrell 	int nreg;
6816ff6d951SJohn Birrell 
6826ff6d951SJohn Birrell 	if (dt_node_is_pointer(dnp)) {
6836ff6d951SJohn Birrell 		type = ctf_type_resolve(ctfp, dnp->dn_type);
6846ff6d951SJohn Birrell 		assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);
6856ff6d951SJohn Birrell 		size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));
6866ff6d951SJohn Birrell 	}
6876ff6d951SJohn Birrell 
6886ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_child, dlp, drp);
6896ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_child->dn_reg;
6906ff6d951SJohn Birrell 
6916ff6d951SJohn Birrell 	if ((nreg = dt_regset_alloc(drp)) == -1)
6926ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
6936ff6d951SJohn Birrell 
6946ff6d951SJohn Birrell 	dt_cg_setx(dlp, nreg, size);
6956ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg);
6966ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
6976ff6d951SJohn Birrell 
6986ff6d951SJohn Birrell 	/*
6996ff6d951SJohn Birrell 	 * If we are modifying a variable, generate an stv instruction from
7006ff6d951SJohn Birrell 	 * the variable specified by the identifier.  If we are storing to a
7016ff6d951SJohn Birrell 	 * memory address, generate code again for the left-hand side using
7026ff6d951SJohn Birrell 	 * DT_NF_REF to get the address, and then generate a store to it.
7036ff6d951SJohn Birrell 	 * In both paths, we store the value from 'nreg' (the new value).
7046ff6d951SJohn Birrell 	 */
7056ff6d951SJohn Birrell 	if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
7066ff6d951SJohn Birrell 		dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
7076ff6d951SJohn Birrell 
7086ff6d951SJohn Birrell 		idp->di_flags |= DT_IDFLG_DIFW;
7096ff6d951SJohn Birrell 		instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, nreg);
7106ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7116ff6d951SJohn Birrell 	} else {
7126ff6d951SJohn Birrell 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
7136ff6d951SJohn Birrell 		int oreg = dnp->dn_reg;
7146ff6d951SJohn Birrell 
7156ff6d951SJohn Birrell 		assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
7166ff6d951SJohn Birrell 		assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
7176ff6d951SJohn Birrell 
7186ff6d951SJohn Birrell 		dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
7196ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
7206ff6d951SJohn Birrell 
7216ff6d951SJohn Birrell 		dnp->dn_reg = nreg;
7226ff6d951SJohn Birrell 		dt_cg_store(dnp, dlp, drp, dnp->dn_child);
7236ff6d951SJohn Birrell 		dnp->dn_reg = oreg;
7246ff6d951SJohn Birrell 
7256ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_child->dn_reg);
7266ff6d951SJohn Birrell 		dnp->dn_left->dn_flags &= ~DT_NF_REF;
7276ff6d951SJohn Birrell 		dnp->dn_left->dn_flags |= rbit;
7286ff6d951SJohn Birrell 	}
7296ff6d951SJohn Birrell 
7306ff6d951SJohn Birrell 	dt_regset_free(drp, nreg);
7316ff6d951SJohn Birrell }
7326ff6d951SJohn Birrell 
7336ff6d951SJohn Birrell /*
7346ff6d951SJohn Birrell  * Determine if we should perform signed or unsigned comparison for an OP2.
7356ff6d951SJohn Birrell  * If both operands are of arithmetic type, perform the usual arithmetic
7366ff6d951SJohn Birrell  * conversions to determine the common real type for comparison [ISOC 6.5.8.3].
7376ff6d951SJohn Birrell  */
7386ff6d951SJohn Birrell static int
7396ff6d951SJohn Birrell dt_cg_compare_signed(dt_node_t *dnp)
7406ff6d951SJohn Birrell {
7416ff6d951SJohn Birrell 	dt_node_t dn;
7426ff6d951SJohn Birrell 
7436ff6d951SJohn Birrell 	if (dt_node_is_string(dnp->dn_left) ||
7446ff6d951SJohn Birrell 	    dt_node_is_string(dnp->dn_right))
7456ff6d951SJohn Birrell 		return (1); /* strings always compare signed */
7466ff6d951SJohn Birrell 	else if (!dt_node_is_arith(dnp->dn_left) ||
7476ff6d951SJohn Birrell 	    !dt_node_is_arith(dnp->dn_right))
7486ff6d951SJohn Birrell 		return (0); /* non-arithmetic types always compare unsigned */
7496ff6d951SJohn Birrell 
7506ff6d951SJohn Birrell 	bzero(&dn, sizeof (dn));
7516ff6d951SJohn Birrell 	dt_node_promote(dnp->dn_left, dnp->dn_right, &dn);
7526ff6d951SJohn Birrell 	return (dn.dn_flags & DT_NF_SIGNED);
7536ff6d951SJohn Birrell }
7546ff6d951SJohn Birrell 
7556ff6d951SJohn Birrell static void
7566ff6d951SJohn Birrell dt_cg_compare_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
7576ff6d951SJohn Birrell {
7586ff6d951SJohn Birrell 	uint_t lbl_true = dt_irlist_label(dlp);
7596ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
7606ff6d951SJohn Birrell 
7616ff6d951SJohn Birrell 	dif_instr_t instr;
7626ff6d951SJohn Birrell 	uint_t opc;
7636ff6d951SJohn Birrell 
7646ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
7656ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
7666ff6d951SJohn Birrell 
7676ff6d951SJohn Birrell 	if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right))
7686ff6d951SJohn Birrell 		opc = DIF_OP_SCMP;
7696ff6d951SJohn Birrell 	else
7706ff6d951SJohn Birrell 		opc = DIF_OP_CMP;
7716ff6d951SJohn Birrell 
7726ff6d951SJohn Birrell 	instr = DIF_INSTR_CMP(opc, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg);
7736ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7746ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_right->dn_reg);
7756ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_left->dn_reg;
7766ff6d951SJohn Birrell 
7776ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(op, lbl_true);
7786ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7796ff6d951SJohn Birrell 
7806ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
7816ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7826ff6d951SJohn Birrell 
7836ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
7846ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7856ff6d951SJohn Birrell 
7866ff6d951SJohn Birrell 	dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);
7876ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
7886ff6d951SJohn Birrell }
7896ff6d951SJohn Birrell 
7906ff6d951SJohn Birrell /*
7916ff6d951SJohn Birrell  * Code generation for the ternary op requires some trickery with the assembler
7926ff6d951SJohn Birrell  * in order to conserve registers.  We generate code for dn_expr and dn_left
7936ff6d951SJohn Birrell  * and free their registers so they do not have be consumed across codegen for
7946ff6d951SJohn Birrell  * dn_right.  We insert a dummy MOV at the end of dn_left into the destination
7956ff6d951SJohn Birrell  * register, which is not yet known because we haven't done dn_right yet, and
7966ff6d951SJohn Birrell  * save the pointer to this instruction node.  We then generate code for
7976ff6d951SJohn Birrell  * dn_right and use its register as our output.  Finally, we reach back and
7986ff6d951SJohn Birrell  * patch the instruction for dn_left to move its output into this register.
7996ff6d951SJohn Birrell  */
8006ff6d951SJohn Birrell static void
8016ff6d951SJohn Birrell dt_cg_ternary_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
8026ff6d951SJohn Birrell {
8036ff6d951SJohn Birrell 	uint_t lbl_false = dt_irlist_label(dlp);
8046ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
8056ff6d951SJohn Birrell 
8066ff6d951SJohn Birrell 	dif_instr_t instr;
8076ff6d951SJohn Birrell 	dt_irnode_t *dip;
8086ff6d951SJohn Birrell 
8096ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_expr, dlp, drp);
8106ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_expr->dn_reg);
8116ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8126ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_expr->dn_reg);
8136ff6d951SJohn Birrell 
8146ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
8156ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8166ff6d951SJohn Birrell 
8176ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
8186ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, DIF_REG_R0);
8196ff6d951SJohn Birrell 	dip = dt_cg_node_alloc(DT_LBL_NONE, instr); /* save dip for below */
8206ff6d951SJohn Birrell 	dt_irlist_append(dlp, dip);
8216ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_left->dn_reg);
8226ff6d951SJohn Birrell 
8236ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
8246ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8256ff6d951SJohn Birrell 
8266ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, DIF_INSTR_NOP));
8276ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
8286ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_right->dn_reg;
8296ff6d951SJohn Birrell 
8306ff6d951SJohn Birrell 	/*
8316ff6d951SJohn Birrell 	 * Now that dn_reg is assigned, reach back and patch the correct MOV
8326ff6d951SJohn Birrell 	 * instruction into the tail of dn_left.  We know dn_reg was unused
8336ff6d951SJohn Birrell 	 * at that point because otherwise dn_right couldn't have allocated it.
8346ff6d951SJohn Birrell 	 */
8356ff6d951SJohn Birrell 	dip->di_instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, dnp->dn_reg);
8366ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
8376ff6d951SJohn Birrell }
8386ff6d951SJohn Birrell 
8396ff6d951SJohn Birrell static void
8406ff6d951SJohn Birrell dt_cg_logical_and(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
8416ff6d951SJohn Birrell {
8426ff6d951SJohn Birrell 	uint_t lbl_false = dt_irlist_label(dlp);
8436ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
8446ff6d951SJohn Birrell 
8456ff6d951SJohn Birrell 	dif_instr_t instr;
8466ff6d951SJohn Birrell 
8476ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
8486ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
8496ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8506ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_left->dn_reg);
8516ff6d951SJohn Birrell 
8526ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
8536ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8546ff6d951SJohn Birrell 
8556ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
8566ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
8576ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8586ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_right->dn_reg;
8596ff6d951SJohn Birrell 
8606ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
8616ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8626ff6d951SJohn Birrell 
8636ff6d951SJohn Birrell 	dt_cg_setx(dlp, dnp->dn_reg, 1);
8646ff6d951SJohn Birrell 
8656ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
8666ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8676ff6d951SJohn Birrell 
8686ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
8696ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));
8706ff6d951SJohn Birrell 
8716ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
8726ff6d951SJohn Birrell }
8736ff6d951SJohn Birrell 
8746ff6d951SJohn Birrell static void
8756ff6d951SJohn Birrell dt_cg_logical_xor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
8766ff6d951SJohn Birrell {
8776ff6d951SJohn Birrell 	uint_t lbl_next = dt_irlist_label(dlp);
8786ff6d951SJohn Birrell 	uint_t lbl_tail = dt_irlist_label(dlp);
8796ff6d951SJohn Birrell 
8806ff6d951SJohn Birrell 	dif_instr_t instr;
8816ff6d951SJohn Birrell 
8826ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
8836ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
8846ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8856ff6d951SJohn Birrell 
8866ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_next);
8876ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8886ff6d951SJohn Birrell 	dt_cg_setx(dlp, dnp->dn_left->dn_reg, 1);
8896ff6d951SJohn Birrell 
8906ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_next, DIF_INSTR_NOP));
8916ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
8926ff6d951SJohn Birrell 
8936ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
8946ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8956ff6d951SJohn Birrell 
8966ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_tail);
8976ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8986ff6d951SJohn Birrell 	dt_cg_setx(dlp, dnp->dn_right->dn_reg, 1);
8996ff6d951SJohn Birrell 
9006ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_XOR, dnp->dn_left->dn_reg,
9016ff6d951SJohn Birrell 	    dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);
9026ff6d951SJohn Birrell 
9036ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_tail, instr));
9046ff6d951SJohn Birrell 
9056ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_right->dn_reg);
9066ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_left->dn_reg;
9076ff6d951SJohn Birrell }
9086ff6d951SJohn Birrell 
9096ff6d951SJohn Birrell static void
9106ff6d951SJohn Birrell dt_cg_logical_or(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9116ff6d951SJohn Birrell {
9126ff6d951SJohn Birrell 	uint_t lbl_true = dt_irlist_label(dlp);
9136ff6d951SJohn Birrell 	uint_t lbl_false = dt_irlist_label(dlp);
9146ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
9156ff6d951SJohn Birrell 
9166ff6d951SJohn Birrell 	dif_instr_t instr;
9176ff6d951SJohn Birrell 
9186ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_left, dlp, drp);
9196ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
9206ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9216ff6d951SJohn Birrell 	dt_regset_free(drp, dnp->dn_left->dn_reg);
9226ff6d951SJohn Birrell 
9236ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BNE, lbl_true);
9246ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9256ff6d951SJohn Birrell 
9266ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_right, dlp, drp);
9276ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
9286ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9296ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_right->dn_reg;
9306ff6d951SJohn Birrell 
9316ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
9326ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9336ff6d951SJohn Birrell 
9346ff6d951SJohn Birrell 	dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);
9356ff6d951SJohn Birrell 
9366ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
9376ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9386ff6d951SJohn Birrell 
9396ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
9406ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));
9416ff6d951SJohn Birrell 
9426ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
9436ff6d951SJohn Birrell }
9446ff6d951SJohn Birrell 
9456ff6d951SJohn Birrell static void
9466ff6d951SJohn Birrell dt_cg_logical_neg(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9476ff6d951SJohn Birrell {
9486ff6d951SJohn Birrell 	uint_t lbl_zero = dt_irlist_label(dlp);
9496ff6d951SJohn Birrell 	uint_t lbl_post = dt_irlist_label(dlp);
9506ff6d951SJohn Birrell 
9516ff6d951SJohn Birrell 	dif_instr_t instr;
9526ff6d951SJohn Birrell 
9536ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_child, dlp, drp);
9546ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_child->dn_reg;
9556ff6d951SJohn Birrell 
9566ff6d951SJohn Birrell 	instr = DIF_INSTR_TST(dnp->dn_reg);
9576ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9586ff6d951SJohn Birrell 
9596ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_zero);
9606ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9616ff6d951SJohn Birrell 
9626ff6d951SJohn Birrell 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
9636ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9646ff6d951SJohn Birrell 
9656ff6d951SJohn Birrell 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
9666ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9676ff6d951SJohn Birrell 
9686ff6d951SJohn Birrell 	dt_cg_xsetx(dlp, NULL, lbl_zero, dnp->dn_reg, 1);
9696ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
9706ff6d951SJohn Birrell }
9716ff6d951SJohn Birrell 
9726ff6d951SJohn Birrell static void
9736ff6d951SJohn Birrell dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9746ff6d951SJohn Birrell {
9756ff6d951SJohn Birrell 	dif_instr_t instr;
9766ff6d951SJohn Birrell 	dt_ident_t *idp;
9776ff6d951SJohn Birrell 
9786ff6d951SJohn Birrell 	/*
9796ff6d951SJohn Birrell 	 * If we are performing a structure assignment of a translated type,
9806ff6d951SJohn Birrell 	 * we must instantiate all members and create a snapshot of the object
9816ff6d951SJohn Birrell 	 * in scratch space.  We allocs a chunk of memory, generate code for
9826ff6d951SJohn Birrell 	 * each member, and then set dnp->dn_reg to the scratch object address.
9836ff6d951SJohn Birrell 	 */
9846ff6d951SJohn Birrell 	if ((idp = dt_node_resolve(dnp->dn_right, DT_IDENT_XLSOU)) != NULL) {
9856ff6d951SJohn Birrell 		ctf_membinfo_t ctm;
9866ff6d951SJohn Birrell 		dt_xlator_t *dxp = idp->di_data;
9876ff6d951SJohn Birrell 		dt_node_t *mnp, dn, mn;
9886ff6d951SJohn Birrell 		int r1, r2;
9896ff6d951SJohn Birrell 
9906ff6d951SJohn Birrell 		/*
9916ff6d951SJohn Birrell 		 * Create two fake dt_node_t's representing operator "." and a
9926ff6d951SJohn Birrell 		 * right-hand identifier child node.  These will be repeatedly
9936ff6d951SJohn Birrell 		 * modified according to each instantiated member so that we
9946ff6d951SJohn Birrell 		 * can pass them to dt_cg_store() and effect a member store.
9956ff6d951SJohn Birrell 		 */
9966ff6d951SJohn Birrell 		bzero(&dn, sizeof (dt_node_t));
9976ff6d951SJohn Birrell 		dn.dn_kind = DT_NODE_OP2;
9986ff6d951SJohn Birrell 		dn.dn_op = DT_TOK_DOT;
9996ff6d951SJohn Birrell 		dn.dn_left = dnp;
10006ff6d951SJohn Birrell 		dn.dn_right = &mn;
10016ff6d951SJohn Birrell 
10026ff6d951SJohn Birrell 		bzero(&mn, sizeof (dt_node_t));
10036ff6d951SJohn Birrell 		mn.dn_kind = DT_NODE_IDENT;
10046ff6d951SJohn Birrell 		mn.dn_op = DT_TOK_IDENT;
10056ff6d951SJohn Birrell 
10066ff6d951SJohn Birrell 		/*
10076ff6d951SJohn Birrell 		 * Allocate a register for our scratch data pointer.  First we
10086ff6d951SJohn Birrell 		 * set it to the size of our data structure, and then replace
10096ff6d951SJohn Birrell 		 * it with the result of an allocs of the specified size.
10106ff6d951SJohn Birrell 		 */
10116ff6d951SJohn Birrell 		if ((r1 = dt_regset_alloc(drp)) == -1)
10126ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
10136ff6d951SJohn Birrell 
10146ff6d951SJohn Birrell 		dt_cg_setx(dlp, r1,
10156ff6d951SJohn Birrell 		    ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base));
10166ff6d951SJohn Birrell 
10176ff6d951SJohn Birrell 		instr = DIF_INSTR_ALLOCS(r1, r1);
10186ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
10196ff6d951SJohn Birrell 
10206ff6d951SJohn Birrell 		/*
10216ff6d951SJohn Birrell 		 * When dt_cg_asgn_op() is called, we have already generated
10226ff6d951SJohn Birrell 		 * code for dnp->dn_right, which is the translator input.  We
10236ff6d951SJohn Birrell 		 * now associate this register with the translator's input
10246ff6d951SJohn Birrell 		 * identifier so it can be referenced during our member loop.
10256ff6d951SJohn Birrell 		 */
10266ff6d951SJohn Birrell 		dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
10276ff6d951SJohn Birrell 		dxp->dx_ident->di_id = dnp->dn_right->dn_reg;
10286ff6d951SJohn Birrell 
10296ff6d951SJohn Birrell 		for (mnp = dxp->dx_members; mnp != NULL; mnp = mnp->dn_list) {
10306ff6d951SJohn Birrell 			/*
10316ff6d951SJohn Birrell 			 * Generate code for the translator member expression,
10326ff6d951SJohn Birrell 			 * and then cast the result to the member type.
10336ff6d951SJohn Birrell 			 */
10346ff6d951SJohn Birrell 			dt_cg_node(mnp->dn_membexpr, dlp, drp);
10356ff6d951SJohn Birrell 			mnp->dn_reg = mnp->dn_membexpr->dn_reg;
10366ff6d951SJohn Birrell 			dt_cg_typecast(mnp->dn_membexpr, mnp, dlp, drp);
10376ff6d951SJohn Birrell 
10386ff6d951SJohn Birrell 			/*
10396ff6d951SJohn Birrell 			 * Ask CTF for the offset of the member so we can store
10406ff6d951SJohn Birrell 			 * to the appropriate offset.  This call has already
10416ff6d951SJohn Birrell 			 * been done once by the parser, so it should succeed.
10426ff6d951SJohn Birrell 			 */
10436ff6d951SJohn Birrell 			if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_base,
10446ff6d951SJohn Birrell 			    mnp->dn_membname, &ctm) == CTF_ERR) {
10456ff6d951SJohn Birrell 				yypcb->pcb_hdl->dt_ctferr =
10466ff6d951SJohn Birrell 				    ctf_errno(dxp->dx_dst_ctfp);
10476ff6d951SJohn Birrell 				longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
10486ff6d951SJohn Birrell 			}
10496ff6d951SJohn Birrell 
10506ff6d951SJohn Birrell 			/*
10516ff6d951SJohn Birrell 			 * If the destination member is at offset 0, store the
10526ff6d951SJohn Birrell 			 * result directly to r1 (the scratch buffer address).
10536ff6d951SJohn Birrell 			 * Otherwise allocate another temporary for the offset
10546ff6d951SJohn Birrell 			 * and add r1 to it before storing the result.
10556ff6d951SJohn Birrell 			 */
10566ff6d951SJohn Birrell 			if (ctm.ctm_offset != 0) {
10576ff6d951SJohn Birrell 				if ((r2 = dt_regset_alloc(drp)) == -1)
10586ff6d951SJohn Birrell 					longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
10596ff6d951SJohn Birrell 
10606ff6d951SJohn Birrell 				/*
10616ff6d951SJohn Birrell 				 * Add the member offset rounded down to the
10626ff6d951SJohn Birrell 				 * nearest byte.  If the offset was not aligned
10636ff6d951SJohn Birrell 				 * on a byte boundary, this member is a bit-
10646ff6d951SJohn Birrell 				 * field and dt_cg_store() will handle masking.
10656ff6d951SJohn Birrell 				 */
10666ff6d951SJohn Birrell 				dt_cg_setx(dlp, r2, ctm.ctm_offset / NBBY);
10676ff6d951SJohn Birrell 				instr = DIF_INSTR_FMT(DIF_OP_ADD, r1, r2, r2);
10686ff6d951SJohn Birrell 				dt_irlist_append(dlp,
10696ff6d951SJohn Birrell 				    dt_cg_node_alloc(DT_LBL_NONE, instr));
10706ff6d951SJohn Birrell 
10716ff6d951SJohn Birrell 				dt_node_type_propagate(mnp, &dn);
10726ff6d951SJohn Birrell 				dn.dn_right->dn_string = mnp->dn_membname;
10736ff6d951SJohn Birrell 				dn.dn_reg = r2;
10746ff6d951SJohn Birrell 
10756ff6d951SJohn Birrell 				dt_cg_store(mnp, dlp, drp, &dn);
10766ff6d951SJohn Birrell 				dt_regset_free(drp, r2);
10776ff6d951SJohn Birrell 
10786ff6d951SJohn Birrell 			} else {
10796ff6d951SJohn Birrell 				dt_node_type_propagate(mnp, &dn);
10806ff6d951SJohn Birrell 				dn.dn_right->dn_string = mnp->dn_membname;
10816ff6d951SJohn Birrell 				dn.dn_reg = r1;
10826ff6d951SJohn Birrell 
10836ff6d951SJohn Birrell 				dt_cg_store(mnp, dlp, drp, &dn);
10846ff6d951SJohn Birrell 			}
10856ff6d951SJohn Birrell 
10866ff6d951SJohn Birrell 			dt_regset_free(drp, mnp->dn_reg);
10876ff6d951SJohn Birrell 		}
10886ff6d951SJohn Birrell 
10896ff6d951SJohn Birrell 		dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
10906ff6d951SJohn Birrell 		dxp->dx_ident->di_id = 0;
10916ff6d951SJohn Birrell 
10926ff6d951SJohn Birrell 		if (dnp->dn_right->dn_reg != -1)
10936ff6d951SJohn Birrell 			dt_regset_free(drp, dnp->dn_right->dn_reg);
10946ff6d951SJohn Birrell 
10956ff6d951SJohn Birrell 		assert(dnp->dn_reg == dnp->dn_right->dn_reg);
10966ff6d951SJohn Birrell 		dnp->dn_reg = r1;
10976ff6d951SJohn Birrell 	}
10986ff6d951SJohn Birrell 
10996ff6d951SJohn Birrell 	/*
11006ff6d951SJohn Birrell 	 * If we are storing to a variable, generate an stv instruction from
11016ff6d951SJohn Birrell 	 * the variable specified by the identifier.  If we are storing to a
11026ff6d951SJohn Birrell 	 * memory address, generate code again for the left-hand side using
11036ff6d951SJohn Birrell 	 * DT_NF_REF to get the address, and then generate a store to it.
11046ff6d951SJohn Birrell 	 * In both paths, we assume dnp->dn_reg already has the new value.
11056ff6d951SJohn Birrell 	 */
11066ff6d951SJohn Birrell 	if (dnp->dn_left->dn_kind == DT_NODE_VAR) {
11076ff6d951SJohn Birrell 		idp = dt_ident_resolve(dnp->dn_left->dn_ident);
11086ff6d951SJohn Birrell 
11096ff6d951SJohn Birrell 		if (idp->di_kind == DT_IDENT_ARRAY)
11106ff6d951SJohn Birrell 			dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp);
11116ff6d951SJohn Birrell 
11126ff6d951SJohn Birrell 		idp->di_flags |= DT_IDFLG_DIFW;
11136ff6d951SJohn Birrell 		instr = DIF_INSTR_STV(dt_cg_stvar(idp),
11146ff6d951SJohn Birrell 		    idp->di_id, dnp->dn_reg);
11156ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11166ff6d951SJohn Birrell 	} else {
11176ff6d951SJohn Birrell 		uint_t rbit = dnp->dn_left->dn_flags & DT_NF_REF;
11186ff6d951SJohn Birrell 
11196ff6d951SJohn Birrell 		assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE);
11206ff6d951SJohn Birrell 		assert(dnp->dn_left->dn_flags & DT_NF_LVALUE);
11216ff6d951SJohn Birrell 
11226ff6d951SJohn Birrell 		dnp->dn_left->dn_flags |= DT_NF_REF; /* force pass-by-ref */
11236ff6d951SJohn Birrell 
11246ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_left, dlp, drp);
11256ff6d951SJohn Birrell 		dt_cg_store(dnp, dlp, drp, dnp->dn_left);
11266ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_left->dn_reg);
11276ff6d951SJohn Birrell 
11286ff6d951SJohn Birrell 		dnp->dn_left->dn_flags &= ~DT_NF_REF;
11296ff6d951SJohn Birrell 		dnp->dn_left->dn_flags |= rbit;
11306ff6d951SJohn Birrell 	}
11316ff6d951SJohn Birrell }
11326ff6d951SJohn Birrell 
11336ff6d951SJohn Birrell static void
11346ff6d951SJohn Birrell dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
11356ff6d951SJohn Birrell {
11366ff6d951SJohn Birrell 	dif_instr_t instr;
11376ff6d951SJohn Birrell 	uint_t op;
11386ff6d951SJohn Birrell 
11396ff6d951SJohn Birrell 	assert(dnp->dn_kind == DT_NODE_VAR);
11406ff6d951SJohn Birrell 	assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL));
11416ff6d951SJohn Birrell 	assert(dnp->dn_args != NULL);
11426ff6d951SJohn Birrell 
11436ff6d951SJohn Birrell 	dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
11446ff6d951SJohn Birrell 
11456ff6d951SJohn Birrell 	if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
11466ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
11476ff6d951SJohn Birrell 
11486ff6d951SJohn Birrell 	if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
11496ff6d951SJohn Birrell 		op = DIF_OP_LDTAA;
11506ff6d951SJohn Birrell 	else
11516ff6d951SJohn Birrell 		op = DIF_OP_LDGAA;
11526ff6d951SJohn Birrell 
11536ff6d951SJohn Birrell 	dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;
11546ff6d951SJohn Birrell 	instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);
11556ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11566ff6d951SJohn Birrell 
11576ff6d951SJohn Birrell 	/*
11586ff6d951SJohn Birrell 	 * If the associative array is a pass-by-reference type, then we are
11596ff6d951SJohn Birrell 	 * loading its value as a pointer to either load or store through it.
11606ff6d951SJohn Birrell 	 * The array element in question may not have been faulted in yet, in
11616ff6d951SJohn Birrell 	 * which case DIF_OP_LD*AA will return zero.  We append an epilogue
11626ff6d951SJohn Birrell 	 * of instructions similar to the following:
11636ff6d951SJohn Birrell 	 *
11646ff6d951SJohn Birrell 	 *	  ld?aa	 id, %r1	! base ld?aa instruction above
11656ff6d951SJohn Birrell 	 *	  tst	 %r1		! start of epilogue
11666ff6d951SJohn Birrell 	 *   +--- bne	 label
11676ff6d951SJohn Birrell 	 *   |    setx	 size, %r1
11686ff6d951SJohn Birrell 	 *   |    allocs %r1, %r1
11696ff6d951SJohn Birrell 	 *   |    st?aa	 id, %r1
11706ff6d951SJohn Birrell 	 *   |    ld?aa	 id, %r1
11716ff6d951SJohn Birrell 	 *   v
11726ff6d951SJohn Birrell 	 * label: < rest of code >
11736ff6d951SJohn Birrell 	 *
11746ff6d951SJohn Birrell 	 * The idea is that we allocs a zero-filled chunk of scratch space and
11756ff6d951SJohn Birrell 	 * do a DIF_OP_ST*AA to fault in and initialize the array element, and
11766ff6d951SJohn Birrell 	 * then reload it to get the faulted-in address of the new variable
11776ff6d951SJohn Birrell 	 * storage.  This isn't cheap, but pass-by-ref associative array values
11786ff6d951SJohn Birrell 	 * are (thus far) uncommon and the allocs cost only occurs once.  If
11796ff6d951SJohn Birrell 	 * this path becomes important to DTrace users, we can improve things
11806ff6d951SJohn Birrell 	 * by adding a new DIF opcode to fault in associative array elements.
11816ff6d951SJohn Birrell 	 */
11826ff6d951SJohn Birrell 	if (dnp->dn_flags & DT_NF_REF) {
11836ff6d951SJohn Birrell 		uint_t stvop = op == DIF_OP_LDTAA ? DIF_OP_STTAA : DIF_OP_STGAA;
11846ff6d951SJohn Birrell 		uint_t label = dt_irlist_label(dlp);
11856ff6d951SJohn Birrell 
11866ff6d951SJohn Birrell 		instr = DIF_INSTR_TST(dnp->dn_reg);
11876ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11886ff6d951SJohn Birrell 
11896ff6d951SJohn Birrell 		instr = DIF_INSTR_BRANCH(DIF_OP_BNE, label);
11906ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11916ff6d951SJohn Birrell 
11926ff6d951SJohn Birrell 		dt_cg_setx(dlp, dnp->dn_reg, dt_node_type_size(dnp));
11936ff6d951SJohn Birrell 		instr = DIF_INSTR_ALLOCS(dnp->dn_reg, dnp->dn_reg);
11946ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11956ff6d951SJohn Birrell 
11966ff6d951SJohn Birrell 		dnp->dn_ident->di_flags |= DT_IDFLG_DIFW;
11976ff6d951SJohn Birrell 		instr = DIF_INSTR_STV(stvop, dnp->dn_ident->di_id, dnp->dn_reg);
11986ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11996ff6d951SJohn Birrell 
12006ff6d951SJohn Birrell 		instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);
12016ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12026ff6d951SJohn Birrell 
12036ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(label, DIF_INSTR_NOP));
12046ff6d951SJohn Birrell 	}
12056ff6d951SJohn Birrell }
12066ff6d951SJohn Birrell 
12076ff6d951SJohn Birrell static void
12086ff6d951SJohn Birrell dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
12096ff6d951SJohn Birrell {
12106ff6d951SJohn Birrell 	dt_probe_t *prp = yypcb->pcb_probe;
12116ff6d951SJohn Birrell 	uintmax_t saved = dnp->dn_args->dn_value;
12126ff6d951SJohn Birrell 	dt_ident_t *idp = dnp->dn_ident;
12136ff6d951SJohn Birrell 
12146ff6d951SJohn Birrell 	dif_instr_t instr;
12156ff6d951SJohn Birrell 	uint_t op;
12166ff6d951SJohn Birrell 	size_t size;
12176ff6d951SJohn Birrell 	int reg, n;
12186ff6d951SJohn Birrell 
12196ff6d951SJohn Birrell 	assert(dnp->dn_kind == DT_NODE_VAR);
12206ff6d951SJohn Birrell 	assert(!(idp->di_flags & DT_IDFLG_LOCAL));
12216ff6d951SJohn Birrell 
12226ff6d951SJohn Birrell 	assert(dnp->dn_args->dn_kind == DT_NODE_INT);
12236ff6d951SJohn Birrell 	assert(dnp->dn_args->dn_list == NULL);
12246ff6d951SJohn Birrell 
12256ff6d951SJohn Birrell 	/*
12266ff6d951SJohn Birrell 	 * If this is a reference in the args[] array, temporarily modify the
12276ff6d951SJohn Birrell 	 * array index according to the static argument mapping (if any),
12286ff6d951SJohn Birrell 	 * unless the argument reference is provided by a dynamic translator.
12296ff6d951SJohn Birrell 	 * If we're using a dynamic translator for args[], then just set dn_reg
12306ff6d951SJohn Birrell 	 * to an invalid reg and return: DIF_OP_XLARG will fetch the arg later.
12316ff6d951SJohn Birrell 	 */
12326ff6d951SJohn Birrell 	if (idp->di_id == DIF_VAR_ARGS) {
12336ff6d951SJohn Birrell 		if ((idp->di_kind == DT_IDENT_XLPTR ||
12346ff6d951SJohn Birrell 		    idp->di_kind == DT_IDENT_XLSOU) &&
12356ff6d951SJohn Birrell 		    dt_xlator_dynamic(idp->di_data)) {
12366ff6d951SJohn Birrell 			dnp->dn_reg = -1;
12376ff6d951SJohn Birrell 			return;
12386ff6d951SJohn Birrell 		}
12396ff6d951SJohn Birrell 		dnp->dn_args->dn_value = prp->pr_mapping[saved];
12406ff6d951SJohn Birrell 	}
12416ff6d951SJohn Birrell 
12426ff6d951SJohn Birrell 	dt_cg_node(dnp->dn_args, dlp, drp);
12436ff6d951SJohn Birrell 	dnp->dn_args->dn_value = saved;
12446ff6d951SJohn Birrell 
12456ff6d951SJohn Birrell 	dnp->dn_reg = dnp->dn_args->dn_reg;
12466ff6d951SJohn Birrell 
12476ff6d951SJohn Birrell 	if (idp->di_flags & DT_IDFLG_TLS)
12486ff6d951SJohn Birrell 		op = DIF_OP_LDTA;
12496ff6d951SJohn Birrell 	else
12506ff6d951SJohn Birrell 		op = DIF_OP_LDGA;
12516ff6d951SJohn Birrell 
12526ff6d951SJohn Birrell 	idp->di_flags |= DT_IDFLG_DIFR;
12536ff6d951SJohn Birrell 
12546ff6d951SJohn Birrell 	instr = DIF_INSTR_LDA(op, idp->di_id,
12556ff6d951SJohn Birrell 	    dnp->dn_args->dn_reg, dnp->dn_reg);
12566ff6d951SJohn Birrell 
12576ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12586ff6d951SJohn Birrell 
12596ff6d951SJohn Birrell 	/*
12606ff6d951SJohn Birrell 	 * If this is a reference to the args[] array, we need to take the
12616ff6d951SJohn Birrell 	 * additional step of explicitly eliminating any bits larger than the
12626ff6d951SJohn Birrell 	 * type size: the DIF interpreter in the kernel will always give us
12636ff6d951SJohn Birrell 	 * the raw (64-bit) argument value, and any bits larger than the type
12646ff6d951SJohn Birrell 	 * size may be junk.  As a practical matter, this arises only on 64-bit
12656ff6d951SJohn Birrell 	 * architectures and only when the argument index is larger than the
12666ff6d951SJohn Birrell 	 * number of arguments passed directly to DTrace: if a 8-, 16- or
12676ff6d951SJohn Birrell 	 * 32-bit argument must be retrieved from the stack, it is possible
12686ff6d951SJohn Birrell 	 * (and it some cases, likely) that the upper bits will be garbage.
12696ff6d951SJohn Birrell 	 */
12706ff6d951SJohn Birrell 	if (idp->di_id != DIF_VAR_ARGS || !dt_node_is_scalar(dnp))
12716ff6d951SJohn Birrell 		return;
12726ff6d951SJohn Birrell 
12736ff6d951SJohn Birrell 	if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t))
12746ff6d951SJohn Birrell 		return;
12756ff6d951SJohn Birrell 
12766ff6d951SJohn Birrell 	if ((reg = dt_regset_alloc(drp)) == -1)
12776ff6d951SJohn Birrell 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
12786ff6d951SJohn Birrell 
12796ff6d951SJohn Birrell 	assert(size < sizeof (uint64_t));
12806ff6d951SJohn Birrell 	n = sizeof (uint64_t) * NBBY - size * NBBY;
12816ff6d951SJohn Birrell 
12826ff6d951SJohn Birrell 	dt_cg_setx(dlp, reg, n);
12836ff6d951SJohn Birrell 
12846ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT(DIF_OP_SLL, dnp->dn_reg, reg, dnp->dn_reg);
12856ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12866ff6d951SJohn Birrell 
12876ff6d951SJohn Birrell 	instr = DIF_INSTR_FMT((dnp->dn_flags & DT_NF_SIGNED) ?
12886ff6d951SJohn Birrell 	    DIF_OP_SRA : DIF_OP_SRL, dnp->dn_reg, reg, dnp->dn_reg);
12896ff6d951SJohn Birrell 
12906ff6d951SJohn Birrell 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12916ff6d951SJohn Birrell 	dt_regset_free(drp, reg);
12926ff6d951SJohn Birrell }
12936ff6d951SJohn Birrell 
12946ff6d951SJohn Birrell /*
12956ff6d951SJohn Birrell  * Generate code for an inlined variable reference.  Inlines can be used to
12966ff6d951SJohn Birrell  * define either scalar or associative array substitutions.  For scalars, we
12976ff6d951SJohn Birrell  * simply generate code for the parse tree saved in the identifier's din_root,
12986ff6d951SJohn Birrell  * and then cast the resulting expression to the inline's declaration type.
12996ff6d951SJohn Birrell  * For arrays, we take the input parameter subtrees from dnp->dn_args and
13006ff6d951SJohn Birrell  * temporarily store them in the din_root of each din_argv[i] identifier,
13016ff6d951SJohn Birrell  * which are themselves inlines and were set up for us by the parser.  The
13026ff6d951SJohn Birrell  * result is that any reference to the inlined parameter inside the top-level
13036ff6d951SJohn Birrell  * din_root will turn into a recursive call to dt_cg_inline() for a scalar
13046ff6d951SJohn Birrell  * inline whose din_root will refer to the subtree pointed to by the argument.
13056ff6d951SJohn Birrell  */
13066ff6d951SJohn Birrell static void
13076ff6d951SJohn Birrell dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
13086ff6d951SJohn Birrell {
13096ff6d951SJohn Birrell 	dt_ident_t *idp = dnp->dn_ident;
13106ff6d951SJohn Birrell 	dt_idnode_t *inp = idp->di_iarg;
13116ff6d951SJohn Birrell 
13126ff6d951SJohn Birrell 	dt_idnode_t *pinp;
13136ff6d951SJohn Birrell 	dt_node_t *pnp;
13146ff6d951SJohn Birrell 	int i;
13156ff6d951SJohn Birrell 
13166ff6d951SJohn Birrell 	assert(idp->di_flags & DT_IDFLG_INLINE);
13176ff6d951SJohn Birrell 	assert(idp->di_ops == &dt_idops_inline);
13186ff6d951SJohn Birrell 
13196ff6d951SJohn Birrell 	if (idp->di_kind == DT_IDENT_ARRAY) {
13206ff6d951SJohn Birrell 		for (i = 0, pnp = dnp->dn_args;
13216ff6d951SJohn Birrell 		    pnp != NULL; pnp = pnp->dn_list, i++) {
13226ff6d951SJohn Birrell 			if (inp->din_argv[i] != NULL) {
13236ff6d951SJohn Birrell 				pinp = inp->din_argv[i]->di_iarg;
13246ff6d951SJohn Birrell 				pinp->din_root = pnp;
13256ff6d951SJohn Birrell 			}
13266ff6d951SJohn Birrell 		}
13276ff6d951SJohn Birrell 	}
13286ff6d951SJohn Birrell 
13296ff6d951SJohn Birrell 	dt_cg_node(inp->din_root, dlp, drp);
13306ff6d951SJohn Birrell 	dnp->dn_reg = inp->din_root->dn_reg;
13316ff6d951SJohn Birrell 	dt_cg_typecast(inp->din_root, dnp, dlp, drp);
13326ff6d951SJohn Birrell 
13336ff6d951SJohn Birrell 	if (idp->di_kind == DT_IDENT_ARRAY) {
13346ff6d951SJohn Birrell 		for (i = 0; i < inp->din_argc; i++) {
13356ff6d951SJohn Birrell 			pinp = inp->din_argv[i]->di_iarg;
13366ff6d951SJohn Birrell 			pinp->din_root = NULL;
13376ff6d951SJohn Birrell 		}
13386ff6d951SJohn Birrell 	}
13396ff6d951SJohn Birrell }
13406ff6d951SJohn Birrell 
13416ff6d951SJohn Birrell static void
134218737969SJohn Birrell dt_cg_func_typeref(dtrace_hdl_t *dtp, dt_node_t *dnp)
134318737969SJohn Birrell {
134418737969SJohn Birrell 	dtrace_typeinfo_t dtt;
134518737969SJohn Birrell 	dt_node_t *addr = dnp->dn_args;
134618737969SJohn Birrell 	dt_node_t *nelm = addr->dn_list;
134718737969SJohn Birrell 	dt_node_t *strp = nelm->dn_list;
134818737969SJohn Birrell 	dt_node_t *typs = strp->dn_list;
134918737969SJohn Birrell 	char buf[DT_TYPE_NAMELEN];
135018737969SJohn Birrell 	char *p;
135118737969SJohn Birrell 
135218737969SJohn Birrell 	ctf_type_name(addr->dn_ctfp, addr->dn_type, buf, sizeof (buf));
135318737969SJohn Birrell 
135418737969SJohn Birrell 	/*
135518737969SJohn Birrell 	 * XXX Hack alert! XXX
135618737969SJohn Birrell 	 * The prototype has two dummy args that we munge to represent
135718737969SJohn Birrell 	 * the type string and the type size.
135818737969SJohn Birrell 	 *
135918737969SJohn Birrell 	 * Yes, I hear your grumble, but it works for now. We'll come
136018737969SJohn Birrell 	 * up with a more elegant implementation later. :-)
136118737969SJohn Birrell 	 */
136218737969SJohn Birrell 	free(strp->dn_string);
136318737969SJohn Birrell 
136418737969SJohn Birrell 	if ((p = strchr(buf, '*')) != NULL)
136518737969SJohn Birrell 		*p = '\0';
136618737969SJohn Birrell 
136718737969SJohn Birrell 	strp->dn_string = strdup(buf);
136818737969SJohn Birrell 
136918737969SJohn Birrell 	if (dtrace_lookup_by_type(dtp,  DTRACE_OBJ_EVERY, buf, &dtt) < 0)
137018737969SJohn Birrell 		return;
137118737969SJohn Birrell 
137218737969SJohn Birrell 	typs->dn_value = ctf_type_size(dtt.dtt_ctfp, dtt.dtt_type);
137318737969SJohn Birrell }
137418737969SJohn Birrell 
137518737969SJohn Birrell static void
13766ff6d951SJohn Birrell dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
13776ff6d951SJohn Birrell {
13786ff6d951SJohn Birrell 	ctf_file_t *ctfp = dnp->dn_ctfp;
13796ff6d951SJohn Birrell 	ctf_file_t *octfp;
13806ff6d951SJohn Birrell 	ctf_membinfo_t m;
13816ff6d951SJohn Birrell 	ctf_id_t type;
13826ff6d951SJohn Birrell 
13836ff6d951SJohn Birrell 	dif_instr_t instr;
13846ff6d951SJohn Birrell 	dt_ident_t *idp;
13856ff6d951SJohn Birrell 	ssize_t stroff;
13866ff6d951SJohn Birrell 	uint_t op;
13876ff6d951SJohn Birrell 	int reg;
13886ff6d951SJohn Birrell 
13896ff6d951SJohn Birrell 	switch (dnp->dn_op) {
13906ff6d951SJohn Birrell 	case DT_TOK_COMMA:
13916ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_left, dlp, drp);
13926ff6d951SJohn Birrell 		dt_regset_free(drp, dnp->dn_left->dn_reg);
13936ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_right, dlp, drp);
13946ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_right->dn_reg;
13956ff6d951SJohn Birrell 		break;
13966ff6d951SJohn Birrell 
13976ff6d951SJohn Birrell 	case DT_TOK_ASGN:
13986ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_right, dlp, drp);
13996ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_right->dn_reg;
14006ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14016ff6d951SJohn Birrell 		break;
14026ff6d951SJohn Birrell 
14036ff6d951SJohn Birrell 	case DT_TOK_ADD_EQ:
14046ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);
14056ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14066ff6d951SJohn Birrell 		break;
14076ff6d951SJohn Birrell 
14086ff6d951SJohn Birrell 	case DT_TOK_SUB_EQ:
14096ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);
14106ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14116ff6d951SJohn Birrell 		break;
14126ff6d951SJohn Birrell 
14136ff6d951SJohn Birrell 	case DT_TOK_MUL_EQ:
14146ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);
14156ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14166ff6d951SJohn Birrell 		break;
14176ff6d951SJohn Birrell 
14186ff6d951SJohn Birrell 	case DT_TOK_DIV_EQ:
14196ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
14206ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);
14216ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14226ff6d951SJohn Birrell 		break;
14236ff6d951SJohn Birrell 
14246ff6d951SJohn Birrell 	case DT_TOK_MOD_EQ:
14256ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
14266ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);
14276ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14286ff6d951SJohn Birrell 		break;
14296ff6d951SJohn Birrell 
14306ff6d951SJohn Birrell 	case DT_TOK_AND_EQ:
14316ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);
14326ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14336ff6d951SJohn Birrell 		break;
14346ff6d951SJohn Birrell 
14356ff6d951SJohn Birrell 	case DT_TOK_XOR_EQ:
14366ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);
14376ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14386ff6d951SJohn Birrell 		break;
14396ff6d951SJohn Birrell 
14406ff6d951SJohn Birrell 	case DT_TOK_OR_EQ:
14416ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);
14426ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14436ff6d951SJohn Birrell 		break;
14446ff6d951SJohn Birrell 
14456ff6d951SJohn Birrell 	case DT_TOK_LSH_EQ:
14466ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);
14476ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14486ff6d951SJohn Birrell 		break;
14496ff6d951SJohn Birrell 
14506ff6d951SJohn Birrell 	case DT_TOK_RSH_EQ:
14516ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
14526ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);
14536ff6d951SJohn Birrell 		dt_cg_asgn_op(dnp, dlp, drp);
14546ff6d951SJohn Birrell 		break;
14556ff6d951SJohn Birrell 
14566ff6d951SJohn Birrell 	case DT_TOK_QUESTION:
14576ff6d951SJohn Birrell 		dt_cg_ternary_op(dnp, dlp, drp);
14586ff6d951SJohn Birrell 		break;
14596ff6d951SJohn Birrell 
14606ff6d951SJohn Birrell 	case DT_TOK_LOR:
14616ff6d951SJohn Birrell 		dt_cg_logical_or(dnp, dlp, drp);
14626ff6d951SJohn Birrell 		break;
14636ff6d951SJohn Birrell 
14646ff6d951SJohn Birrell 	case DT_TOK_LXOR:
14656ff6d951SJohn Birrell 		dt_cg_logical_xor(dnp, dlp, drp);
14666ff6d951SJohn Birrell 		break;
14676ff6d951SJohn Birrell 
14686ff6d951SJohn Birrell 	case DT_TOK_LAND:
14696ff6d951SJohn Birrell 		dt_cg_logical_and(dnp, dlp, drp);
14706ff6d951SJohn Birrell 		break;
14716ff6d951SJohn Birrell 
14726ff6d951SJohn Birrell 	case DT_TOK_BOR:
14736ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);
14746ff6d951SJohn Birrell 		break;
14756ff6d951SJohn Birrell 
14766ff6d951SJohn Birrell 	case DT_TOK_XOR:
14776ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);
14786ff6d951SJohn Birrell 		break;
14796ff6d951SJohn Birrell 
14806ff6d951SJohn Birrell 	case DT_TOK_BAND:
14816ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);
14826ff6d951SJohn Birrell 		break;
14836ff6d951SJohn Birrell 
14846ff6d951SJohn Birrell 	case DT_TOK_EQU:
14856ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BE);
14866ff6d951SJohn Birrell 		break;
14876ff6d951SJohn Birrell 
14886ff6d951SJohn Birrell 	case DT_TOK_NEQ:
14896ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BNE);
14906ff6d951SJohn Birrell 		break;
14916ff6d951SJohn Birrell 
14926ff6d951SJohn Birrell 	case DT_TOK_LT:
14936ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp,
14946ff6d951SJohn Birrell 		    dt_cg_compare_signed(dnp) ? DIF_OP_BL : DIF_OP_BLU);
14956ff6d951SJohn Birrell 		break;
14966ff6d951SJohn Birrell 
14976ff6d951SJohn Birrell 	case DT_TOK_LE:
14986ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp,
14996ff6d951SJohn Birrell 		    dt_cg_compare_signed(dnp) ? DIF_OP_BLE : DIF_OP_BLEU);
15006ff6d951SJohn Birrell 		break;
15016ff6d951SJohn Birrell 
15026ff6d951SJohn Birrell 	case DT_TOK_GT:
15036ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp,
15046ff6d951SJohn Birrell 		    dt_cg_compare_signed(dnp) ? DIF_OP_BG : DIF_OP_BGU);
15056ff6d951SJohn Birrell 		break;
15066ff6d951SJohn Birrell 
15076ff6d951SJohn Birrell 	case DT_TOK_GE:
15086ff6d951SJohn Birrell 		dt_cg_compare_op(dnp, dlp, drp,
15096ff6d951SJohn Birrell 		    dt_cg_compare_signed(dnp) ? DIF_OP_BGE : DIF_OP_BGEU);
15106ff6d951SJohn Birrell 		break;
15116ff6d951SJohn Birrell 
15126ff6d951SJohn Birrell 	case DT_TOK_LSH:
15136ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);
15146ff6d951SJohn Birrell 		break;
15156ff6d951SJohn Birrell 
15166ff6d951SJohn Birrell 	case DT_TOK_RSH:
15176ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
15186ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);
15196ff6d951SJohn Birrell 		break;
15206ff6d951SJohn Birrell 
15216ff6d951SJohn Birrell 	case DT_TOK_ADD:
15226ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);
15236ff6d951SJohn Birrell 		break;
15246ff6d951SJohn Birrell 
15256ff6d951SJohn Birrell 	case DT_TOK_SUB:
15266ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);
15276ff6d951SJohn Birrell 		break;
15286ff6d951SJohn Birrell 
15296ff6d951SJohn Birrell 	case DT_TOK_MUL:
15306ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);
15316ff6d951SJohn Birrell 		break;
15326ff6d951SJohn Birrell 
15336ff6d951SJohn Birrell 	case DT_TOK_DIV:
15346ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
15356ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);
15366ff6d951SJohn Birrell 		break;
15376ff6d951SJohn Birrell 
15386ff6d951SJohn Birrell 	case DT_TOK_MOD:
15396ff6d951SJohn Birrell 		dt_cg_arithmetic_op(dnp, dlp, drp,
15406ff6d951SJohn Birrell 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);
15416ff6d951SJohn Birrell 		break;
15426ff6d951SJohn Birrell 
15436ff6d951SJohn Birrell 	case DT_TOK_LNEG:
15446ff6d951SJohn Birrell 		dt_cg_logical_neg(dnp, dlp, drp);
15456ff6d951SJohn Birrell 		break;
15466ff6d951SJohn Birrell 
15476ff6d951SJohn Birrell 	case DT_TOK_BNEG:
15486ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
15496ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
15506ff6d951SJohn Birrell 		instr = DIF_INSTR_NOT(dnp->dn_reg, dnp->dn_reg);
15516ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
15526ff6d951SJohn Birrell 		break;
15536ff6d951SJohn Birrell 
15546ff6d951SJohn Birrell 	case DT_TOK_PREINC:
15556ff6d951SJohn Birrell 		dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_ADD);
15566ff6d951SJohn Birrell 		break;
15576ff6d951SJohn Birrell 
15586ff6d951SJohn Birrell 	case DT_TOK_POSTINC:
15596ff6d951SJohn Birrell 		dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_ADD);
15606ff6d951SJohn Birrell 		break;
15616ff6d951SJohn Birrell 
15626ff6d951SJohn Birrell 	case DT_TOK_PREDEC:
15636ff6d951SJohn Birrell 		dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_SUB);
15646ff6d951SJohn Birrell 		break;
15656ff6d951SJohn Birrell 
15666ff6d951SJohn Birrell 	case DT_TOK_POSTDEC:
15676ff6d951SJohn Birrell 		dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_SUB);
15686ff6d951SJohn Birrell 		break;
15696ff6d951SJohn Birrell 
15706ff6d951SJohn Birrell 	case DT_TOK_IPOS:
15716ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
15726ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
15736ff6d951SJohn Birrell 		break;
15746ff6d951SJohn Birrell 
15756ff6d951SJohn Birrell 	case DT_TOK_INEG:
15766ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
15776ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
15786ff6d951SJohn Birrell 
15796ff6d951SJohn Birrell 		instr = DIF_INSTR_FMT(DIF_OP_SUB, DIF_REG_R0,
15806ff6d951SJohn Birrell 		    dnp->dn_reg, dnp->dn_reg);
15816ff6d951SJohn Birrell 
15826ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
15836ff6d951SJohn Birrell 		break;
15846ff6d951SJohn Birrell 
15856ff6d951SJohn Birrell 	case DT_TOK_DEREF:
15866ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
15876ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
15886ff6d951SJohn Birrell 
15896ff6d951SJohn Birrell 		if (!(dnp->dn_flags & DT_NF_REF)) {
15906ff6d951SJohn Birrell 			uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
15916ff6d951SJohn Birrell 
15926ff6d951SJohn Birrell 			/*
15936ff6d951SJohn Birrell 			 * Save and restore DT_NF_USERLAND across dt_cg_load():
15946ff6d951SJohn Birrell 			 * we need the sign bit from dnp and the user bit from
15956ff6d951SJohn Birrell 			 * dnp->dn_child in order to get the proper opcode.
15966ff6d951SJohn Birrell 			 */
15976ff6d951SJohn Birrell 			dnp->dn_flags |=
15986ff6d951SJohn Birrell 			    (dnp->dn_child->dn_flags & DT_NF_USERLAND);
15996ff6d951SJohn Birrell 
16006ff6d951SJohn Birrell 			instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,
16016ff6d951SJohn Birrell 			    dnp->dn_type), dnp->dn_reg, dnp->dn_reg);
16026ff6d951SJohn Birrell 
16036ff6d951SJohn Birrell 			dnp->dn_flags &= ~DT_NF_USERLAND;
16046ff6d951SJohn Birrell 			dnp->dn_flags |= ubit;
16056ff6d951SJohn Birrell 
16066ff6d951SJohn Birrell 			dt_irlist_append(dlp,
16076ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
16086ff6d951SJohn Birrell 		}
16096ff6d951SJohn Birrell 		break;
16106ff6d951SJohn Birrell 
16116ff6d951SJohn Birrell 	case DT_TOK_ADDROF: {
16126ff6d951SJohn Birrell 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
16136ff6d951SJohn Birrell 
16146ff6d951SJohn Birrell 		dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
16156ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
16166ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
16176ff6d951SJohn Birrell 
16186ff6d951SJohn Birrell 		dnp->dn_child->dn_flags &= ~DT_NF_REF;
16196ff6d951SJohn Birrell 		dnp->dn_child->dn_flags |= rbit;
16206ff6d951SJohn Birrell 		break;
16216ff6d951SJohn Birrell 	}
16226ff6d951SJohn Birrell 
16236ff6d951SJohn Birrell 	case DT_TOK_SIZEOF: {
16246ff6d951SJohn Birrell 		size_t size = dt_node_sizeof(dnp->dn_child);
16256ff6d951SJohn Birrell 
16266ff6d951SJohn Birrell 		if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
16276ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
16286ff6d951SJohn Birrell 
16296ff6d951SJohn Birrell 		assert(size != 0);
16306ff6d951SJohn Birrell 		dt_cg_setx(dlp, dnp->dn_reg, size);
16316ff6d951SJohn Birrell 		break;
16326ff6d951SJohn Birrell 	}
16336ff6d951SJohn Birrell 
16346ff6d951SJohn Birrell 	case DT_TOK_STRINGOF:
16356ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_child, dlp, drp);
16366ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_child->dn_reg;
16376ff6d951SJohn Birrell 		break;
16386ff6d951SJohn Birrell 
16396ff6d951SJohn Birrell 	case DT_TOK_XLATE:
16406ff6d951SJohn Birrell 		/*
16416ff6d951SJohn Birrell 		 * An xlate operator appears in either an XLATOR, indicating a
16426ff6d951SJohn Birrell 		 * reference to a dynamic translator, or an OP2, indicating
16436ff6d951SJohn Birrell 		 * use of the xlate operator in the user's program.  For the
16446ff6d951SJohn Birrell 		 * dynamic case, generate an xlate opcode with a reference to
16456ff6d951SJohn Birrell 		 * the corresponding member, pre-computed for us in dn_members.
16466ff6d951SJohn Birrell 		 */
16476ff6d951SJohn Birrell 		if (dnp->dn_kind == DT_NODE_XLATOR) {
16486ff6d951SJohn Birrell 			dt_xlator_t *dxp = dnp->dn_xlator;
16496ff6d951SJohn Birrell 
16506ff6d951SJohn Birrell 			assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG);
16516ff6d951SJohn Birrell 			assert(dxp->dx_ident->di_id != 0);
16526ff6d951SJohn Birrell 
16536ff6d951SJohn Birrell 			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
16546ff6d951SJohn Birrell 				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
16556ff6d951SJohn Birrell 
16566ff6d951SJohn Birrell 			if (dxp->dx_arg == -1) {
16576ff6d951SJohn Birrell 				instr = DIF_INSTR_MOV(
16586ff6d951SJohn Birrell 				    dxp->dx_ident->di_id, dnp->dn_reg);
16596ff6d951SJohn Birrell 				dt_irlist_append(dlp,
16606ff6d951SJohn Birrell 				    dt_cg_node_alloc(DT_LBL_NONE, instr));
16616ff6d951SJohn Birrell 				op = DIF_OP_XLATE;
16626ff6d951SJohn Birrell 			} else
16636ff6d951SJohn Birrell 				op = DIF_OP_XLARG;
16646ff6d951SJohn Birrell 
16656ff6d951SJohn Birrell 			instr = DIF_INSTR_XLATE(op, 0, dnp->dn_reg);
16666ff6d951SJohn Birrell 			dt_irlist_append(dlp,
16676ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
16686ff6d951SJohn Birrell 
16696ff6d951SJohn Birrell 			dlp->dl_last->di_extern = dnp->dn_xmember;
16706ff6d951SJohn Birrell 			break;
16716ff6d951SJohn Birrell 		}
16726ff6d951SJohn Birrell 
16736ff6d951SJohn Birrell 		assert(dnp->dn_kind == DT_NODE_OP2);
16746ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_right, dlp, drp);
16756ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_right->dn_reg;
16766ff6d951SJohn Birrell 		break;
16776ff6d951SJohn Birrell 
16786ff6d951SJohn Birrell 	case DT_TOK_LPAR:
16796ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_right, dlp, drp);
16806ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_right->dn_reg;
16816ff6d951SJohn Birrell 		dt_cg_typecast(dnp->dn_right, dnp, dlp, drp);
16826ff6d951SJohn Birrell 		break;
16836ff6d951SJohn Birrell 
16846ff6d951SJohn Birrell 	case DT_TOK_PTR:
16856ff6d951SJohn Birrell 	case DT_TOK_DOT:
16866ff6d951SJohn Birrell 		assert(dnp->dn_right->dn_kind == DT_NODE_IDENT);
16876ff6d951SJohn Birrell 		dt_cg_node(dnp->dn_left, dlp, drp);
16886ff6d951SJohn Birrell 
16896ff6d951SJohn Birrell 		/*
16906ff6d951SJohn Birrell 		 * If the left-hand side of PTR or DOT is a dynamic variable,
16916ff6d951SJohn Birrell 		 * we expect it to be the output of a D translator.   In this
16926ff6d951SJohn Birrell 		 * case, we look up the parse tree corresponding to the member
16936ff6d951SJohn Birrell 		 * that is being accessed and run the code generator over it.
16946ff6d951SJohn Birrell 		 * We then cast the result as if by the assignment operator.
16956ff6d951SJohn Birrell 		 */
16966ff6d951SJohn Birrell 		if ((idp = dt_node_resolve(
16976ff6d951SJohn Birrell 		    dnp->dn_left, DT_IDENT_XLSOU)) != NULL ||
16986ff6d951SJohn Birrell 		    (idp = dt_node_resolve(
16996ff6d951SJohn Birrell 		    dnp->dn_left, DT_IDENT_XLPTR)) != NULL) {
17006ff6d951SJohn Birrell 
17016ff6d951SJohn Birrell 			dt_xlator_t *dxp;
17026ff6d951SJohn Birrell 			dt_node_t *mnp;
17036ff6d951SJohn Birrell 
17046ff6d951SJohn Birrell 			dxp = idp->di_data;
17056ff6d951SJohn Birrell 			mnp = dt_xlator_member(dxp, dnp->dn_right->dn_string);
17066ff6d951SJohn Birrell 			assert(mnp != NULL);
17076ff6d951SJohn Birrell 
17086ff6d951SJohn Birrell 			dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
17096ff6d951SJohn Birrell 			dxp->dx_ident->di_id = dnp->dn_left->dn_reg;
17106ff6d951SJohn Birrell 
17116ff6d951SJohn Birrell 			dt_cg_node(mnp->dn_membexpr, dlp, drp);
17126ff6d951SJohn Birrell 			dnp->dn_reg = mnp->dn_membexpr->dn_reg;
17136ff6d951SJohn Birrell 			dt_cg_typecast(mnp->dn_membexpr, dnp, dlp, drp);
17146ff6d951SJohn Birrell 
17156ff6d951SJohn Birrell 			dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
17166ff6d951SJohn Birrell 			dxp->dx_ident->di_id = 0;
17176ff6d951SJohn Birrell 
17186ff6d951SJohn Birrell 			if (dnp->dn_left->dn_reg != -1)
17196ff6d951SJohn Birrell 				dt_regset_free(drp, dnp->dn_left->dn_reg);
17206ff6d951SJohn Birrell 			break;
17216ff6d951SJohn Birrell 		}
17226ff6d951SJohn Birrell 
17236ff6d951SJohn Birrell 		ctfp = dnp->dn_left->dn_ctfp;
17246ff6d951SJohn Birrell 		type = ctf_type_resolve(ctfp, dnp->dn_left->dn_type);
17256ff6d951SJohn Birrell 
17266ff6d951SJohn Birrell 		if (dnp->dn_op == DT_TOK_PTR) {
17276ff6d951SJohn Birrell 			type = ctf_type_reference(ctfp, type);
17286ff6d951SJohn Birrell 			type = ctf_type_resolve(ctfp, type);
17296ff6d951SJohn Birrell 		}
17306ff6d951SJohn Birrell 
17316ff6d951SJohn Birrell 		if ((ctfp = dt_cg_membinfo(octfp = ctfp, type,
17326ff6d951SJohn Birrell 		    dnp->dn_right->dn_string, &m)) == NULL) {
17336ff6d951SJohn Birrell 			yypcb->pcb_hdl->dt_ctferr = ctf_errno(octfp);
17346ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
17356ff6d951SJohn Birrell 		}
17366ff6d951SJohn Birrell 
17376ff6d951SJohn Birrell 		if (m.ctm_offset != 0) {
17386ff6d951SJohn Birrell 			if ((reg = dt_regset_alloc(drp)) == -1)
17396ff6d951SJohn Birrell 				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
17406ff6d951SJohn Birrell 
17416ff6d951SJohn Birrell 			/*
17426ff6d951SJohn Birrell 			 * If the offset is not aligned on a byte boundary, it
17436ff6d951SJohn Birrell 			 * is a bit-field member and we will extract the value
17446ff6d951SJohn Birrell 			 * bits below after we generate the appropriate load.
17456ff6d951SJohn Birrell 			 */
17466ff6d951SJohn Birrell 			dt_cg_setx(dlp, reg, m.ctm_offset / NBBY);
17476ff6d951SJohn Birrell 
17486ff6d951SJohn Birrell 			instr = DIF_INSTR_FMT(DIF_OP_ADD,
17496ff6d951SJohn Birrell 			    dnp->dn_left->dn_reg, reg, dnp->dn_left->dn_reg);
17506ff6d951SJohn Birrell 
17516ff6d951SJohn Birrell 			dt_irlist_append(dlp,
17526ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
17536ff6d951SJohn Birrell 			dt_regset_free(drp, reg);
17546ff6d951SJohn Birrell 		}
17556ff6d951SJohn Birrell 
17566ff6d951SJohn Birrell 		if (!(dnp->dn_flags & DT_NF_REF)) {
17576ff6d951SJohn Birrell 			uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
17586ff6d951SJohn Birrell 
17596ff6d951SJohn Birrell 			/*
17606ff6d951SJohn Birrell 			 * Save and restore DT_NF_USERLAND across dt_cg_load():
17616ff6d951SJohn Birrell 			 * we need the sign bit from dnp and the user bit from
17626ff6d951SJohn Birrell 			 * dnp->dn_left in order to get the proper opcode.
17636ff6d951SJohn Birrell 			 */
17646ff6d951SJohn Birrell 			dnp->dn_flags |=
17656ff6d951SJohn Birrell 			    (dnp->dn_left->dn_flags & DT_NF_USERLAND);
17666ff6d951SJohn Birrell 
17676ff6d951SJohn Birrell 			instr = DIF_INSTR_LOAD(dt_cg_load(dnp,
17686ff6d951SJohn Birrell 			    ctfp, m.ctm_type), dnp->dn_left->dn_reg,
17696ff6d951SJohn Birrell 			    dnp->dn_left->dn_reg);
17706ff6d951SJohn Birrell 
17716ff6d951SJohn Birrell 			dnp->dn_flags &= ~DT_NF_USERLAND;
17726ff6d951SJohn Birrell 			dnp->dn_flags |= ubit;
17736ff6d951SJohn Birrell 
17746ff6d951SJohn Birrell 			dt_irlist_append(dlp,
17756ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
17766ff6d951SJohn Birrell 
17776ff6d951SJohn Birrell 			if (dnp->dn_flags & DT_NF_BITFIELD)
17786ff6d951SJohn Birrell 				dt_cg_field_get(dnp, dlp, drp, ctfp, &m);
17796ff6d951SJohn Birrell 		}
17806ff6d951SJohn Birrell 
17816ff6d951SJohn Birrell 		dnp->dn_reg = dnp->dn_left->dn_reg;
17826ff6d951SJohn Birrell 		break;
17836ff6d951SJohn Birrell 
17846ff6d951SJohn Birrell 	case DT_TOK_STRING:
17856ff6d951SJohn Birrell 		if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
17866ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
17876ff6d951SJohn Birrell 
17886ff6d951SJohn Birrell 		assert(dnp->dn_kind == DT_NODE_STRING);
17896ff6d951SJohn Birrell 		stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string);
17906ff6d951SJohn Birrell 
17916ff6d951SJohn Birrell 		if (stroff == -1L)
17926ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
17936ff6d951SJohn Birrell 		if (stroff > DIF_STROFF_MAX)
17946ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG);
17956ff6d951SJohn Birrell 
17966ff6d951SJohn Birrell 		instr = DIF_INSTR_SETS((ulong_t)stroff, dnp->dn_reg);
17976ff6d951SJohn Birrell 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
17986ff6d951SJohn Birrell 		break;
17996ff6d951SJohn Birrell 
18006ff6d951SJohn Birrell 	case DT_TOK_IDENT:
18016ff6d951SJohn Birrell 		/*
18026ff6d951SJohn Birrell 		 * If the specified identifier is a variable on which we have
18036ff6d951SJohn Birrell 		 * set the code generator register flag, then this variable
18046ff6d951SJohn Birrell 		 * has already had code generated for it and saved in di_id.
18056ff6d951SJohn Birrell 		 * Allocate a new register and copy the existing value to it.
18066ff6d951SJohn Birrell 		 */
18076ff6d951SJohn Birrell 		if (dnp->dn_kind == DT_NODE_VAR &&
18086ff6d951SJohn Birrell 		    (dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) {
18096ff6d951SJohn Birrell 			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
18106ff6d951SJohn Birrell 				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
18116ff6d951SJohn Birrell 			instr = DIF_INSTR_MOV(dnp->dn_ident->di_id,
18126ff6d951SJohn Birrell 			    dnp->dn_reg);
18136ff6d951SJohn Birrell 			dt_irlist_append(dlp,
18146ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
18156ff6d951SJohn Birrell 			break;
18166ff6d951SJohn Birrell 		}
18176ff6d951SJohn Birrell 
18186ff6d951SJohn Birrell 		/*
18196ff6d951SJohn Birrell 		 * Identifiers can represent function calls, variable refs, or
18206ff6d951SJohn Birrell 		 * symbols.  First we check for inlined variables, and handle
18216ff6d951SJohn Birrell 		 * them by generating code for the inline parse tree.
18226ff6d951SJohn Birrell 		 */
18236ff6d951SJohn Birrell 		if (dnp->dn_kind == DT_NODE_VAR &&
18246ff6d951SJohn Birrell 		    (dnp->dn_ident->di_flags & DT_IDFLG_INLINE)) {
18256ff6d951SJohn Birrell 			dt_cg_inline(dnp, dlp, drp);
18266ff6d951SJohn Birrell 			break;
18276ff6d951SJohn Birrell 		}
18286ff6d951SJohn Birrell 
18296ff6d951SJohn Birrell 		switch (dnp->dn_kind) {
183018737969SJohn Birrell 		case DT_NODE_FUNC: {
183118737969SJohn Birrell 			dtrace_hdl_t *dtp = yypcb->pcb_hdl;
183218737969SJohn Birrell 
18336ff6d951SJohn Birrell 			if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) {
18346ff6d951SJohn Birrell 				dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be "
18356ff6d951SJohn Birrell 				    "called from a D expression (D program "
18366ff6d951SJohn Birrell 				    "context required)\n",
18376ff6d951SJohn Birrell 				    dt_idkind_name(idp->di_kind), idp->di_name);
18386ff6d951SJohn Birrell 			}
18396ff6d951SJohn Birrell 
184018737969SJohn Birrell 			switch (idp->di_id) {
184118737969SJohn Birrell 			case DIF_SUBR_TYPEREF:
184218737969SJohn Birrell 				dt_cg_func_typeref(dtp, dnp);
184318737969SJohn Birrell 				break;
184418737969SJohn Birrell 
184518737969SJohn Birrell 			default:
184618737969SJohn Birrell 				break;
184718737969SJohn Birrell 			}
184818737969SJohn Birrell 
18496ff6d951SJohn Birrell 			dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
18506ff6d951SJohn Birrell 
18516ff6d951SJohn Birrell 			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
18526ff6d951SJohn Birrell 				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
18536ff6d951SJohn Birrell 
18546ff6d951SJohn Birrell 			instr = DIF_INSTR_CALL(
18556ff6d951SJohn Birrell 			    dnp->dn_ident->di_id, dnp->dn_reg);
18566ff6d951SJohn Birrell 
18576ff6d951SJohn Birrell 			dt_irlist_append(dlp,
18586ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
18596ff6d951SJohn Birrell 
18606ff6d951SJohn Birrell 			break;
186118737969SJohn Birrell 		}
18626ff6d951SJohn Birrell 
18636ff6d951SJohn Birrell 		case DT_NODE_VAR:
18646ff6d951SJohn Birrell 			if (dnp->dn_ident->di_kind == DT_IDENT_XLSOU ||
18656ff6d951SJohn Birrell 			    dnp->dn_ident->di_kind == DT_IDENT_XLPTR) {
18666ff6d951SJohn Birrell 				/*
18676ff6d951SJohn Birrell 				 * This can only happen if we have translated
18686ff6d951SJohn Birrell 				 * args[].  See dt_idcook_args() for details.
18696ff6d951SJohn Birrell 				 */
18706ff6d951SJohn Birrell 				assert(dnp->dn_ident->di_id == DIF_VAR_ARGS);
18716ff6d951SJohn Birrell 				dt_cg_array_op(dnp, dlp, drp);
18726ff6d951SJohn Birrell 				break;
18736ff6d951SJohn Birrell 			}
18746ff6d951SJohn Birrell 
18756ff6d951SJohn Birrell 			if (dnp->dn_ident->di_kind == DT_IDENT_ARRAY) {
18766ff6d951SJohn Birrell 				if (dnp->dn_ident->di_id > DIF_VAR_ARRAY_MAX)
18776ff6d951SJohn Birrell 					dt_cg_assoc_op(dnp, dlp, drp);
18786ff6d951SJohn Birrell 				else
18796ff6d951SJohn Birrell 					dt_cg_array_op(dnp, dlp, drp);
18806ff6d951SJohn Birrell 				break;
18816ff6d951SJohn Birrell 			}
18826ff6d951SJohn Birrell 
18836ff6d951SJohn Birrell 			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
18846ff6d951SJohn Birrell 				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
18856ff6d951SJohn Birrell 
18866ff6d951SJohn Birrell 			if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)
18876ff6d951SJohn Birrell 				op = DIF_OP_LDLS;
18886ff6d951SJohn Birrell 			else if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
18896ff6d951SJohn Birrell 				op = DIF_OP_LDTS;
18906ff6d951SJohn Birrell 			else
18916ff6d951SJohn Birrell 				op = DIF_OP_LDGS;
18926ff6d951SJohn Birrell 
18936ff6d951SJohn Birrell 			dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;
18946ff6d951SJohn Birrell 
18956ff6d951SJohn Birrell 			instr = DIF_INSTR_LDV(op,
18966ff6d951SJohn Birrell 			    dnp->dn_ident->di_id, dnp->dn_reg);
18976ff6d951SJohn Birrell 
18986ff6d951SJohn Birrell 			dt_irlist_append(dlp,
18996ff6d951SJohn Birrell 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
19006ff6d951SJohn Birrell 			break;
19016ff6d951SJohn Birrell 
19026ff6d951SJohn Birrell 		case DT_NODE_SYM: {
19036ff6d951SJohn Birrell 			dtrace_hdl_t *dtp = yypcb->pcb_hdl;
19046ff6d951SJohn Birrell 			dtrace_syminfo_t *sip = dnp->dn_ident->di_data;
19056ff6d951SJohn Birrell 			GElf_Sym sym;
19066ff6d951SJohn Birrell 
19076ff6d951SJohn Birrell 			if (dtrace_lookup_by_name(dtp,
19086ff6d951SJohn Birrell 			    sip->dts_object, sip->dts_name, &sym, NULL) == -1) {
19096ff6d951SJohn Birrell 				xyerror(D_UNKNOWN, "cg failed for symbol %s`%s:"
19106ff6d951SJohn Birrell 				    " %s\n", sip->dts_object, sip->dts_name,
19116ff6d951SJohn Birrell 				    dtrace_errmsg(dtp, dtrace_errno(dtp)));
19126ff6d951SJohn Birrell 			}
19136ff6d951SJohn Birrell 
19146ff6d951SJohn Birrell 			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
19156ff6d951SJohn Birrell 				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
19166ff6d951SJohn Birrell 
19176ff6d951SJohn Birrell 			dt_cg_xsetx(dlp, dnp->dn_ident,
19186ff6d951SJohn Birrell 			    DT_LBL_NONE, dnp->dn_reg, sym.st_value);
19196ff6d951SJohn Birrell 
19206ff6d951SJohn Birrell 			if (!(dnp->dn_flags & DT_NF_REF)) {
19216ff6d951SJohn Birrell 				instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,
19226ff6d951SJohn Birrell 				    dnp->dn_type), dnp->dn_reg, dnp->dn_reg);
19236ff6d951SJohn Birrell 				dt_irlist_append(dlp,
19246ff6d951SJohn Birrell 				    dt_cg_node_alloc(DT_LBL_NONE, instr));
19256ff6d951SJohn Birrell 			}
19266ff6d951SJohn Birrell 			break;
19276ff6d951SJohn Birrell 		}
19286ff6d951SJohn Birrell 
19296ff6d951SJohn Birrell 		default:
19306ff6d951SJohn Birrell 			xyerror(D_UNKNOWN, "internal error -- node type %u is "
19316ff6d951SJohn Birrell 			    "not valid for an identifier\n", dnp->dn_kind);
19326ff6d951SJohn Birrell 		}
19336ff6d951SJohn Birrell 		break;
19346ff6d951SJohn Birrell 
19356ff6d951SJohn Birrell 	case DT_TOK_INT:
19366ff6d951SJohn Birrell 		if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
19376ff6d951SJohn Birrell 			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
19386ff6d951SJohn Birrell 
19396ff6d951SJohn Birrell 		dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value);
19406ff6d951SJohn Birrell 		break;
19416ff6d951SJohn Birrell 
19426ff6d951SJohn Birrell 	default:
19436ff6d951SJohn Birrell 		xyerror(D_UNKNOWN, "internal error -- token type %u is not a "
19446ff6d951SJohn Birrell 		    "valid D compilation token\n", dnp->dn_op);
19456ff6d951SJohn Birrell 	}
19466ff6d951SJohn Birrell }
19476ff6d951SJohn Birrell 
19486ff6d951SJohn Birrell void
19496ff6d951SJohn Birrell dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
19506ff6d951SJohn Birrell {
19516ff6d951SJohn Birrell 	dif_instr_t instr;
19526ff6d951SJohn Birrell 	dt_xlator_t *dxp;
19536ff6d951SJohn Birrell 
19546ff6d951SJohn Birrell 	if (pcb->pcb_regs == NULL && (pcb->pcb_regs =
19556ff6d951SJohn Birrell 	    dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL)
19566ff6d951SJohn Birrell 		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
19576ff6d951SJohn Birrell 
19586ff6d951SJohn Birrell 	dt_regset_reset(pcb->pcb_regs);
19596ff6d951SJohn Birrell 	(void) dt_regset_alloc(pcb->pcb_regs); /* allocate %r0 */
19606ff6d951SJohn Birrell 
19616ff6d951SJohn Birrell 	if (pcb->pcb_inttab != NULL)
19626ff6d951SJohn Birrell 		dt_inttab_destroy(pcb->pcb_inttab);
19636ff6d951SJohn Birrell 
19646ff6d951SJohn Birrell 	if ((pcb->pcb_inttab = dt_inttab_create(yypcb->pcb_hdl)) == NULL)
19656ff6d951SJohn Birrell 		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
19666ff6d951SJohn Birrell 
19676ff6d951SJohn Birrell 	if (pcb->pcb_strtab != NULL)
19686ff6d951SJohn Birrell 		dt_strtab_destroy(pcb->pcb_strtab);
19696ff6d951SJohn Birrell 
19706ff6d951SJohn Birrell 	if ((pcb->pcb_strtab = dt_strtab_create(BUFSIZ)) == NULL)
19716ff6d951SJohn Birrell 		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
19726ff6d951SJohn Birrell 
19736ff6d951SJohn Birrell 	dt_irlist_destroy(&pcb->pcb_ir);
19746ff6d951SJohn Birrell 	dt_irlist_create(&pcb->pcb_ir);
19756ff6d951SJohn Birrell 
19766ff6d951SJohn Birrell 	assert(pcb->pcb_dret == NULL);
19776ff6d951SJohn Birrell 	pcb->pcb_dret = dnp;
19786ff6d951SJohn Birrell 
19796ff6d951SJohn Birrell 	if (dt_node_is_dynamic(dnp)) {
19806ff6d951SJohn Birrell 		dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result "
19816ff6d951SJohn Birrell 		    "of dynamic type\n");
19826ff6d951SJohn Birrell 	}
19836ff6d951SJohn Birrell 
19846ff6d951SJohn Birrell 	/*
19856ff6d951SJohn Birrell 	 * If we're generating code for a translator body, assign the input
19866ff6d951SJohn Birrell 	 * parameter to the first available register (i.e. caller passes %r1).
19876ff6d951SJohn Birrell 	 */
19886ff6d951SJohn Birrell 	if (dnp->dn_kind == DT_NODE_MEMBER) {
19896ff6d951SJohn Birrell 		dxp = dnp->dn_membxlator;
19906ff6d951SJohn Birrell 		dnp = dnp->dn_membexpr;
19916ff6d951SJohn Birrell 
19926ff6d951SJohn Birrell 		dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
19936ff6d951SJohn Birrell 		dxp->dx_ident->di_id = dt_regset_alloc(pcb->pcb_regs);
19946ff6d951SJohn Birrell 	}
19956ff6d951SJohn Birrell 
19966ff6d951SJohn Birrell 	dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs);
19976ff6d951SJohn Birrell 	instr = DIF_INSTR_RET(dnp->dn_reg);
19986ff6d951SJohn Birrell 	dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
19996ff6d951SJohn Birrell 	dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr));
20006ff6d951SJohn Birrell 
20016ff6d951SJohn Birrell 	if (dnp->dn_kind == DT_NODE_MEMBER) {
20026ff6d951SJohn Birrell 		dt_regset_free(pcb->pcb_regs, dxp->dx_ident->di_id);
20036ff6d951SJohn Birrell 		dxp->dx_ident->di_id = 0;
20046ff6d951SJohn Birrell 		dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
20056ff6d951SJohn Birrell 	}
20066ff6d951SJohn Birrell }
2007