Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android and AArch64: tweak tests that trip #6790

Merged
merged 2 commits into from
Dec 18, 2018
Merged

Android and AArch64: tweak tests that trip #6790

merged 2 commits into from
Dec 18, 2018

Conversation

joakim-noah
Copy link
Contributor

@joakim-noah joakim-noah commented Dec 4, 2018

I'm still looking at some alignment issues with std.variant because Android/x64 uses an IEEE Quad 128-bit long double, will be finished once I track that down.

I'm targeting stable because we'll just pull these into the final release of ldc 1.13 when the final point release of dmd 2.083 is out. Only the /proc/cpuinfo change has the potential to affect the dmd release, since most everything else is versioned out for the official dmd release.

@dlang-bot dlang-bot added the Review:WIP Work In Progress - not ready for review or pulling label Dec 4, 2018
@dlang-bot
Copy link
Contributor

Thanks for your pull request, @joakim-noah!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub fetch digger
dub run digger -- build "stable + phobos#6790"

Copy link
Contributor

@thewilsonator thewilsonator left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, let me know when this is good to go.

@thewilsonator
Copy link
Contributor

Also did you mean to create a branch for this pr rather that from your stable?

@@ -4110,7 +4110,7 @@ real log(real x) @safe pure nothrow @nogc
///
@safe pure nothrow @nogc unittest
{
assert(log(E) == 1);
assert(feqrel(log(E), 1) >= real.mant_dig - 1);
Copy link
Contributor Author

@joakim-noah joakim-noah Dec 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assert for equality only trips on Android with Quad reals, but not on linux/glibc/AArch64. Since it's a documented test, I can version this only for IEEE Quadruples like the std.complex test above and keep this simpler assert for readability if wanted.

std/math.d Outdated
static if (floatTraits!(real).realFormat == RealFormat.ieeeQuadruple)
{
// This static assert overflows when cross-compiling from lower-precision
// floating-point reals at compile-time to higher precision at runtime.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted, this isn't an issue just for Quadruples, but also hits when say the compile-time real is 64-bit and runtime is 80-bit, as I just tested with ldc on Android/ARM cross-compiling to linux/x64 (a Win/MSVC target works however, as it also uses 64-bit reals).

I'm unsure how to check the compile-time real's precision however, so I just settled for disabling this test whenever compiling to a Quad runtime real. Anyone know how to get the compile-time real's precision?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ibuclaw or @jpf91, any input?

Copy link
Contributor

@kinke kinke Dec 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted in the forum, there's no way of detecting the host's compile-time precision. Compiled code shouldn't have to know, and an assert makes perfect sense to guarantee the precision is sufficiently high. It clearly isn't with current LDC in all cross-compilation scenarios, as we don't have a software real_t yet.

So maybe weakening the static assert to a runtime enum <actual-ct-value> = ...; assert(...) would be a solution for this problem, potentially probably restricted to LDC only (and so not here upstream).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't affect gdc, as we have used soft float since the start.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These static asserts assume IEEE though. Non-IEEE reals could (and infact do in the case of ibm real) throw a compile time assert.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, since this doesn't affect dmd, because it only supports Intel, or gdc, because it uses a wider-precision soft-float at compile-time, I'll keep this in ldc: removed here.

@joakim-noah
Copy link
Contributor Author

I don't have a stable branch on my Phobos fork, deleted it a while back and just pushed this now for this pull, after which I'll delete it again. 😉

@thewilsonator
Copy link
Contributor

This good to go?

@joakim-noah
Copy link
Contributor Author

Almost, but no hurry now that the point release shipped.

std/variant.d Outdated
@@ -102,6 +102,23 @@ struct This;

private alias This2Variant(V, T...) = AliasSeq!(ReplaceType!(This, V, T));

// copied from std.traits and modified the base case
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could reduce the code duplication by simply checking for an empty tuple (and returning the pointer-alignment then, which seems like a valid guess, although max(size_t.alignof, real.alignof) would be safer), and otherwise use the std.traits version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the std.traits version package, so I can reuse it like you said.

As for setting the maximum alignment of real or size_t, that hits the Android/x64 segfaults I mentioned in the ldc pull, when using align(16) for the union. It's using 128-bit alignment then, as the real alignment is always larger than 64-bit size_t there, and then segfaults when trying to MOVAPS a 64-bit aligned location into the FP register $xmm0. With size_t alignment, it uses a MOVUPS instead.

Another case where LLVM isn't expecting that __float128 alignment?

Copy link
Contributor

@kinke kinke Dec 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and then segfaults when trying to MOVAPS a 64-bit aligned location into the FP register $xmm0

That's exactly what shouldn't happen when aligning the union at 16 bytes. What that does though is change the min size of the union to 16 bytes (and move its offset in VariantN from 8 to 16), which might be unexpected for some test.

I mentioned max(size_t.alignof, real.alignof) for an empty AllowedTypes tuples (=> arbitrary types) as that should make sure it can be used as real too on platforms like Android x64. I'm pretty sure you'll hit alignment issues otherwise, just like the ones you currently get when using that max, for some bizarre reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we're clear, the original failing test passes now: it's the other tests that start to fail if I use real.alignof when no types are passed to Variant, as I mentioned before. Looking into it more in a debugger and after hacking that first test block down to just two lines, Variant b = 42; assert(b.type == typeid(int));, it loads a 64-bit-aligned _D3std7variant__T8VariantNVmi32ZQp6__initZ and tries to MOVAPS the first 128-bit word and fails.

If I use this pull with size_t.alignof instead, all the std.variant tests pass, and it loads the FP registers from that same 64-bit aligned initializer with MOVUPS instructions instead.

I honestly don't care how this stuff is aligned, as long as the tests pass. 😉

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it loads a 64-bit-aligned _D3std7variant__T8VariantNVmi32ZQp6__initZ

That seems to be the issue then - our (LDC) init symbols seem to violate the alignment.

Copy link
Contributor

@kinke kinke Dec 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I wasn't really focused - movups is of course used for align(8). movaps should be fine, and the reduced testcase suggests LDC does the right thing by requesting 16-bytes alignment for the init symbol -> I guess it's really a linker issue, wouldn't be the first of this kind.

Should be easily testable; real.alignof is 16 for x86_64 Linux and macOS too, so if CI passes there, it's Android specific.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, trying it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works on the auto-tester, could the Android/x64 linker be why std.variant passed its tests when I used align(16) and linked that module alone, but failed when I linked it into the test runner? If you think it's more correct this way, fine with me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wiped my build directory and rebuilt the phobos test runner from scratch, all the std.variant tests pass now. Maybe that 64-bit-aligned variant initializer was lying around in another object file and then getting picked up first by the linker every time I incrementally compiled std.variant alone. Sorry about the confusion, everything's working with this pull now, using the scheme you suggested.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, very nice then.

std/variant.d Outdated
@@ -167,7 +184,7 @@ private:
// state
ptrdiff_t function(OpID selector, ubyte[size]* store, void* data) fptr
= &handler!(void);
union
align(maxAlignment!(AllowedTypes)) union
{
ubyte[size] store;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you move the align() down here, you won't change the alignment for AllowedTypes = { int[2], short[4] } for 64-bit targets (so that it would still be 8-bytes pointer-aligned due to the pointers array). It doesn't really matter, as the function pointer field makes sure the whole VariantN struct is still at least pointer-aligned and that the union's offset is 8; it'd just be good practice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't really want to think about these alignment issues, just moved it down like you said: works on Android/x64.

@@ -4759,7 +4759,7 @@ template TemplateArgsOf(T : Base!Args, alias Base, Args...)
}


private template maxAlignment(U...)
package template maxAlignment(U...)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This protection plus the modification was why I copied it before.

@joakim-noah joakim-noah changed the title [WIP] Android and AArch64: tweak tests that trip Android and AArch64: tweak tests that trip Dec 11, 2018
@joakim-noah
Copy link
Contributor Author

Single dmd testsuite failure on linux seems spurious, since it passes everywhere else. Once the yaml-d issue is resolved, should be ready to go: removed the WIP title.

@thewilsonator
Copy link
Contributor

This trips an assert in dyaml
../.dub/packages/dyaml-0.7.0/dyaml/source/dyaml/node.d(188,9): Error: static assert: "Unexpected YAML value size"

struct Node
{
    ...
    alias Value = Algebraic!(YAMLNull, YAMLMerge, bool, long, real, ubyte[], SysTime, string,
                         Node.Pair[], Node[], YAMLObject);
    ...
    Value value_;
    ...
    static assert(Value.sizeof <= 24, "Unexpected YAML value size");
}

because value is, with this change effectively

struct 
{
    void* functionPointer;
    align(16) ubyte[16];
}

for 32 bytes.

@kinke
Copy link
Contributor

kinke commented Dec 11, 2018

That's a bug in dyaml then. ;) - The layout can be optimized to struct VariantN { union { ... }; void* functionPointer }, that'll save padding.

Edit: Well, in this case it would just move the inner padding to trailing padding, the VariantN struct would still be 32-bytes large.

@ghost ghost mentioned this pull request Dec 11, 2018
std/variant.d Outdated
enum maxVariantAlignment = size_t.alignof;
else
{
import std.traits : maxAlignment;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a global import std.traits at the top of the file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

@joakim-noah
Copy link
Contributor Author

@bbasile and @wilzbach, thanks for updating dyaml and dlang-tour for this pull. However, dlang-tour appears to have broken when checking out now, which is stalling buildkite.

@ghost
Copy link

ghost commented Dec 12, 2018

The problem is really related to dlang-tour, forced push won't help.

@thewilsonator
Copy link
Contributor

Yeah dlang/tour fails on other build as well. Is this still WIP?

@joakim-noah
Copy link
Contributor Author

Looks like the problem is the shallow clone, strange that that would affect the submodule. Just tried it and not reproducible for me on my Android tablet, running the same two commands for dlang-tour plus its English version.

@joakim-noah
Copy link
Contributor Author

Is this still WIP?

Looks done to me.

@thewilsonator thewilsonator added Merge:72h no objection -> merge The PR will be merged if there are no objections raised. and removed Review:WIP Work In Progress - not ready for review or pulling labels Dec 12, 2018
@wilzbach
Copy link
Member

Looks like the problem is the shallow clone, strange that that would affect the submodule. Just tried it and not reproducible for me on my Android tablet, running the same two commands for dlang-tour plus its English version.

See dlang/ci#363 which should hopefully fix Buildkite.
Anyhow, the failure is unrelated.

@joakim-noah
Copy link
Contributor Author

Alright, fixed the Buildkite issue, but the build agents seem flakier and slow now: some hardware changes going on right now?

@thewilsonator
Copy link
Contributor

Yeah I noticed that on a few dmd PRs recently, no idea.

@wilzbach
Copy link
Member

@MartinNowak recently changed all agents to be auto-provisioned depending on the current load.

…nt.VariantN is properly aligned for Quadruples.
@joakim-noah
Copy link
Contributor Author

OK, ready to merge, CI passes.

@thewilsonator thewilsonator added Merge:auto-merge and removed Merge:72h no objection -> merge The PR will be merged if there are no objections raised. labels Dec 18, 2018
@dlang-bot dlang-bot merged commit 43be36c into dlang:stable Dec 18, 2018
@joakim-noah joakim-noah deleted the stable branch December 18, 2018 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants