diff --git a/lld/test/wasm/lto/Inputs/builtins.ll b/lld/test/wasm/lto/Inputs/builtins.ll new file mode 100644 --- /dev/null +++ b/lld/test/wasm/lto/Inputs/builtins.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define half @__truncsfhf2(float) { + ret half 0.0 +} diff --git a/lld/test/wasm/lto/builtins.ll b/lld/test/wasm/lto/builtins.ll new file mode 100644 --- /dev/null +++ b/lld/test/wasm/lto/builtins.ll @@ -0,0 +1,26 @@ +; References to builtin symbols can be created for the first time during LTO. +; If those builtins are implemented themselved in lazy LTO objects there are +; otherwise not referenced this can result in bitfiles being added to the link +; *after* LTO, which will not work. +; Veriftr that we detect this and report a meaningful error. + +; RUN: llvm-as %s -o %t.o +; RUN: llvm-as %p/Inputs/builtins.ll -o %t.truncsfhf2.o +; RUN: rm -f %t.a +; RUN: llvm-ar rcs %t.a %t.truncsfhf2.o +; RUN: not wasm-ld --export-all %t.o %t.a -o %t.wasm 2>&1 | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +@g_float = global float 0.0 +@g_half = global half 0.0 + +define void @_start() { + %val1 = load float, float* @g_float + %v0 = fptrunc float %val1 to half + store half %v0, half* @g_half + ret void +} + +; CHECK: wasm-ld: error: {{.*}}truncsfhf2.o: attempt to add bitcode file after LTO. diff --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h --- a/lld/wasm/InputFiles.h +++ b/lld/wasm/InputFiles.h @@ -160,6 +160,10 @@ void parse(); std::unique_ptr obj; + + // Set to true once LTO is complete in order prevent further bitcode objects + // being added. + static bool doneLTO; }; // Will report a fatal() error if the input buffer is not a valid bitcode diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -537,7 +537,16 @@ return symtab->addDefinedData(name, flags, &f, nullptr, 0, 0); } +bool BitcodeFile::doneLTO = false; + void BitcodeFile::parse() { + if (doneLTO) { + error(toString(mb.getBufferIdentifier()) + + ": attempt to add bitcode file after LTO."); + error("This is most often caused by builtin functions into LTO objects."); + return; + } + obj = check(lto::InputFile::create(MemoryBufferRef( mb.getBuffer(), saver.save(archiveName + mb.getBufferIdentifier())))); Triple t(obj->getTargetTriple()); diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -65,6 +65,9 @@ // Because all bitcode files that the program consists of are passed // to the compiler at once, it can do whole-program optimization. void SymbolTable::addCombinedLTOObject() { + // Prevent further LTO objects being included + BitcodeFile::doneLTO = true; + if (bitcodeFiles.empty()) return;