Path: blob/main/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c
39562 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License, Version 1.0 only5* (the "License"). You may not use this file except in compliance6* with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or http://www.opensolaris.org/os/licensing.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright 2005 Sun Microsystems, Inc. All rights reserved.24* Use is subject to license terms.25*/2627/*28* Copyright (c) 2012 by Delphix. All rights reserved.29*/3031#include <sys/types.h>32#include <sys/sysmacros.h>33#include <sys/isa_defs.h>3435#include <strings.h>36#include <stdlib.h>37#include <setjmp.h>38#include <assert.h>39#include <errno.h>4041#include <dt_impl.h>42#include <dt_grammar.h>43#include <dt_parser.h>44#include <dt_provider.h>4546static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *);4748static dt_irnode_t *49dt_cg_node_alloc(uint_t label, dif_instr_t instr)50{51dt_irnode_t *dip = malloc(sizeof (dt_irnode_t));5253if (dip == NULL)54longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);5556dip->di_label = label;57dip->di_instr = instr;58dip->di_extern = NULL;59dip->di_next = NULL;6061return (dip);62}6364/*65* Code generator wrapper function for ctf_member_info. If we are given a66* reference to a forward declaration tag, search the entire type space for67* the actual definition and then call ctf_member_info on the result.68*/69static ctf_file_t *70dt_cg_membinfo(ctf_file_t *fp, ctf_id_t type, const char *s, ctf_membinfo_t *mp)71{72while (ctf_type_kind(fp, type) == CTF_K_FORWARD) {73char n[DT_TYPE_NAMELEN];74dtrace_typeinfo_t dtt;7576if (ctf_type_name(fp, type, n, sizeof (n)) == NULL ||77dt_type_lookup(n, &dtt) == -1 || (78dtt.dtt_ctfp == fp && dtt.dtt_type == type))79break; /* unable to improve our position */8081fp = dtt.dtt_ctfp;82type = ctf_type_resolve(fp, dtt.dtt_type);83}8485if (ctf_member_info(fp, type, s, mp) == CTF_ERR)86return (NULL); /* ctf_errno is set for us */8788return (fp);89}9091static void92dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x)93{94int flag = idp != NULL ? DT_INT_PRIVATE : DT_INT_SHARED;95int intoff = dt_inttab_insert(yypcb->pcb_inttab, x, flag);96dif_instr_t instr = DIF_INSTR_SETX((uint_t)intoff, reg);9798if (intoff == -1)99longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);100101if (intoff > DIF_INTOFF_MAX)102longjmp(yypcb->pcb_jmpbuf, EDT_INT2BIG);103104dt_irlist_append(dlp, dt_cg_node_alloc(lbl, instr));105106if (idp != NULL)107dlp->dl_last->di_extern = idp;108}109110static void111dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x)112{113dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x);114}115116/*117* When loading bit-fields, we want to convert a byte count in the range118* 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function119* is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.120*/121static size_t122clp2(size_t x)123{124x--;125126x |= (x >> 1);127x |= (x >> 2);128x |= (x >> 4);129x |= (x >> 8);130x |= (x >> 16);131132return (x + 1);133}134135/*136* Lookup the correct load opcode to use for the specified node and CTF type.137* We determine the size and convert it to a 3-bit index. Our lookup table138* is constructed to use a 5-bit index, consisting of the 3-bit size 0-7, a139* bit for the sign, and a bit for userland address. For example, a 4-byte140* signed load from userland would be at the following table index:141* user=1 sign=1 size=4 => binary index 11011 = decimal index 27142*/143static uint_t144dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)145{146static const uint_t ops[] = {147DIF_OP_LDUB, DIF_OP_LDUH, 0, DIF_OP_LDUW,1480, 0, 0, DIF_OP_LDX,149DIF_OP_LDSB, DIF_OP_LDSH, 0, DIF_OP_LDSW,1500, 0, 0, DIF_OP_LDX,151DIF_OP_ULDUB, DIF_OP_ULDUH, 0, DIF_OP_ULDUW,1520, 0, 0, DIF_OP_ULDX,153DIF_OP_ULDSB, DIF_OP_ULDSH, 0, DIF_OP_ULDSW,1540, 0, 0, DIF_OP_ULDX,155};156157ctf_encoding_t e;158ssize_t size;159160/*161* If we're loading a bit-field, the size of our load is found by162* rounding cte_bits up to a byte boundary and then finding the163* nearest power of two to this value (see clp2(), above).164*/165if ((dnp->dn_flags & DT_NF_BITFIELD) &&166ctf_type_encoding(ctfp, type, &e) != CTF_ERR)167size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);168else169size = ctf_type_size(ctfp, type);170171if (size < 1 || size > 8 || (size & (size - 1)) != 0) {172xyerror(D_UNKNOWN, "internal error -- cg cannot load "173"size %ld when passed by value\n", (long)size);174}175176size--; /* convert size to 3-bit index */177178if (dnp->dn_flags & DT_NF_SIGNED)179size |= 0x08;180if (dnp->dn_flags & DT_NF_USERLAND)181size |= 0x10;182183return (ops[size]);184}185186static void187dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,188uint_t op, int dreg)189{190ctf_file_t *ctfp = dnp->dn_ctfp;191ctf_arinfo_t r;192dif_instr_t instr;193ctf_id_t type;194uint_t kind;195ssize_t size;196int sreg;197198type = ctf_type_resolve(ctfp, dnp->dn_type);199kind = ctf_type_kind(ctfp, type);200assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY);201202if (kind == CTF_K_ARRAY) {203if (ctf_array_info(ctfp, type, &r) != 0) {204yypcb->pcb_hdl->dt_ctferr = ctf_errno(ctfp);205longjmp(yypcb->pcb_jmpbuf, EDT_CTF);206}207type = r.ctr_contents;208} else209type = ctf_type_reference(ctfp, type);210211if ((size = ctf_type_size(ctfp, type)) == 1)212return; /* multiply or divide by one can be omitted */213214sreg = dt_regset_alloc(drp);215dt_cg_setx(dlp, sreg, size);216instr = DIF_INSTR_FMT(op, dreg, sreg, dreg);217dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));218dt_regset_free(drp, sreg);219}220221/*222* If the result of a "." or "->" operation is a bit-field, we use this routine223* to generate an epilogue to the load instruction that extracts the value. In224* the diagrams below the "ld??" is the load instruction that is generated to225* load the containing word that is generating prior to calling this function.226*227* Epilogue for unsigned fields: Epilogue for signed fields:228*229* ldu? [r1], r1 lds? [r1], r1230* setx USHIFT, r2 setx 64 - SSHIFT, r2231* srl r1, r2, r1 sll r1, r2, r1232* setx (1 << bits) - 1, r2 setx 64 - bits, r2233* and r1, r2, r1 sra r1, r2, r1234*235* The *SHIFT constants above changes value depending on the endian-ness of our236* target architecture. Refer to the comments below for more details.237*/238static void239dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,240ctf_file_t *fp, const ctf_membinfo_t *mp)241{242ctf_encoding_t e;243dif_instr_t instr;244uint64_t shift;245int r1, r2;246247if (ctf_type_encoding(fp, mp->ctm_type, &e) != 0 || e.cte_bits > 64) {248xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "249"bits %u\n", mp->ctm_offset, mp->ctm_type, e.cte_bits);250}251252assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT);253r1 = dnp->dn_left->dn_reg;254r2 = dt_regset_alloc(drp);255256/*257* On little-endian architectures, ctm_offset counts from the right so258* ctm_offset % NBBY itself is the amount we want to shift right to259* move the value bits to the little end of the register to mask them.260* On big-endian architectures, ctm_offset counts from the left so we261* must subtract (ctm_offset % NBBY + cte_bits) from the size in bits262* we used for the load. The size of our load in turn is found by263* rounding cte_bits up to a byte boundary and then finding the264* nearest power of two to this value (see clp2(), above). These265* properties are used to compute shift as USHIFT or SSHIFT, below.266*/267if (dnp->dn_flags & DT_NF_SIGNED) {268#if BYTE_ORDER == _BIG_ENDIAN269shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -270mp->ctm_offset % NBBY;271#else272shift = mp->ctm_offset % NBBY + e.cte_bits;273#endif274dt_cg_setx(dlp, r2, 64 - shift);275instr = DIF_INSTR_FMT(DIF_OP_SLL, r1, r2, r1);276dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));277278dt_cg_setx(dlp, r2, 64 - e.cte_bits);279instr = DIF_INSTR_FMT(DIF_OP_SRA, r1, r2, r1);280dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));281} else {282#if BYTE_ORDER == _BIG_ENDIAN283shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -284(mp->ctm_offset % NBBY + e.cte_bits);285#else286shift = mp->ctm_offset % NBBY;287#endif288dt_cg_setx(dlp, r2, shift);289instr = DIF_INSTR_FMT(DIF_OP_SRL, r1, r2, r1);290dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));291292dt_cg_setx(dlp, r2, (1ULL << e.cte_bits) - 1);293instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);294dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));295}296297dt_regset_free(drp, r2);298}299300/*301* If the destination of a store operation is a bit-field, we use this routine302* to generate a prologue to the store instruction that loads the surrounding303* bits, clears the destination field, and ORs in the new value of the field.304* In the diagram below the "st?" is the store instruction that is generated to305* store the containing word that is generating after calling this function.306*307* ld [dst->dn_reg], r1308* setx ~(((1 << cte_bits) - 1) << (ctm_offset % NBBY)), r2309* and r1, r2, r1310*311* setx (1 << cte_bits) - 1, r2312* and src->dn_reg, r2, r2313* setx ctm_offset % NBBY, r3314* sll r2, r3, r2315*316* or r1, r2, r1317* st? r1, [dst->dn_reg]318*319* This routine allocates a new register to hold the value to be stored and320* returns it. The caller is responsible for freeing this register later.321*/322static int323dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp,324dt_regset_t *drp, dt_node_t *dst)325{326uint64_t cmask, fmask, shift;327dif_instr_t instr;328int r1, r2, r3;329330ctf_membinfo_t m;331ctf_encoding_t e;332ctf_file_t *fp, *ofp;333ctf_id_t type;334335assert(dst->dn_op == DT_TOK_PTR || dst->dn_op == DT_TOK_DOT);336assert(dst->dn_right->dn_kind == DT_NODE_IDENT);337338fp = dst->dn_left->dn_ctfp;339type = ctf_type_resolve(fp, dst->dn_left->dn_type);340341if (dst->dn_op == DT_TOK_PTR) {342type = ctf_type_reference(fp, type);343type = ctf_type_resolve(fp, type);344}345346if ((fp = dt_cg_membinfo(ofp = fp, type,347dst->dn_right->dn_string, &m)) == NULL) {348yypcb->pcb_hdl->dt_ctferr = ctf_errno(ofp);349longjmp(yypcb->pcb_jmpbuf, EDT_CTF);350}351352if (ctf_type_encoding(fp, m.ctm_type, &e) != 0 || e.cte_bits > 64) {353xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "354"bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits);355}356357r1 = dt_regset_alloc(drp);358r2 = dt_regset_alloc(drp);359r3 = dt_regset_alloc(drp);360361/*362* Compute shifts and masks. We need to compute "shift" as the amount363* we need to shift left to position our field in the containing word.364* Refer to the comments in dt_cg_field_get(), above, for more info.365* We then compute fmask as the mask that truncates the value in the366* input register to width cte_bits, and cmask as the mask used to367* pass through the containing bits and zero the field bits.368*/369#if BYTE_ORDER == _BIG_ENDIAN370shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -371(m.ctm_offset % NBBY + e.cte_bits);372#else373shift = m.ctm_offset % NBBY;374#endif375fmask = (1ULL << e.cte_bits) - 1;376cmask = ~(fmask << shift);377378instr = DIF_INSTR_LOAD(379dt_cg_load(dst, fp, m.ctm_type), dst->dn_reg, r1);380dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));381382dt_cg_setx(dlp, r2, cmask);383instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);384dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));385386dt_cg_setx(dlp, r2, fmask);387instr = DIF_INSTR_FMT(DIF_OP_AND, src->dn_reg, r2, r2);388dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));389390dt_cg_setx(dlp, r3, shift);391instr = DIF_INSTR_FMT(DIF_OP_SLL, r2, r3, r2);392dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));393394instr = DIF_INSTR_FMT(DIF_OP_OR, r1, r2, r1);395dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));396397dt_regset_free(drp, r3);398dt_regset_free(drp, r2);399400return (r1);401}402403static void404dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)405{406ctf_encoding_t e;407dif_instr_t instr;408size_t size;409int reg;410411/*412* If we're loading a bit-field, the size of our store is found by413* rounding dst's cte_bits up to a byte boundary and then finding the414* nearest power of two to this value (see clp2(), above).415*/416if ((dst->dn_flags & DT_NF_BITFIELD) &&417ctf_type_encoding(dst->dn_ctfp, dst->dn_type, &e) != CTF_ERR)418size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);419else420size = dt_node_type_size(src);421422if (src->dn_flags & DT_NF_REF) {423reg = dt_regset_alloc(drp);424dt_cg_setx(dlp, reg, size);425instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg);426dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));427dt_regset_free(drp, reg);428} else {429if (dst->dn_flags & DT_NF_BITFIELD)430reg = dt_cg_field_set(src, dlp, drp, dst);431else432reg = src->dn_reg;433434switch (size) {435case 1:436instr = DIF_INSTR_STORE(DIF_OP_STB, reg, dst->dn_reg);437break;438case 2:439instr = DIF_INSTR_STORE(DIF_OP_STH, reg, dst->dn_reg);440break;441case 4:442instr = DIF_INSTR_STORE(DIF_OP_STW, reg, dst->dn_reg);443break;444case 8:445instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg);446break;447default:448xyerror(D_UNKNOWN, "internal error -- cg cannot store "449"size %lu when passed by value\n", (ulong_t)size);450}451dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));452453if (dst->dn_flags & DT_NF_BITFIELD)454dt_regset_free(drp, reg);455}456}457458/*459* Generate code for a typecast or for argument promotion from the type of the460* actual to the type of the formal. We need to generate code for casts when461* a scalar type is being narrowed or changing signed-ness. We first shift the462* desired bits high (losing excess bits if narrowing) and then shift them down463* using logical shift (unsigned result) or arithmetic shift (signed result).464*/465static void466dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,467dt_irlist_t *dlp, dt_regset_t *drp)468{469size_t srcsize = dt_node_type_size(src);470size_t dstsize = dt_node_type_size(dst);471472dif_instr_t instr;473int rg;474475if (!dt_node_is_scalar(dst))476return; /* not a scalar */477if (dstsize == srcsize &&478((src->dn_flags ^ dst->dn_flags) & DT_NF_SIGNED) != 0)479return; /* not narrowing or changing signed-ness */480if (dstsize > srcsize && (src->dn_flags & DT_NF_SIGNED) == 0)481return; /* nothing to do in this case */482483rg = dt_regset_alloc(drp);484485if (dstsize > srcsize) {486int n = sizeof (uint64_t) * NBBY - srcsize * NBBY;487int s = (dstsize - srcsize) * NBBY;488489dt_cg_setx(dlp, rg, n);490491instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);492dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));493494if ((dst->dn_flags & DT_NF_SIGNED) || n == s) {495instr = DIF_INSTR_FMT(DIF_OP_SRA,496dst->dn_reg, rg, dst->dn_reg);497dt_irlist_append(dlp,498dt_cg_node_alloc(DT_LBL_NONE, instr));499} else {500dt_cg_setx(dlp, rg, s);501instr = DIF_INSTR_FMT(DIF_OP_SRA,502dst->dn_reg, rg, dst->dn_reg);503dt_irlist_append(dlp,504dt_cg_node_alloc(DT_LBL_NONE, instr));505dt_cg_setx(dlp, rg, n - s);506instr = DIF_INSTR_FMT(DIF_OP_SRL,507dst->dn_reg, rg, dst->dn_reg);508dt_irlist_append(dlp,509dt_cg_node_alloc(DT_LBL_NONE, instr));510}511} else if (dstsize != sizeof (uint64_t)) {512int n = sizeof (uint64_t) * NBBY - dstsize * NBBY;513514dt_cg_setx(dlp, rg, n);515516instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);517dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));518519instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ?520DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, rg, dst->dn_reg);521dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));522}523524dt_regset_free(drp, rg);525}526527/*528* Generate code to push the specified argument list on to the tuple stack.529* We use this routine for handling subroutine calls and associative arrays.530* We must first generate code for all subexpressions before loading the stack531* because any subexpression could itself require the use of the tuple stack.532* This holds a number of registers equal to the number of arguments, but this533* is not a huge problem because the number of arguments can't exceed the534* number of tuple register stack elements anyway. At most one extra register535* is required (either by dt_cg_typecast() or for dtdt_size, below). This536* implies that a DIF implementation should offer a number of general purpose537* registers at least one greater than the number of tuple registers.538*/539static void540dt_cg_arglist(dt_ident_t *idp, dt_node_t *args,541dt_irlist_t *dlp, dt_regset_t *drp)542{543const dt_idsig_t *isp = idp->di_data;544dt_node_t *dnp;545int i = 0;546547for (dnp = args; dnp != NULL; dnp = dnp->dn_list)548dt_cg_node(dnp, dlp, drp);549550dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));551552for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) {553dtrace_diftype_t t;554dif_instr_t instr;555uint_t op;556int reg;557558dt_node_diftype(yypcb->pcb_hdl, dnp, &t);559560isp->dis_args[i].dn_reg = dnp->dn_reg; /* re-use register */561dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp);562isp->dis_args[i].dn_reg = -1;563564if (t.dtdt_flags & DIF_TF_BYREF) {565op = DIF_OP_PUSHTR;566if (t.dtdt_size != 0) {567reg = dt_regset_alloc(drp);568dt_cg_setx(dlp, reg, t.dtdt_size);569} else {570reg = DIF_REG_R0;571}572} else {573op = DIF_OP_PUSHTV;574reg = DIF_REG_R0;575}576577instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg);578dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));579dt_regset_free(drp, dnp->dn_reg);580581if (reg != DIF_REG_R0)582dt_regset_free(drp, reg);583}584585if (i > yypcb->pcb_hdl->dt_conf.dtc_diftupregs)586longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG);587}588589static void590dt_cg_arithmetic_op(dt_node_t *dnp, dt_irlist_t *dlp,591dt_regset_t *drp, uint_t op)592{593int is_ptr_op = (dnp->dn_op == DT_TOK_ADD || dnp->dn_op == DT_TOK_SUB ||594dnp->dn_op == DT_TOK_ADD_EQ || dnp->dn_op == DT_TOK_SUB_EQ);595596int lp_is_ptr = dt_node_is_pointer(dnp->dn_left);597int rp_is_ptr = dt_node_is_pointer(dnp->dn_right);598599dif_instr_t instr;600601if (lp_is_ptr && rp_is_ptr) {602assert(dnp->dn_op == DT_TOK_SUB);603is_ptr_op = 0;604}605606dt_cg_node(dnp->dn_left, dlp, drp);607if (is_ptr_op && rp_is_ptr)608dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_left->dn_reg);609610dt_cg_node(dnp->dn_right, dlp, drp);611if (is_ptr_op && lp_is_ptr)612dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_right->dn_reg);613614instr = DIF_INSTR_FMT(op, dnp->dn_left->dn_reg,615dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);616617dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));618dt_regset_free(drp, dnp->dn_right->dn_reg);619dnp->dn_reg = dnp->dn_left->dn_reg;620621if (lp_is_ptr && rp_is_ptr)622dt_cg_ptrsize(dnp->dn_right,623dlp, drp, DIF_OP_UDIV, dnp->dn_reg);624}625626static uint_t627dt_cg_stvar(const dt_ident_t *idp)628{629static const uint_t aops[] = { DIF_OP_STGAA, DIF_OP_STTAA, DIF_OP_NOP };630static const uint_t sops[] = { DIF_OP_STGS, DIF_OP_STTS, DIF_OP_STLS };631632uint_t i = (((idp->di_flags & DT_IDFLG_LOCAL) != 0) << 1) |633((idp->di_flags & DT_IDFLG_TLS) != 0);634635return (idp->di_kind == DT_IDENT_ARRAY ? aops[i] : sops[i]);636}637638static void639dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)640{641ctf_file_t *ctfp = dnp->dn_ctfp;642dif_instr_t instr;643ctf_id_t type;644ssize_t size = 1;645int reg;646647if (dt_node_is_pointer(dnp)) {648type = ctf_type_resolve(ctfp, dnp->dn_type);649assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);650size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));651}652653dt_cg_node(dnp->dn_child, dlp, drp);654dnp->dn_reg = dnp->dn_child->dn_reg;655656reg = dt_regset_alloc(drp);657dt_cg_setx(dlp, reg, size);658659instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg);660dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));661dt_regset_free(drp, reg);662663/*664* If we are modifying a variable, generate an stv instruction from665* the variable specified by the identifier. If we are storing to a666* memory address, generate code again for the left-hand side using667* DT_NF_REF to get the address, and then generate a store to it.668* In both paths, we store the value in dnp->dn_reg (the new value).669*/670if (dnp->dn_child->dn_kind == DT_NODE_VAR) {671dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);672673idp->di_flags |= DT_IDFLG_DIFW;674instr = DIF_INSTR_STV(dt_cg_stvar(idp),675idp->di_id, dnp->dn_reg);676dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));677} else {678uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;679680assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);681assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);682683dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */684dt_cg_node(dnp->dn_child, dlp, drp);685686dt_cg_store(dnp, dlp, drp, dnp->dn_child);687dt_regset_free(drp, dnp->dn_child->dn_reg);688689dnp->dn_left->dn_flags &= ~DT_NF_REF;690dnp->dn_left->dn_flags |= rbit;691}692}693694static void695dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,696dt_regset_t *drp, uint_t op)697{698ctf_file_t *ctfp = dnp->dn_ctfp;699dif_instr_t instr;700ctf_id_t type;701ssize_t size = 1;702int nreg;703704if (dt_node_is_pointer(dnp)) {705type = ctf_type_resolve(ctfp, dnp->dn_type);706assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);707size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));708}709710dt_cg_node(dnp->dn_child, dlp, drp);711dnp->dn_reg = dnp->dn_child->dn_reg;712713nreg = dt_regset_alloc(drp);714dt_cg_setx(dlp, nreg, size);715instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg);716dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));717718/*719* If we are modifying a variable, generate an stv instruction from720* the variable specified by the identifier. If we are storing to a721* memory address, generate code again for the left-hand side using722* DT_NF_REF to get the address, and then generate a store to it.723* In both paths, we store the value from 'nreg' (the new value).724*/725if (dnp->dn_child->dn_kind == DT_NODE_VAR) {726dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);727728idp->di_flags |= DT_IDFLG_DIFW;729instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, nreg);730dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));731} else {732uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;733int oreg = dnp->dn_reg;734735assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);736assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);737738dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */739dt_cg_node(dnp->dn_child, dlp, drp);740741dnp->dn_reg = nreg;742dt_cg_store(dnp, dlp, drp, dnp->dn_child);743dnp->dn_reg = oreg;744745dt_regset_free(drp, dnp->dn_child->dn_reg);746dnp->dn_left->dn_flags &= ~DT_NF_REF;747dnp->dn_left->dn_flags |= rbit;748}749750dt_regset_free(drp, nreg);751}752753/*754* Determine if we should perform signed or unsigned comparison for an OP2.755* If both operands are of arithmetic type, perform the usual arithmetic756* conversions to determine the common real type for comparison [ISOC 6.5.8.3].757*/758static int759dt_cg_compare_signed(dt_node_t *dnp)760{761dt_node_t dn;762763if (dt_node_is_string(dnp->dn_left) ||764dt_node_is_string(dnp->dn_right))765return (1); /* strings always compare signed */766else if (!dt_node_is_arith(dnp->dn_left) ||767!dt_node_is_arith(dnp->dn_right))768return (0); /* non-arithmetic types always compare unsigned */769770bzero(&dn, sizeof (dn));771dt_node_promote(dnp->dn_left, dnp->dn_right, &dn);772return (dn.dn_flags & DT_NF_SIGNED);773}774775static void776dt_cg_compare_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)777{778uint_t lbl_true = dt_irlist_label(dlp);779uint_t lbl_post = dt_irlist_label(dlp);780781dif_instr_t instr;782uint_t opc;783784dt_cg_node(dnp->dn_left, dlp, drp);785dt_cg_node(dnp->dn_right, dlp, drp);786787if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right))788opc = DIF_OP_SCMP;789else790opc = DIF_OP_CMP;791792instr = DIF_INSTR_CMP(opc, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg);793dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));794dt_regset_free(drp, dnp->dn_right->dn_reg);795dnp->dn_reg = dnp->dn_left->dn_reg;796797instr = DIF_INSTR_BRANCH(op, lbl_true);798dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));799800instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);801dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));802803instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);804dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));805806dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);807dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));808}809810/*811* Code generation for the ternary op requires some trickery with the assembler812* in order to conserve registers. We generate code for dn_expr and dn_left813* and free their registers so they do not have be consumed across codegen for814* dn_right. We insert a dummy MOV at the end of dn_left into the destination815* register, which is not yet known because we haven't done dn_right yet, and816* save the pointer to this instruction node. We then generate code for817* dn_right and use its register as our output. Finally, we reach back and818* patch the instruction for dn_left to move its output into this register.819*/820static void821dt_cg_ternary_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)822{823uint_t lbl_false = dt_irlist_label(dlp);824uint_t lbl_post = dt_irlist_label(dlp);825826dif_instr_t instr;827dt_irnode_t *dip;828829dt_cg_node(dnp->dn_expr, dlp, drp);830instr = DIF_INSTR_TST(dnp->dn_expr->dn_reg);831dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));832dt_regset_free(drp, dnp->dn_expr->dn_reg);833834instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);835dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));836837dt_cg_node(dnp->dn_left, dlp, drp);838instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, DIF_REG_R0);839dip = dt_cg_node_alloc(DT_LBL_NONE, instr); /* save dip for below */840dt_irlist_append(dlp, dip);841dt_regset_free(drp, dnp->dn_left->dn_reg);842843instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);844dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));845846dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, DIF_INSTR_NOP));847dt_cg_node(dnp->dn_right, dlp, drp);848dnp->dn_reg = dnp->dn_right->dn_reg;849850/*851* Now that dn_reg is assigned, reach back and patch the correct MOV852* instruction into the tail of dn_left. We know dn_reg was unused853* at that point because otherwise dn_right couldn't have allocated it.854*/855dip->di_instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, dnp->dn_reg);856dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));857}858859static void860dt_cg_logical_and(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)861{862uint_t lbl_false = dt_irlist_label(dlp);863uint_t lbl_post = dt_irlist_label(dlp);864865dif_instr_t instr;866867dt_cg_node(dnp->dn_left, dlp, drp);868instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);869dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));870dt_regset_free(drp, dnp->dn_left->dn_reg);871872instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);873dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));874875dt_cg_node(dnp->dn_right, dlp, drp);876instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);877dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));878dnp->dn_reg = dnp->dn_right->dn_reg;879880instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);881dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));882883dt_cg_setx(dlp, dnp->dn_reg, 1);884885instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);886dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));887888instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);889dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));890891dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));892}893894static void895dt_cg_logical_xor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)896{897uint_t lbl_next = dt_irlist_label(dlp);898uint_t lbl_tail = dt_irlist_label(dlp);899900dif_instr_t instr;901902dt_cg_node(dnp->dn_left, dlp, drp);903instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);904dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));905906instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_next);907dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));908dt_cg_setx(dlp, dnp->dn_left->dn_reg, 1);909910dt_irlist_append(dlp, dt_cg_node_alloc(lbl_next, DIF_INSTR_NOP));911dt_cg_node(dnp->dn_right, dlp, drp);912913instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);914dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));915916instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_tail);917dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));918dt_cg_setx(dlp, dnp->dn_right->dn_reg, 1);919920instr = DIF_INSTR_FMT(DIF_OP_XOR, dnp->dn_left->dn_reg,921dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);922923dt_irlist_append(dlp, dt_cg_node_alloc(lbl_tail, instr));924925dt_regset_free(drp, dnp->dn_right->dn_reg);926dnp->dn_reg = dnp->dn_left->dn_reg;927}928929static void930dt_cg_logical_or(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)931{932uint_t lbl_true = dt_irlist_label(dlp);933uint_t lbl_false = dt_irlist_label(dlp);934uint_t lbl_post = dt_irlist_label(dlp);935936dif_instr_t instr;937938dt_cg_node(dnp->dn_left, dlp, drp);939instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);940dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));941dt_regset_free(drp, dnp->dn_left->dn_reg);942943instr = DIF_INSTR_BRANCH(DIF_OP_BNE, lbl_true);944dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));945946dt_cg_node(dnp->dn_right, dlp, drp);947instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);948dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));949dnp->dn_reg = dnp->dn_right->dn_reg;950951instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);952dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));953954dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);955956instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);957dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));958959instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);960dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));961962dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));963}964965static void966dt_cg_logical_neg(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)967{968uint_t lbl_zero = dt_irlist_label(dlp);969uint_t lbl_post = dt_irlist_label(dlp);970971dif_instr_t instr;972973dt_cg_node(dnp->dn_child, dlp, drp);974dnp->dn_reg = dnp->dn_child->dn_reg;975976instr = DIF_INSTR_TST(dnp->dn_reg);977dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));978979instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_zero);980dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));981982instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);983dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));984985instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);986dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));987988dt_cg_xsetx(dlp, NULL, lbl_zero, dnp->dn_reg, 1);989dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));990}991992static void993dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)994{995dif_instr_t instr;996dt_ident_t *idp;997998/*999* If we are performing a structure assignment of a translated type,1000* we must instantiate all members and create a snapshot of the object1001* in scratch space. We allocs a chunk of memory, generate code for1002* each member, and then set dnp->dn_reg to the scratch object address.1003*/1004if ((idp = dt_node_resolve(dnp->dn_right, DT_IDENT_XLSOU)) != NULL) {1005ctf_membinfo_t ctm;1006dt_xlator_t *dxp = idp->di_data;1007dt_node_t *mnp, dn, mn;1008int r1, r2;10091010/*1011* Create two fake dt_node_t's representing operator "." and a1012* right-hand identifier child node. These will be repeatedly1013* modified according to each instantiated member so that we1014* can pass them to dt_cg_store() and effect a member store.1015*/1016bzero(&dn, sizeof (dt_node_t));1017dn.dn_kind = DT_NODE_OP2;1018dn.dn_op = DT_TOK_DOT;1019dn.dn_left = dnp;1020dn.dn_right = &mn;10211022bzero(&mn, sizeof (dt_node_t));1023mn.dn_kind = DT_NODE_IDENT;1024mn.dn_op = DT_TOK_IDENT;10251026/*1027* Allocate a register for our scratch data pointer. First we1028* set it to the size of our data structure, and then replace1029* it with the result of an allocs of the specified size.1030*/1031r1 = dt_regset_alloc(drp);1032dt_cg_setx(dlp, r1,1033ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base));10341035instr = DIF_INSTR_ALLOCS(r1, r1);1036dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));10371038/*1039* When dt_cg_asgn_op() is called, we have already generated1040* code for dnp->dn_right, which is the translator input. We1041* now associate this register with the translator's input1042* identifier so it can be referenced during our member loop.1043*/1044dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;1045dxp->dx_ident->di_id = dnp->dn_right->dn_reg;10461047for (mnp = dxp->dx_members; mnp != NULL; mnp = mnp->dn_list) {1048/*1049* Generate code for the translator member expression,1050* and then cast the result to the member type.1051*/1052dt_cg_node(mnp->dn_membexpr, dlp, drp);1053mnp->dn_reg = mnp->dn_membexpr->dn_reg;1054dt_cg_typecast(mnp->dn_membexpr, mnp, dlp, drp);10551056/*1057* Ask CTF for the offset of the member so we can store1058* to the appropriate offset. This call has already1059* been done once by the parser, so it should succeed.1060*/1061if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_base,1062mnp->dn_membname, &ctm) == CTF_ERR) {1063yypcb->pcb_hdl->dt_ctferr =1064ctf_errno(dxp->dx_dst_ctfp);1065longjmp(yypcb->pcb_jmpbuf, EDT_CTF);1066}10671068/*1069* If the destination member is at offset 0, store the1070* result directly to r1 (the scratch buffer address).1071* Otherwise allocate another temporary for the offset1072* and add r1 to it before storing the result.1073*/1074if (ctm.ctm_offset != 0) {1075r2 = dt_regset_alloc(drp);10761077/*1078* Add the member offset rounded down to the1079* nearest byte. If the offset was not aligned1080* on a byte boundary, this member is a bit-1081* field and dt_cg_store() will handle masking.1082*/1083dt_cg_setx(dlp, r2, ctm.ctm_offset / NBBY);1084instr = DIF_INSTR_FMT(DIF_OP_ADD, r1, r2, r2);1085dt_irlist_append(dlp,1086dt_cg_node_alloc(DT_LBL_NONE, instr));10871088dt_node_type_propagate(mnp, &dn);1089dn.dn_right->dn_string = mnp->dn_membname;1090dn.dn_reg = r2;10911092dt_cg_store(mnp, dlp, drp, &dn);1093dt_regset_free(drp, r2);10941095} else {1096dt_node_type_propagate(mnp, &dn);1097dn.dn_right->dn_string = mnp->dn_membname;1098dn.dn_reg = r1;10991100dt_cg_store(mnp, dlp, drp, &dn);1101}11021103dt_regset_free(drp, mnp->dn_reg);1104}11051106dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;1107dxp->dx_ident->di_id = 0;11081109if (dnp->dn_right->dn_reg != -1)1110dt_regset_free(drp, dnp->dn_right->dn_reg);11111112assert(dnp->dn_reg == dnp->dn_right->dn_reg);1113dnp->dn_reg = r1;1114}11151116/*1117* If we are storing to a variable, generate an stv instruction from1118* the variable specified by the identifier. If we are storing to a1119* memory address, generate code again for the left-hand side using1120* DT_NF_REF to get the address, and then generate a store to it.1121* In both paths, we assume dnp->dn_reg already has the new value.1122*/1123if (dnp->dn_left->dn_kind == DT_NODE_VAR) {1124idp = dt_ident_resolve(dnp->dn_left->dn_ident);11251126if (idp->di_kind == DT_IDENT_ARRAY)1127dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp);11281129idp->di_flags |= DT_IDFLG_DIFW;1130instr = DIF_INSTR_STV(dt_cg_stvar(idp),1131idp->di_id, dnp->dn_reg);1132dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1133} else {1134uint_t rbit = dnp->dn_left->dn_flags & DT_NF_REF;11351136assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE);1137assert(dnp->dn_left->dn_flags & DT_NF_LVALUE);11381139dnp->dn_left->dn_flags |= DT_NF_REF; /* force pass-by-ref */11401141dt_cg_node(dnp->dn_left, dlp, drp);1142dt_cg_store(dnp, dlp, drp, dnp->dn_left);1143dt_regset_free(drp, dnp->dn_left->dn_reg);11441145dnp->dn_left->dn_flags &= ~DT_NF_REF;1146dnp->dn_left->dn_flags |= rbit;1147}1148}11491150static void1151dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)1152{1153dif_instr_t instr;1154uint_t op;11551156assert(dnp->dn_kind == DT_NODE_VAR);1157assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL));1158assert(dnp->dn_args != NULL);11591160dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);11611162dnp->dn_reg = dt_regset_alloc(drp);11631164if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)1165op = DIF_OP_LDTAA;1166else1167op = DIF_OP_LDGAA;11681169dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;1170instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);1171dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));11721173/*1174* If the associative array is a pass-by-reference type, then we are1175* loading its value as a pointer to either load or store through it.1176* The array element in question may not have been faulted in yet, in1177* which case DIF_OP_LD*AA will return zero. We append an epilogue1178* of instructions similar to the following:1179*1180* ld?aa id, %r1 ! base ld?aa instruction above1181* tst %r1 ! start of epilogue1182* +--- bne label1183* | setx size, %r11184* | allocs %r1, %r11185* | st?aa id, %r11186* | ld?aa id, %r11187* v1188* label: < rest of code >1189*1190* The idea is that we allocs a zero-filled chunk of scratch space and1191* do a DIF_OP_ST*AA to fault in and initialize the array element, and1192* then reload it to get the faulted-in address of the new variable1193* storage. This isn't cheap, but pass-by-ref associative array values1194* are (thus far) uncommon and the allocs cost only occurs once. If1195* this path becomes important to DTrace users, we can improve things1196* by adding a new DIF opcode to fault in associative array elements.1197*/1198if (dnp->dn_flags & DT_NF_REF) {1199uint_t stvop = op == DIF_OP_LDTAA ? DIF_OP_STTAA : DIF_OP_STGAA;1200uint_t label = dt_irlist_label(dlp);12011202instr = DIF_INSTR_TST(dnp->dn_reg);1203dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));12041205instr = DIF_INSTR_BRANCH(DIF_OP_BNE, label);1206dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));12071208dt_cg_setx(dlp, dnp->dn_reg, dt_node_type_size(dnp));1209instr = DIF_INSTR_ALLOCS(dnp->dn_reg, dnp->dn_reg);1210dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));12111212dnp->dn_ident->di_flags |= DT_IDFLG_DIFW;1213instr = DIF_INSTR_STV(stvop, dnp->dn_ident->di_id, dnp->dn_reg);1214dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));12151216instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);1217dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));12181219dt_irlist_append(dlp, dt_cg_node_alloc(label, DIF_INSTR_NOP));1220}1221}12221223static void1224dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)1225{1226dt_probe_t *prp = yypcb->pcb_probe;1227uintmax_t saved = dnp->dn_args->dn_value;1228dt_ident_t *idp = dnp->dn_ident;12291230dif_instr_t instr;1231uint_t op;1232size_t size;1233int reg, n;12341235assert(dnp->dn_kind == DT_NODE_VAR);1236assert(!(idp->di_flags & DT_IDFLG_LOCAL));12371238assert(dnp->dn_args->dn_kind == DT_NODE_INT);1239assert(dnp->dn_args->dn_list == NULL);12401241/*1242* If this is a reference in the args[] array, temporarily modify the1243* array index according to the static argument mapping (if any),1244* unless the argument reference is provided by a dynamic translator.1245* If we're using a dynamic translator for args[], then just set dn_reg1246* to an invalid reg and return: DIF_OP_XLARG will fetch the arg later.1247*/1248if (idp->di_id == DIF_VAR_ARGS) {1249if ((idp->di_kind == DT_IDENT_XLPTR ||1250idp->di_kind == DT_IDENT_XLSOU) &&1251dt_xlator_dynamic(idp->di_data)) {1252dnp->dn_reg = -1;1253return;1254}1255dnp->dn_args->dn_value = prp->pr_mapping[saved];1256}12571258dt_cg_node(dnp->dn_args, dlp, drp);1259dnp->dn_args->dn_value = saved;12601261dnp->dn_reg = dnp->dn_args->dn_reg;12621263if (idp->di_flags & DT_IDFLG_TLS)1264op = DIF_OP_LDTA;1265else1266op = DIF_OP_LDGA;12671268idp->di_flags |= DT_IDFLG_DIFR;12691270instr = DIF_INSTR_LDA(op, idp->di_id,1271dnp->dn_args->dn_reg, dnp->dn_reg);12721273dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));12741275/*1276* If this is a reference to the args[] array, we need to take the1277* additional step of explicitly eliminating any bits larger than the1278* type size: the DIF interpreter in the kernel will always give us1279* the raw (64-bit) argument value, and any bits larger than the type1280* size may be junk. As a practical matter, this arises only on 64-bit1281* architectures and only when the argument index is larger than the1282* number of arguments passed directly to DTrace: if a 8-, 16- or1283* 32-bit argument must be retrieved from the stack, it is possible1284* (and it some cases, likely) that the upper bits will be garbage.1285*/1286if (idp->di_id != DIF_VAR_ARGS || !dt_node_is_scalar(dnp))1287return;12881289if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t))1290return;12911292reg = dt_regset_alloc(drp);1293assert(size < sizeof (uint64_t));1294n = sizeof (uint64_t) * NBBY - size * NBBY;12951296dt_cg_setx(dlp, reg, n);12971298instr = DIF_INSTR_FMT(DIF_OP_SLL, dnp->dn_reg, reg, dnp->dn_reg);1299dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));13001301instr = DIF_INSTR_FMT((dnp->dn_flags & DT_NF_SIGNED) ?1302DIF_OP_SRA : DIF_OP_SRL, dnp->dn_reg, reg, dnp->dn_reg);13031304dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1305dt_regset_free(drp, reg);1306}13071308/*1309* Generate code for an inlined variable reference. Inlines can be used to1310* define either scalar or associative array substitutions. For scalars, we1311* simply generate code for the parse tree saved in the identifier's din_root,1312* and then cast the resulting expression to the inline's declaration type.1313* For arrays, we take the input parameter subtrees from dnp->dn_args and1314* temporarily store them in the din_root of each din_argv[i] identifier,1315* which are themselves inlines and were set up for us by the parser. The1316* result is that any reference to the inlined parameter inside the top-level1317* din_root will turn into a recursive call to dt_cg_inline() for a scalar1318* inline whose din_root will refer to the subtree pointed to by the argument.1319*/1320static void1321dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)1322{1323dt_ident_t *idp = dnp->dn_ident;1324dt_idnode_t *inp = idp->di_iarg;13251326dt_idnode_t *pinp;1327dt_node_t *pnp;1328int i;13291330assert(idp->di_flags & DT_IDFLG_INLINE);1331assert(idp->di_ops == &dt_idops_inline);13321333if (idp->di_kind == DT_IDENT_ARRAY) {1334for (i = 0, pnp = dnp->dn_args;1335pnp != NULL; pnp = pnp->dn_list, i++) {1336if (inp->din_argv[i] != NULL) {1337pinp = inp->din_argv[i]->di_iarg;1338pinp->din_root = pnp;1339}1340}1341}13421343dt_cg_node(inp->din_root, dlp, drp);1344dnp->dn_reg = inp->din_root->dn_reg;1345dt_cg_typecast(inp->din_root, dnp, dlp, drp);13461347if (idp->di_kind == DT_IDENT_ARRAY) {1348for (i = 0; i < inp->din_argc; i++) {1349pinp = inp->din_argv[i]->di_iarg;1350pinp->din_root = NULL;1351}1352}1353}13541355typedef struct dt_xlmemb {1356dt_ident_t *dtxl_idp; /* translated ident */1357dt_irlist_t *dtxl_dlp; /* instruction list */1358dt_regset_t *dtxl_drp; /* register set */1359int dtxl_sreg; /* location of the translation input */1360int dtxl_dreg; /* location of our allocated buffer */1361} dt_xlmemb_t;13621363/*ARGSUSED*/1364static int1365dt_cg_xlate_member(const char *name, ctf_id_t type, ulong_t off, void *arg)1366{1367dt_xlmemb_t *dx = arg;1368dt_ident_t *idp = dx->dtxl_idp;1369dt_irlist_t *dlp = dx->dtxl_dlp;1370dt_regset_t *drp = dx->dtxl_drp;13711372dt_node_t *mnp;1373dt_xlator_t *dxp;13741375int reg, treg;1376uint32_t instr;1377size_t size;13781379/* Generate code for the translation. */1380dxp = idp->di_data;1381mnp = dt_xlator_member(dxp, name);13821383/* If there's no translator for the given member, skip it. */1384if (mnp == NULL)1385return (0);13861387dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;1388dxp->dx_ident->di_id = dx->dtxl_sreg;13891390dt_cg_node(mnp->dn_membexpr, dlp, drp);13911392dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;1393dxp->dx_ident->di_id = 0;13941395treg = mnp->dn_membexpr->dn_reg;13961397/* Compute the offset into our buffer and store the result there. */1398reg = dt_regset_alloc(drp);13991400dt_cg_setx(dlp, reg, off / NBBY);1401instr = DIF_INSTR_FMT(DIF_OP_ADD, dx->dtxl_dreg, reg, reg);1402dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));14031404size = ctf_type_size(mnp->dn_membexpr->dn_ctfp,1405mnp->dn_membexpr->dn_type);1406if (dt_node_is_scalar(mnp->dn_membexpr)) {1407/*1408* Copying scalars is simple.1409*/1410switch (size) {1411case 1:1412instr = DIF_INSTR_STORE(DIF_OP_STB, treg, reg);1413break;1414case 2:1415instr = DIF_INSTR_STORE(DIF_OP_STH, treg, reg);1416break;1417case 4:1418instr = DIF_INSTR_STORE(DIF_OP_STW, treg, reg);1419break;1420case 8:1421instr = DIF_INSTR_STORE(DIF_OP_STX, treg, reg);1422break;1423default:1424xyerror(D_UNKNOWN, "internal error -- unexpected "1425"size: %lu\n", (ulong_t)size);1426}14271428dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));14291430} else if (dt_node_is_string(mnp->dn_membexpr)) {1431int szreg;14321433/*1434* Use the copys instruction for strings.1435*/1436szreg = dt_regset_alloc(drp);1437dt_cg_setx(dlp, szreg, size);1438instr = DIF_INSTR_COPYS(treg, szreg, reg);1439dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1440dt_regset_free(drp, szreg);1441} else {1442int szreg;14431444/*1445* If it's anything else then we'll just bcopy it.1446*/1447szreg = dt_regset_alloc(drp);1448dt_cg_setx(dlp, szreg, size);1449dt_irlist_append(dlp,1450dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));1451instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,1452DIF_REG_R0, treg);1453dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1454instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,1455DIF_REG_R0, reg);1456dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1457instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,1458DIF_REG_R0, szreg);1459dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1460instr = DIF_INSTR_CALL(DIF_SUBR_BCOPY, szreg);1461dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1462dt_regset_free(drp, szreg);1463}14641465dt_regset_free(drp, reg);1466dt_regset_free(drp, treg);14671468return (0);1469}14701471/*1472* If we're expanding a translated type, we create an appropriately sized1473* buffer with alloca() and then translate each member into it.1474*/1475static int1476dt_cg_xlate_expand(dt_node_t *dnp, dt_ident_t *idp, dt_irlist_t *dlp,1477dt_regset_t *drp)1478{1479dt_xlmemb_t dlm;1480uint32_t instr;1481int dreg;1482size_t size;14831484dreg = dt_regset_alloc(drp);1485size = ctf_type_size(dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type);14861487/* Call alloca() to create the buffer. */1488dt_cg_setx(dlp, dreg, size);14891490dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));14911492instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, DIF_REG_R0, dreg);1493dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));14941495instr = DIF_INSTR_CALL(DIF_SUBR_ALLOCA, dreg);1496dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));14971498/* Generate the translation for each member. */1499dlm.dtxl_idp = idp;1500dlm.dtxl_dlp = dlp;1501dlm.dtxl_drp = drp;1502dlm.dtxl_sreg = dnp->dn_reg;1503dlm.dtxl_dreg = dreg;1504(void) ctf_member_iter(dnp->dn_ident->di_ctfp,1505dnp->dn_ident->di_type, dt_cg_xlate_member,1506&dlm);15071508return (dreg);1509}15101511static void1512dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)1513{1514ctf_file_t *ctfp = dnp->dn_ctfp;1515ctf_file_t *octfp;1516ctf_membinfo_t m;1517ctf_id_t type;15181519dif_instr_t instr;1520dt_ident_t *idp;1521ssize_t stroff;1522uint_t op;15231524switch (dnp->dn_op) {1525case DT_TOK_COMMA:1526dt_cg_node(dnp->dn_left, dlp, drp);1527dt_regset_free(drp, dnp->dn_left->dn_reg);1528dt_cg_node(dnp->dn_right, dlp, drp);1529dnp->dn_reg = dnp->dn_right->dn_reg;1530break;15311532case DT_TOK_ASGN:1533dt_cg_node(dnp->dn_right, dlp, drp);1534dnp->dn_reg = dnp->dn_right->dn_reg;1535dt_cg_asgn_op(dnp, dlp, drp);1536break;15371538case DT_TOK_ADD_EQ:1539dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);1540dt_cg_asgn_op(dnp, dlp, drp);1541break;15421543case DT_TOK_SUB_EQ:1544dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);1545dt_cg_asgn_op(dnp, dlp, drp);1546break;15471548case DT_TOK_MUL_EQ:1549dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);1550dt_cg_asgn_op(dnp, dlp, drp);1551break;15521553case DT_TOK_DIV_EQ:1554dt_cg_arithmetic_op(dnp, dlp, drp,1555(dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);1556dt_cg_asgn_op(dnp, dlp, drp);1557break;15581559case DT_TOK_MOD_EQ:1560dt_cg_arithmetic_op(dnp, dlp, drp,1561(dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);1562dt_cg_asgn_op(dnp, dlp, drp);1563break;15641565case DT_TOK_AND_EQ:1566dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);1567dt_cg_asgn_op(dnp, dlp, drp);1568break;15691570case DT_TOK_XOR_EQ:1571dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);1572dt_cg_asgn_op(dnp, dlp, drp);1573break;15741575case DT_TOK_OR_EQ:1576dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);1577dt_cg_asgn_op(dnp, dlp, drp);1578break;15791580case DT_TOK_LSH_EQ:1581dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);1582dt_cg_asgn_op(dnp, dlp, drp);1583break;15841585case DT_TOK_RSH_EQ:1586dt_cg_arithmetic_op(dnp, dlp, drp,1587(dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);1588dt_cg_asgn_op(dnp, dlp, drp);1589break;15901591case DT_TOK_QUESTION:1592dt_cg_ternary_op(dnp, dlp, drp);1593break;15941595case DT_TOK_LOR:1596dt_cg_logical_or(dnp, dlp, drp);1597break;15981599case DT_TOK_LXOR:1600dt_cg_logical_xor(dnp, dlp, drp);1601break;16021603case DT_TOK_LAND:1604dt_cg_logical_and(dnp, dlp, drp);1605break;16061607case DT_TOK_BOR:1608dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);1609break;16101611case DT_TOK_XOR:1612dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);1613break;16141615case DT_TOK_BAND:1616dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);1617break;16181619case DT_TOK_EQU:1620dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BE);1621break;16221623case DT_TOK_NEQ:1624dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BNE);1625break;16261627case DT_TOK_LT:1628dt_cg_compare_op(dnp, dlp, drp,1629dt_cg_compare_signed(dnp) ? DIF_OP_BL : DIF_OP_BLU);1630break;16311632case DT_TOK_LE:1633dt_cg_compare_op(dnp, dlp, drp,1634dt_cg_compare_signed(dnp) ? DIF_OP_BLE : DIF_OP_BLEU);1635break;16361637case DT_TOK_GT:1638dt_cg_compare_op(dnp, dlp, drp,1639dt_cg_compare_signed(dnp) ? DIF_OP_BG : DIF_OP_BGU);1640break;16411642case DT_TOK_GE:1643dt_cg_compare_op(dnp, dlp, drp,1644dt_cg_compare_signed(dnp) ? DIF_OP_BGE : DIF_OP_BGEU);1645break;16461647case DT_TOK_LSH:1648dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);1649break;16501651case DT_TOK_RSH:1652dt_cg_arithmetic_op(dnp, dlp, drp,1653(dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);1654break;16551656case DT_TOK_ADD:1657dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);1658break;16591660case DT_TOK_SUB:1661dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);1662break;16631664case DT_TOK_MUL:1665dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);1666break;16671668case DT_TOK_DIV:1669dt_cg_arithmetic_op(dnp, dlp, drp,1670(dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);1671break;16721673case DT_TOK_MOD:1674dt_cg_arithmetic_op(dnp, dlp, drp,1675(dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);1676break;16771678case DT_TOK_LNEG:1679dt_cg_logical_neg(dnp, dlp, drp);1680break;16811682case DT_TOK_BNEG:1683dt_cg_node(dnp->dn_child, dlp, drp);1684dnp->dn_reg = dnp->dn_child->dn_reg;1685instr = DIF_INSTR_NOT(dnp->dn_reg, dnp->dn_reg);1686dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1687break;16881689case DT_TOK_PREINC:1690dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_ADD);1691break;16921693case DT_TOK_POSTINC:1694dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_ADD);1695break;16961697case DT_TOK_PREDEC:1698dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_SUB);1699break;17001701case DT_TOK_POSTDEC:1702dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_SUB);1703break;17041705case DT_TOK_IPOS:1706dt_cg_node(dnp->dn_child, dlp, drp);1707dnp->dn_reg = dnp->dn_child->dn_reg;1708break;17091710case DT_TOK_INEG:1711dt_cg_node(dnp->dn_child, dlp, drp);1712dnp->dn_reg = dnp->dn_child->dn_reg;17131714instr = DIF_INSTR_FMT(DIF_OP_SUB, DIF_REG_R0,1715dnp->dn_reg, dnp->dn_reg);17161717dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1718break;17191720case DT_TOK_DEREF:1721dt_cg_node(dnp->dn_child, dlp, drp);1722dnp->dn_reg = dnp->dn_child->dn_reg;17231724if (dt_node_is_dynamic(dnp->dn_child)) {1725int reg;1726idp = dt_node_resolve(dnp->dn_child, DT_IDENT_XLPTR);1727assert(idp != NULL);1728reg = dt_cg_xlate_expand(dnp, idp, dlp, drp);17291730dt_regset_free(drp, dnp->dn_child->dn_reg);1731dnp->dn_reg = reg;17321733} else if (!(dnp->dn_flags & DT_NF_REF)) {1734uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;17351736/*1737* Save and restore DT_NF_USERLAND across dt_cg_load():1738* we need the sign bit from dnp and the user bit from1739* dnp->dn_child in order to get the proper opcode.1740*/1741dnp->dn_flags |=1742(dnp->dn_child->dn_flags & DT_NF_USERLAND);17431744instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,1745dnp->dn_type), dnp->dn_reg, dnp->dn_reg);17461747dnp->dn_flags &= ~DT_NF_USERLAND;1748dnp->dn_flags |= ubit;17491750dt_irlist_append(dlp,1751dt_cg_node_alloc(DT_LBL_NONE, instr));1752}1753break;17541755case DT_TOK_ADDROF: {1756uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;17571758dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */1759dt_cg_node(dnp->dn_child, dlp, drp);1760dnp->dn_reg = dnp->dn_child->dn_reg;17611762dnp->dn_child->dn_flags &= ~DT_NF_REF;1763dnp->dn_child->dn_flags |= rbit;1764break;1765}17661767case DT_TOK_SIZEOF: {1768size_t size = dt_node_sizeof(dnp->dn_child);1769dnp->dn_reg = dt_regset_alloc(drp);1770assert(size != 0);1771dt_cg_setx(dlp, dnp->dn_reg, size);1772break;1773}17741775case DT_TOK_STRINGOF:1776dt_cg_node(dnp->dn_child, dlp, drp);1777dnp->dn_reg = dnp->dn_child->dn_reg;1778break;17791780case DT_TOK_XLATE:1781/*1782* An xlate operator appears in either an XLATOR, indicating a1783* reference to a dynamic translator, or an OP2, indicating1784* use of the xlate operator in the user's program. For the1785* dynamic case, generate an xlate opcode with a reference to1786* the corresponding member, pre-computed for us in dn_members.1787*/1788if (dnp->dn_kind == DT_NODE_XLATOR) {1789dt_xlator_t *dxp = dnp->dn_xlator;17901791assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG);1792assert(dxp->dx_ident->di_id != 0);17931794dnp->dn_reg = dt_regset_alloc(drp);17951796if (dxp->dx_arg == -1) {1797instr = DIF_INSTR_MOV(1798dxp->dx_ident->di_id, dnp->dn_reg);1799dt_irlist_append(dlp,1800dt_cg_node_alloc(DT_LBL_NONE, instr));1801op = DIF_OP_XLATE;1802} else1803op = DIF_OP_XLARG;18041805instr = DIF_INSTR_XLATE(op, 0, dnp->dn_reg);1806dt_irlist_append(dlp,1807dt_cg_node_alloc(DT_LBL_NONE, instr));18081809dlp->dl_last->di_extern = dnp->dn_xmember;1810break;1811}18121813assert(dnp->dn_kind == DT_NODE_OP2);1814dt_cg_node(dnp->dn_right, dlp, drp);1815dnp->dn_reg = dnp->dn_right->dn_reg;1816break;18171818case DT_TOK_LPAR:1819dt_cg_node(dnp->dn_right, dlp, drp);1820dnp->dn_reg = dnp->dn_right->dn_reg;1821dt_cg_typecast(dnp->dn_right, dnp, dlp, drp);1822break;18231824case DT_TOK_PTR:1825case DT_TOK_DOT:1826assert(dnp->dn_right->dn_kind == DT_NODE_IDENT);1827dt_cg_node(dnp->dn_left, dlp, drp);18281829/*1830* If the left-hand side of PTR or DOT is a dynamic variable,1831* we expect it to be the output of a D translator. In this1832* case, we look up the parse tree corresponding to the member1833* that is being accessed and run the code generator over it.1834* We then cast the result as if by the assignment operator.1835*/1836if ((idp = dt_node_resolve(1837dnp->dn_left, DT_IDENT_XLSOU)) != NULL ||1838(idp = dt_node_resolve(1839dnp->dn_left, DT_IDENT_XLPTR)) != NULL) {18401841dt_xlator_t *dxp;1842dt_node_t *mnp;18431844dxp = idp->di_data;1845mnp = dt_xlator_member(dxp, dnp->dn_right->dn_string);1846assert(mnp != NULL);18471848dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;1849dxp->dx_ident->di_id = dnp->dn_left->dn_reg;18501851dt_cg_node(mnp->dn_membexpr, dlp, drp);1852dnp->dn_reg = mnp->dn_membexpr->dn_reg;1853dt_cg_typecast(mnp->dn_membexpr, dnp, dlp, drp);18541855dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;1856dxp->dx_ident->di_id = 0;18571858if (dnp->dn_left->dn_reg != -1)1859dt_regset_free(drp, dnp->dn_left->dn_reg);1860break;1861}18621863ctfp = dnp->dn_left->dn_ctfp;1864type = ctf_type_resolve(ctfp, dnp->dn_left->dn_type);18651866if (dnp->dn_op == DT_TOK_PTR) {1867type = ctf_type_reference(ctfp, type);1868type = ctf_type_resolve(ctfp, type);1869}18701871if ((ctfp = dt_cg_membinfo(octfp = ctfp, type,1872dnp->dn_right->dn_string, &m)) == NULL) {1873yypcb->pcb_hdl->dt_ctferr = ctf_errno(octfp);1874longjmp(yypcb->pcb_jmpbuf, EDT_CTF);1875}18761877if (m.ctm_offset != 0) {1878int reg;18791880reg = dt_regset_alloc(drp);18811882/*1883* If the offset is not aligned on a byte boundary, it1884* is a bit-field member and we will extract the value1885* bits below after we generate the appropriate load.1886*/1887dt_cg_setx(dlp, reg, m.ctm_offset / NBBY);18881889instr = DIF_INSTR_FMT(DIF_OP_ADD,1890dnp->dn_left->dn_reg, reg, dnp->dn_left->dn_reg);18911892dt_irlist_append(dlp,1893dt_cg_node_alloc(DT_LBL_NONE, instr));1894dt_regset_free(drp, reg);1895}18961897if (!(dnp->dn_flags & DT_NF_REF)) {1898uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;18991900/*1901* Save and restore DT_NF_USERLAND across dt_cg_load():1902* we need the sign bit from dnp and the user bit from1903* dnp->dn_left in order to get the proper opcode.1904*/1905dnp->dn_flags |=1906(dnp->dn_left->dn_flags & DT_NF_USERLAND);19071908instr = DIF_INSTR_LOAD(dt_cg_load(dnp,1909ctfp, m.ctm_type), dnp->dn_left->dn_reg,1910dnp->dn_left->dn_reg);19111912dnp->dn_flags &= ~DT_NF_USERLAND;1913dnp->dn_flags |= ubit;19141915dt_irlist_append(dlp,1916dt_cg_node_alloc(DT_LBL_NONE, instr));19171918if (dnp->dn_flags & DT_NF_BITFIELD)1919dt_cg_field_get(dnp, dlp, drp, ctfp, &m);1920}19211922dnp->dn_reg = dnp->dn_left->dn_reg;1923break;19241925case DT_TOK_STRING:1926dnp->dn_reg = dt_regset_alloc(drp);19271928assert(dnp->dn_kind == DT_NODE_STRING);1929stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string);19301931if (stroff == -1L)1932longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);1933if (stroff > DIF_STROFF_MAX)1934longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG);19351936instr = DIF_INSTR_SETS((ulong_t)stroff, dnp->dn_reg);1937dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));1938break;19391940case DT_TOK_IDENT:1941/*1942* If the specified identifier is a variable on which we have1943* set the code generator register flag, then this variable1944* has already had code generated for it and saved in di_id.1945* Allocate a new register and copy the existing value to it.1946*/1947if (dnp->dn_kind == DT_NODE_VAR &&1948(dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) {1949dnp->dn_reg = dt_regset_alloc(drp);1950instr = DIF_INSTR_MOV(dnp->dn_ident->di_id,1951dnp->dn_reg);1952dt_irlist_append(dlp,1953dt_cg_node_alloc(DT_LBL_NONE, instr));1954break;1955}19561957/*1958* Identifiers can represent function calls, variable refs, or1959* symbols. First we check for inlined variables, and handle1960* them by generating code for the inline parse tree.1961*/1962if (dnp->dn_kind == DT_NODE_VAR &&1963(dnp->dn_ident->di_flags & DT_IDFLG_INLINE)) {1964dt_cg_inline(dnp, dlp, drp);1965break;1966}19671968switch (dnp->dn_kind) {1969case DT_NODE_FUNC: {1970if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) {1971dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be "1972"called from a D expression (D program "1973"context required)\n",1974dt_idkind_name(idp->di_kind), idp->di_name);1975}19761977dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);19781979dnp->dn_reg = dt_regset_alloc(drp);1980instr = DIF_INSTR_CALL(dnp->dn_ident->di_id,1981dnp->dn_reg);19821983dt_irlist_append(dlp,1984dt_cg_node_alloc(DT_LBL_NONE, instr));19851986break;1987}19881989case DT_NODE_VAR:1990if (dnp->dn_ident->di_kind == DT_IDENT_XLSOU ||1991dnp->dn_ident->di_kind == DT_IDENT_XLPTR) {1992/*1993* This can only happen if we have translated1994* args[]. See dt_idcook_args() for details.1995*/1996assert(dnp->dn_ident->di_id == DIF_VAR_ARGS);1997dt_cg_array_op(dnp, dlp, drp);1998break;1999}20002001if (dnp->dn_ident->di_kind == DT_IDENT_ARRAY) {2002if (dnp->dn_ident->di_id > DIF_VAR_ARRAY_MAX)2003dt_cg_assoc_op(dnp, dlp, drp);2004else2005dt_cg_array_op(dnp, dlp, drp);2006break;2007}20082009dnp->dn_reg = dt_regset_alloc(drp);20102011if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)2012op = DIF_OP_LDLS;2013else if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)2014op = DIF_OP_LDTS;2015else2016op = DIF_OP_LDGS;20172018dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;20192020instr = DIF_INSTR_LDV(op,2021dnp->dn_ident->di_id, dnp->dn_reg);20222023dt_irlist_append(dlp,2024dt_cg_node_alloc(DT_LBL_NONE, instr));2025break;20262027case DT_NODE_SYM: {2028dtrace_hdl_t *dtp = yypcb->pcb_hdl;2029dtrace_syminfo_t *sip = dnp->dn_ident->di_data;2030GElf_Sym sym;20312032if (dtrace_lookup_by_name(dtp,2033sip->dts_object, sip->dts_name, &sym, NULL) == -1) {2034xyerror(D_UNKNOWN, "cg failed for symbol %s`%s:"2035" %s\n", sip->dts_object, sip->dts_name,2036dtrace_errmsg(dtp, dtrace_errno(dtp)));2037}20382039dnp->dn_reg = dt_regset_alloc(drp);2040dt_cg_xsetx(dlp, dnp->dn_ident,2041DT_LBL_NONE, dnp->dn_reg, sym.st_value);20422043if (!(dnp->dn_flags & DT_NF_REF)) {2044instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,2045dnp->dn_type), dnp->dn_reg, dnp->dn_reg);2046dt_irlist_append(dlp,2047dt_cg_node_alloc(DT_LBL_NONE, instr));2048}2049break;2050}20512052default:2053xyerror(D_UNKNOWN, "internal error -- node type %u is "2054"not valid for an identifier\n", dnp->dn_kind);2055}2056break;20572058case DT_TOK_INT:2059dnp->dn_reg = dt_regset_alloc(drp);2060dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value);2061break;20622063default:2064xyerror(D_UNKNOWN, "internal error -- token type %u is not a "2065"valid D compilation token\n", dnp->dn_op);2066}2067}20682069void2070dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)2071{2072dif_instr_t instr;2073dt_xlator_t *dxp;2074dt_ident_t *idp;20752076if (pcb->pcb_regs == NULL && (pcb->pcb_regs =2077dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL)2078longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);20792080dt_regset_reset(pcb->pcb_regs);2081(void) dt_regset_alloc(pcb->pcb_regs); /* allocate %r0 */20822083if (pcb->pcb_inttab != NULL)2084dt_inttab_destroy(pcb->pcb_inttab);20852086if ((pcb->pcb_inttab = dt_inttab_create(yypcb->pcb_hdl)) == NULL)2087longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);20882089if (pcb->pcb_strtab != NULL)2090dt_strtab_destroy(pcb->pcb_strtab);20912092if ((pcb->pcb_strtab = dt_strtab_create(BUFSIZ)) == NULL)2093longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);20942095dt_irlist_destroy(&pcb->pcb_ir);2096dt_irlist_create(&pcb->pcb_ir);20972098assert(pcb->pcb_dret == NULL);2099pcb->pcb_dret = dnp;21002101if (dt_node_resolve(dnp, DT_IDENT_XLPTR) != NULL) {2102dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result "2103"of a translated pointer\n");2104}21052106/*2107* If we're generating code for a translator body, assign the input2108* parameter to the first available register (i.e. caller passes %r1).2109*/2110if (dnp->dn_kind == DT_NODE_MEMBER) {2111dxp = dnp->dn_membxlator;2112dnp = dnp->dn_membexpr;21132114dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;2115dxp->dx_ident->di_id = dt_regset_alloc(pcb->pcb_regs);2116}21172118dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs);21192120if ((idp = dt_node_resolve(dnp, DT_IDENT_XLSOU)) != NULL) {2121int reg = dt_cg_xlate_expand(dnp, idp,2122&pcb->pcb_ir, pcb->pcb_regs);2123dt_regset_free(pcb->pcb_regs, dnp->dn_reg);2124dnp->dn_reg = reg;2125}21262127instr = DIF_INSTR_RET(dnp->dn_reg);2128dt_regset_free(pcb->pcb_regs, dnp->dn_reg);2129dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr));21302131if (dnp->dn_kind == DT_NODE_MEMBER) {2132dt_regset_free(pcb->pcb_regs, dxp->dx_ident->di_id);2133dxp->dx_ident->di_id = 0;2134dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;2135}21362137dt_regset_free(pcb->pcb_regs, 0);2138dt_regset_assert_free(pcb->pcb_regs);2139}214021412142