Repository navigation
sparc issue when calling C++ functions which returns >16bytes structure #46679
Description
Activity
- addedC-bugCategory: This is a bug.Category: This is a bug.I-crashIssue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics.Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics.O-SPARCTarget: SPARC processorsTarget: SPARC processors
on Dec 12, 2017 I wrote more minimalistic version of test case which rules out use of clang-sys.
mkdir -p rust-test/src cd rust-test cat > Cargo.toml <<EOF [package] name = "rust-test" version = "0.1.0" authors = ["Petr Sumbera <petr.sumbera@oracle.com>"] build = "build.rs" [dependencies] libc = "0.2.33" [build-dependencies] cc = "1.0" EOF cat > build.rs <<EOF extern crate cc; fn main() { cc::Build::new() .file("src/myfunc.c") .compile("libmyfunc.a"); } EOF cat > src/myfunc.c <<EOF #define LEN 32 struct MyObj { char a[LEN]; }; struct MyObj MyFunc() { struct MyObj obj; for (int i=0; i<LEN; i++) obj.a[i]=i; return obj; } EOF cat >> src/main.rs << EOF extern crate libc; #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct MyObj { pub a: [u8; 32], } extern { fn MyFunc() -> MyObj; } fn main() { unsafe { let obj = MyFunc(); for i in 0..16 { println!("obj.a[{}]={} ", i, obj.a[i]); } } } EOF cargo runOn intel it works as expected:
Updating registry `https://github.com/rust-lang/crates.io-index` Compiling cc v1.0.3 Compiling libc v0.2.34 Compiling rust-test v0.1.0 (file:///scratch/rust-test) Finished dev [unoptimized + debuginfo] target(s) in 8.77 secs Running `target/debug/rust-test` obj.a[0]=0 obj.a[1]=1 obj.a[2]=2 obj.a[3]=3 obj.a[4]=4 obj.a[5]=5 obj.a[6]=6 obj.a[7]=7 obj.a[8]=8 obj.a[9]=9 obj.a[10]=10 obj.a[11]=11 obj.a[12]=12 obj.a[13]=13 obj.a[14]=14 obj.a[15]=15But on sparc it looks weird:
Updating registry `https://github.com/rust-lang/crates.io-index` Compiling libc v0.2.34 Compiling cc v1.0.3 Compiling rust-test v0.1.0 (file:///scratch/rust-ffi-examples/rust-test) Finished dev [unoptimized + debuginfo] target(s) in 8.64 secs Running `target/debug/rust-test` obj.a[0]=255 obj.a[1]=255 obj.a[2]=255 obj.a[3]=255 obj.a[4]=255 obj.a[5]=255 obj.a[6]=255 obj.a[7]=255 obj.a[8]=255 obj.a[9]=255 obj.a[10]=255 obj.a[11]=255 obj.a[12]=255 obj.a[13]=255 obj.a[14]=255 obj.a[15]=255But with this "hack" it looks better:
--- src/main.rs +++ src/main.rs @@ -3,7 +3,7 @@ #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct MyObj { - pub a: [u8; 32], + pub a: [u8; 16], } extern {Compiling rust-test v0.1.0 (file:///scratch/rust-ffi-examples/rust-test) Finished dev [unoptimized + debuginfo] target(s) in 1.26 secs Running `target/debug/rust-test` obj.a[0]=0 obj.a[1]=1 obj.a[2]=2 obj.a[3]=3 obj.a[4]=4 obj.a[5]=5 obj.a[6]=6 obj.a[7]=7 obj.a[8]=8 obj.a[9]=9 obj.a[10]=10 obj.a[11]=11 obj.a[12]=12 obj.a[13]=13 obj.a[14]=14 obj.a[15]=15Ok. I'm new to both Rust and LLVM. I tried to create for above example llvm-ir data on intel and used llc to build it on sparc. The same result could be seen. Does it mean that that issue is rather in LLVM?!
On intel I did:
rustc --crate-name rust_test src/main.rs --crate-type bin --emit=llvm-ir -C debuginfo=2 -C metadata=e19299b369c7fab4 -C extra-filename=-e19299b369c7fab4 --out-dir /scratch/rust-test/target/debug/deps -L dependency=/scratch/rust-test/target/debug/deps --extern libc=/scratch/rust-test/target/debug/deps/liblibc-4242d2235e1c985c.rlib -L native=/scratch/rust-test/target/debug/build/rust-test-1c2036192ff415b2/out -l static=myfunc cp target/debug/deps/rust_test-e19299b369c7fab4.ll ~/rust-intel.llOn Sparc I did:
cp ~/rust-intel.ll . # Following allows to build llvm-ir from intel on sparc (e.g. hashes differs) gsed -i 's/target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"/target datalayout = "E-m:e-i64:64-n32:64-S128"/' rust-intel.ll gsed -i 's/target triple = "x86_64-pc-solaris"/target triple = "sparcv9-sun-solaris"/' rust-intel.ll gsed -i 's/h25e88cdc4b742d37/868f8880dc2af3fb/' rust-intel.ll gsed -i 's/h62ae80c5f7549c57/h695fc56fad203862/' rust-intel.ll gsed -i 's/hb1a77afe5cf34a1f/h12114874ef566064/' rust-intel.ll gsed -i 's/h01dfd331a3ddfd23/hde26e71a5da81bd3/' rust-intel.ll gsed -i 's/h92300f5a5dcbe9fc/h6e897821881fc078/' rust-intel.ll gsed -i 's/h260bdf0389a41d93/he0edee3f5f00176d/' rust-intel.ll gsed -i 's/h68259f12b9557c97/hb3a671a76eb88d18/' rust-intel.ll gsed -i 's/h93039a1a453ca6fa/h89b991e782a34d3c/' rust-intel.ll gsed -i 's/h1cedb2ea3dec2dd2/h565f072da92eba4a/' rust-intel.ll gsed -i 's/ha4d058251336ce5a/hce1c61317f4621e6/' rust-intel.ll gsed -i 's/hd203f6187fbbf08f/h23743788f08f09ac/' rust-intel.ll gsed -i 's/h887a1a8a37a961fb/h92ddcfd6dccbb247/' rust-intel.ll gsed -i 's/868f8880dc2af3fb/h868f8880dc2af3fb/' rust-intel.ll # Without this I'm getting error [1] gsed -i 's/, file: !6)/)/' rust-intel.ll llc --filetype=obj -o test.o rust-intel.ll gcc -c -o myfunc.o src/myfunc.c gcc -o test test.o myfunc.o -L /usr/lib/rustlib/sparcv9-sun-solaris/lib/ -lstd-899f7b6f82885664 LD_LIBRARY_PATH=/usr/lib/rustlib/sparcv9-sun-solaris/lib/ ./testThe output is bad. See comment above (
obj.a[?]=255).[1]
$ llc --filetype=obj -o test.o rust-intel.ll llc: rust-intel.ll:2187:46: error: invalid field 'file' !7 = !DINamespace(name: "result", scope: !8, file: !6) ^https://github.com/rust-lang/rust/blob/master/src/librustc_trans/cabi_sparc64.rs#L27 and https://github.com/rust-lang/rust/blob/master/src/librustc_trans/cabi_sparc64.rs#L53 are wrong; structs up to 32 bytes in size, i.e. 256 bits, are returned in registers. I was also suspicious of this code in general when it was first merged as it doesn't seem very long, and handling mixed float and int structs is a little fiddly.
EDIT: Well, actually,
is_homogeneous_aggregateshould vary based on whether it's an argument (which can be up to 16 bytes) or return value (up to 32 bytes).EDIT: Well, actually, is_homogeneous_aggregate should vary based on whether it's an argument (which can be up to 16 bytes) or return value (up to 32 bytes).
Can you please suggest how to implement this?
I can confirm that when modifying cabi_sparc64.rs to contain 256 my above test examples passes as expected (though Firefox still wouldn't build).
As mentioned above. With partial fix Firefox build dies later when it calls
clang_visitChildren(). Which takes three arguments and the problematic first one is again 32 bytes long structure (CXCursor).@psumbera Maybe you can suggest a preliminary patch to at least improve the code generation?
EDIT: Well, actually,
is_homogeneous_aggregateshould vary based on whether it's an argument (which can be up to 16 bytes) or return value (up to 32 bytes).Are you sure? That doesn't entirely control whether a
structis passed by value or indirectly, but specifically it handlesstructs which the ABI treats like arrays of primitives (incl. SIMD vectors).- added a commit that references this issue
on Jan 23, 2018
I have an issue with rust (now version 1.22.1) on Solaris sparc (64bit). On intel I don't see it. I originally see it as part of Firefox build (https://bugzilla.mozilla.org/show_bug.cgi?id=1413887)
I now believe it's rustc issue (though it could be still issue with clang-sys). Any help would be greatly appreciated.
Run output looks like:
Stack:
With tracing:
Note that clang_getTranslationUnitCursor isn't called with 'tu' set to 0.
I have find out that the issue seems to be with the size of CXCursor structure which is returned:
CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU);CXCursor is 32 bytes long. But if I tell clang-sys it's 16 bytes everything is perfect (when it's 17 bytes or more it causes the trouble):
Following is disassembly when CXCursor is pretended to be just 16 bytes:
And now with 17 bytes: