[DTrace-devel] [PATCH] Fix typecast

Eugene Loh eugene.loh at oracle.com
Mon Aug 1 21:40:28 UTC 2022


On 8/1/22 12:15, Kris Van Hees via DTrace-devel wrote:
> DTrace internally keeps integers basically in a 64-bit format.  Shorter,
> signed integers are already sign-extended.
>
> The current logic makes an error when an integer is extended and the
> signedness changes.  It truncates the source and then extends.  E.g.,
> consider a 1-byte source and 2-byte destination:
>
>      signed?
>      src dst  input  expected  currently
>
>       N   Y    0xff   0x00ff       -1
>       Y   N    0xff   0xffff      0xff
>
> Note:
>
> *) In the first case, no casting is even necessary.  If the integer
> is being extended and it is unsigned, then higher-order bits can simply
> be left alone.
>
> *) In the second case, the signed input is supposed to be sign-extended
> before truncating to the new size.  We currently truncate first, at the
> smaller size.
>
> Fix.  Add tests.
>
> Notice that:
>
> *) Casting constants like "var = (type) constant" is handled
>     in the parser.
>
> *) Casting variables like "var1 = (type) var2" is handled
>     in the code generator.
>
> This patch is a modified version of an earlier patch by Eugene Loh.
>
> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
> Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
> Reviewed-by: Kris Van Hees <kris.van.hees at oracle.com>
> ---
>   libdtrace/dt_cg.c                       |  34 ++++----
>   libdtrace/dt_parser.c                   |  14 ++--
>   test/unittest/arithmetic/tst.cast-exp.d | 101 ++++++++++++++++++++++++
>   test/unittest/arithmetic/tst.cast-exp.r |  43 ++++++++++
>   4 files changed, 167 insertions(+), 25 deletions(-)
>   create mode 100644 test/unittest/arithmetic/tst.cast-exp.d
>   create mode 100644 test/unittest/arithmetic/tst.cast-exp.r
>
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index 3e53c4bc..b40c9e48 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -2515,30 +2515,19 @@ dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
>   {
>   	size_t srcsize;
>   	size_t dstsize;
> -	int n;
>   
>   	/* If the destination type is '@' (any type) we need not cast. */
>   	if (dst->dn_ctfp == NULL && dst->dn_type == CTF_ERR)
>   		return;
>   
> -	srcsize = dt_node_type_size(src);
> -	dstsize = dt_node_type_size(dst);
> -
> -	if (dstsize < srcsize)
> -		n = sizeof(uint64_t) * NBBY - dstsize * NBBY;
> -	else
> -		n = sizeof(uint64_t) * NBBY - srcsize * NBBY;
> -
>   	if (!dt_node_is_scalar(dst))
>   		return;
>   
> -	if (n != 0 && (dstsize < srcsize ||
> -	    (src->dn_flags & DT_NF_SIGNED) ^ (dst->dn_flags & DT_NF_SIGNED))) {
> -		emit(dlp, BPF_MOV_REG(dst->dn_reg, src->dn_reg));
> -		emit(dlp, BPF_ALU64_IMM(BPF_LSH, dst->dn_reg, n));
> -		emit(dlp, BPF_ALU64_IMM((dst->dn_flags & DT_NF_SIGNED) ? BPF_ARSH : BPF_RSH, dst->dn_reg, n));
> -	} else if (dt_node_is_arith(dst) && dt_node_is_pointer(src) &&
> -		   (src->dn_flags & DT_NF_ALLOCA)) {
> +	srcsize = dt_node_type_size(src);
> +	dstsize = dt_node_type_size(dst);
> +
> +	if (dt_node_is_arith(dst) && dt_node_is_pointer(src) &&
> +	    (src->dn_flags & DT_NF_ALLOCA)) {
>   		int mst;
>   
>   		if ((mst = dt_regset_alloc(drp)) == -1)
> @@ -2550,6 +2539,19 @@ dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
>   		emit(dlp,  BPF_LOAD(BPF_DW, dst->dn_reg, mst, DMST_SCALARIZER));
>   
>   		dt_regset_free(drp, mst);
> +	} else {
> +		int srcsigned = src->dn_flags & DT_NF_SIGNED;
> +		int dstsigned = dst->dn_flags & DT_NF_SIGNED;
> +
> +		if (dst->dn_reg != src->dn_reg)
> +			emit(dlp, BPF_MOV_REG(dst->dn_reg, src->dn_reg));
> +
> +		if ((!srcsigned && dstsigned) && srcsize == dstsize) {
> +			int n = (sizeof(uint64_t) - dstsize) * NBBY;
> +
> +			emit(dlp, BPF_ALU64_IMM(BPF_LSH, dst->dn_reg, n));
> +			emit(dlp, BPF_ALU64_IMM(BPF_ARSH, dst->dn_reg, n));
> +		}
>   	}
>   }

So if the src is signed and the dst unsigned, we leave the upper bits 
alone?  That suggests that we could have upper nonzero bits that will 
pollute the result unless we automatically store the result to truncate 
those upper bits.  So, yes, the tests need to be expanded.  I'll post a 
revised patch (with updated tests).

PS  No need for LSH/[A]RSH if n==0.

PPS  a long time ago, I thought you didn't like "if (dstreg!=srcreg) 
BPF_MOV_REG(dstreg, srcreg)" since you expected that sort of 
optimization to be done later in some code-optimization phase.

Anyhow, I've been working on the revised tests.  The results match a gcc 
test program.  My patch passes with the expanded tests; this version of 
the patch does not.  I'm not convinced I fully understand what's going 
on, however, and hence the delay.  This has taken so long, so I figured 
i'd update you what's going on.



More information about the DTrace-devel mailing list