Skip to content

[stdlib] Correctly import C Int types on Windows x64 #14575

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

Merged
merged 1 commit into from
Feb 14, 2018

Conversation

troughton
Copy link
Contributor

64-bit Windows is an LLP64 architecture; unlike on other 64-bit platforms, long is a 32-bit type. This means we don't have a one-to-one mapping between CInt/Int32, CLong/Int, CLongLong/Int64 like we do on other platforms.

Instead, import long as Int32 and long long as Int64. An alternative would be to import long long as Int; however, that would mean that code would require changes in many cases between 32-bit and 64-bit Windows.

Since there's no direct mapping from a C type to Int, manually create mappings back from Int to long long.

Do the same for unsigned data types.

@troughton troughton changed the title Correctly import C Int types on Windows x64 [stdlib] Correctly import C Int types on Windows x64 Feb 13, 2018
@gparker42
Copy link
Contributor

How important is 32-bit Windows development nowadays? How much better does the interface become if we abandon 32-bit and import long long to Int?

@troughton
Copy link
Contributor Author

troughton commented Feb 13, 2018

I can't speak to the importance of 32-bit Windows development, but I can say that importing as Int64 doesn't add any friction in my experience porting a large mixed Swift/C/C++ project to 64-bit Windows. Most of the Windows APIs still deal in 32-bit arguments and return values (e.g. DWORD, which is a uint32_t), which requires explicit conversion anyway.

On the other hand, importing as Int always would break compatibility with other platforms. As one example, Dispatch's time.h header has an int64_t argument for some of its functions (e.g. dispatch_time(dispatch_time_t, int64_t)), and the Dispatch overlays assume that's imported as an Int64.

@jrose-apple
Copy link
Contributor

Yeah, I think I'd come down on the long-long-as-Int64 side, since everyone else does that. It stinks about long but I don't think there's much we can do about it. There's always intptr_t if you really meant intptr_t.

// add mappings to C for Int and UInt.
if (IGM.Triple.isOSWindows() && IGM.Triple.isArch64Bit()) {
cacheStdlibType("UInt", clang::BuiltinType::ULongLong);
cacheStdlibType("Int", clang::BuiltinType::LongLong);
Copy link
Contributor

Choose a reason for hiding this comment

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

[u]intptr_t might be a better choice here.

Copy link
Contributor Author

@troughton troughton Feb 13, 2018

Choose a reason for hiding this comment

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

I can't find a definition for pointer types in Clang's BuiltinTypes.def. Where would that be defined, or is there a different way we could achieve that mapping? Void is defined if that's equivalent, but in that case I think LongLong is clearer.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can get Clang's choice for (u)intptr_t from clang::ASTContext::get(U)IntPtrType. There'll be a builtin type under that.

@jrose-apple
Copy link
Contributor

@compnerd, opinions?

@compnerd
Copy link
Member

I think that 32-bit windows is still quite important. There are still a plethora of packages which are still 32-bit.

I think that using long long as Int64 is reasonable. I am worried about how this will impact thee rest of the swift SDK.

@troughton
Copy link
Contributor Author

troughton commented Feb 13, 2018

@compnerd What specifically are your concerns? I’ve encountered no issues with it in my (>20k LOC) Swift codebase on Windows - I actually picked these issues up where a few DWORD return values from Windows APIs were getting imported as UInts and had garbage data.

@compnerd
Copy link
Member

Oh, this will work fine for Windows itself, I just don't like the idea of differences across the targets. We have the ability to get this right unlike C/C++, so we should take advantage of that. I think that generalizing your change to all targets is what I would aim for.

Quoting the Swift Language Reference:

Int

  • On a 32-bit platform, Int is the same size as Int32.
  • On a 64-bit platform, Int is the same size as Int64.

UInt

  • On a 32-bit platform, UInt is the same size as UInt32.
  • On a 64-bit platform, UInt is the same size as UInt64.

It seems like the mapping being recommended here is the most portable approach, which I think we should aim to generalize it to all targets.

@troughton
Copy link
Contributor Author

What you’re specifically proposing is that long should be imported as a sized type rather than as an Int, correct?

I don’t have strong feelings on that, but my instinct would be that you’d just be introducing another type that differs between systems: rather than long being an Int everywhere apart from Win64, it becomes an Int32 on 32-bit platforms and Win64 and an Int64 elsewhere.

Rather, I think a better solution is just to be explicit (where possible) in the C code: use int where you want an Int32 value, long long where you want an Int64, and NSInteger, size_t, intptr_t etc. if you want an Int.

Passing an Int to a size_t parameter still works in this patch; likewise, a size_t return value is imported as an Int.

@jrose-apple
Copy link
Contributor

I could see how consistency across 64-bit platforms is more useful than consistency across 32-bit and 64-bit versions of the same OS (which is the property we'd maintain with the current version of this patch), but in practice it's way too late to change this on Apple platforms, and it's convenient that all the Apple platforms—a mix of 32-bit and 64-bit environments—use the same Swift type for long.

I think "CLong is Int on LP64 platforms and Int32 on LLP64 platforms" is a reasonable rule, especially with size_t and intptr_t already being understood specially by the compiler everywhere. (Let's hope we don't have any ILP64 platforms to support any time soon.)

@compnerd
Copy link
Member

Okay, if its not possible to get the consistency across all the targets, then lets stick with the behavior that we have on Windows. I do think that the && arch(x86_64) is unnecessary, since there is consistency on the types across all of the Windows variants.

@compnerd
Copy link
Member

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 01f57fc20503c704c44dee6e44559107abd17d7c

@troughton
Copy link
Contributor Author

troughton commented Feb 14, 2018

Not having arch(x86_64) would make long Int32 rather than Int on 32-bit Windows, so it would be consistent with Win64 but inconsistent with other 32-bit platforms. It’s not exactly ‘unnecessary’, but I can see why that’d be better - @compnerd, would that be your preference?

In short, is it more important that Swift code from other platforms works on Windows 32-bit without modification, or that Swift code works without modification between 32- and 64-bit Windows?

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 01f57fc20503c704c44dee6e44559107abd17d7c

@compnerd
Copy link
Member

TBH, I don't have enough of a gut feeling on which would be better here. I think that tabling that for now is the best approach. Lets get Windows x86_64 working, and then when restoring the Windows x86 build, we could easily see how painful that would be.

@jrose-apple
Copy link
Contributor

I'm inclined to say long on 32-bit Windows should be Int32 rather than Int so that we have consistency across Windowses, but on the other hand I'm not sure how much that matters in practice. That's also easy to say from over here where I'm unlikely to be building anything for Windows any time soon.

@troughton
Copy link
Contributor Author

The 'wait and see' approach sits comfortably with me. If it ends up being an issue on 32-bit Windows then it'll only be a three-line change to have 32-bit get the same behaviour as Win64, and I don't think source compatibility is going to be a concern on Windows for quite some time yet.

@compnerd
Copy link
Member

Sounds like we have quorum. Could you squash the two commits, since they aren't standalone I believe and I think we should get this in then.

@troughton
Copy link
Contributor Author

Commits squashed. No changes since the tests passed but feel free to test again if you'd like.

@jrose-apple
Copy link
Contributor

Still need to at least smoke test to be allowed to merge, so

@swift-ci Please smoke test

@compnerd
Copy link
Member

@swift-ci please smoke test macOS platform

@compnerd compnerd merged commit cc8ef9d into swiftlang:master Feb 14, 2018
@troughton troughton deleted the win64-int-import branch April 18, 2018 04:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants