EmitX86BuiltinExpr() emits all args into Ops at the beginning, so don't do that work again.
This changes behavior: If e.g. ++a was passed as an arg, we incremented a twice previously. This change fixes that bug.
Differential D50979
Eliminate instances of `EmitScalarExpr(E->getArg(n))` in EmitX86BuiltinExpr(). thakis on Aug 20 2018, 10:28 AM. Authored by
Details
EmitX86BuiltinExpr() emits all args into Ops at the beginning, so don't do that work again. This changes behavior: If e.g. ++a was passed as an arg, we incremented a twice previously. This change fixes that bug.
Diff Detail Event TimelineComment Actions I don't think this is NFC. Testcase: long long int a, b, c, d; unsigned char f() { return _InterlockedCompareExchange128(&(++a), ++b, ++c, &(++d)); } Today, Clang increments a, b, c, and d twice each in f(). Comment Actions Thanks for pointing this out, good to hear that this even happens to find a bug :-) I'll add some tests to document the progression. Comment Actions
Took me a while to remember, but I can at least explain this bit now I think. The key is that there are two kinds of NEON intrinsics. Overloaded ones have a constant last argument that describes the real type, and non-overloaded ones use that last argument as a normal parameter. The first massive switch you see handles the ones in the second case, so it always CodeGens the last parameter, but if you scroll all the way down to line 7369 there's another switch where only the pregenerated Ops are used, and this last arg is visible as Ty and/or VTy. It may or may not be the best way to handle that situation, of course.
|
I noticed that EmitMSVCBuiltinExpr evaluates args again, so each one of these intrinsic implementations has this same bug. :(
I'll put together a fix.
It's a bit not straightforward because AArch64 doesn't pre-evaluate all the builtin arguments like x86, so we need an adapter from one style to the other.