⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dt_cg.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Copyright 2005 Sun Microsystems, Inc.  All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident	"@(#)dt_cg.c	1.9	04/12/27 SMI"#include <sys/types.h>#include <sys/sysmacros.h>#include <sys/isa_defs.h>#include <strings.h>#include <stdlib.h>#include <setjmp.h>#include <assert.h>#include <errno.h>#include <dt_impl.h>#include <dt_grammar.h>#include <dt_parser.h>static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *);static dt_irnode_t *dt_cg_node_alloc(uint_t label, dif_instr_t instr){	dt_irnode_t *dip = malloc(sizeof (dt_irnode_t));	if (dip == NULL)		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);	dip->di_label = label;	dip->di_instr = instr;	dip->di_ident = NULL;	dip->di_next = NULL;	return (dip);}/* * Code generator wrapper function for ctf_member_info.  If we are given a * reference to a forward declaration tag, search the entire type space for * the actual definition and then call ctf_member_info on the result. */static ctf_file_t *dt_cg_membinfo(ctf_file_t *fp, ctf_id_t type, const char *s, ctf_membinfo_t *mp){	while (ctf_type_kind(fp, type) == CTF_K_FORWARD) {		char n[DT_TYPE_NAMELEN];		dtrace_typeinfo_t dtt;		if (ctf_type_name(fp, type, n, sizeof (n)) == NULL ||		    dt_type_lookup(n, &dtt) == -1 || (		    dtt.dtt_ctfp == fp && dtt.dtt_type == type))			break; /* unable to improve our position */		fp = dtt.dtt_ctfp;		type = ctf_type_resolve(fp, dtt.dtt_type);	}	if (ctf_member_info(fp, type, s, mp) == CTF_ERR)		return (NULL); /* ctf_errno is set for us */	return (fp);}static voiddt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x){	int flag = idp != NULL ? DT_INT_PRIVATE : DT_INT_SHARED;	int intoff = dt_inttab_insert(yypcb->pcb_inttab, x, flag);	dif_instr_t instr = DIF_INSTR_SETX((uint_t)intoff, reg);	if (intoff == -1)		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);	if (intoff > DIF_INTOFF_MAX)		longjmp(yypcb->pcb_jmpbuf, EDT_INT2BIG);	dt_irlist_append(dlp, dt_cg_node_alloc(lbl, instr));	if (idp != NULL)		dlp->dl_last->di_ident = idp;}static voiddt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x){	dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x);}/* * When loading bit-fields, we want to convert a byte count in the range * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc).  The clp2() function * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr. */static size_tclp2(size_t x){	x--;	x |= (x >> 1);	x |= (x >> 2);	x |= (x >> 4);	x |= (x >> 8);	x |= (x >> 16);	return (x + 1);}/* * Lookup the correct load opcode to use for the specified node and CTF type. * We determine the size and convert it to a 3-bit index.  Our lookup table * is constructed to use a 5-bit index, consisting of the 3-bit size 0-7, a * bit for the sign, and a bit for userland address.  For example, a 4-byte * signed load from userland would be at the following table index: * user=1 sign=1 size=4 => binary index 11011 = decimal index 27 */static uint_tdt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type){	static const uint_t ops[] = {		DIF_OP_LDUB,	DIF_OP_LDUH,	0,	DIF_OP_LDUW,		0,		0,		0,	DIF_OP_LDX,		DIF_OP_LDSB,	DIF_OP_LDSH,	0,	DIF_OP_LDSW,		0,		0,		0,	DIF_OP_LDX,		DIF_OP_ULDUB,	DIF_OP_ULDUH,	0,	DIF_OP_ULDUW,		0,		0,		0,	DIF_OP_ULDX,		DIF_OP_ULDSB,	DIF_OP_ULDSH,	0,	DIF_OP_ULDSW,		0,		0,		0,	DIF_OP_ULDX,	};	ctf_encoding_t e;	ssize_t size;	/*	 * If we're loading a bit-field, the size of our load is found by	 * rounding cte_bits up to a byte boundary and then finding the	 * nearest power of two to this value (see clp2(), above).	 */	if ((dnp->dn_flags & DT_NF_BITFIELD) &&	    ctf_type_encoding(ctfp, type, &e) != CTF_ERR)		size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);	else		size = ctf_type_size(ctfp, type);	if (size < 1 || size > 8 || (size & (size - 1)) != 0) {		xyerror(D_UNKNOWN, "internal error -- cg cannot load "		    "size %ld when passed by value\n", (long)size);	}	size--; /* convert size to 3-bit index */	if (dnp->dn_flags & DT_NF_SIGNED)		size |= 0x08;	if (dnp->dn_flags & DT_NF_USERLAND)		size |= 0x10;	return (ops[size]);}static voiddt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,    uint_t op, int dreg){	ctf_file_t *ctfp = dnp->dn_ctfp;	ctf_arinfo_t r;	dif_instr_t instr;	ctf_id_t type;	uint_t kind;	ssize_t size;	int sreg;	if ((sreg = dt_regset_alloc(drp)) == -1)		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);	type = ctf_type_resolve(ctfp, dnp->dn_type);	kind = ctf_type_kind(ctfp, type);	assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY);	if (kind == CTF_K_ARRAY) {		if (ctf_array_info(ctfp, type, &r) != 0) {			yypcb->pcb_hdl->dt_ctferr = ctf_errno(ctfp);			longjmp(yypcb->pcb_jmpbuf, EDT_CTF);		}		type = r.ctr_contents;	} else		type = ctf_type_reference(ctfp, type);	if ((size = ctf_type_size(ctfp, type)) == 1)		return; /* multiply or divide by one can be omitted */	dt_cg_setx(dlp, sreg, size);	instr = DIF_INSTR_FMT(op, dreg, sreg, dreg);	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));	dt_regset_free(drp, sreg);}/* * If the result of a "." or "->" operation is a bit-field, we use this routine * to generate an epilogue to the load instruction that extracts the value.  In * the diagrams below the "ld??" is the load instruction that is generated to * load the containing word that is generating prior to calling this function. * * Epilogue for unsigned fields:	Epilogue for signed fields: * * ldu?	[r1], r1			lds? [r1], r1 * setx	USHIFT, r2			setx 64 - SSHIFT, r2 * srl	r1, r2, r1			sll  r1, r2, r1 * setx	(1 << bits) - 1, r2		setx 64 - bits, r2 * and	r1, r2, r1			sra  r1, r2, r1 * * The *SHIFT constants above changes value depending on the endian-ness of our * target architecture.  Refer to the comments below for more details. */static voiddt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,    ctf_file_t *fp, const ctf_membinfo_t *mp){	ctf_encoding_t e;	dif_instr_t instr;	uint64_t shift;	int r1, r2;	if (ctf_type_encoding(fp, mp->ctm_type, &e) != 0 || e.cte_bits > 64) {		xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "		    "bits %u\n", mp->ctm_offset, mp->ctm_type, e.cte_bits);	}	assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT);	r1 = dnp->dn_left->dn_reg;	if ((r2 = dt_regset_alloc(drp)) == -1)		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);	/*	 * On little-endian architectures, ctm_offset counts from the right so	 * ctm_offset % NBBY itself is the amount we want to shift right to	 * move the value bits to the little end of the register to mask them.	 * On big-endian architectures, ctm_offset counts from the left so we	 * must subtract (ctm_offset % NBBY + cte_bits) from the size in bits	 * we used for the load.  The size of our load in turn is found by	 * rounding cte_bits up to a byte boundary and then finding the	 * nearest power of two to this value (see clp2(), above).  These	 * properties are used to compute shift as USHIFT or SSHIFT, below.	 */	if (dnp->dn_flags & DT_NF_SIGNED) {#ifdef _BIG_ENDIAN		shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -		    mp->ctm_offset % NBBY;#else		shift = mp->ctm_offset % NBBY + e.cte_bits;#endif		dt_cg_setx(dlp, r2, 64 - shift);		instr = DIF_INSTR_FMT(DIF_OP_SLL, r1, r2, r1);		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));		dt_cg_setx(dlp, r2, 64 - e.cte_bits);		instr = DIF_INSTR_FMT(DIF_OP_SRA, r1, r2, r1);		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));	} else {#ifdef _BIG_ENDIAN		shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -		    (mp->ctm_offset % NBBY + e.cte_bits);#else		shift = mp->ctm_offset % NBBY;#endif		dt_cg_setx(dlp, r2, shift);		instr = DIF_INSTR_FMT(DIF_OP_SRL, r1, r2, r1);		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));		dt_cg_setx(dlp, r2, (1ULL << e.cte_bits) - 1);		instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));	}	dt_regset_free(drp, r2);}/* * If the destination of a store operation is a bit-field, we use this routine * to generate a prologue to the store instruction that loads the surrounding * bits, clears the destination field, and ORs in the new value of the field. * In the diagram below the "st?" is the store instruction that is generated to * store the containing word that is generating after calling this function. * * ld	[dst->dn_reg], r1 * setx	~(((1 << cte_bits) - 1) << (ctm_offset % NBBY)), r2 * and	r1, r2, r1 * * setx	(1 << cte_bits) - 1, r2 * and	src->dn_reg, r2, r2 * setx ctm_offset % NBBY, r3 * sll	r2, r3, r2 * * or	r1, r2, r1 * st?	r1, [dst->dn_reg] * * This routine allocates a new register to hold the value to be stored and * returns it.  The caller is responsible for freeing this register later. */static intdt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp,    dt_regset_t *drp, dt_node_t *dst){	uint64_t cmask, fmask, shift;	dif_instr_t instr;	int r1, r2, r3;	ctf_membinfo_t m;	ctf_encoding_t e;	ctf_file_t *fp, *ofp;	ctf_id_t type;	assert(dst->dn_op == DT_TOK_PTR || dst->dn_op == DT_TOK_DOT);	assert(dst->dn_right->dn_kind == DT_NODE_IDENT);	fp = dst->dn_left->dn_ctfp;	type = ctf_type_resolve(fp, dst->dn_left->dn_type);	if (dst->dn_op == DT_TOK_PTR) {		type = ctf_type_reference(fp, type);		type = ctf_type_resolve(fp, type);	}	if ((fp = dt_cg_membinfo(ofp = fp, type,	    dst->dn_right->dn_string, &m)) == NULL) {		yypcb->pcb_hdl->dt_ctferr = ctf_errno(ofp);		longjmp(yypcb->pcb_jmpbuf, EDT_CTF);	}	if (ctf_type_encoding(fp, m.ctm_type, &e) != 0 || e.cte_bits > 64) {		xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "		    "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits);	}	if ((r1 = dt_regset_alloc(drp)) == -1 ||	    (r2 = dt_regset_alloc(drp)) == -1 ||	    (r3 = dt_regset_alloc(drp)) == -1)		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);	/*	 * Compute shifts and masks.  We need to compute "shift" as the amount	 * we need to shift left to position our field in the containing word.	 * Refer to the comments in dt_cg_field_get(), above, for more info.	 * We then compute fmask as the mask that truncates the value in the	 * input register to width cte_bits, and cmask as the mask used to	 * pass through the containing bits and zero the field bits.	 */#ifdef _BIG_ENDIAN	shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -	    (m.ctm_offset % NBBY + e.cte_bits);#else	shift = m.ctm_offset % NBBY;#endif	fmask = (1ULL << e.cte_bits) - 1;	cmask = ~(fmask << shift);	instr = DIF_INSTR_LOAD(	    dt_cg_load(dst, fp, m.ctm_type), dst->dn_reg, r1);	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));	dt_cg_setx(dlp, r2, cmask);	instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));	dt_cg_setx(dlp, r2, fmask);	instr = DIF_INSTR_FMT(DIF_OP_AND, src->dn_reg, r2, r2);	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));	dt_cg_setx(dlp, r3, shift);	instr = DIF_INSTR_FMT(DIF_OP_SLL, r2, r3, r2);	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));	instr = DIF_INSTR_FMT(DIF_OP_OR, r1, r2, r1);	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));	dt_regset_free(drp, r3);	dt_regset_free(drp, r2);	return (r1);}static voiddt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst){	ctf_encoding_t e;	dif_instr_t instr;	size_t size;	int reg;	/*	 * If we're loading a bit-field, the size of our store is found by	 * rounding dst's cte_bits up to a byte boundary and then finding the	 * nearest power of two to this value (see clp2(), above).	 */	if ((dst->dn_flags & DT_NF_BITFIELD) &&	    ctf_type_encoding(dst->dn_ctfp, dst->dn_type, &e) != CTF_ERR)		size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);	else		size = dt_node_type_size(src);	if (src->dn_flags & DT_NF_REF) {		if ((reg = dt_regset_alloc(drp)) == -1)			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);		dt_cg_setx(dlp, reg, size);		instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg);		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));		dt_regset_free(drp, reg);	} else {		if (dst->dn_flags & DT_NF_BITFIELD)			reg = dt_cg_field_set(src, dlp, drp, dst);		else			reg = src->dn_reg;		switch (size) {		case 1:			instr = DIF_INSTR_STORE(DIF_OP_STB, reg, dst->dn_reg);			break;		case 2:			instr = DIF_INSTR_STORE(DIF_OP_STH, reg, dst->dn_reg);			break;		case 4:			instr = DIF_INSTR_STORE(DIF_OP_STW, reg, dst->dn_reg);			break;		case 8:			instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg);			break;		default:			xyerror(D_UNKNOWN, "internal error -- cg cannot store "			    "size %lu when passed by value\n", (ulong_t)size);		}		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));		if (dst->dn_flags & DT_NF_BITFIELD)			dt_regset_free(drp, reg);	}}/* * Generate code for a typecast or for argument promotion from the type of the * actual to the type of the formal.  We need to generate code for casts when * a scalar type is being narrowed or changing signed-ness.  We first shift the * desired bits high (losing excess bits if narrowing) and then shift them down * using logical shift (unsigned result) or arithmetic shift (signed result). */static voiddt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,    dt_irlist_t *dlp, dt_regset_t *drp){	size_t srcsize = dt_node_type_size(src);	size_t dstsize = dt_node_type_size(dst);	dif_instr_t instr;	int reg, n;	if (dt_node_is_scalar(dst) && (dstsize < srcsize ||	    (src->dn_flags & DT_NF_SIGNED) ^ (dst->dn_flags & DT_NF_SIGNED))) {		if ((reg = dt_regset_alloc(drp)) == -1)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -