17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22e5803b76SAdam H. Leventhal 
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
28e5803b76SAdam H. Leventhal /*
29e5803b76SAdam H. Leventhal  * Copyright (c) 2012 by Delphix. All rights reserved.
3056a20711SPatrick Mooney  * Copyright 2017 Joyent, Inc.
31*6eeafb34SRobert Mustacchi  * Copyright 2022 Oxide Computer Company
32e5803b76SAdam H. Leventhal  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
367c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <stdlib.h>
407c478bd9Sstevel@tonic-gate #include <setjmp.h>
417c478bd9Sstevel@tonic-gate #include <assert.h>
427c478bd9Sstevel@tonic-gate #include <errno.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <dt_impl.h>
457c478bd9Sstevel@tonic-gate #include <dt_grammar.h>
467c478bd9Sstevel@tonic-gate #include <dt_parser.h>
477c478bd9Sstevel@tonic-gate #include <dt_provider.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *);
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static dt_irnode_t *
dt_cg_node_alloc(uint_t label,dif_instr_t instr)527c478bd9Sstevel@tonic-gate dt_cg_node_alloc(uint_t label, dif_instr_t instr)
537c478bd9Sstevel@tonic-gate {
547c478bd9Sstevel@tonic-gate 	dt_irnode_t *dip = malloc(sizeof (dt_irnode_t));
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	if (dip == NULL)
577c478bd9Sstevel@tonic-gate 		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	dip->di_label = label;
607c478bd9Sstevel@tonic-gate 	dip->di_instr = instr;
611a7c1b72Smws 	dip->di_extern = NULL;
627c478bd9Sstevel@tonic-gate 	dip->di_next = NULL;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	return (dip);
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate  * Code generator wrapper function for ctf_member_info.  If we are given a
697c478bd9Sstevel@tonic-gate  * reference to a forward declaration tag, search the entire type space for
707c478bd9Sstevel@tonic-gate  * the actual definition and then call ctf_member_info on the result.
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate static ctf_file_t *
dt_cg_membinfo(ctf_file_t * fp,ctf_id_t type,const char * s,ctf_membinfo_t * mp)737c478bd9Sstevel@tonic-gate dt_cg_membinfo(ctf_file_t *fp, ctf_id_t type, const char *s, ctf_membinfo_t *mp)
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate 	while (ctf_type_kind(fp, type) == CTF_K_FORWARD) {
767c478bd9Sstevel@tonic-gate 		char n[DT_TYPE_NAMELEN];
777c478bd9Sstevel@tonic-gate 		dtrace_typeinfo_t dtt;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 		if (ctf_type_name(fp, type, n, sizeof (n)) == NULL ||
807c478bd9Sstevel@tonic-gate 		    dt_type_lookup(n, &dtt) == -1 || (
817c478bd9Sstevel@tonic-gate 		    dtt.dtt_ctfp == fp && dtt.dtt_type == type))
827c478bd9Sstevel@tonic-gate 			break; /* unable to improve our position */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 		fp = dtt.dtt_ctfp;
857c478bd9Sstevel@tonic-gate 		type = ctf_type_resolve(fp, dtt.dtt_type);
867c478bd9Sstevel@tonic-gate 	}
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	if (ctf_member_info(fp, type, s, mp) == CTF_ERR)
897c478bd9Sstevel@tonic-gate 		return (NULL); /* ctf_errno is set for us */
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	return (fp);
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate static void
dt_cg_xsetx(dt_irlist_t * dlp,dt_ident_t * idp,uint_t lbl,int reg,uint64_t x)957c478bd9Sstevel@tonic-gate dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x)
967c478bd9Sstevel@tonic-gate {
977c478bd9Sstevel@tonic-gate 	int flag = idp != NULL ? DT_INT_PRIVATE : DT_INT_SHARED;
987c478bd9Sstevel@tonic-gate 	int intoff = dt_inttab_insert(yypcb->pcb_inttab, x, flag);
997c478bd9Sstevel@tonic-gate 	dif_instr_t instr = DIF_INSTR_SETX((uint_t)intoff, reg);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	if (intoff == -1)
1027c478bd9Sstevel@tonic-gate 		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	if (intoff > DIF_INTOFF_MAX)
1057c478bd9Sstevel@tonic-gate 		longjmp(yypcb->pcb_jmpbuf, EDT_INT2BIG);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl, instr));
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	if (idp != NULL)
1101a7c1b72Smws 		dlp->dl_last->di_extern = idp;
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static void
dt_cg_setx(dt_irlist_t * dlp,int reg,uint64_t x)1147c478bd9Sstevel@tonic-gate dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate 	dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate  * When loading bit-fields, we want to convert a byte count in the range
1217c478bd9Sstevel@tonic-gate  * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc).  The clp2() function
1227c478bd9Sstevel@tonic-gate  * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static size_t
clp2(size_t x)1257c478bd9Sstevel@tonic-gate clp2(size_t x)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	x--;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	x |= (x >> 1);
1307c478bd9Sstevel@tonic-gate 	x |= (x >> 2);
1317c478bd9Sstevel@tonic-gate 	x |= (x >> 4);
1327c478bd9Sstevel@tonic-gate 	x |= (x >> 8);
1337c478bd9Sstevel@tonic-gate 	x |= (x >> 16);
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	return (x + 1);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate  * Lookup the correct load opcode to use for the specified node and CTF type.
1407c478bd9Sstevel@tonic-gate  * We determine the size and convert it to a 3-bit index.  Our lookup table
1417c478bd9Sstevel@tonic-gate  * is constructed to use a 5-bit index, consisting of the 3-bit size 0-7, a
1427c478bd9Sstevel@tonic-gate  * bit for the sign, and a bit for userland address.  For example, a 4-byte
1437c478bd9Sstevel@tonic-gate  * signed load from userland would be at the following table index:
1447c478bd9Sstevel@tonic-gate  * user=1 sign=1 size=4 => binary index 11011 = decimal index 27
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate static uint_t
dt_cg_load(dt_node_t * dnp,ctf_file_t * ctfp,ctf_id_t type)1477c478bd9Sstevel@tonic-gate dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	static const uint_t ops[] = {
1507c478bd9Sstevel@tonic-gate 		DIF_OP_LDUB,	DIF_OP_LDUH,	0,	DIF_OP_LDUW,
1517c478bd9Sstevel@tonic-gate 		0,		0,		0,	DIF_OP_LDX,
1527c478bd9Sstevel@tonic-gate 		DIF_OP_LDSB,	DIF_OP_LDSH,	0,	DIF_OP_LDSW,
1537c478bd9Sstevel@tonic-gate 		0,		0,		0,	DIF_OP_LDX,
1547c478bd9Sstevel@tonic-gate 		DIF_OP_ULDUB,	DIF_OP_ULDUH,	0,	DIF_OP_ULDUW,
1557c478bd9Sstevel@tonic-gate 		0,		0,		0,	DIF_OP_ULDX,
1567c478bd9Sstevel@tonic-gate 		DIF_OP_ULDSB,	DIF_OP_ULDSH,	0,	DIF_OP_ULDSW,
1577c478bd9Sstevel@tonic-gate 		0,		0,		0,	DIF_OP_ULDX,
1587c478bd9Sstevel@tonic-gate 	};
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	ctf_encoding_t e;
1617c478bd9Sstevel@tonic-gate 	ssize_t size;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/*
164*6eeafb34SRobert Mustacchi 	 * If we're loading a bit-field, we find the power-of-two that spans the
165*6eeafb34SRobert Mustacchi 	 * full value. To do this we count the number of bytes that contain a
166*6eeafb34SRobert Mustacchi 	 * portion of the bit-field.
1677c478bd9Sstevel@tonic-gate 	 */
1687c478bd9Sstevel@tonic-gate 	if ((dnp->dn_flags & DT_NF_BITFIELD) &&
169*6eeafb34SRobert Mustacchi 	    ctf_type_encoding(ctfp, type, &e) != CTF_ERR) {
170*6eeafb34SRobert Mustacchi 		uint_t nbits = e.cte_bits + (dnp->dn_bitoff % NBBY);
171*6eeafb34SRobert Mustacchi 		size = clp2(P2ROUNDUP(nbits, NBBY) / NBBY);
172*6eeafb34SRobert Mustacchi 	} else {
1737c478bd9Sstevel@tonic-gate 		size = ctf_type_size(ctfp, type);
174*6eeafb34SRobert Mustacchi 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	if (size < 1 || size > 8 || (size & (size - 1)) != 0) {
1777c478bd9Sstevel@tonic-gate 		xyerror(D_UNKNOWN, "internal error -- cg cannot load "
1787c478bd9Sstevel@tonic-gate 		    "size %ld when passed by value\n", (long)size);
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	size--; /* convert size to 3-bit index */
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	if (dnp->dn_flags & DT_NF_SIGNED)
1847c478bd9Sstevel@tonic-gate 		size |= 0x08;
1857c478bd9Sstevel@tonic-gate 	if (dnp->dn_flags & DT_NF_USERLAND)
1867c478bd9Sstevel@tonic-gate 		size |= 0x10;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	return (ops[size]);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate static void
dt_cg_ptrsize(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op,int dreg)1927c478bd9Sstevel@tonic-gate dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
1937c478bd9Sstevel@tonic-gate     uint_t op, int dreg)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	ctf_file_t *ctfp = dnp->dn_ctfp;
1967c478bd9Sstevel@tonic-gate 	ctf_arinfo_t r;
1977c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
1987c478bd9Sstevel@tonic-gate 	ctf_id_t type;
1997c478bd9Sstevel@tonic-gate 	uint_t kind;
2007c478bd9Sstevel@tonic-gate 	ssize_t size;
2017c478bd9Sstevel@tonic-gate 	int sreg;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	type = ctf_type_resolve(ctfp, dnp->dn_type);
2047c478bd9Sstevel@tonic-gate 	kind = ctf_type_kind(ctfp, type);
2057c478bd9Sstevel@tonic-gate 	assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	if (kind == CTF_K_ARRAY) {
2087c478bd9Sstevel@tonic-gate 		if (ctf_array_info(ctfp, type, &r) != 0) {
2097c478bd9Sstevel@tonic-gate 			yypcb->pcb_hdl->dt_ctferr = ctf_errno(ctfp);
2107c478bd9Sstevel@tonic-gate 			longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
2117c478bd9Sstevel@tonic-gate 		}
2127c478bd9Sstevel@tonic-gate 		type = r.ctr_contents;
2137c478bd9Sstevel@tonic-gate 	} else
2147c478bd9Sstevel@tonic-gate 		type = ctf_type_reference(ctfp, type);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if ((size = ctf_type_size(ctfp, type)) == 1)
2177c478bd9Sstevel@tonic-gate 		return; /* multiply or divide by one can be omitted */
2187c478bd9Sstevel@tonic-gate 
219e5803b76SAdam H. Leventhal 	sreg = dt_regset_alloc(drp);
2207c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, sreg, size);
2217c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(op, dreg, sreg, dreg);
2227c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2237c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, sreg);
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate /*
2277c478bd9Sstevel@tonic-gate  * If the result of a "." or "->" operation is a bit-field, we use this routine
2287c478bd9Sstevel@tonic-gate  * to generate an epilogue to the load instruction that extracts the value.  In
2297c478bd9Sstevel@tonic-gate  * the diagrams below the "ld??" is the load instruction that is generated to
2307c478bd9Sstevel@tonic-gate  * load the containing word that is generating prior to calling this function.
2317c478bd9Sstevel@tonic-gate  *
2327c478bd9Sstevel@tonic-gate  * Epilogue for unsigned fields:	Epilogue for signed fields:
2337c478bd9Sstevel@tonic-gate  *
2347c478bd9Sstevel@tonic-gate  * ldu?	[r1], r1			lds? [r1], r1
2357c478bd9Sstevel@tonic-gate  * setx	USHIFT, r2			setx 64 - SSHIFT, r2
2367c478bd9Sstevel@tonic-gate  * srl	r1, r2, r1			sll  r1, r2, r1
2377c478bd9Sstevel@tonic-gate  * setx	(1 << bits) - 1, r2		setx 64 - bits, r2
2387c478bd9Sstevel@tonic-gate  * and	r1, r2, r1			sra  r1, r2, r1
2397c478bd9Sstevel@tonic-gate  *
2407c478bd9Sstevel@tonic-gate  * The *SHIFT constants above changes value depending on the endian-ness of our
2417c478bd9Sstevel@tonic-gate  * target architecture.  Refer to the comments below for more details.
2427c478bd9Sstevel@tonic-gate  */
2437c478bd9Sstevel@tonic-gate static void
dt_cg_field_get(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,ctf_file_t * fp,const ctf_membinfo_t * mp)2447c478bd9Sstevel@tonic-gate dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
2457c478bd9Sstevel@tonic-gate     ctf_file_t *fp, const ctf_membinfo_t *mp)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	ctf_encoding_t e;
2487c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
2497c478bd9Sstevel@tonic-gate 	uint64_t shift;
2507c478bd9Sstevel@tonic-gate 	int r1, r2;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if (ctf_type_encoding(fp, mp->ctm_type, &e) != 0 || e.cte_bits > 64) {
2537c478bd9Sstevel@tonic-gate 		xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "
2547c478bd9Sstevel@tonic-gate 		    "bits %u\n", mp->ctm_offset, mp->ctm_type, e.cte_bits);
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT);
2587c478bd9Sstevel@tonic-gate 	r1 = dnp->dn_left->dn_reg;
259e5803b76SAdam H. Leventhal 	r2 = dt_regset_alloc(drp);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	/*
2627c478bd9Sstevel@tonic-gate 	 * On little-endian architectures, ctm_offset counts from the right so
2637c478bd9Sstevel@tonic-gate 	 * ctm_offset % NBBY itself is the amount we want to shift right to
2647c478bd9Sstevel@tonic-gate 	 * move the value bits to the little end of the register to mask them.
2657c478bd9Sstevel@tonic-gate 	 * On big-endian architectures, ctm_offset counts from the left so we
2667c478bd9Sstevel@tonic-gate 	 * must subtract (ctm_offset % NBBY + cte_bits) from the size in bits
2677c478bd9Sstevel@tonic-gate 	 * we used for the load.  The size of our load in turn is found by
2687c478bd9Sstevel@tonic-gate 	 * rounding cte_bits up to a byte boundary and then finding the
2697c478bd9Sstevel@tonic-gate 	 * nearest power of two to this value (see clp2(), above).  These
2707c478bd9Sstevel@tonic-gate 	 * properties are used to compute shift as USHIFT or SSHIFT, below.
2717c478bd9Sstevel@tonic-gate 	 */
2727c478bd9Sstevel@tonic-gate 	if (dnp->dn_flags & DT_NF_SIGNED) {
2737c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN
2747c478bd9Sstevel@tonic-gate 		shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
2757c478bd9Sstevel@tonic-gate 		    mp->ctm_offset % NBBY;
2767c478bd9Sstevel@tonic-gate #else
2777c478bd9Sstevel@tonic-gate 		shift = mp->ctm_offset % NBBY + e.cte_bits;
2787c478bd9Sstevel@tonic-gate #endif
2797c478bd9Sstevel@tonic-gate 		dt_cg_setx(dlp, r2, 64 - shift);
2807c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_FMT(DIF_OP_SLL, r1, r2, r1);
2817c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		dt_cg_setx(dlp, r2, 64 - e.cte_bits);
2847c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_FMT(DIF_OP_SRA, r1, r2, r1);
2857c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2867c478bd9Sstevel@tonic-gate 	} else {
2877c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN
2887c478bd9Sstevel@tonic-gate 		shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
2897c478bd9Sstevel@tonic-gate 		    (mp->ctm_offset % NBBY + e.cte_bits);
2907c478bd9Sstevel@tonic-gate #else
2917c478bd9Sstevel@tonic-gate 		shift = mp->ctm_offset % NBBY;
2927c478bd9Sstevel@tonic-gate #endif
2937c478bd9Sstevel@tonic-gate 		dt_cg_setx(dlp, r2, shift);
2947c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_FMT(DIF_OP_SRL, r1, r2, r1);
2957c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 		dt_cg_setx(dlp, r2, (1ULL << e.cte_bits) - 1);
2987c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);
2997c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, r2);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate /*
3067c478bd9Sstevel@tonic-gate  * If the destination of a store operation is a bit-field, we use this routine
3077c478bd9Sstevel@tonic-gate  * to generate a prologue to the store instruction that loads the surrounding
3087c478bd9Sstevel@tonic-gate  * bits, clears the destination field, and ORs in the new value of the field.
3097c478bd9Sstevel@tonic-gate  * In the diagram below the "st?" is the store instruction that is generated to
3107c478bd9Sstevel@tonic-gate  * store the containing word that is generating after calling this function.
3117c478bd9Sstevel@tonic-gate  *
3127c478bd9Sstevel@tonic-gate  * ld	[dst->dn_reg], r1
3137c478bd9Sstevel@tonic-gate  * setx	~(((1 << cte_bits) - 1) << (ctm_offset % NBBY)), r2
3147c478bd9Sstevel@tonic-gate  * and	r1, r2, r1
3157c478bd9Sstevel@tonic-gate  *
3167c478bd9Sstevel@tonic-gate  * setx	(1 << cte_bits) - 1, r2
3177c478bd9Sstevel@tonic-gate  * and	src->dn_reg, r2, r2
3187c478bd9Sstevel@tonic-gate  * setx ctm_offset % NBBY, r3
3197c478bd9Sstevel@tonic-gate  * sll	r2, r3, r2
3207c478bd9Sstevel@tonic-gate  *
3217c478bd9Sstevel@tonic-gate  * or	r1, r2, r1
3227c478bd9Sstevel@tonic-gate  * st?	r1, [dst->dn_reg]
3237c478bd9Sstevel@tonic-gate  *
3247c478bd9Sstevel@tonic-gate  * This routine allocates a new register to hold the value to be stored and
3257c478bd9Sstevel@tonic-gate  * returns it.  The caller is responsible for freeing this register later.
3267c478bd9Sstevel@tonic-gate  */
3277c478bd9Sstevel@tonic-gate static int
dt_cg_field_set(dt_node_t * src,dt_irlist_t * dlp,dt_regset_t * drp,dt_node_t * dst)3287c478bd9Sstevel@tonic-gate dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp,
3297c478bd9Sstevel@tonic-gate     dt_regset_t *drp, dt_node_t *dst)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate 	uint64_t cmask, fmask, shift;
3327c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
3337c478bd9Sstevel@tonic-gate 	int r1, r2, r3;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	ctf_membinfo_t m;
3367c478bd9Sstevel@tonic-gate 	ctf_encoding_t e;
3377c478bd9Sstevel@tonic-gate 	ctf_file_t *fp, *ofp;
3387c478bd9Sstevel@tonic-gate 	ctf_id_t type;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	assert(dst->dn_op == DT_TOK_PTR || dst->dn_op == DT_TOK_DOT);
3417c478bd9Sstevel@tonic-gate 	assert(dst->dn_right->dn_kind == DT_NODE_IDENT);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	fp = dst->dn_left->dn_ctfp;
3447c478bd9Sstevel@tonic-gate 	type = ctf_type_resolve(fp, dst->dn_left->dn_type);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	if (dst->dn_op == DT_TOK_PTR) {
3477c478bd9Sstevel@tonic-gate 		type = ctf_type_reference(fp, type);
3487c478bd9Sstevel@tonic-gate 		type = ctf_type_resolve(fp, type);
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	if ((fp = dt_cg_membinfo(ofp = fp, type,
3527c478bd9Sstevel@tonic-gate 	    dst->dn_right->dn_string, &m)) == NULL) {
3537c478bd9Sstevel@tonic-gate 		yypcb->pcb_hdl->dt_ctferr = ctf_errno(ofp);
3547c478bd9Sstevel@tonic-gate 		longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	if (ctf_type_encoding(fp, m.ctm_type, &e) != 0 || e.cte_bits > 64) {
3587c478bd9Sstevel@tonic-gate 		xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "
3597c478bd9Sstevel@tonic-gate 		    "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits);
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 
362e5803b76SAdam H. Leventhal 	r1 = dt_regset_alloc(drp);
363e5803b76SAdam H. Leventhal 	r2 = dt_regset_alloc(drp);
364e5803b76SAdam H. Leventhal 	r3 = dt_regset_alloc(drp);
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	/*
3677c478bd9Sstevel@tonic-gate 	 * Compute shifts and masks.  We need to compute "shift" as the amount
3687c478bd9Sstevel@tonic-gate 	 * we need to shift left to position our field in the containing word.
3697c478bd9Sstevel@tonic-gate 	 * Refer to the comments in dt_cg_field_get(), above, for more info.
3707c478bd9Sstevel@tonic-gate 	 * We then compute fmask as the mask that truncates the value in the
3717c478bd9Sstevel@tonic-gate 	 * input register to width cte_bits, and cmask as the mask used to
3727c478bd9Sstevel@tonic-gate 	 * pass through the containing bits and zero the field bits.
3737c478bd9Sstevel@tonic-gate 	 */
3747c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN
3757c478bd9Sstevel@tonic-gate 	shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
3767c478bd9Sstevel@tonic-gate 	    (m.ctm_offset % NBBY + e.cte_bits);
3777c478bd9Sstevel@tonic-gate #else
3787c478bd9Sstevel@tonic-gate 	shift = m.ctm_offset % NBBY;
3797c478bd9Sstevel@tonic-gate #endif
3807c478bd9Sstevel@tonic-gate 	fmask = (1ULL << e.cte_bits) - 1;
3817c478bd9Sstevel@tonic-gate 	cmask = ~(fmask << shift);
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_LOAD(
3847c478bd9Sstevel@tonic-gate 	    dt_cg_load(dst, fp, m.ctm_type), dst->dn_reg, r1);
3857c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, r2, cmask);
3887c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);
3897c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, r2, fmask);
3927c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(DIF_OP_AND, src->dn_reg, r2, r2);
3937c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, r3, shift);
3967c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(DIF_OP_SLL, r2, r3, r2);
3977c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(DIF_OP_OR, r1, r2, r1);
4007c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, r3);
4037c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, r2);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	return (r1);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate static void
dt_cg_store(dt_node_t * src,dt_irlist_t * dlp,dt_regset_t * drp,dt_node_t * dst)4097c478bd9Sstevel@tonic-gate dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	ctf_encoding_t e;
4127c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
4137c478bd9Sstevel@tonic-gate 	size_t size;
4147c478bd9Sstevel@tonic-gate 	int reg;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	/*
4177c478bd9Sstevel@tonic-gate 	 * If we're loading a bit-field, the size of our store is found by
4187c478bd9Sstevel@tonic-gate 	 * rounding dst's cte_bits up to a byte boundary and then finding the
4197c478bd9Sstevel@tonic-gate 	 * nearest power of two to this value (see clp2(), above).
4207c478bd9Sstevel@tonic-gate 	 */
4217c478bd9Sstevel@tonic-gate 	if ((dst->dn_flags & DT_NF_BITFIELD) &&
4227c478bd9Sstevel@tonic-gate 	    ctf_type_encoding(dst->dn_ctfp, dst->dn_type, &e) != CTF_ERR)
4237c478bd9Sstevel@tonic-gate 		size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);
4247c478bd9Sstevel@tonic-gate 	else
4257c478bd9Sstevel@tonic-gate 		size = dt_node_type_size(src);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (src->dn_flags & DT_NF_REF) {
428e5803b76SAdam H. Leventhal 		reg = dt_regset_alloc(drp);
4297c478bd9Sstevel@tonic-gate 		dt_cg_setx(dlp, reg, size);
4307c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg);
4317c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4327c478bd9Sstevel@tonic-gate 		dt_regset_free(drp, reg);
4337c478bd9Sstevel@tonic-gate 	} else {
4347c478bd9Sstevel@tonic-gate 		if (dst->dn_flags & DT_NF_BITFIELD)
4357c478bd9Sstevel@tonic-gate 			reg = dt_cg_field_set(src, dlp, drp, dst);
4367c478bd9Sstevel@tonic-gate 		else
4377c478bd9Sstevel@tonic-gate 			reg = src->dn_reg;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 		switch (size) {
4407c478bd9Sstevel@tonic-gate 		case 1:
4417c478bd9Sstevel@tonic-gate 			instr = DIF_INSTR_STORE(DIF_OP_STB, reg, dst->dn_reg);
4427c478bd9Sstevel@tonic-gate 			break;
4437c478bd9Sstevel@tonic-gate 		case 2:
4447c478bd9Sstevel@tonic-gate 			instr = DIF_INSTR_STORE(DIF_OP_STH, reg, dst->dn_reg);
4457c478bd9Sstevel@tonic-gate 			break;
4467c478bd9Sstevel@tonic-gate 		case 4:
4477c478bd9Sstevel@tonic-gate 			instr = DIF_INSTR_STORE(DIF_OP_STW, reg, dst->dn_reg);
4487c478bd9Sstevel@tonic-gate 			break;
4497c478bd9Sstevel@tonic-gate 		case 8:
4507c478bd9Sstevel@tonic-gate 			instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg);
4517c478bd9Sstevel@tonic-gate 			break;
4527c478bd9Sstevel@tonic-gate 		default:
4537c478bd9Sstevel@tonic-gate 			xyerror(D_UNKNOWN, "internal error -- cg cannot store "
4547c478bd9Sstevel@tonic-gate 			    "size %lu when passed by value\n", (ulong_t)size);
4557c478bd9Sstevel@tonic-gate 		}
4567c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 		if (dst->dn_flags & DT_NF_BITFIELD)
4597c478bd9Sstevel@tonic-gate 			dt_regset_free(drp, reg);
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate /*
4647c478bd9Sstevel@tonic-gate  * Generate code for a typecast or for argument promotion from the type of the
4657c478bd9Sstevel@tonic-gate  * actual to the type of the formal.  We need to generate code for casts when
4667c478bd9Sstevel@tonic-gate  * a scalar type is being narrowed or changing signed-ness.  We first shift the
4677c478bd9Sstevel@tonic-gate  * desired bits high (losing excess bits if narrowing) and then shift them down
4687c478bd9Sstevel@tonic-gate  * using logical shift (unsigned result) or arithmetic shift (signed result).
4697c478bd9Sstevel@tonic-gate  */
4707c478bd9Sstevel@tonic-gate static void
dt_cg_typecast(const dt_node_t * src,const dt_node_t * dst,dt_irlist_t * dlp,dt_regset_t * drp)4717c478bd9Sstevel@tonic-gate dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
4727c478bd9Sstevel@tonic-gate     dt_irlist_t *dlp, dt_regset_t *drp)
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate 	size_t srcsize = dt_node_type_size(src);
4757c478bd9Sstevel@tonic-gate 	size_t dstsize = dt_node_type_size(dst);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
478e5803b76SAdam H. Leventhal 	int rg;
4797c478bd9Sstevel@tonic-gate 
480e5803b76SAdam H. Leventhal 	if (!dt_node_is_scalar(dst))
481e5803b76SAdam H. Leventhal 		return; /* not a scalar */
482e5803b76SAdam H. Leventhal 	if (dstsize == srcsize &&
4832e055267SBryan Cantrill 	    ((src->dn_flags ^ dst->dn_flags) & DT_NF_SIGNED) == 0)
484e5803b76SAdam H. Leventhal 		return; /* not narrowing or changing signed-ness */
485e5803b76SAdam H. Leventhal 	if (dstsize > srcsize && (src->dn_flags & DT_NF_SIGNED) == 0)
486e5803b76SAdam H. Leventhal 		return; /* nothing to do in this case */
4877c478bd9Sstevel@tonic-gate 
488e5803b76SAdam H. Leventhal 	rg = dt_regset_alloc(drp);
489e5803b76SAdam H. Leventhal 
490e5803b76SAdam H. Leventhal 	if (dstsize > srcsize) {
491e5803b76SAdam H. Leventhal 		int n = sizeof (uint64_t) * NBBY - srcsize * NBBY;
492e5803b76SAdam H. Leventhal 		int s = (dstsize - srcsize) * NBBY;
4937c478bd9Sstevel@tonic-gate 
494e5803b76SAdam H. Leventhal 		dt_cg_setx(dlp, rg, n);
4957c478bd9Sstevel@tonic-gate 
496e5803b76SAdam H. Leventhal 		instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
4977c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
4987c478bd9Sstevel@tonic-gate 
499e5803b76SAdam H. Leventhal 		if ((dst->dn_flags & DT_NF_SIGNED) || n == s) {
500e5803b76SAdam H. Leventhal 			instr = DIF_INSTR_FMT(DIF_OP_SRA,
501e5803b76SAdam H. Leventhal 			    dst->dn_reg, rg, dst->dn_reg);
502e5803b76SAdam H. Leventhal 			dt_irlist_append(dlp,
503e5803b76SAdam H. Leventhal 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
504e5803b76SAdam H. Leventhal 		} else {
505e5803b76SAdam H. Leventhal 			dt_cg_setx(dlp, rg, s);
506e5803b76SAdam H. Leventhal 			instr = DIF_INSTR_FMT(DIF_OP_SRA,
507e5803b76SAdam H. Leventhal 			    dst->dn_reg, rg, dst->dn_reg);
508e5803b76SAdam H. Leventhal 			dt_irlist_append(dlp,
509e5803b76SAdam H. Leventhal 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
510e5803b76SAdam H. Leventhal 			dt_cg_setx(dlp, rg, n - s);
511e5803b76SAdam H. Leventhal 			instr = DIF_INSTR_FMT(DIF_OP_SRL,
512e5803b76SAdam H. Leventhal 			    dst->dn_reg, rg, dst->dn_reg);
513e5803b76SAdam H. Leventhal 			dt_irlist_append(dlp,
514e5803b76SAdam H. Leventhal 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
515e5803b76SAdam H. Leventhal 		}
516e5803b76SAdam H. Leventhal 	} else if (dstsize != sizeof (uint64_t)) {
517e5803b76SAdam H. Leventhal 		int n = sizeof (uint64_t) * NBBY - dstsize * NBBY;
518e5803b76SAdam H. Leventhal 
519e5803b76SAdam H. Leventhal 		dt_cg_setx(dlp, rg, n);
5207c478bd9Sstevel@tonic-gate 
521e5803b76SAdam H. Leventhal 		instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
522e5803b76SAdam H. Leventhal 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
523e5803b76SAdam H. Leventhal 
524e5803b76SAdam H. Leventhal 		instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ?
525e5803b76SAdam H. Leventhal 		    DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, rg, dst->dn_reg);
5267c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
5277c478bd9Sstevel@tonic-gate 	}
528e5803b76SAdam H. Leventhal 
529e5803b76SAdam H. Leventhal 	dt_regset_free(drp, rg);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate /*
5337c478bd9Sstevel@tonic-gate  * Generate code to push the specified argument list on to the tuple stack.
5347c478bd9Sstevel@tonic-gate  * We use this routine for handling subroutine calls and associative arrays.
5357c478bd9Sstevel@tonic-gate  * We must first generate code for all subexpressions before loading the stack
5367c478bd9Sstevel@tonic-gate  * because any subexpression could itself require the use of the tuple stack.
5377c478bd9Sstevel@tonic-gate  * This holds a number of registers equal to the number of arguments, but this
5387c478bd9Sstevel@tonic-gate  * is not a huge problem because the number of arguments can't exceed the
5397c478bd9Sstevel@tonic-gate  * number of tuple register stack elements anyway.  At most one extra register
5407c478bd9Sstevel@tonic-gate  * is required (either by dt_cg_typecast() or for dtdt_size, below).  This
5417c478bd9Sstevel@tonic-gate  * implies that a DIF implementation should offer a number of general purpose
5427c478bd9Sstevel@tonic-gate  * registers at least one greater than the number of tuple registers.
5437c478bd9Sstevel@tonic-gate  */
5447c478bd9Sstevel@tonic-gate static void
dt_cg_arglist(dt_ident_t * idp,dt_node_t * args,dt_irlist_t * dlp,dt_regset_t * drp)5457c478bd9Sstevel@tonic-gate dt_cg_arglist(dt_ident_t *idp, dt_node_t *args,
5467c478bd9Sstevel@tonic-gate     dt_irlist_t *dlp, dt_regset_t *drp)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	const dt_idsig_t *isp = idp->di_data;
5497c478bd9Sstevel@tonic-gate 	dt_node_t *dnp;
5507c478bd9Sstevel@tonic-gate 	int i = 0;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	for (dnp = args; dnp != NULL; dnp = dnp->dn_list)
5537c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp, dlp, drp);
5547c478bd9Sstevel@tonic-gate 
555e5803b76SAdam H. Leventhal 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) {
5587c478bd9Sstevel@tonic-gate 		dtrace_diftype_t t;
5597c478bd9Sstevel@tonic-gate 		dif_instr_t instr;
5607c478bd9Sstevel@tonic-gate 		uint_t op;
5617c478bd9Sstevel@tonic-gate 		int reg;
5627c478bd9Sstevel@tonic-gate 
5631a7c1b72Smws 		dt_node_diftype(yypcb->pcb_hdl, dnp, &t);
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 		isp->dis_args[i].dn_reg = dnp->dn_reg; /* re-use register */
5667c478bd9Sstevel@tonic-gate 		dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp);
5677c478bd9Sstevel@tonic-gate 		isp->dis_args[i].dn_reg = -1;
5687c478bd9Sstevel@tonic-gate 
569e5803b76SAdam H. Leventhal 		if (t.dtdt_flags & DIF_TF_BYREF) {
5707c478bd9Sstevel@tonic-gate 			op = DIF_OP_PUSHTR;
571e5803b76SAdam H. Leventhal 			if (t.dtdt_size != 0) {
572e5803b76SAdam H. Leventhal 				reg = dt_regset_alloc(drp);
573e5803b76SAdam H. Leventhal 				dt_cg_setx(dlp, reg, t.dtdt_size);
574e5803b76SAdam H. Leventhal 			} else {
575e5803b76SAdam H. Leventhal 				reg = DIF_REG_R0;
576e5803b76SAdam H. Leventhal 			}
577e5803b76SAdam H. Leventhal 		} else {
5787c478bd9Sstevel@tonic-gate 			op = DIF_OP_PUSHTV;
5797c478bd9Sstevel@tonic-gate 			reg = DIF_REG_R0;
580e5803b76SAdam H. Leventhal 		}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg);
5837c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
5847c478bd9Sstevel@tonic-gate 		dt_regset_free(drp, dnp->dn_reg);
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 		if (reg != DIF_REG_R0)
5877c478bd9Sstevel@tonic-gate 			dt_regset_free(drp, reg);
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	if (i > yypcb->pcb_hdl->dt_conf.dtc_diftupregs)
5917c478bd9Sstevel@tonic-gate 		longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG);
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate static void
dt_cg_arithmetic_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op)5957c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dt_node_t *dnp, dt_irlist_t *dlp,
5967c478bd9Sstevel@tonic-gate     dt_regset_t *drp, uint_t op)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	int is_ptr_op = (dnp->dn_op == DT_TOK_ADD || dnp->dn_op == DT_TOK_SUB ||
5997c478bd9Sstevel@tonic-gate 	    dnp->dn_op == DT_TOK_ADD_EQ || dnp->dn_op == DT_TOK_SUB_EQ);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	int lp_is_ptr = dt_node_is_pointer(dnp->dn_left);
6027c478bd9Sstevel@tonic-gate 	int rp_is_ptr = dt_node_is_pointer(dnp->dn_right);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	if (lp_is_ptr && rp_is_ptr) {
6077c478bd9Sstevel@tonic-gate 		assert(dnp->dn_op == DT_TOK_SUB);
6087c478bd9Sstevel@tonic-gate 		is_ptr_op = 0;
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_left, dlp, drp);
6127c478bd9Sstevel@tonic-gate 	if (is_ptr_op && rp_is_ptr)
6137c478bd9Sstevel@tonic-gate 		dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_left->dn_reg);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_right, dlp, drp);
6167c478bd9Sstevel@tonic-gate 	if (is_ptr_op && lp_is_ptr)
6177c478bd9Sstevel@tonic-gate 		dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_right->dn_reg);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(op, dnp->dn_left->dn_reg,
6207c478bd9Sstevel@tonic-gate 	    dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
6237c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, dnp->dn_right->dn_reg);
6247c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_left->dn_reg;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	if (lp_is_ptr && rp_is_ptr)
6277c478bd9Sstevel@tonic-gate 		dt_cg_ptrsize(dnp->dn_right,
6287c478bd9Sstevel@tonic-gate 		    dlp, drp, DIF_OP_UDIV, dnp->dn_reg);
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate static uint_t
dt_cg_stvar(const dt_ident_t * idp)6327c478bd9Sstevel@tonic-gate dt_cg_stvar(const dt_ident_t *idp)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate 	static const uint_t aops[] = { DIF_OP_STGAA, DIF_OP_STTAA, DIF_OP_NOP };
6357c478bd9Sstevel@tonic-gate 	static const uint_t sops[] = { DIF_OP_STGS, DIF_OP_STTS, DIF_OP_STLS };
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	uint_t i = (((idp->di_flags & DT_IDFLG_LOCAL) != 0) << 1) |
6387c478bd9Sstevel@tonic-gate 	    ((idp->di_flags & DT_IDFLG_TLS) != 0);
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	return (idp->di_kind == DT_IDENT_ARRAY ? aops[i] : sops[i]);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate static void
dt_cg_prearith_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op)6447c478bd9Sstevel@tonic-gate dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
6457c478bd9Sstevel@tonic-gate {
6467c478bd9Sstevel@tonic-gate 	ctf_file_t *ctfp = dnp->dn_ctfp;
6477c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
6487c478bd9Sstevel@tonic-gate 	ctf_id_t type;
6497c478bd9Sstevel@tonic-gate 	ssize_t size = 1;
6507c478bd9Sstevel@tonic-gate 	int reg;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	if (dt_node_is_pointer(dnp)) {
6537c478bd9Sstevel@tonic-gate 		type = ctf_type_resolve(ctfp, dnp->dn_type);
6547c478bd9Sstevel@tonic-gate 		assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);
6557c478bd9Sstevel@tonic-gate 		size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_child, dlp, drp);
6597c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_child->dn_reg;
6607c478bd9Sstevel@tonic-gate 
661e5803b76SAdam H. Leventhal 	reg = dt_regset_alloc(drp);
6627c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, reg, size);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg);
6657c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
6667c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, reg);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	/*
6697c478bd9Sstevel@tonic-gate 	 * If we are modifying a variable, generate an stv instruction from
6707c478bd9Sstevel@tonic-gate 	 * the variable specified by the identifier.  If we are storing to a
6717c478bd9Sstevel@tonic-gate 	 * memory address, generate code again for the left-hand side using
6727c478bd9Sstevel@tonic-gate 	 * DT_NF_REF to get the address, and then generate a store to it.
6737c478bd9Sstevel@tonic-gate 	 * In both paths, we store the value in dnp->dn_reg (the new value).
6747c478bd9Sstevel@tonic-gate 	 */
6757c478bd9Sstevel@tonic-gate 	if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
6767c478bd9Sstevel@tonic-gate 		dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 		idp->di_flags |= DT_IDFLG_DIFW;
6797c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_STV(dt_cg_stvar(idp),
6807c478bd9Sstevel@tonic-gate 		    idp->di_id, dnp->dn_reg);
6817c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
6827c478bd9Sstevel@tonic-gate 	} else {
6837c478bd9Sstevel@tonic-gate 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 		assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
6867c478bd9Sstevel@tonic-gate 		assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 		dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
6897c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_child, dlp, drp);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 		dt_cg_store(dnp, dlp, drp, dnp->dn_child);
6927c478bd9Sstevel@tonic-gate 		dt_regset_free(drp, dnp->dn_child->dn_reg);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 		dnp->dn_left->dn_flags &= ~DT_NF_REF;
6957c478bd9Sstevel@tonic-gate 		dnp->dn_left->dn_flags |= rbit;
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate static void
dt_cg_postarith_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op)7007c478bd9Sstevel@tonic-gate dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,
7017c478bd9Sstevel@tonic-gate     dt_regset_t *drp, uint_t op)
7027c478bd9Sstevel@tonic-gate {
7037c478bd9Sstevel@tonic-gate 	ctf_file_t *ctfp = dnp->dn_ctfp;
7047c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
7057c478bd9Sstevel@tonic-gate 	ctf_id_t type;
7067c478bd9Sstevel@tonic-gate 	ssize_t size = 1;
7077c478bd9Sstevel@tonic-gate 	int nreg;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	if (dt_node_is_pointer(dnp)) {
7107c478bd9Sstevel@tonic-gate 		type = ctf_type_resolve(ctfp, dnp->dn_type);
7117c478bd9Sstevel@tonic-gate 		assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);
7127c478bd9Sstevel@tonic-gate 		size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_child, dlp, drp);
7167c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_child->dn_reg;
7177c478bd9Sstevel@tonic-gate 
718e5803b76SAdam H. Leventhal 	nreg = dt_regset_alloc(drp);
7197c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, nreg, size);
7207c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg);
7217c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	/*
7247c478bd9Sstevel@tonic-gate 	 * If we are modifying a variable, generate an stv instruction from
7257c478bd9Sstevel@tonic-gate 	 * the variable specified by the identifier.  If we are storing to a
7267c478bd9Sstevel@tonic-gate 	 * memory address, generate code again for the left-hand side using
7277c478bd9Sstevel@tonic-gate 	 * DT_NF_REF to get the address, and then generate a store to it.
7287c478bd9Sstevel@tonic-gate 	 * In both paths, we store the value from 'nreg' (the new value).
7297c478bd9Sstevel@tonic-gate 	 */
7307c478bd9Sstevel@tonic-gate 	if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
7317c478bd9Sstevel@tonic-gate 		dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 		idp->di_flags |= DT_IDFLG_DIFW;
7347c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, nreg);
7357c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7367c478bd9Sstevel@tonic-gate 	} else {
7377c478bd9Sstevel@tonic-gate 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
7387c478bd9Sstevel@tonic-gate 		int oreg = dnp->dn_reg;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 		assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
7417c478bd9Sstevel@tonic-gate 		assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 		dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
7447c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_child, dlp, drp);
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 		dnp->dn_reg = nreg;
7477c478bd9Sstevel@tonic-gate 		dt_cg_store(dnp, dlp, drp, dnp->dn_child);
7487c478bd9Sstevel@tonic-gate 		dnp->dn_reg = oreg;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 		dt_regset_free(drp, dnp->dn_child->dn_reg);
7517c478bd9Sstevel@tonic-gate 		dnp->dn_left->dn_flags &= ~DT_NF_REF;
7527c478bd9Sstevel@tonic-gate 		dnp->dn_left->dn_flags |= rbit;
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, nreg);
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate /*
7597c478bd9Sstevel@tonic-gate  * Determine if we should perform signed or unsigned comparison for an OP2.
7607c478bd9Sstevel@tonic-gate  * If both operands are of arithmetic type, perform the usual arithmetic
7617c478bd9Sstevel@tonic-gate  * conversions to determine the common real type for comparison [ISOC 6.5.8.3].
7627c478bd9Sstevel@tonic-gate  */
7637c478bd9Sstevel@tonic-gate static int
dt_cg_compare_signed(dt_node_t * dnp)7647c478bd9Sstevel@tonic-gate dt_cg_compare_signed(dt_node_t *dnp)
7657c478bd9Sstevel@tonic-gate {
7667c478bd9Sstevel@tonic-gate 	dt_node_t dn;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	if (dt_node_is_string(dnp->dn_left) ||
7697c478bd9Sstevel@tonic-gate 	    dt_node_is_string(dnp->dn_right))
7707c478bd9Sstevel@tonic-gate 		return (1); /* strings always compare signed */
7717c478bd9Sstevel@tonic-gate 	else if (!dt_node_is_arith(dnp->dn_left) ||
7727c478bd9Sstevel@tonic-gate 	    !dt_node_is_arith(dnp->dn_right))
7737c478bd9Sstevel@tonic-gate 		return (0); /* non-arithmetic types always compare unsigned */
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	bzero(&dn, sizeof (dn));
7767c478bd9Sstevel@tonic-gate 	dt_node_promote(dnp->dn_left, dnp->dn_right, &dn);
7777c478bd9Sstevel@tonic-gate 	return (dn.dn_flags & DT_NF_SIGNED);
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate static void
dt_cg_compare_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp,uint_t op)7817c478bd9Sstevel@tonic-gate dt_cg_compare_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
7827c478bd9Sstevel@tonic-gate {
7837c478bd9Sstevel@tonic-gate 	uint_t lbl_true = dt_irlist_label(dlp);
7847c478bd9Sstevel@tonic-gate 	uint_t lbl_post = dt_irlist_label(dlp);
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
7877c478bd9Sstevel@tonic-gate 	uint_t opc;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_left, dlp, drp);
7907c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_right, dlp, drp);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right))
7937c478bd9Sstevel@tonic-gate 		opc = DIF_OP_SCMP;
7947c478bd9Sstevel@tonic-gate 	else
7957c478bd9Sstevel@tonic-gate 		opc = DIF_OP_CMP;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_CMP(opc, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg);
7987c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
7997c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, dnp->dn_right->dn_reg);
8007c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_left->dn_reg;
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(op, lbl_true);
8037c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
8067c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
8097c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);
8127c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate /*
8167c478bd9Sstevel@tonic-gate  * Code generation for the ternary op requires some trickery with the assembler
8177c478bd9Sstevel@tonic-gate  * in order to conserve registers.  We generate code for dn_expr and dn_left
8187c478bd9Sstevel@tonic-gate  * and free their registers so they do not have be consumed across codegen for
8197c478bd9Sstevel@tonic-gate  * dn_right.  We insert a dummy MOV at the end of dn_left into the destination
8207c478bd9Sstevel@tonic-gate  * register, which is not yet known because we haven't done dn_right yet, and
8217c478bd9Sstevel@tonic-gate  * save the pointer to this instruction node.  We then generate code for
8227c478bd9Sstevel@tonic-gate  * dn_right and use its register as our output.  Finally, we reach back and
8237c478bd9Sstevel@tonic-gate  * patch the instruction for dn_left to move its output into this register.
8247c478bd9Sstevel@tonic-gate  */
8257c478bd9Sstevel@tonic-gate static void
dt_cg_ternary_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)8267c478bd9Sstevel@tonic-gate dt_cg_ternary_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate 	uint_t lbl_false = dt_irlist_label(dlp);
8297c478bd9Sstevel@tonic-gate 	uint_t lbl_post = dt_irlist_label(dlp);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
8327c478bd9Sstevel@tonic-gate 	dt_irnode_t *dip;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_expr, dlp, drp);
8357c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_TST(dnp->dn_expr->dn_reg);
8367c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8377c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, dnp->dn_expr->dn_reg);
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
8407c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_left, dlp, drp);
8437c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, DIF_REG_R0);
8447c478bd9Sstevel@tonic-gate 	dip = dt_cg_node_alloc(DT_LBL_NONE, instr); /* save dip for below */
8457c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dip);
8467c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, dnp->dn_left->dn_reg);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
8497c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, DIF_INSTR_NOP));
8527c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_right, dlp, drp);
8537c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_right->dn_reg;
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	/*
8567c478bd9Sstevel@tonic-gate 	 * Now that dn_reg is assigned, reach back and patch the correct MOV
8577c478bd9Sstevel@tonic-gate 	 * instruction into the tail of dn_left.  We know dn_reg was unused
8587c478bd9Sstevel@tonic-gate 	 * at that point because otherwise dn_right couldn't have allocated it.
8597c478bd9Sstevel@tonic-gate 	 */
8607c478bd9Sstevel@tonic-gate 	dip->di_instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, dnp->dn_reg);
8617c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate static void
dt_cg_logical_and(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)8657c478bd9Sstevel@tonic-gate dt_cg_logical_and(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate 	uint_t lbl_false = dt_irlist_label(dlp);
8687c478bd9Sstevel@tonic-gate 	uint_t lbl_post = dt_irlist_label(dlp);
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_left, dlp, drp);
8737c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
8747c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8757c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, dnp->dn_left->dn_reg);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
8787c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_right, dlp, drp);
8817c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
8827c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8837c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_right->dn_reg;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
8867c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, dnp->dn_reg, 1);
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
8917c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
8947c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate static void
dt_cg_logical_xor(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)9007c478bd9Sstevel@tonic-gate dt_cg_logical_xor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9017c478bd9Sstevel@tonic-gate {
9027c478bd9Sstevel@tonic-gate 	uint_t lbl_next = dt_irlist_label(dlp);
9037c478bd9Sstevel@tonic-gate 	uint_t lbl_tail = dt_irlist_label(dlp);
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_left, dlp, drp);
9087c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
9097c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_next);
9127c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9137c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, dnp->dn_left->dn_reg, 1);
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_next, DIF_INSTR_NOP));
9167c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_right, dlp, drp);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
9197c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_tail);
9227c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9237c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, dnp->dn_right->dn_reg, 1);
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(DIF_OP_XOR, dnp->dn_left->dn_reg,
9267c478bd9Sstevel@tonic-gate 	    dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_tail, instr));
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, dnp->dn_right->dn_reg);
9317c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_left->dn_reg;
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate static void
dt_cg_logical_or(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)9357c478bd9Sstevel@tonic-gate dt_cg_logical_or(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9367c478bd9Sstevel@tonic-gate {
9377c478bd9Sstevel@tonic-gate 	uint_t lbl_true = dt_irlist_label(dlp);
9387c478bd9Sstevel@tonic-gate 	uint_t lbl_false = dt_irlist_label(dlp);
9397c478bd9Sstevel@tonic-gate 	uint_t lbl_post = dt_irlist_label(dlp);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_left, dlp, drp);
9447c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
9457c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9467c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, dnp->dn_left->dn_reg);
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BNE, lbl_true);
9497c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_right, dlp, drp);
9527c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
9537c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9547c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_right->dn_reg;
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
9577c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
9627c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
9657c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate static void
dt_cg_logical_neg(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)9717c478bd9Sstevel@tonic-gate dt_cg_logical_neg(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9727c478bd9Sstevel@tonic-gate {
9737c478bd9Sstevel@tonic-gate 	uint_t lbl_zero = dt_irlist_label(dlp);
9747c478bd9Sstevel@tonic-gate 	uint_t lbl_post = dt_irlist_label(dlp);
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_child, dlp, drp);
9797c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_child->dn_reg;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_TST(dnp->dn_reg);
9827c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_zero);
9857c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
9887c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
9917c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	dt_cg_xsetx(dlp, NULL, lbl_zero, dnp->dn_reg, 1);
9947c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate static void
dt_cg_asgn_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)9987c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
9997c478bd9Sstevel@tonic-gate {
10007c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
10017c478bd9Sstevel@tonic-gate 	dt_ident_t *idp;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	/*
10047c478bd9Sstevel@tonic-gate 	 * If we are performing a structure assignment of a translated type,
10057c478bd9Sstevel@tonic-gate 	 * we must instantiate all members and create a snapshot of the object
10067c478bd9Sstevel@tonic-gate 	 * in scratch space.  We allocs a chunk of memory, generate code for
10077c478bd9Sstevel@tonic-gate 	 * each member, and then set dnp->dn_reg to the scratch object address.
10087c478bd9Sstevel@tonic-gate 	 */
10097c478bd9Sstevel@tonic-gate 	if ((idp = dt_node_resolve(dnp->dn_right, DT_IDENT_XLSOU)) != NULL) {
10107c478bd9Sstevel@tonic-gate 		ctf_membinfo_t ctm;
10117c478bd9Sstevel@tonic-gate 		dt_xlator_t *dxp = idp->di_data;
10127c478bd9Sstevel@tonic-gate 		dt_node_t *mnp, dn, mn;
10137c478bd9Sstevel@tonic-gate 		int r1, r2;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 		/*
10167c478bd9Sstevel@tonic-gate 		 * Create two fake dt_node_t's representing operator "." and a
10177c478bd9Sstevel@tonic-gate 		 * right-hand identifier child node.  These will be repeatedly
10187c478bd9Sstevel@tonic-gate 		 * modified according to each instantiated member so that we
10197c478bd9Sstevel@tonic-gate 		 * can pass them to dt_cg_store() and effect a member store.
10207c478bd9Sstevel@tonic-gate 		 */
10217c478bd9Sstevel@tonic-gate 		bzero(&dn, sizeof (dt_node_t));
10227c478bd9Sstevel@tonic-gate 		dn.dn_kind = DT_NODE_OP2;
10237c478bd9Sstevel@tonic-gate 		dn.dn_op = DT_TOK_DOT;
10247c478bd9Sstevel@tonic-gate 		dn.dn_left = dnp;
10257c478bd9Sstevel@tonic-gate 		dn.dn_right = &mn;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 		bzero(&mn, sizeof (dt_node_t));
10287c478bd9Sstevel@tonic-gate 		mn.dn_kind = DT_NODE_IDENT;
10297c478bd9Sstevel@tonic-gate 		mn.dn_op = DT_TOK_IDENT;
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 		/*
10327c478bd9Sstevel@tonic-gate 		 * Allocate a register for our scratch data pointer.  First we
10337c478bd9Sstevel@tonic-gate 		 * set it to the size of our data structure, and then replace
10347c478bd9Sstevel@tonic-gate 		 * it with the result of an allocs of the specified size.
10357c478bd9Sstevel@tonic-gate 		 */
1036e5803b76SAdam H. Leventhal 		r1 = dt_regset_alloc(drp);
10377c478bd9Sstevel@tonic-gate 		dt_cg_setx(dlp, r1,
10387c478bd9Sstevel@tonic-gate 		    ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base));
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_ALLOCS(r1, r1);
10417c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 		/*
10447c478bd9Sstevel@tonic-gate 		 * When dt_cg_asgn_op() is called, we have already generated
10457c478bd9Sstevel@tonic-gate 		 * code for dnp->dn_right, which is the translator input.  We
10467c478bd9Sstevel@tonic-gate 		 * now associate this register with the translator's input
10477c478bd9Sstevel@tonic-gate 		 * identifier so it can be referenced during our member loop.
10487c478bd9Sstevel@tonic-gate 		 */
10497c478bd9Sstevel@tonic-gate 		dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
10507c478bd9Sstevel@tonic-gate 		dxp->dx_ident->di_id = dnp->dn_right->dn_reg;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 		for (mnp = dxp->dx_members; mnp != NULL; mnp = mnp->dn_list) {
10537c478bd9Sstevel@tonic-gate 			/*
10547c478bd9Sstevel@tonic-gate 			 * Generate code for the translator member expression,
10557c478bd9Sstevel@tonic-gate 			 * and then cast the result to the member type.
10567c478bd9Sstevel@tonic-gate 			 */
10577c478bd9Sstevel@tonic-gate 			dt_cg_node(mnp->dn_membexpr, dlp, drp);
10587c478bd9Sstevel@tonic-gate 			mnp->dn_reg = mnp->dn_membexpr->dn_reg;
10597c478bd9Sstevel@tonic-gate 			dt_cg_typecast(mnp->dn_membexpr, mnp, dlp, drp);
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 			/*
10627c478bd9Sstevel@tonic-gate 			 * Ask CTF for the offset of the member so we can store
10637c478bd9Sstevel@tonic-gate 			 * to the appropriate offset.  This call has already
10647c478bd9Sstevel@tonic-gate 			 * been done once by the parser, so it should succeed.
10657c478bd9Sstevel@tonic-gate 			 */
10667c478bd9Sstevel@tonic-gate 			if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_base,
10677c478bd9Sstevel@tonic-gate 			    mnp->dn_membname, &ctm) == CTF_ERR) {
10687c478bd9Sstevel@tonic-gate 				yypcb->pcb_hdl->dt_ctferr =
10697c478bd9Sstevel@tonic-gate 				    ctf_errno(dxp->dx_dst_ctfp);
10707c478bd9Sstevel@tonic-gate 				longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
10717c478bd9Sstevel@tonic-gate 			}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 			/*
10747c478bd9Sstevel@tonic-gate 			 * If the destination member is at offset 0, store the
10757c478bd9Sstevel@tonic-gate 			 * result directly to r1 (the scratch buffer address).
10767c478bd9Sstevel@tonic-gate 			 * Otherwise allocate another temporary for the offset
10777c478bd9Sstevel@tonic-gate 			 * and add r1 to it before storing the result.
10787c478bd9Sstevel@tonic-gate 			 */
10797c478bd9Sstevel@tonic-gate 			if (ctm.ctm_offset != 0) {
1080e5803b76SAdam H. Leventhal 				r2 = dt_regset_alloc(drp);
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 				/*
10837c478bd9Sstevel@tonic-gate 				 * Add the member offset rounded down to the
10847c478bd9Sstevel@tonic-gate 				 * nearest byte.  If the offset was not aligned
10857c478bd9Sstevel@tonic-gate 				 * on a byte boundary, this member is a bit-
10867c478bd9Sstevel@tonic-gate 				 * field and dt_cg_store() will handle masking.
10877c478bd9Sstevel@tonic-gate 				 */
10887c478bd9Sstevel@tonic-gate 				dt_cg_setx(dlp, r2, ctm.ctm_offset / NBBY);
10897c478bd9Sstevel@tonic-gate 				instr = DIF_INSTR_FMT(DIF_OP_ADD, r1, r2, r2);
10907c478bd9Sstevel@tonic-gate 				dt_irlist_append(dlp,
10917c478bd9Sstevel@tonic-gate 				    dt_cg_node_alloc(DT_LBL_NONE, instr));
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 				dt_node_type_propagate(mnp, &dn);
10947c478bd9Sstevel@tonic-gate 				dn.dn_right->dn_string = mnp->dn_membname;
10957c478bd9Sstevel@tonic-gate 				dn.dn_reg = r2;
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 				dt_cg_store(mnp, dlp, drp, &dn);
10987c478bd9Sstevel@tonic-gate 				dt_regset_free(drp, r2);
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 			} else {
11017c478bd9Sstevel@tonic-gate 				dt_node_type_propagate(mnp, &dn);
11027c478bd9Sstevel@tonic-gate 				dn.dn_right->dn_string = mnp->dn_membname;
11037c478bd9Sstevel@tonic-gate 				dn.dn_reg = r1;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 				dt_cg_store(mnp, dlp, drp, &dn);
11067c478bd9Sstevel@tonic-gate 			}
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 			dt_regset_free(drp, mnp->dn_reg);
11097c478bd9Sstevel@tonic-gate 		}
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 		dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
11127c478bd9Sstevel@tonic-gate 		dxp->dx_ident->di_id = 0;
11137c478bd9Sstevel@tonic-gate 
11141a7c1b72Smws 		if (dnp->dn_right->dn_reg != -1)
11151a7c1b72Smws 			dt_regset_free(drp, dnp->dn_right->dn_reg);
11161a7c1b72Smws 
11177c478bd9Sstevel@tonic-gate 		assert(dnp->dn_reg == dnp->dn_right->dn_reg);
11187c478bd9Sstevel@tonic-gate 		dnp->dn_reg = r1;
11197c478bd9Sstevel@tonic-gate 	}
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	/*
112256a20711SPatrick Mooney 	 * If we are storing to a memory address, generate code again for the
112356a20711SPatrick Mooney 	 * left-hand side using DT_NF_REF to get the address, and then generate
112456a20711SPatrick Mooney 	 * a store to it.
112556a20711SPatrick Mooney 	 *
112656a20711SPatrick Mooney 	 * Both here and the other variable-store paths, we assume dnp->dn_reg
112756a20711SPatrick Mooney 	 * already has the new value.
11287c478bd9Sstevel@tonic-gate 	 */
112956a20711SPatrick Mooney 	if (dnp->dn_left->dn_kind != DT_NODE_VAR) {
11307c478bd9Sstevel@tonic-gate 		uint_t rbit = dnp->dn_left->dn_flags & DT_NF_REF;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 		assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE);
11337c478bd9Sstevel@tonic-gate 		assert(dnp->dn_left->dn_flags & DT_NF_LVALUE);
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 		dnp->dn_left->dn_flags |= DT_NF_REF; /* force pass-by-ref */
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_left, dlp, drp);
11387c478bd9Sstevel@tonic-gate 		dt_cg_store(dnp, dlp, drp, dnp->dn_left);
11397c478bd9Sstevel@tonic-gate 		dt_regset_free(drp, dnp->dn_left->dn_reg);
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 		dnp->dn_left->dn_flags &= ~DT_NF_REF;
11427c478bd9Sstevel@tonic-gate 		dnp->dn_left->dn_flags |= rbit;
114356a20711SPatrick Mooney 		return;
11447c478bd9Sstevel@tonic-gate 	}
114556a20711SPatrick Mooney 
114656a20711SPatrick Mooney 	idp = dt_ident_resolve(dnp->dn_left->dn_ident);
114756a20711SPatrick Mooney 	idp->di_flags |= DT_IDFLG_DIFW;
114856a20711SPatrick Mooney 
114956a20711SPatrick Mooney 	/*
115056a20711SPatrick Mooney 	 * Storing to an array variable is a special case.
115156a20711SPatrick Mooney 	 * Only 'uregs[]' supports this for the time being.
115256a20711SPatrick Mooney 	 */
115356a20711SPatrick Mooney 	if (idp->di_kind == DT_IDENT_ARRAY &&
115456a20711SPatrick Mooney 	    idp->di_id <= DIF_VAR_ARRAY_MAX) {
115556a20711SPatrick Mooney 		dt_node_t *idx = dnp->dn_left->dn_args;
115656a20711SPatrick Mooney 
115756a20711SPatrick Mooney 		dt_cg_node(idx, dlp, drp);
115856a20711SPatrick Mooney 		instr = DIF_INSTR_FMT(DIF_OP_STGA, idp->di_id, idx->dn_reg,
115956a20711SPatrick Mooney 		    dnp->dn_reg);
116056a20711SPatrick Mooney 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
116156a20711SPatrick Mooney 		dt_regset_free(drp, idx->dn_reg);
116256a20711SPatrick Mooney 		return;
116356a20711SPatrick Mooney 	}
116456a20711SPatrick Mooney 
116556a20711SPatrick Mooney 	if (idp->di_kind == DT_IDENT_ARRAY)
116656a20711SPatrick Mooney 		dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp);
116756a20711SPatrick Mooney 
116856a20711SPatrick Mooney 	instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, dnp->dn_reg);
116956a20711SPatrick Mooney 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11707c478bd9Sstevel@tonic-gate }
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate static void
dt_cg_assoc_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)11737c478bd9Sstevel@tonic-gate dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
11747c478bd9Sstevel@tonic-gate {
11757c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
11767c478bd9Sstevel@tonic-gate 	uint_t op;
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	assert(dnp->dn_kind == DT_NODE_VAR);
11797c478bd9Sstevel@tonic-gate 	assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL));
11807c478bd9Sstevel@tonic-gate 	assert(dnp->dn_args != NULL);
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
11837c478bd9Sstevel@tonic-gate 
1184e5803b76SAdam H. Leventhal 	dnp->dn_reg = dt_regset_alloc(drp);
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
11877c478bd9Sstevel@tonic-gate 		op = DIF_OP_LDTAA;
11887c478bd9Sstevel@tonic-gate 	else
11897c478bd9Sstevel@tonic-gate 		op = DIF_OP_LDGAA;
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;
11927c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);
11937c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	/*
11967c478bd9Sstevel@tonic-gate 	 * If the associative array is a pass-by-reference type, then we are
11977c478bd9Sstevel@tonic-gate 	 * loading its value as a pointer to either load or store through it.
11987c478bd9Sstevel@tonic-gate 	 * The array element in question may not have been faulted in yet, in
11997c478bd9Sstevel@tonic-gate 	 * which case DIF_OP_LD*AA will return zero.  We append an epilogue
12007c478bd9Sstevel@tonic-gate 	 * of instructions similar to the following:
12017c478bd9Sstevel@tonic-gate 	 *
12027c478bd9Sstevel@tonic-gate 	 *	  ld?aa	 id, %r1	! base ld?aa instruction above
12037c478bd9Sstevel@tonic-gate 	 *	  tst	 %r1		! start of epilogue
12047c478bd9Sstevel@tonic-gate 	 *   +--- bne	 label
12057c478bd9Sstevel@tonic-gate 	 *   |    setx	 size, %r1
12067c478bd9Sstevel@tonic-gate 	 *   |    allocs %r1, %r1
12077c478bd9Sstevel@tonic-gate 	 *   |    st?aa	 id, %r1
12087c478bd9Sstevel@tonic-gate 	 *   |    ld?aa	 id, %r1
12097c478bd9Sstevel@tonic-gate 	 *   v
12107c478bd9Sstevel@tonic-gate 	 * label: < rest of code >
12117c478bd9Sstevel@tonic-gate 	 *
12127c478bd9Sstevel@tonic-gate 	 * The idea is that we allocs a zero-filled chunk of scratch space and
12137c478bd9Sstevel@tonic-gate 	 * do a DIF_OP_ST*AA to fault in and initialize the array element, and
12147c478bd9Sstevel@tonic-gate 	 * then reload it to get the faulted-in address of the new variable
12157c478bd9Sstevel@tonic-gate 	 * storage.  This isn't cheap, but pass-by-ref associative array values
12167c478bd9Sstevel@tonic-gate 	 * are (thus far) uncommon and the allocs cost only occurs once.  If
12177c478bd9Sstevel@tonic-gate 	 * this path becomes important to DTrace users, we can improve things
12187c478bd9Sstevel@tonic-gate 	 * by adding a new DIF opcode to fault in associative array elements.
12197c478bd9Sstevel@tonic-gate 	 */
12207c478bd9Sstevel@tonic-gate 	if (dnp->dn_flags & DT_NF_REF) {
12217c478bd9Sstevel@tonic-gate 		uint_t stvop = op == DIF_OP_LDTAA ? DIF_OP_STTAA : DIF_OP_STGAA;
12227c478bd9Sstevel@tonic-gate 		uint_t label = dt_irlist_label(dlp);
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_TST(dnp->dn_reg);
12257c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_BRANCH(DIF_OP_BNE, label);
12287c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 		dt_cg_setx(dlp, dnp->dn_reg, dt_node_type_size(dnp));
12317c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_ALLOCS(dnp->dn_reg, dnp->dn_reg);
12327c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 		dnp->dn_ident->di_flags |= DT_IDFLG_DIFW;
12357c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_STV(stvop, dnp->dn_ident->di_id, dnp->dn_reg);
12367c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);
12397c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(label, DIF_INSTR_NOP));
12427c478bd9Sstevel@tonic-gate 	}
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate static void
dt_cg_array_op(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)12467c478bd9Sstevel@tonic-gate dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
12477c478bd9Sstevel@tonic-gate {
12487c478bd9Sstevel@tonic-gate 	dt_probe_t *prp = yypcb->pcb_probe;
12497c478bd9Sstevel@tonic-gate 	uintmax_t saved = dnp->dn_args->dn_value;
12501a7c1b72Smws 	dt_ident_t *idp = dnp->dn_ident;
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
12537c478bd9Sstevel@tonic-gate 	uint_t op;
12547c478bd9Sstevel@tonic-gate 	size_t size;
12557c478bd9Sstevel@tonic-gate 	int reg, n;
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	assert(dnp->dn_kind == DT_NODE_VAR);
12581a7c1b72Smws 	assert(!(idp->di_flags & DT_IDFLG_LOCAL));
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	assert(dnp->dn_args->dn_kind == DT_NODE_INT);
12617c478bd9Sstevel@tonic-gate 	assert(dnp->dn_args->dn_list == NULL);
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 	/*
12647c478bd9Sstevel@tonic-gate 	 * If this is a reference in the args[] array, temporarily modify the
12651a7c1b72Smws 	 * array index according to the static argument mapping (if any),
12661a7c1b72Smws 	 * unless the argument reference is provided by a dynamic translator.
12671a7c1b72Smws 	 * If we're using a dynamic translator for args[], then just set dn_reg
12681a7c1b72Smws 	 * to an invalid reg and return: DIF_OP_XLARG will fetch the arg later.
12697c478bd9Sstevel@tonic-gate 	 */
12701a7c1b72Smws 	if (idp->di_id == DIF_VAR_ARGS) {
12711a7c1b72Smws 		if ((idp->di_kind == DT_IDENT_XLPTR ||
12721a7c1b72Smws 		    idp->di_kind == DT_IDENT_XLSOU) &&
12731a7c1b72Smws 		    dt_xlator_dynamic(idp->di_data)) {
12741a7c1b72Smws 			dnp->dn_reg = -1;
12751a7c1b72Smws 			return;
12761a7c1b72Smws 		}
12777c478bd9Sstevel@tonic-gate 		dnp->dn_args->dn_value = prp->pr_mapping[saved];
12781a7c1b72Smws 	}
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp->dn_args, dlp, drp);
12817c478bd9Sstevel@tonic-gate 	dnp->dn_args->dn_value = saved;
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	dnp->dn_reg = dnp->dn_args->dn_reg;
12847c478bd9Sstevel@tonic-gate 
12851a7c1b72Smws 	if (idp->di_flags & DT_IDFLG_TLS)
12867c478bd9Sstevel@tonic-gate 		op = DIF_OP_LDTA;
12877c478bd9Sstevel@tonic-gate 	else
12887c478bd9Sstevel@tonic-gate 		op = DIF_OP_LDGA;
12897c478bd9Sstevel@tonic-gate 
12901a7c1b72Smws 	idp->di_flags |= DT_IDFLG_DIFR;
12917c478bd9Sstevel@tonic-gate 
12921a7c1b72Smws 	instr = DIF_INSTR_LDA(op, idp->di_id,
12937c478bd9Sstevel@tonic-gate 	    dnp->dn_args->dn_reg, dnp->dn_reg);
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 	/*
12987c478bd9Sstevel@tonic-gate 	 * If this is a reference to the args[] array, we need to take the
12997c478bd9Sstevel@tonic-gate 	 * additional step of explicitly eliminating any bits larger than the
13007c478bd9Sstevel@tonic-gate 	 * type size: the DIF interpreter in the kernel will always give us
13017c478bd9Sstevel@tonic-gate 	 * the raw (64-bit) argument value, and any bits larger than the type
13027c478bd9Sstevel@tonic-gate 	 * size may be junk.  As a practical matter, this arises only on 64-bit
13037c478bd9Sstevel@tonic-gate 	 * architectures and only when the argument index is larger than the
13047c478bd9Sstevel@tonic-gate 	 * number of arguments passed directly to DTrace: if a 8-, 16- or
13057c478bd9Sstevel@tonic-gate 	 * 32-bit argument must be retrieved from the stack, it is possible
13067c478bd9Sstevel@tonic-gate 	 * (and it some cases, likely) that the upper bits will be garbage.
13077c478bd9Sstevel@tonic-gate 	 */
13081a7c1b72Smws 	if (idp->di_id != DIF_VAR_ARGS || !dt_node_is_scalar(dnp))
13097c478bd9Sstevel@tonic-gate 		return;
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t))
13127c478bd9Sstevel@tonic-gate 		return;
13137c478bd9Sstevel@tonic-gate 
1314e5803b76SAdam H. Leventhal 	reg = dt_regset_alloc(drp);
13157c478bd9Sstevel@tonic-gate 	assert(size < sizeof (uint64_t));
13167c478bd9Sstevel@tonic-gate 	n = sizeof (uint64_t) * NBBY - size * NBBY;
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	dt_cg_setx(dlp, reg, n);
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT(DIF_OP_SLL, dnp->dn_reg, reg, dnp->dn_reg);
13217c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_FMT((dnp->dn_flags & DT_NF_SIGNED) ?
13247c478bd9Sstevel@tonic-gate 	    DIF_OP_SRA : DIF_OP_SRL, dnp->dn_reg, reg, dnp->dn_reg);
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
13277c478bd9Sstevel@tonic-gate 	dt_regset_free(drp, reg);
13287c478bd9Sstevel@tonic-gate }
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate /*
13317c478bd9Sstevel@tonic-gate  * Generate code for an inlined variable reference.  Inlines can be used to
13327c478bd9Sstevel@tonic-gate  * define either scalar or associative array substitutions.  For scalars, we
13337c478bd9Sstevel@tonic-gate  * simply generate code for the parse tree saved in the identifier's din_root,
13347c478bd9Sstevel@tonic-gate  * and then cast the resulting expression to the inline's declaration type.
13357c478bd9Sstevel@tonic-gate  * For arrays, we take the input parameter subtrees from dnp->dn_args and
13367c478bd9Sstevel@tonic-gate  * temporarily store them in the din_root of each din_argv[i] identifier,
13377c478bd9Sstevel@tonic-gate  * which are themselves inlines and were set up for us by the parser.  The
13387c478bd9Sstevel@tonic-gate  * result is that any reference to the inlined parameter inside the top-level
13397c478bd9Sstevel@tonic-gate  * din_root will turn into a recursive call to dt_cg_inline() for a scalar
13407c478bd9Sstevel@tonic-gate  * inline whose din_root will refer to the subtree pointed to by the argument.
13417c478bd9Sstevel@tonic-gate  */
13427c478bd9Sstevel@tonic-gate static void
dt_cg_inline(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)13437c478bd9Sstevel@tonic-gate dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
13447c478bd9Sstevel@tonic-gate {
13457c478bd9Sstevel@tonic-gate 	dt_ident_t *idp = dnp->dn_ident;
13467c478bd9Sstevel@tonic-gate 	dt_idnode_t *inp = idp->di_iarg;
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	dt_idnode_t *pinp;
13497c478bd9Sstevel@tonic-gate 	dt_node_t *pnp;
13507c478bd9Sstevel@tonic-gate 	int i;
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	assert(idp->di_flags & DT_IDFLG_INLINE);
13537c478bd9Sstevel@tonic-gate 	assert(idp->di_ops == &dt_idops_inline);
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	if (idp->di_kind == DT_IDENT_ARRAY) {
13567c478bd9Sstevel@tonic-gate 		for (i = 0, pnp = dnp->dn_args;
13577c478bd9Sstevel@tonic-gate 		    pnp != NULL; pnp = pnp->dn_list, i++) {
13587c478bd9Sstevel@tonic-gate 			if (inp->din_argv[i] != NULL) {
13597c478bd9Sstevel@tonic-gate 				pinp = inp->din_argv[i]->di_iarg;
13607c478bd9Sstevel@tonic-gate 				pinp->din_root = pnp;
13617c478bd9Sstevel@tonic-gate 			}
13627c478bd9Sstevel@tonic-gate 		}
13637c478bd9Sstevel@tonic-gate 	}
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	dt_cg_node(inp->din_root, dlp, drp);
13667c478bd9Sstevel@tonic-gate 	dnp->dn_reg = inp->din_root->dn_reg;
13677c478bd9Sstevel@tonic-gate 	dt_cg_typecast(inp->din_root, dnp, dlp, drp);
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	if (idp->di_kind == DT_IDENT_ARRAY) {
13707c478bd9Sstevel@tonic-gate 		for (i = 0; i < inp->din_argc; i++) {
13717c478bd9Sstevel@tonic-gate 			pinp = inp->din_argv[i]->di_iarg;
13727c478bd9Sstevel@tonic-gate 			pinp->din_root = NULL;
13737c478bd9Sstevel@tonic-gate 		}
13747c478bd9Sstevel@tonic-gate 	}
13757c478bd9Sstevel@tonic-gate }
13767c478bd9Sstevel@tonic-gate 
1377e5803b76SAdam H. Leventhal typedef struct dt_xlmemb {
1378e5803b76SAdam H. Leventhal 	dt_ident_t *dtxl_idp;		/* translated ident */
1379e5803b76SAdam H. Leventhal 	dt_irlist_t *dtxl_dlp;		/* instruction list */
1380e5803b76SAdam H. Leventhal 	dt_regset_t *dtxl_drp;		/* register set */
1381e5803b76SAdam H. Leventhal 	int dtxl_sreg;			/* location of the translation input */
1382e5803b76SAdam H. Leventhal 	int dtxl_dreg;			/* location of our allocated buffer */
1383e5803b76SAdam H. Leventhal } dt_xlmemb_t;
1384e5803b76SAdam H. Leventhal 
1385e5803b76SAdam H. Leventhal /*ARGSUSED*/
1386e5803b76SAdam H. Leventhal static int
dt_cg_xlate_member(const char * name,ctf_id_t type,ulong_t off,void * arg)1387e5803b76SAdam H. Leventhal dt_cg_xlate_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
1388e5803b76SAdam H. Leventhal {
1389e5803b76SAdam H. Leventhal 	dt_xlmemb_t *dx = arg;
1390e5803b76SAdam H. Leventhal 	dt_ident_t *idp = dx->dtxl_idp;
1391e5803b76SAdam H. Leventhal 	dt_irlist_t *dlp = dx->dtxl_dlp;
1392e5803b76SAdam H. Leventhal 	dt_regset_t *drp = dx->dtxl_drp;
1393e5803b76SAdam H. Leventhal 
1394e5803b76SAdam H. Leventhal 	dt_node_t *mnp;
1395e5803b76SAdam H. Leventhal 	dt_xlator_t *dxp;
1396e5803b76SAdam H. Leventhal 
1397e5803b76SAdam H. Leventhal 	int reg, treg;
1398e5803b76SAdam H. Leventhal 	uint32_t instr;
1399e5803b76SAdam H. Leventhal 	size_t size;
1400e5803b76SAdam H. Leventhal 
1401e5803b76SAdam H. Leventhal 	/* Generate code for the translation. */
1402e5803b76SAdam H. Leventhal 	dxp = idp->di_data;
1403e5803b76SAdam H. Leventhal 	mnp = dt_xlator_member(dxp, name);
1404e5803b76SAdam H. Leventhal 
1405e5803b76SAdam H. Leventhal 	/* If there's no translator for the given member, skip it. */
1406e5803b76SAdam H. Leventhal 	if (mnp == NULL)
1407e5803b76SAdam H. Leventhal 		return (0);
1408e5803b76SAdam H. Leventhal 
1409e5803b76SAdam H. Leventhal 	dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
1410e5803b76SAdam H. Leventhal 	dxp->dx_ident->di_id = dx->dtxl_sreg;
1411e5803b76SAdam H. Leventhal 
1412e5803b76SAdam H. Leventhal 	dt_cg_node(mnp->dn_membexpr, dlp, drp);
1413e5803b76SAdam H. Leventhal 
1414e5803b76SAdam H. Leventhal 	dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
1415e5803b76SAdam H. Leventhal 	dxp->dx_ident->di_id = 0;
1416e5803b76SAdam H. Leventhal 
1417e5803b76SAdam H. Leventhal 	treg = mnp->dn_membexpr->dn_reg;
1418e5803b76SAdam H. Leventhal 
1419e5803b76SAdam H. Leventhal 	/* Compute the offset into our buffer and store the result there. */
1420e5803b76SAdam H. Leventhal 	reg = dt_regset_alloc(drp);
1421e5803b76SAdam H. Leventhal 
1422e5803b76SAdam H. Leventhal 	dt_cg_setx(dlp, reg, off / NBBY);
1423e5803b76SAdam H. Leventhal 	instr = DIF_INSTR_FMT(DIF_OP_ADD, dx->dtxl_dreg, reg, reg);
1424e5803b76SAdam H. Leventhal 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1425e5803b76SAdam H. Leventhal 
1426e5803b76SAdam H. Leventhal 	size = ctf_type_size(mnp->dn_membexpr->dn_ctfp,
1427e5803b76SAdam H. Leventhal 	    mnp->dn_membexpr->dn_type);
1428e5803b76SAdam H. Leventhal 	if (dt_node_is_scalar(mnp->dn_membexpr)) {
1429e5803b76SAdam H. Leventhal 		/*
1430e5803b76SAdam H. Leventhal 		 * Copying scalars is simple.
1431e5803b76SAdam H. Leventhal 		 */
1432e5803b76SAdam H. Leventhal 		switch (size) {
1433e5803b76SAdam H. Leventhal 		case 1:
1434e5803b76SAdam H. Leventhal 			instr = DIF_INSTR_STORE(DIF_OP_STB, treg, reg);
1435e5803b76SAdam H. Leventhal 			break;
1436e5803b76SAdam H. Leventhal 		case 2:
1437e5803b76SAdam H. Leventhal 			instr = DIF_INSTR_STORE(DIF_OP_STH, treg, reg);
1438e5803b76SAdam H. Leventhal 			break;
1439e5803b76SAdam H. Leventhal 		case 4:
1440e5803b76SAdam H. Leventhal 			instr = DIF_INSTR_STORE(DIF_OP_STW, treg, reg);
1441e5803b76SAdam H. Leventhal 			break;
1442e5803b76SAdam H. Leventhal 		case 8:
1443e5803b76SAdam H. Leventhal 			instr = DIF_INSTR_STORE(DIF_OP_STX, treg, reg);
1444e5803b76SAdam H. Leventhal 			break;
1445e5803b76SAdam H. Leventhal 		default:
1446e5803b76SAdam H. Leventhal 			xyerror(D_UNKNOWN, "internal error -- unexpected "
1447e5803b76SAdam H. Leventhal 			    "size: %lu\n", (ulong_t)size);
1448e5803b76SAdam H. Leventhal 		}
1449e5803b76SAdam H. Leventhal 
1450e5803b76SAdam H. Leventhal 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1451e5803b76SAdam H. Leventhal 
1452e5803b76SAdam H. Leventhal 	} else if (dt_node_is_string(mnp->dn_membexpr)) {
1453e5803b76SAdam H. Leventhal 		int szreg;
1454e5803b76SAdam H. Leventhal 
1455e5803b76SAdam H. Leventhal 		/*
1456e5803b76SAdam H. Leventhal 		 * Use the copys instruction for strings.
1457e5803b76SAdam H. Leventhal 		 */
1458e5803b76SAdam H. Leventhal 		szreg = dt_regset_alloc(drp);
1459e5803b76SAdam H. Leventhal 		dt_cg_setx(dlp, szreg, size);
1460e5803b76SAdam H. Leventhal 		instr = DIF_INSTR_COPYS(treg, szreg, reg);
1461e5803b76SAdam H. Leventhal 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1462e5803b76SAdam H. Leventhal 		dt_regset_free(drp, szreg);
1463e5803b76SAdam H. Leventhal 	} else {
1464e5803b76SAdam H. Leventhal 		int szreg;
1465e5803b76SAdam H. Leventhal 
1466e5803b76SAdam H. Leventhal 		/*
1467e5803b76SAdam H. Leventhal 		 * If it's anything else then we'll just bcopy it.
1468e5803b76SAdam H. Leventhal 		 */
1469e5803b76SAdam H. Leventhal 		szreg = dt_regset_alloc(drp);
1470e5803b76SAdam H. Leventhal 		dt_cg_setx(dlp, szreg, size);
1471e5803b76SAdam H. Leventhal 		dt_irlist_append(dlp,
1472e5803b76SAdam H. Leventhal 		    dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
1473e5803b76SAdam H. Leventhal 		instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
1474e5803b76SAdam H. Leventhal 		    DIF_REG_R0, treg);
1475e5803b76SAdam H. Leventhal 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1476e5803b76SAdam H. Leventhal 		instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
1477e5803b76SAdam H. Leventhal 		    DIF_REG_R0, reg);
1478e5803b76SAdam H. Leventhal 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1479e5803b76SAdam H. Leventhal 		instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
1480e5803b76SAdam H. Leventhal 		    DIF_REG_R0, szreg);
1481e5803b76SAdam H. Leventhal 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1482e5803b76SAdam H. Leventhal 		instr = DIF_INSTR_CALL(DIF_SUBR_BCOPY, szreg);
1483e5803b76SAdam H. Leventhal 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1484e5803b76SAdam H. Leventhal 		dt_regset_free(drp, szreg);
1485e5803b76SAdam H. Leventhal 	}
1486e5803b76SAdam H. Leventhal 
1487e5803b76SAdam H. Leventhal 	dt_regset_free(drp, reg);
1488e5803b76SAdam H. Leventhal 	dt_regset_free(drp, treg);
1489e5803b76SAdam H. Leventhal 
1490e5803b76SAdam H. Leventhal 	return (0);
1491e5803b76SAdam H. Leventhal }
1492e5803b76SAdam H. Leventhal 
1493e5803b76SAdam H. Leventhal /*
1494e5803b76SAdam H. Leventhal  * If we're expanding a translated type, we create an appropriately sized
1495e5803b76SAdam H. Leventhal  * buffer with alloca() and then translate each member into it.
1496e5803b76SAdam H. Leventhal  */
1497e5803b76SAdam H. Leventhal static int
dt_cg_xlate_expand(dt_node_t * dnp,dt_ident_t * idp,dt_irlist_t * dlp,dt_regset_t * drp)1498e5803b76SAdam H. Leventhal dt_cg_xlate_expand(dt_node_t *dnp, dt_ident_t *idp, dt_irlist_t *dlp,
1499e5803b76SAdam H. Leventhal     dt_regset_t *drp)
1500e5803b76SAdam H. Leventhal {
1501e5803b76SAdam H. Leventhal 	dt_xlmemb_t dlm;
1502e5803b76SAdam H. Leventhal 	uint32_t instr;
1503e5803b76SAdam H. Leventhal 	int dreg;
1504e5803b76SAdam H. Leventhal 	size_t size;
1505e5803b76SAdam H. Leventhal 
1506e5803b76SAdam H. Leventhal 	dreg = dt_regset_alloc(drp);
1507e5803b76SAdam H. Leventhal 	size = ctf_type_size(dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type);
1508e5803b76SAdam H. Leventhal 
1509e5803b76SAdam H. Leventhal 	/* Call alloca() to create the buffer. */
1510e5803b76SAdam H. Leventhal 	dt_cg_setx(dlp, dreg, size);
1511e5803b76SAdam H. Leventhal 
1512e5803b76SAdam H. Leventhal 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
1513e5803b76SAdam H. Leventhal 
1514e5803b76SAdam H. Leventhal 	instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, DIF_REG_R0, dreg);
1515e5803b76SAdam H. Leventhal 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1516e5803b76SAdam H. Leventhal 
1517e5803b76SAdam H. Leventhal 	instr = DIF_INSTR_CALL(DIF_SUBR_ALLOCA, dreg);
1518e5803b76SAdam H. Leventhal 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
1519e5803b76SAdam H. Leventhal 
1520e5803b76SAdam H. Leventhal 	/* Generate the translation for each member. */
1521e5803b76SAdam H. Leventhal 	dlm.dtxl_idp = idp;
1522e5803b76SAdam H. Leventhal 	dlm.dtxl_dlp = dlp;
1523e5803b76SAdam H. Leventhal 	dlm.dtxl_drp = drp;
1524e5803b76SAdam H. Leventhal 	dlm.dtxl_sreg = dnp->dn_reg;
1525e5803b76SAdam H. Leventhal 	dlm.dtxl_dreg = dreg;
1526e5803b76SAdam H. Leventhal 	(void) ctf_member_iter(dnp->dn_ident->di_ctfp,
1527e5803b76SAdam H. Leventhal 	    dnp->dn_ident->di_type, dt_cg_xlate_member,
1528e5803b76SAdam H. Leventhal 	    &dlm);
1529e5803b76SAdam H. Leventhal 
1530e5803b76SAdam H. Leventhal 	return (dreg);
1531e5803b76SAdam H. Leventhal }
1532e5803b76SAdam H. Leventhal 
15337c478bd9Sstevel@tonic-gate static void
dt_cg_node(dt_node_t * dnp,dt_irlist_t * dlp,dt_regset_t * drp)15347c478bd9Sstevel@tonic-gate dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
15357c478bd9Sstevel@tonic-gate {
15367c478bd9Sstevel@tonic-gate 	ctf_file_t *ctfp = dnp->dn_ctfp;
15377c478bd9Sstevel@tonic-gate 	ctf_file_t *octfp;
15387c478bd9Sstevel@tonic-gate 	ctf_membinfo_t m;
15397c478bd9Sstevel@tonic-gate 	ctf_id_t type;
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
15427c478bd9Sstevel@tonic-gate 	dt_ident_t *idp;
15437c478bd9Sstevel@tonic-gate 	ssize_t stroff;
15447c478bd9Sstevel@tonic-gate 	uint_t op;
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	switch (dnp->dn_op) {
15477c478bd9Sstevel@tonic-gate 	case DT_TOK_COMMA:
15487c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_left, dlp, drp);
15497c478bd9Sstevel@tonic-gate 		dt_regset_free(drp, dnp->dn_left->dn_reg);
15507c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_right, dlp, drp);
15517c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_right->dn_reg;
15527c478bd9Sstevel@tonic-gate 		break;
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 	case DT_TOK_ASGN:
15557c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_right, dlp, drp);
15567c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_right->dn_reg;
15577c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
15587c478bd9Sstevel@tonic-gate 		break;
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	case DT_TOK_ADD_EQ:
15617c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);
15627c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
15637c478bd9Sstevel@tonic-gate 		break;
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	case DT_TOK_SUB_EQ:
15667c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);
15677c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
15687c478bd9Sstevel@tonic-gate 		break;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	case DT_TOK_MUL_EQ:
15717c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);
15727c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
15737c478bd9Sstevel@tonic-gate 		break;
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	case DT_TOK_DIV_EQ:
15767c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp,
15777c478bd9Sstevel@tonic-gate 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);
15787c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
15797c478bd9Sstevel@tonic-gate 		break;
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	case DT_TOK_MOD_EQ:
15827c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp,
15837c478bd9Sstevel@tonic-gate 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);
15847c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
15857c478bd9Sstevel@tonic-gate 		break;
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 	case DT_TOK_AND_EQ:
15887c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);
15897c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
15907c478bd9Sstevel@tonic-gate 		break;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	case DT_TOK_XOR_EQ:
15937c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);
15947c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
15957c478bd9Sstevel@tonic-gate 		break;
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	case DT_TOK_OR_EQ:
15987c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);
15997c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
16007c478bd9Sstevel@tonic-gate 		break;
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	case DT_TOK_LSH_EQ:
16037c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);
16047c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
16057c478bd9Sstevel@tonic-gate 		break;
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 	case DT_TOK_RSH_EQ:
16087c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp,
16097c478bd9Sstevel@tonic-gate 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);
16107c478bd9Sstevel@tonic-gate 		dt_cg_asgn_op(dnp, dlp, drp);
16117c478bd9Sstevel@tonic-gate 		break;
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	case DT_TOK_QUESTION:
16147c478bd9Sstevel@tonic-gate 		dt_cg_ternary_op(dnp, dlp, drp);
16157c478bd9Sstevel@tonic-gate 		break;
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	case DT_TOK_LOR:
16187c478bd9Sstevel@tonic-gate 		dt_cg_logical_or(dnp, dlp, drp);
16197c478bd9Sstevel@tonic-gate 		break;
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 	case DT_TOK_LXOR:
16227c478bd9Sstevel@tonic-gate 		dt_cg_logical_xor(dnp, dlp, drp);
16237c478bd9Sstevel@tonic-gate 		break;
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate 	case DT_TOK_LAND:
16267c478bd9Sstevel@tonic-gate 		dt_cg_logical_and(dnp, dlp, drp);
16277c478bd9Sstevel@tonic-gate 		break;
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	case DT_TOK_BOR:
16307c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);
16317c478bd9Sstevel@tonic-gate 		break;
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	case DT_TOK_XOR:
16347c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);
16357c478bd9Sstevel@tonic-gate 		break;
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	case DT_TOK_BAND:
16387c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);
16397c478bd9Sstevel@tonic-gate 		break;
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 	case DT_TOK_EQU:
16427c478bd9Sstevel@tonic-gate 		dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BE);
16437c478bd9Sstevel@tonic-gate 		break;
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	case DT_TOK_NEQ:
16467c478bd9Sstevel@tonic-gate 		dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BNE);
16477c478bd9Sstevel@tonic-gate 		break;
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	case DT_TOK_LT:
16507c478bd9Sstevel@tonic-gate 		dt_cg_compare_op(dnp, dlp, drp,
16517c478bd9Sstevel@tonic-gate 		    dt_cg_compare_signed(dnp) ? DIF_OP_BL : DIF_OP_BLU);
16527c478bd9Sstevel@tonic-gate 		break;
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	case DT_TOK_LE:
16557c478bd9Sstevel@tonic-gate 		dt_cg_compare_op(dnp, dlp, drp,
16567c478bd9Sstevel@tonic-gate 		    dt_cg_compare_signed(dnp) ? DIF_OP_BLE : DIF_OP_BLEU);
16577c478bd9Sstevel@tonic-gate 		break;
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	case DT_TOK_GT:
16607c478bd9Sstevel@tonic-gate 		dt_cg_compare_op(dnp, dlp, drp,
16617c478bd9Sstevel@tonic-gate 		    dt_cg_compare_signed(dnp) ? DIF_OP_BG : DIF_OP_BGU);
16627c478bd9Sstevel@tonic-gate 		break;
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate 	case DT_TOK_GE:
16657c478bd9Sstevel@tonic-gate 		dt_cg_compare_op(dnp, dlp, drp,
16667c478bd9Sstevel@tonic-gate 		    dt_cg_compare_signed(dnp) ? DIF_OP_BGE : DIF_OP_BGEU);
16677c478bd9Sstevel@tonic-gate 		break;
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	case DT_TOK_LSH:
16707c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);
16717c478bd9Sstevel@tonic-gate 		break;
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 	case DT_TOK_RSH:
16747c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp,
16757c478bd9Sstevel@tonic-gate 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);
16767c478bd9Sstevel@tonic-gate 		break;
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 	case DT_TOK_ADD:
16797c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);
16807c478bd9Sstevel@tonic-gate 		break;
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	case DT_TOK_SUB:
16837c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);
16847c478bd9Sstevel@tonic-gate 		break;
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	case DT_TOK_MUL:
16877c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);
16887c478bd9Sstevel@tonic-gate 		break;
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 	case DT_TOK_DIV:
16917c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp,
16927c478bd9Sstevel@tonic-gate 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);
16937c478bd9Sstevel@tonic-gate 		break;
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate 	case DT_TOK_MOD:
16967c478bd9Sstevel@tonic-gate 		dt_cg_arithmetic_op(dnp, dlp, drp,
16977c478bd9Sstevel@tonic-gate 		    (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);
16987c478bd9Sstevel@tonic-gate 		break;
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	case DT_TOK_LNEG:
17017c478bd9Sstevel@tonic-gate 		dt_cg_logical_neg(dnp, dlp, drp);
17027c478bd9Sstevel@tonic-gate 		break;
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	case DT_TOK_BNEG:
17057c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_child, dlp, drp);
17067c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_child->dn_reg;
17077c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_NOT(dnp->dn_reg, dnp->dn_reg);
17087c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
17097c478bd9Sstevel@tonic-gate 		break;
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	case DT_TOK_PREINC:
17127c478bd9Sstevel@tonic-gate 		dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_ADD);
17137c478bd9Sstevel@tonic-gate 		break;
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	case DT_TOK_POSTINC:
17167c478bd9Sstevel@tonic-gate 		dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_ADD);
17177c478bd9Sstevel@tonic-gate 		break;
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	case DT_TOK_PREDEC:
17207c478bd9Sstevel@tonic-gate 		dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_SUB);
17217c478bd9Sstevel@tonic-gate 		break;
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	case DT_TOK_POSTDEC:
17247c478bd9Sstevel@tonic-gate 		dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_SUB);
17257c478bd9Sstevel@tonic-gate 		break;
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 	case DT_TOK_IPOS:
17287c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_child, dlp, drp);
17297c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_child->dn_reg;
17307c478bd9Sstevel@tonic-gate 		break;
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	case DT_TOK_INEG:
17337c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_child, dlp, drp);
17347c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_child->dn_reg;
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_FMT(DIF_OP_SUB, DIF_REG_R0,
17377c478bd9Sstevel@tonic-gate 		    dnp->dn_reg, dnp->dn_reg);
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
17407c478bd9Sstevel@tonic-gate 		break;
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 	case DT_TOK_DEREF:
17437c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_child, dlp, drp);
17447c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_child->dn_reg;
17457c478bd9Sstevel@tonic-gate 
1746e5803b76SAdam H. Leventhal 		if (dt_node_is_dynamic(dnp->dn_child)) {
1747e5803b76SAdam H. Leventhal 			int reg;
1748e5803b76SAdam H. Leventhal 			idp = dt_node_resolve(dnp->dn_child, DT_IDENT_XLPTR);
1749e5803b76SAdam H. Leventhal 			assert(idp != NULL);
1750e5803b76SAdam H. Leventhal 			reg = dt_cg_xlate_expand(dnp, idp, dlp, drp);
1751e5803b76SAdam H. Leventhal 
1752e5803b76SAdam H. Leventhal 			dt_regset_free(drp, dnp->dn_child->dn_reg);
1753e5803b76SAdam H. Leventhal 			dnp->dn_reg = reg;
1754e5803b76SAdam H. Leventhal 
1755e5803b76SAdam H. Leventhal 		} else if (!(dnp->dn_flags & DT_NF_REF)) {
17567c478bd9Sstevel@tonic-gate 			uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 			/*
17597c478bd9Sstevel@tonic-gate 			 * Save and restore DT_NF_USERLAND across dt_cg_load():
17607c478bd9Sstevel@tonic-gate 			 * we need the sign bit from dnp and the user bit from
17617c478bd9Sstevel@tonic-gate 			 * dnp->dn_child in order to get the proper opcode.
17627c478bd9Sstevel@tonic-gate 			 */
17637c478bd9Sstevel@tonic-gate 			dnp->dn_flags |=
17647c478bd9Sstevel@tonic-gate 			    (dnp->dn_child->dn_flags & DT_NF_USERLAND);
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 			instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,
17677c478bd9Sstevel@tonic-gate 			    dnp->dn_type), dnp->dn_reg, dnp->dn_reg);
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 			dnp->dn_flags &= ~DT_NF_USERLAND;
17707c478bd9Sstevel@tonic-gate 			dnp->dn_flags |= ubit;
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 			dt_irlist_append(dlp,
17737c478bd9Sstevel@tonic-gate 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
17747c478bd9Sstevel@tonic-gate 		}
17757c478bd9Sstevel@tonic-gate 		break;
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	case DT_TOK_ADDROF: {
17787c478bd9Sstevel@tonic-gate 		uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 		dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
17817c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_child, dlp, drp);
17827c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_child->dn_reg;
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 		dnp->dn_child->dn_flags &= ~DT_NF_REF;
17857c478bd9Sstevel@tonic-gate 		dnp->dn_child->dn_flags |= rbit;
17867c478bd9Sstevel@tonic-gate 		break;
17877c478bd9Sstevel@tonic-gate 	}
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 	case DT_TOK_SIZEOF: {
17907c478bd9Sstevel@tonic-gate 		size_t size = dt_node_sizeof(dnp->dn_child);
1791e5803b76SAdam H. Leventhal 		dnp->dn_reg = dt_regset_alloc(drp);
17927c478bd9Sstevel@tonic-gate 		assert(size != 0);
17937c478bd9Sstevel@tonic-gate 		dt_cg_setx(dlp, dnp->dn_reg, size);
17947c478bd9Sstevel@tonic-gate 		break;
17957c478bd9Sstevel@tonic-gate 	}
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 	case DT_TOK_STRINGOF:
17987c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_child, dlp, drp);
17997c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_child->dn_reg;
18007c478bd9Sstevel@tonic-gate 		break;
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 	case DT_TOK_XLATE:
18031a7c1b72Smws 		/*
18041a7c1b72Smws 		 * An xlate operator appears in either an XLATOR, indicating a
18051a7c1b72Smws 		 * reference to a dynamic translator, or an OP2, indicating
18061a7c1b72Smws 		 * use of the xlate operator in the user's program.  For the
18071a7c1b72Smws 		 * dynamic case, generate an xlate opcode with a reference to
18081a7c1b72Smws 		 * the corresponding member, pre-computed for us in dn_members.
18091a7c1b72Smws 		 */
18101a7c1b72Smws 		if (dnp->dn_kind == DT_NODE_XLATOR) {
18111a7c1b72Smws 			dt_xlator_t *dxp = dnp->dn_xlator;
18121a7c1b72Smws 
18131a7c1b72Smws 			assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG);
18141a7c1b72Smws 			assert(dxp->dx_ident->di_id != 0);
18151a7c1b72Smws 
1816e5803b76SAdam H. Leventhal 			dnp->dn_reg = dt_regset_alloc(drp);
18171a7c1b72Smws 
18181a7c1b72Smws 			if (dxp->dx_arg == -1) {
18191a7c1b72Smws 				instr = DIF_INSTR_MOV(
18201a7c1b72Smws 				    dxp->dx_ident->di_id, dnp->dn_reg);
18211a7c1b72Smws 				dt_irlist_append(dlp,
18221a7c1b72Smws 				    dt_cg_node_alloc(DT_LBL_NONE, instr));
18231a7c1b72Smws 				op = DIF_OP_XLATE;
18241a7c1b72Smws 			} else
18251a7c1b72Smws 				op = DIF_OP_XLARG;
18261a7c1b72Smws 
18271a7c1b72Smws 			instr = DIF_INSTR_XLATE(op, 0, dnp->dn_reg);
18281a7c1b72Smws 			dt_irlist_append(dlp,
18291a7c1b72Smws 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
18301a7c1b72Smws 
18311a7c1b72Smws 			dlp->dl_last->di_extern = dnp->dn_xmember;
18321a7c1b72Smws 			break;
18331a7c1b72Smws 		}
18341a7c1b72Smws 
18351a7c1b72Smws 		assert(dnp->dn_kind == DT_NODE_OP2);
18367c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_right, dlp, drp);
18377c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_right->dn_reg;
18387c478bd9Sstevel@tonic-gate 		break;
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate 	case DT_TOK_LPAR:
18417c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_right, dlp, drp);
18427c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_right->dn_reg;
18437c478bd9Sstevel@tonic-gate 		dt_cg_typecast(dnp->dn_right, dnp, dlp, drp);
18447c478bd9Sstevel@tonic-gate 		break;
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate 	case DT_TOK_PTR:
18477c478bd9Sstevel@tonic-gate 	case DT_TOK_DOT:
18487c478bd9Sstevel@tonic-gate 		assert(dnp->dn_right->dn_kind == DT_NODE_IDENT);
18497c478bd9Sstevel@tonic-gate 		dt_cg_node(dnp->dn_left, dlp, drp);
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 		/*
18527c478bd9Sstevel@tonic-gate 		 * If the left-hand side of PTR or DOT is a dynamic variable,
18537c478bd9Sstevel@tonic-gate 		 * we expect it to be the output of a D translator.   In this
18547c478bd9Sstevel@tonic-gate 		 * case, we look up the parse tree corresponding to the member
18557c478bd9Sstevel@tonic-gate 		 * that is being accessed and run the code generator over it.
18567c478bd9Sstevel@tonic-gate 		 * We then cast the result as if by the assignment operator.
18577c478bd9Sstevel@tonic-gate 		 */
18587c478bd9Sstevel@tonic-gate 		if ((idp = dt_node_resolve(
18597c478bd9Sstevel@tonic-gate 		    dnp->dn_left, DT_IDENT_XLSOU)) != NULL ||
18607c478bd9Sstevel@tonic-gate 		    (idp = dt_node_resolve(
18617c478bd9Sstevel@tonic-gate 		    dnp->dn_left, DT_IDENT_XLPTR)) != NULL) {
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate 			dt_xlator_t *dxp;
18647c478bd9Sstevel@tonic-gate 			dt_node_t *mnp;
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 			dxp = idp->di_data;
18677c478bd9Sstevel@tonic-gate 			mnp = dt_xlator_member(dxp, dnp->dn_right->dn_string);
18687c478bd9Sstevel@tonic-gate 			assert(mnp != NULL);
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 			dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
18717c478bd9Sstevel@tonic-gate 			dxp->dx_ident->di_id = dnp->dn_left->dn_reg;
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 			dt_cg_node(mnp->dn_membexpr, dlp, drp);
18747c478bd9Sstevel@tonic-gate 			dnp->dn_reg = mnp->dn_membexpr->dn_reg;
18757c478bd9Sstevel@tonic-gate 			dt_cg_typecast(mnp->dn_membexpr, dnp, dlp, drp);
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 			dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
18787c478bd9Sstevel@tonic-gate 			dxp->dx_ident->di_id = 0;
18797c478bd9Sstevel@tonic-gate 
18801a7c1b72Smws 			if (dnp->dn_left->dn_reg != -1)
18811a7c1b72Smws 				dt_regset_free(drp, dnp->dn_left->dn_reg);
18827c478bd9Sstevel@tonic-gate 			break;
18837c478bd9Sstevel@tonic-gate 		}
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 		ctfp = dnp->dn_left->dn_ctfp;
18867c478bd9Sstevel@tonic-gate 		type = ctf_type_resolve(ctfp, dnp->dn_left->dn_type);
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 		if (dnp->dn_op == DT_TOK_PTR) {
18897c478bd9Sstevel@tonic-gate 			type = ctf_type_reference(ctfp, type);
18907c478bd9Sstevel@tonic-gate 			type = ctf_type_resolve(ctfp, type);
18917c478bd9Sstevel@tonic-gate 		}
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 		if ((ctfp = dt_cg_membinfo(octfp = ctfp, type,
18947c478bd9Sstevel@tonic-gate 		    dnp->dn_right->dn_string, &m)) == NULL) {
18957c478bd9Sstevel@tonic-gate 			yypcb->pcb_hdl->dt_ctferr = ctf_errno(octfp);
18967c478bd9Sstevel@tonic-gate 			longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
18977c478bd9Sstevel@tonic-gate 		}
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 		if (m.ctm_offset != 0) {
1900e5803b76SAdam H. Leventhal 			int reg;
1901e5803b76SAdam H. Leventhal 
1902e5803b76SAdam H. Leventhal 			reg = dt_regset_alloc(drp);
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 			/*
19057c478bd9Sstevel@tonic-gate 			 * If the offset is not aligned on a byte boundary, it
19067c478bd9Sstevel@tonic-gate 			 * is a bit-field member and we will extract the value
19077c478bd9Sstevel@tonic-gate 			 * bits below after we generate the appropriate load.
19087c478bd9Sstevel@tonic-gate 			 */
19097c478bd9Sstevel@tonic-gate 			dt_cg_setx(dlp, reg, m.ctm_offset / NBBY);
19107c478bd9Sstevel@tonic-gate 
19117c478bd9Sstevel@tonic-gate 			instr = DIF_INSTR_FMT(DIF_OP_ADD,
19127c478bd9Sstevel@tonic-gate 			    dnp->dn_left->dn_reg, reg, dnp->dn_left->dn_reg);
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 			dt_irlist_append(dlp,
19157c478bd9Sstevel@tonic-gate 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
19167c478bd9Sstevel@tonic-gate 			dt_regset_free(drp, reg);
19177c478bd9Sstevel@tonic-gate 		}
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 		if (!(dnp->dn_flags & DT_NF_REF)) {
19207c478bd9Sstevel@tonic-gate 			uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 			/*
19237c478bd9Sstevel@tonic-gate 			 * Save and restore DT_NF_USERLAND across dt_cg_load():
19247c478bd9Sstevel@tonic-gate 			 * we need the sign bit from dnp and the user bit from
19257c478bd9Sstevel@tonic-gate 			 * dnp->dn_left in order to get the proper opcode.
19267c478bd9Sstevel@tonic-gate 			 */
19277c478bd9Sstevel@tonic-gate 			dnp->dn_flags |=
19287c478bd9Sstevel@tonic-gate 			    (dnp->dn_left->dn_flags & DT_NF_USERLAND);
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 			instr = DIF_INSTR_LOAD(dt_cg_load(dnp,
19317c478bd9Sstevel@tonic-gate 			    ctfp, m.ctm_type), dnp->dn_left->dn_reg,
19327c478bd9Sstevel@tonic-gate 			    dnp->dn_left->dn_reg);
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 			dnp->dn_flags &= ~DT_NF_USERLAND;
19357c478bd9Sstevel@tonic-gate 			dnp->dn_flags |= ubit;
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 			dt_irlist_append(dlp,
19387c478bd9Sstevel@tonic-gate 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 			if (dnp->dn_flags & DT_NF_BITFIELD)
19417c478bd9Sstevel@tonic-gate 				dt_cg_field_get(dnp, dlp, drp, ctfp, &m);
19427c478bd9Sstevel@tonic-gate 		}
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 		dnp->dn_reg = dnp->dn_left->dn_reg;
19457c478bd9Sstevel@tonic-gate 		break;
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	case DT_TOK_STRING:
1948e5803b76SAdam H. Leventhal 		dnp->dn_reg = dt_regset_alloc(drp);
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 		assert(dnp->dn_kind == DT_NODE_STRING);
19517c478bd9Sstevel@tonic-gate 		stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string);
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 		if (stroff == -1L)
19547c478bd9Sstevel@tonic-gate 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
19557c478bd9Sstevel@tonic-gate 		if (stroff > DIF_STROFF_MAX)
19567c478bd9Sstevel@tonic-gate 			longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG);
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 		instr = DIF_INSTR_SETS((ulong_t)stroff, dnp->dn_reg);
19597c478bd9Sstevel@tonic-gate 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
19607c478bd9Sstevel@tonic-gate 		break;
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	case DT_TOK_IDENT:
19637c478bd9Sstevel@tonic-gate 		/*
19647c478bd9Sstevel@tonic-gate 		 * If the specified identifier is a variable on which we have
19657c478bd9Sstevel@tonic-gate 		 * set the code generator register flag, then this variable
19667c478bd9Sstevel@tonic-gate 		 * has already had code generated for it and saved in di_id.
19677c478bd9Sstevel@tonic-gate 		 * Allocate a new register and copy the existing value to it.
19687c478bd9Sstevel@tonic-gate 		 */
19697c478bd9Sstevel@tonic-gate 		if (dnp->dn_kind == DT_NODE_VAR &&
19707c478bd9Sstevel@tonic-gate 		    (dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) {
1971e5803b76SAdam H. Leventhal 			dnp->dn_reg = dt_regset_alloc(drp);
19727c478bd9Sstevel@tonic-gate 			instr = DIF_INSTR_MOV(dnp->dn_ident->di_id,
19737c478bd9Sstevel@tonic-gate 			    dnp->dn_reg);
19747c478bd9Sstevel@tonic-gate 			dt_irlist_append(dlp,
19757c478bd9Sstevel@tonic-gate 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
19767c478bd9Sstevel@tonic-gate 			break;
19777c478bd9Sstevel@tonic-gate 		}
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 		/*
19807c478bd9Sstevel@tonic-gate 		 * Identifiers can represent function calls, variable refs, or
19817c478bd9Sstevel@tonic-gate 		 * symbols.  First we check for inlined variables, and handle
19827c478bd9Sstevel@tonic-gate 		 * them by generating code for the inline parse tree.
19837c478bd9Sstevel@tonic-gate 		 */
19847c478bd9Sstevel@tonic-gate 		if (dnp->dn_kind == DT_NODE_VAR &&
19857c478bd9Sstevel@tonic-gate 		    (dnp->dn_ident->di_flags & DT_IDFLG_INLINE)) {
19867c478bd9Sstevel@tonic-gate 			dt_cg_inline(dnp, dlp, drp);
19877c478bd9Sstevel@tonic-gate 			break;
19887c478bd9Sstevel@tonic-gate 		}
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 		switch (dnp->dn_kind) {
19917c478bd9Sstevel@tonic-gate 		case DT_NODE_FUNC:
19927c478bd9Sstevel@tonic-gate 			if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) {
19937c478bd9Sstevel@tonic-gate 				dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be "
19947c478bd9Sstevel@tonic-gate 				    "called from a D expression (D program "
19957c478bd9Sstevel@tonic-gate 				    "context required)\n",
19967c478bd9Sstevel@tonic-gate 				    dt_idkind_name(idp->di_kind), idp->di_name);
19977c478bd9Sstevel@tonic-gate 			}
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 			dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
20007c478bd9Sstevel@tonic-gate 
2001e5803b76SAdam H. Leventhal 			dnp->dn_reg = dt_regset_alloc(drp);
2002e5803b76SAdam H. Leventhal 			instr = DIF_INSTR_CALL(dnp->dn_ident->di_id,
2003e5803b76SAdam H. Leventhal 			    dnp->dn_reg);
20047c478bd9Sstevel@tonic-gate 
20057c478bd9Sstevel@tonic-gate 			dt_irlist_append(dlp,
20067c478bd9Sstevel@tonic-gate 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
20077c478bd9Sstevel@tonic-gate 
20087c478bd9Sstevel@tonic-gate 			break;
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate 		case DT_NODE_VAR:
20117c478bd9Sstevel@tonic-gate 			if (dnp->dn_ident->di_kind == DT_IDENT_XLSOU ||
20127c478bd9Sstevel@tonic-gate 			    dnp->dn_ident->di_kind == DT_IDENT_XLPTR) {
20137c478bd9Sstevel@tonic-gate 				/*
20147c478bd9Sstevel@tonic-gate 				 * This can only happen if we have translated
20157c478bd9Sstevel@tonic-gate 				 * args[].  See dt_idcook_args() for details.
20167c478bd9Sstevel@tonic-gate 				 */
20177c478bd9Sstevel@tonic-gate 				assert(dnp->dn_ident->di_id == DIF_VAR_ARGS);
20187c478bd9Sstevel@tonic-gate 				dt_cg_array_op(dnp, dlp, drp);
20197c478bd9Sstevel@tonic-gate 				break;
20207c478bd9Sstevel@tonic-gate 			}
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate 			if (dnp->dn_ident->di_kind == DT_IDENT_ARRAY) {
20237c478bd9Sstevel@tonic-gate 				if (dnp->dn_ident->di_id > DIF_VAR_ARRAY_MAX)
20247c478bd9Sstevel@tonic-gate 					dt_cg_assoc_op(dnp, dlp, drp);
20257c478bd9Sstevel@tonic-gate 				else
20267c478bd9Sstevel@tonic-gate 					dt_cg_array_op(dnp, dlp, drp);
20277c478bd9Sstevel@tonic-gate 				break;
20287c478bd9Sstevel@tonic-gate 			}
20297c478bd9Sstevel@tonic-gate 
2030e5803b76SAdam H. Leventhal 			dnp->dn_reg = dt_regset_alloc(drp);
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 			if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)
20337c478bd9Sstevel@tonic-gate 				op = DIF_OP_LDLS;
20347c478bd9Sstevel@tonic-gate 			else if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
20357c478bd9Sstevel@tonic-gate 				op = DIF_OP_LDTS;
20367c478bd9Sstevel@tonic-gate 			else
20377c478bd9Sstevel@tonic-gate 				op = DIF_OP_LDGS;
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 			dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate 			instr = DIF_INSTR_LDV(op,
20427c478bd9Sstevel@tonic-gate 			    dnp->dn_ident->di_id, dnp->dn_reg);
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 			dt_irlist_append(dlp,
20457c478bd9Sstevel@tonic-gate 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
20467c478bd9Sstevel@tonic-gate 			break;
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 		case DT_NODE_SYM: {
20497c478bd9Sstevel@tonic-gate 			dtrace_hdl_t *dtp = yypcb->pcb_hdl;
20507c478bd9Sstevel@tonic-gate 			dtrace_syminfo_t *sip = dnp->dn_ident->di_data;
20517c478bd9Sstevel@tonic-gate 			GElf_Sym sym;
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 			if (dtrace_lookup_by_name(dtp,
20547c478bd9Sstevel@tonic-gate 			    sip->dts_object, sip->dts_name, &sym, NULL) == -1) {
20557c478bd9Sstevel@tonic-gate 				xyerror(D_UNKNOWN, "cg failed for symbol %s`%s:"
20567c478bd9Sstevel@tonic-gate 				    " %s\n", sip->dts_object, sip->dts_name,
20577c478bd9Sstevel@tonic-gate 				    dtrace_errmsg(dtp, dtrace_errno(dtp)));
20587c478bd9Sstevel@tonic-gate 			}
20597c478bd9Sstevel@tonic-gate 
2060e5803b76SAdam H. Leventhal 			dnp->dn_reg = dt_regset_alloc(drp);
20617c478bd9Sstevel@tonic-gate 			dt_cg_xsetx(dlp, dnp->dn_ident,
20627c478bd9Sstevel@tonic-gate 			    DT_LBL_NONE, dnp->dn_reg, sym.st_value);
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 			if (!(dnp->dn_flags & DT_NF_REF)) {
20657c478bd9Sstevel@tonic-gate 				instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,
20667c478bd9Sstevel@tonic-gate 				    dnp->dn_type), dnp->dn_reg, dnp->dn_reg);
20677c478bd9Sstevel@tonic-gate 				dt_irlist_append(dlp,
20687c478bd9Sstevel@tonic-gate 				    dt_cg_node_alloc(DT_LBL_NONE, instr));
20697c478bd9Sstevel@tonic-gate 			}
20707c478bd9Sstevel@tonic-gate 			break;
20717c478bd9Sstevel@tonic-gate 		}
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 		default:
20747c478bd9Sstevel@tonic-gate 			xyerror(D_UNKNOWN, "internal error -- node type %u is "
20757c478bd9Sstevel@tonic-gate 			    "not valid for an identifier\n", dnp->dn_kind);
20767c478bd9Sstevel@tonic-gate 		}
20777c478bd9Sstevel@tonic-gate 		break;
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate 	case DT_TOK_INT:
2080e5803b76SAdam H. Leventhal 		dnp->dn_reg = dt_regset_alloc(drp);
20817c478bd9Sstevel@tonic-gate 		dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value);
20827c478bd9Sstevel@tonic-gate 		break;
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 	default:
20857c478bd9Sstevel@tonic-gate 		xyerror(D_UNKNOWN, "internal error -- token type %u is not a "
20867c478bd9Sstevel@tonic-gate 		    "valid D compilation token\n", dnp->dn_op);
20877c478bd9Sstevel@tonic-gate 	}
20887c478bd9Sstevel@tonic-gate }
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate void
dt_cg(dt_pcb_t * pcb,dt_node_t * dnp)20917c478bd9Sstevel@tonic-gate dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate 	dif_instr_t instr;
20941a7c1b72Smws 	dt_xlator_t *dxp;
2095e5803b76SAdam H. Leventhal 	dt_ident_t *idp;
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 	if (pcb->pcb_regs == NULL && (pcb->pcb_regs =
20987c478bd9Sstevel@tonic-gate 	    dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL)
20997c478bd9Sstevel@tonic-gate 		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	dt_regset_reset(pcb->pcb_regs);
21027c478bd9Sstevel@tonic-gate 	(void) dt_regset_alloc(pcb->pcb_regs); /* allocate %r0 */
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	if (pcb->pcb_inttab != NULL)
21057c478bd9Sstevel@tonic-gate 		dt_inttab_destroy(pcb->pcb_inttab);
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	if ((pcb->pcb_inttab = dt_inttab_create(yypcb->pcb_hdl)) == NULL)
21087c478bd9Sstevel@tonic-gate 		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 	if (pcb->pcb_strtab != NULL)
21117c478bd9Sstevel@tonic-gate 		dt_strtab_destroy(pcb->pcb_strtab);
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 	if ((pcb->pcb_strtab = dt_strtab_create(BUFSIZ)) == NULL)
21147c478bd9Sstevel@tonic-gate 		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 	dt_irlist_destroy(&pcb->pcb_ir);
21177c478bd9Sstevel@tonic-gate 	dt_irlist_create(&pcb->pcb_ir);
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	assert(pcb->pcb_dret == NULL);
21207c478bd9Sstevel@tonic-gate 	pcb->pcb_dret = dnp;
21217c478bd9Sstevel@tonic-gate 
2122e5803b76SAdam H. Leventhal 	if (dt_node_resolve(dnp, DT_IDENT_XLPTR) != NULL) {
21237c478bd9Sstevel@tonic-gate 		dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result "
2124e5803b76SAdam H. Leventhal 		    "of a translated pointer\n");
21257c478bd9Sstevel@tonic-gate 	}
21267c478bd9Sstevel@tonic-gate 
21271a7c1b72Smws 	/*
21281a7c1b72Smws 	 * If we're generating code for a translator body, assign the input
21291a7c1b72Smws 	 * parameter to the first available register (i.e. caller passes %r1).
21301a7c1b72Smws 	 */
21311a7c1b72Smws 	if (dnp->dn_kind == DT_NODE_MEMBER) {
21321a7c1b72Smws 		dxp = dnp->dn_membxlator;
21331a7c1b72Smws 		dnp = dnp->dn_membexpr;
21341a7c1b72Smws 
21351a7c1b72Smws 		dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
21361a7c1b72Smws 		dxp->dx_ident->di_id = dt_regset_alloc(pcb->pcb_regs);
21371a7c1b72Smws 	}
21381a7c1b72Smws 
21397c478bd9Sstevel@tonic-gate 	dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs);
2140e5803b76SAdam H. Leventhal 
2141e5803b76SAdam H. Leventhal 	if ((idp = dt_node_resolve(dnp, DT_IDENT_XLSOU)) != NULL) {
2142e5803b76SAdam H. Leventhal 		int reg = dt_cg_xlate_expand(dnp, idp,
2143e5803b76SAdam H. Leventhal 		    &pcb->pcb_ir, pcb->pcb_regs);
2144e5803b76SAdam H. Leventhal 		dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
2145e5803b76SAdam H. Leventhal 		dnp->dn_reg = reg;
2146e5803b76SAdam H. Leventhal 	}
2147e5803b76SAdam H. Leventhal 
21487c478bd9Sstevel@tonic-gate 	instr = DIF_INSTR_RET(dnp->dn_reg);
21497c478bd9Sstevel@tonic-gate 	dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
21507c478bd9Sstevel@tonic-gate 	dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr));
21511a7c1b72Smws 
21521a7c1b72Smws 	if (dnp->dn_kind == DT_NODE_MEMBER) {
21531a7c1b72Smws 		dt_regset_free(pcb->pcb_regs, dxp->dx_ident->di_id);
21541a7c1b72Smws 		dxp->dx_ident->di_id = 0;
21551a7c1b72Smws 		dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
21561a7c1b72Smws 	}
2157e5803b76SAdam H. Leventhal 
2158e5803b76SAdam H. Leventhal 	dt_regset_free(pcb->pcb_regs, 0);
2159e5803b76SAdam H. Leventhal 	dt_regset_assert_free(pcb->pcb_regs);
21607c478bd9Sstevel@tonic-gate }
2161