-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[swiftc] Fixed for Cygwin #3841
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,6 +117,11 @@ static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context, | |
return ClangCodeGen; | ||
} | ||
|
||
/// A helper for determining if the triple uses the DLL storage | ||
static bool useDllStorage(const llvm::Triple &Triple) { | ||
return Triple.isOSBinFormatCOFF() && !Triple.isOSCygMing(); | ||
} | ||
|
||
IRGenModule::IRGenModule(IRGenerator &irgen, | ||
std::unique_ptr<llvm::TargetMachine> &&target, | ||
SourceFile *SF, llvm::LLVMContext &LLVMContext, | ||
|
@@ -439,7 +444,7 @@ llvm::Constant *swift::getRuntimeFn(llvm::Module &Module, | |
if (auto fn = dyn_cast<llvm::Function>(cache)) { | ||
fn->setCallingConv(cc); | ||
|
||
if (llvm::Triple(Module.getTargetTriple()).isOSBinFormatCOFF() && | ||
if (::useDllStorage(llvm::Triple(Module.getTargetTriple())) && | ||
(fn->getLinkage() == llvm::GlobalValue::ExternalLinkage || | ||
fn->getLinkage() == llvm::GlobalValue::AvailableExternallyLinkage)) | ||
fn->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); | ||
|
@@ -519,7 +524,7 @@ llvm::Constant *swift::getWrapperFn(llvm::Module &Module, | |
auto *globalFnPtr = new llvm::GlobalVariable( | ||
Module, fnPtrTy, false, llvm::GlobalValue::ExternalLinkage, nullptr, | ||
symbol); | ||
if (llvm::Triple(Module.getTargetTriple()).isOSBinFormatCOFF()) | ||
if (::useDllStorage(llvm::Triple(Module.getTargetTriple()))) | ||
globalFnPtr->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); | ||
|
||
// Forward all arguments. | ||
|
@@ -638,7 +643,7 @@ llvm::Constant *IRGenModule::getEmptyTupleMetadata() { | |
EmptyTupleMetadata = Module.getOrInsertGlobal( | ||
MANGLE_AS_STRING(METADATA_SYM(EMPTY_TUPLE_MANGLING)), | ||
FullTypeMetadataStructTy); | ||
if (Triple.isOSBinFormatCOFF()) | ||
if (useDllStorage()) | ||
cast<llvm::GlobalVariable>(EmptyTupleMetadata) | ||
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); | ||
return EmptyTupleMetadata; | ||
|
@@ -652,7 +657,7 @@ llvm::Constant *IRGenModule::getObjCEmptyCachePtr() { | |
// struct objc_cache _objc_empty_cache; | ||
ObjCEmptyCachePtr = Module.getOrInsertGlobal("_objc_empty_cache", | ||
OpaquePtrTy->getElementType()); | ||
if (Triple.isOSBinFormatCOFF()) | ||
if (useDllStorage()) | ||
cast<llvm::GlobalVariable>(ObjCEmptyCachePtr) | ||
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); | ||
} else { | ||
|
@@ -685,7 +690,7 @@ Address IRGenModule::getAddrOfObjCISAMask() { | |
assert(TargetInfo.hasISAMasking()); | ||
if (!ObjCISAMaskPtr) { | ||
ObjCISAMaskPtr = Module.getOrInsertGlobal("swift_isaMask", IntPtrTy); | ||
if (Triple.isOSBinFormatCOFF()) | ||
if (useDllStorage()) | ||
cast<llvm::GlobalVariable>(ObjCISAMaskPtr) | ||
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); | ||
} | ||
|
@@ -851,7 +856,7 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) { | |
llvm::SmallString<64> buf; | ||
encodeForceLoadSymbolName(buf, linkLib.getName()); | ||
auto symbolAddr = Module.getOrInsertGlobal(buf.str(), Int1Ty); | ||
if (Triple.isOSBinFormatCOFF()) | ||
if (useDllStorage()) | ||
cast<llvm::GlobalVariable>(symbolAddr) | ||
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); | ||
|
||
|
@@ -916,9 +921,9 @@ void IRGenModule::emitAutolinkInfo() { | |
}), | ||
AutolinkEntries.end()); | ||
|
||
if (TargetInfo.OutputObjectFormat == llvm::Triple::COFF || | ||
TargetInfo.OutputObjectFormat == llvm::Triple::MachO || | ||
Triple.isPS4()) { | ||
if ((TargetInfo.OutputObjectFormat == llvm::Triple::COFF && | ||
!Triple.isOSCygMing()) || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MinGW can properly handle directives for export. Why are you disabling this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MinGW/Cygwin's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Im familiar with the directive handling in binutils. That sounds like something else is going wrong. I know that the directives generated by LLVM should be properly handled by binutils linker. We should look at the generated object file and figure out what exactly prevents us from using that infrastructure. If its a bug in LLVM, we can fix that :-). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think LLVM should not emit '-lFoo' into
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, we should use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The root cause of the incompatibility of |
||
TargetInfo.OutputObjectFormat == llvm::Triple::MachO || Triple.isPS4()) { | ||
llvm::LLVMContext &ctx = Module.getContext(); | ||
|
||
if (!LinkerOptions) { | ||
|
@@ -935,8 +940,9 @@ void IRGenModule::emitAutolinkInfo() { | |
assert(FoundOldEntry && "Could not replace old linker options entry?"); | ||
} | ||
} else { | ||
assert(TargetInfo.OutputObjectFormat == llvm::Triple::ELF && | ||
"expected ELF output format"); | ||
assert((TargetInfo.OutputObjectFormat == llvm::Triple::ELF || | ||
Triple.isOSCygMing()) && | ||
"expected ELF output format or COFF format for Cygwin/MinGW"); | ||
|
||
// Merge the entries into null-separated string. | ||
llvm::SmallString<64> EntriesString; | ||
|
@@ -969,7 +975,7 @@ void IRGenModule::emitAutolinkInfo() { | |
llvm::GlobalValue::CommonLinkage, | ||
llvm::Constant::getNullValue(Int1Ty), | ||
buf.str()); | ||
if (Triple.isOSBinFormatCOFF()) | ||
if (useDllStorage()) | ||
symbol->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); | ||
} | ||
} | ||
|
@@ -1072,6 +1078,8 @@ void IRGenModule::error(SourceLoc loc, const Twine &message) { | |
message.toStringRef(buffer)); | ||
} | ||
|
||
bool IRGenModule::useDllStorage() { return ::useDllStorage(Triple); } | ||
|
||
void IRGenerator::addGenModule(SourceFile *SF, IRGenModule *IGM) { | ||
assert(GenModules.count(SF) == 0); | ||
GenModules[SF] = IGM; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// RUN: rm -rf %t | ||
// RUN: mkdir -p %t | ||
|
||
// RUN: %swift -target x86_64--windows-gnu -parse-as-library -parse-stdlib -emit-module-path %t/module.swiftmodule -module-name module -module-link-name module %s | ||
// RUN: %swift -target x86_64--windows-gnu -parse-as-library -parse-stdlib -module-name autolink -I %t -D MAIN_MODULE -emit-ir -o - %s | %FileCheck %s -check-prefix CHECK-GNU-IR | ||
// RUN: %swift -target x86_64--windows-gnu -parse-as-library -parse-stdlib -module-name autolink -I %t -D MAIN_MODULE -S -o - %s | %FileCheck %s -check-prefix CHECK-GNU-ASM | ||
|
||
// REQUIRES: CODEGENERATOR=X86 | ||
|
||
#if MAIN_MODULE | ||
import module | ||
#endif | ||
|
||
// CHECK-GNU-IR: @_swift1_autolink_entries = private constant [9 x i8] c"-lmodule\00", section ".swift1_autolink_entries", align 8 | ||
// CHECK-GNU-IR: @llvm.used = appending global [{{.*}} x i8*] [{{.*}}i8* getelementptr inbounds ([9 x i8], [9 x i8]* @_swift1_autolink_entries, i32 0, i32 0){{.*}}], section "llvm.metadata", align 8 | ||
|
||
// CHECK-GNU-ASM: .section .swift1_autolink_entries{{.*}} | ||
// CHECK-GNU-ASM: .asciz "-lmodule" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need the large code model?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DLL's are loaded above the max address for 32bit. (for example, cygswiftcore.dll is loaded at 0x459F40000).
Without large model, generated code had problems to reference the .data section of DLL's, and generated segment fault.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. Thats something that I somehow did not hit. However, even for the MSVC environment, we should be using
LARGEADDRESSAWARE
mode. So, perhaps its best to just always enable the large code model. I think the selection can just be inlined via a ternary.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I didn't understand last sentence. 'via a ternary' means all MinGW, Cygwin, MSVC ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, thinking more about it, do you have the code from an instance where this happens? The code generation issue that you sounds very much like a bug in LLVM. x86 has fully addressability, so within a 32-bit range should be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I can show you the sample codes.
This is a line of LLVM of Hello.swift.
@_TZvOs11CommandLine5_argcVs5Int32 = external global %Vs5Int32, align 4
That is
static Swift.CommandLine._argc : Swift.Int32
,and is a part of the standard library and declared in data section of
cygswiftCore.dll
,so the application code should read/write the data section of the dll.
The generated assembly code is as follows.
In default model,
movl %edi, _TZvOs11CommandLine5_argcVs5Int32(%rip)
,and in large model,
movabsq $_TZvOs11CommandLine5_argcVs5Int32, %rax
movl %ecx, (%rax)
.In case of 64bit default memory model, since the DLL is located at higher memory (for example, cygswiftcore.dll is loaded at 0x459F40000 > maximum 32bit), and the generated code only references 32bit address, the executable file didn't work correctly.
If we link the static library instead of dll, it might be work correctly, so I think it is hard to say llvm has a bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, doesnt this problem exist beyond just cygwin? Perhaps it should be a 64-bit windows check here instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, This will be same in case of MinGW 64bit and Windows MSVC 64bit.
What about 64bit Windows with different arch, such as ARM ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesnt 64-bit MSVC also have 2-GB limitations (PE+).