[DTrace-devel] [PATCH] Fix typecast
Kris Van Hees
kris.van.hees at oracle.com
Tue Aug 2 01:29:01 UTC 2022
On Mon, Aug 01, 2022 at 02:40:28PM -0700, Eugene Loh via DTrace-devel wrote:
>
> 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).
That is what I thought indeed,
> PS No need for LSH/[A]RSH if n==0.
Yes, I forgot to add that when I moved code around.
> 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.
No, I didn't like making the assumption that src and dst *are* the same
register. But I do think that it makes sense to ensure that we code the
ecurrently unused) case of srcreg != dstreg.
> 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.
I think we should actually include the gcc programs somewhere, if that is our
reference. Just having result files without any indication on how they were
created makes it a lot more difficult to ensure that the results *are* indeed
the correct output we should expect.
More information about the DTrace-devel
mailing list