Closed modocache closed 8 years ago
va_list
is part of an architecture's calling conventions, so it's important to do whatever's expected on that architecture. I'm a little surprised the existing mapping didn't work, but the one you're adding should be fine.
For the actual arguments being passed incorrectly, you'll need to make sure that the logic in stdlib/public/core/VarArgs.swift actually makes sense for your platform. In this case that's probably the AAPCS, although I'm surprised that either Apple or Linux diverged here.
Awesome, thanks @jrose-apple! I'll try adding the mapping and double-checking the logic in stdlib/public/core/VarArgs.swift
. :bow:
The following gets this test passing for me:
diff --git a/lib/ClangImporter/MappedTypes.def b/lib/ClangImporter/MappedTypes.def
index 474a78b..77e4620 100644
--- a/lib/ClangImporter/MappedTypes.def
+++ b/lib/ClangImporter/MappedTypes.def
@@ -126,6 +126,7 @@ MAP_STDLIB_TYPE("u_int64_t", UnsignedInt, 64, "UInt64", false, DoNothing)
// stdarg.h types.
// FIXME: why does this not catch va_list on x86_64?
MAP_STDLIB_TYPE("va_list", VaList, 0, "CVaListPointer", false, DoNothing)
+MAP_STDLIB_TYPE("__va_list", VaList, 0, "CVaListPointer", false, DoNothing)
// libkern/OSTypes.h types.
MAP_STDLIB_TYPE("UInt", UnsignedInt, 32, "CUnsignedInt", false, DoNothing)
diff --git a/stdlib/public/core/VarArgs.swift b/stdlib/public/core/VarArgs.swift
index ce4ee0e..83f5a7e 100644
--- a/stdlib/public/core/VarArgs.swift
+++ b/stdlib/public/core/VarArgs.swift
@@ -290,7 +290,7 @@ final public class VaListBuilder {
// supported vararg type is greater than the alignment of Int.
// FIXME: this implementation is not portable because
// alignof differs from the ABI alignment on some architectures
-#if os(watchOS) && arch(arm) // FIXME: rdar://21203036 should be arch(armv7k)
+#if (os(watchOS) || os(Android)) && arch(arm) // FIXME: rdar://21203036 should be arch(armv7k)
if let arg = arg as? _CVarArgAlignedType {
let alignmentInWords = arg._cVarArgAlignment / sizeof(Int)
let misalignmentInWords = count % alignmentInWords
android-armv7 is soft float, and I'm assuming that watchos-armv7k is as well--I think that's the real issue here. So instead of checking for #if os(watchOS) && arch(arm)
, we should probably check for something like #if arch(arm) && floattype(hard)
. Is something like floattype
available? Should it be added? @jrose-apple
I think the work @hpux735 is doing on hard float, though... so I'm curious what sort of failure output you're seeing, @hpux735. Is it the compilation error from above? What happens if you add the __va_list
mapping?
@modocache This is what I get from test/1_stdlib/VarArgs.swift
on a linux-armv7 with hard float (GNUEABIHF)
FAIL: Swift :: 1_stdlib/VarArgs.swift (111 of 2471)
******************** TEST 'Swift :: 1_stdlib/VarArgs.swift' FAILED ********************
Script:
--
rm -rf /mnt/temp/Ninja-ReleaseAssert/swift-linux-armv7/test-linux-armv7/1_stdlib/Output/VarArgs.swift.tmp && mkdir -p /mnt/temp/Ninja-ReleaseAssert/swift-linux-armv7/test-linux-armv7/1_stdlib/Output/VarArgs.swift.tmp && /home/wdillon/swift-build/build/Ninja-ReleaseAssert/swift-linux-armv7/bin/swiftc -target armv7-unknown-linux-gnueabihf -module-cache-path '/tmp/swift-testsuite-clang-module-cacheZiExII' -module-cache-path '/tmp/swift-testsuite-clang-module-cacheZiExII' /home/wdillon/swift-build/swift/test/1_stdlib/VarArgs.swift -o /mnt/temp/Ninja-ReleaseAssert/swift-linux-armv7/test-linux-armv7/1_stdlib/Output/VarArgs.swift.tmp/a.out -module-name main -Xfrontend -disable-access-control && /mnt/temp/Ninja-ReleaseAssert/swift-linux-armv7/test-linux-armv7/1_stdlib/Output/VarArgs.swift.tmp/a.out -parse-stdlib /home/wdillon/swift-build/swift/test/1_stdlib/VarArgs.swift | FileCheck /home/wdillon/swift-build/swift/test/1_stdlib/VarArgs.swift
--
Exit Code: 1
Command Output (stderr):
--
/home/wdillon/swift-build/swift/test/1_stdlib/VarArgs.swift:15:25: error: cannot convert value of type '(_) -> Int32' to expected argument type 'CVaListPointer -> _'
withVaList(arguments) {
^
/home/wdillon/swift-build/swift/test/1_stdlib/VarArgs.swift:39:20: error: cannot convert value of type '(_) -> Int32' to expected argument type 'CVaListPointer -> _'
withVaList(args) {
^
/home/wdillon/swift-build/swift/test/1_stdlib/VarArgs.swift:63:20: error: cannot convert value of type '(_) -> Int32' to expected argument type 'CVaListPointer -> _'
withVaList(args) {
^
--
********************
@hpux735 Awesome, thank you! And what if you apply the following patch?
```diff
diff --git a/lib/ClangImporter/MappedTypes.def b/lib/ClangImporter/MappedTypes.def
index 474a78b..77e4620 100644
--- a/lib/ClangImporter/MappedTypes.def
+++ b/lib/ClangImporter/MappedTypes.def
@@ -126,6 +126,7 @@ MAP_STDLIB_TYPE("u_int64_t", UnsignedInt, 64, "UInt64", false, DoNothing)
// stdarg.h types.
// FIXME: why does this not catch va_list on x86_64?
MAP_STDLIB_TYPE("va_list", VaList, 0, "CVaListPointer", false, DoNothing)
+MAP_STDLIB_TYPE("__va_list", VaList, 0, "CVaListPointer", false, DoNothing)
// libkern/OSTypes.h types.
MAP_STDLIB_TYPE("UInt", UnsignedInt, 32, "CUnsignedInt", false, DoNothing)
My theory is that the above patch will get your test to compile and pass.
I'm not sure if floattype
is something we want as a first-class predicate just yet, but maybe if we underscored it (_floattype
) for now. That's a discussion for a separate PR on the main Swift repo, though.
(I think you also meant "watchOS uses hard float". At least, that's what I see from reading the LLVM target info; I can't find official documentation on developer.apple.com, and I don't actually know myself.)
After further investigation we're beginning to think this isn't a hard float vs. soft float issue. android-armv7 is soft float, whereas linux-armv7 is hard float, but both have the same problem.
We're thinking that actually iOS and tvOS don't conform to AAPCS, so those are the only ARM-based systems that won't need this check. Every other ARM-based system will.
The solution we're going with is going to be adding va_list
mappings for each platform and adding os(Linux) || os(Android)
to the watchOS os check. Alternatively, it might be a good idea to check !os(iOS) && !os(tvOS)
-- but we can discuss in a pull request.
Oh, good catch! Indeed that is in Apple's docs and I just breezed over it.
The function calling conventions used in the ARMv6 environment are the same as those used in the Procedure Call Standard for the ARM Architecture (release 1.07), with the following exceptions:
- Large data types (larger than 4 bytes) are 4-byte aligned.
- …
There's no 32-bit tvOS, so we shouldn't need to worry about that. Feel free to submit a pull request upstream.
It looks like the arm64/aarch64 conventions are different too, if/when that becomes interesting.
@jrose-apple https://github.com/apple/swift/pull/1271 :+1:
test/1_stdlib/VarArgs.swift
fails to compile when targeting android-armv7. @hpux735 tells me it also fails for Linux armv6/armv7.I found the error message hard to understand.
cannot convert value of type '(_) -> Int32' to expected argument type 'CVaListPointer -> _'
-- huh? So I made the following change:This results in the following error message, which is much easier to understand:
Aha! So
vprintf
expects a__va_list
, but we're giving it aCVaListPointer
.As far as I understand, it's
lib/ClangImporter
's responsibility to convert certain raw C types like__va_list
toCVaListPointer
. Sure enough, there are a few commits related tova_list
:va_list
asCVaListPointer
. The author struggles with behavior on arm vs. x86_64--perhaps the same sort of problem we're seeing here?va_list
import implementation.It appears that on android-armv7 and linux-armv7,
va_list
is not being imported asCVaListPointer
, and as a result ourvprintf
function takes a__va_list
instead of aCVaListPointer
.Just for fun I tried adding the following mapping:
This actually gets
1_stdlib/VarArgs.swift
to compile, but it fails with the following error:Anyway, something is wrong with
va_list
importing on android-armv7 and linux-armv7, but I'm not sure what yet.