diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h index 05edc98f9ec892..a43b4766218045 100644 --- a/clang/include/clang/Basic/SourceManager.h +++ b/clang/include/clang/Basic/SourceManager.h @@ -958,6 +958,10 @@ class SourceManager : public RefCountedBase { /// data in the given source file. void overrideFileContents(const FileEntry *SourceFile, std::unique_ptr Buffer); + void overrideFileContents(FileEntryRef SourceFile, + std::unique_ptr Buffer) { + overrideFileContents(&SourceFile.getFileEntry(), std::move(Buffer)); + } /// Override the given source file with another one. /// @@ -1029,6 +1033,13 @@ class SourceManager : public RefCountedBase { return nullptr; } + /// Returns the FileEntryRef for the provided FileID. + Optional getFileEntryRefForID(FileID FID) const { + if (auto *Entry = getFileEntryForID(FID)) + return Entry->getLastRef(); + return None; + } + /// Returns the filename for the provided FileID, unless it's a built-in /// buffer that's not represented by a filename. /// diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index 5bee57042ca68e..6cf9f3ff936f1c 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -688,14 +688,15 @@ class ASTUnit { /// lifetime is expected to extend past that of the returned ASTUnit. /// /// \returns - The initialized ASTUnit or null if the AST failed to load. - static std::unique_ptr LoadFromASTFile( - const std::string &Filename, const PCHContainerReader &PCHContainerRdr, - WhatToLoad ToLoad, IntrusiveRefCntPtr Diags, - const FileSystemOptions &FileSystemOpts, bool UseDebugInfo = false, - bool OnlyLocalDecls = false, ArrayRef RemappedFiles = None, - CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, - bool AllowASTWithCompilerErrors = false, - bool UserFilesAreVolatile = false); + static std::unique_ptr + LoadFromASTFile(const std::string &Filename, + const PCHContainerReader &PCHContainerRdr, WhatToLoad ToLoad, + IntrusiveRefCntPtr Diags, + const FileSystemOptions &FileSystemOpts, + bool UseDebugInfo = false, bool OnlyLocalDecls = false, + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, + bool AllowASTWithCompilerErrors = false, + bool UserFilesAreVolatile = false); private: /// Helper function for \c LoadFromCompilerInvocation() and diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index dfc0d935316549..68a51a49c71823 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/lib/ARCMigrate/ObjCMT.cpp @@ -156,7 +156,7 @@ class ObjCMigrateASTConsumer : public ASTConsumer { return WhiteListFilenames.find(llvm::sys::path::filename(Path)) != WhiteListFilenames.end(); } - bool canModifyFile(const FileEntry *FE) { + bool canModifyFile(Optional FE) { if (!FE) return false; return canModifyFile(FE->getName()); @@ -164,7 +164,7 @@ class ObjCMigrateASTConsumer : public ASTConsumer { bool canModifyFile(FileID FID) { if (FID.isInvalid()) return false; - return canModifyFile(PP.getSourceManager().getFileEntryForID(FID)); + return canModifyFile(PP.getSourceManager().getFileEntryRefForID(FID)); } bool canModify(const Decl *D) { @@ -1964,7 +1964,7 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { FileID FID = I->first; RewriteBuffer &buf = I->second; - const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); + Optional file = Ctx.getSourceManager().getFileEntryRefForID(FID); assert(file); SmallString<512> newText; llvm::raw_svector_ostream vecOS(newText); @@ -2034,7 +2034,7 @@ MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { namespace { struct EditEntry { - const FileEntry *File = nullptr; + Optional File; unsigned Offset = 0; unsigned RemoveLen = 0; std::string Text; @@ -2127,9 +2127,8 @@ class RemapFileParser { StringRef Val = ValueString->getValue(ValueStorage); if (Key == "file") { - auto FE = FileMgr.getFile(Val); - if (FE) - Entry.File = *FE; + if (auto File = FileMgr.getOptionalFileRef(Val)) + Entry.File = File; else Ignore = true; } else if (Key == "offset") { @@ -2155,7 +2154,7 @@ static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag) { return true; } -static std::string applyEditsToTemp(const FileEntry *FE, +static std::string applyEditsToTemp(FileEntryRef FE, ArrayRef Edits, FileManager &FileMgr, DiagnosticsEngine &Diag) { @@ -2199,8 +2198,8 @@ static std::string applyEditsToTemp(const FileEntry *FE, SmallString<64> TempPath; int FD; - if (fs::createTemporaryFile(path::filename(FE->getName()), - path::extension(FE->getName()).drop_front(), FD, + if (fs::createTemporaryFile(path::filename(FE.getName()), + path::extension(FE.getName()).drop_front(), FD, TempPath)) { reportDiag("Could not create file: " + TempPath.str(), Diag); return std::string(); @@ -2228,7 +2227,7 @@ bool arcmt::getFileRemappingsFromFileList( new DiagnosticsEngine(DiagID, new DiagnosticOptions, DiagClient, /*ShouldOwnClient=*/false)); - typedef llvm::DenseMap > + typedef llvm::DenseMap > FileEditEntriesTy; FileEditEntriesTy FileEditEntries; @@ -2250,7 +2249,7 @@ bool arcmt::getFileRemappingsFromFileList( if (!Insert.second) continue; - FileEditEntries[Entry.File].push_back(Entry); + FileEditEntries[*Entry.File].push_back(Entry); } } @@ -2263,7 +2262,7 @@ bool arcmt::getFileRemappingsFromFileList( continue; } - remap.emplace_back(std::string(I->first->getName()), TempFile); + remap.emplace_back(std::string(I->first.getName()), TempFile); } return hasErrorOccurred; diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index d9154e9b459e26..51851a5bac83be 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -758,9 +758,8 @@ std::unique_ptr ASTUnit::LoadFromASTFile( const std::string &Filename, const PCHContainerReader &PCHContainerRdr, WhatToLoad ToLoad, IntrusiveRefCntPtr Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo, - bool OnlyLocalDecls, ArrayRef RemappedFiles, - CaptureDiagsKind CaptureDiagnostics, bool AllowASTWithCompilerErrors, - bool UserFilesAreVolatile) { + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, + bool AllowASTWithCompilerErrors, bool UserFilesAreVolatile) { std::unique_ptr AST(new ASTUnit(true)); // Recover resources if we crash before exiting this method. @@ -793,9 +792,6 @@ std::unique_ptr ASTUnit::LoadFromASTFile( /*Target=*/nullptr)); AST->PPOpts = std::make_shared(); - for (const auto &RemappedFile : RemappedFiles) - AST->PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second); - // Gather Info for preprocessor construction later on. HeaderSearch &HeaderInfo = *AST->HeaderInfo; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index fa3d50aeedfe0e..92e5208b193ba6 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -891,8 +891,8 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, } std::unique_ptr SB = std::move(SBOrErr.get()); - const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), - SB->getBufferSize(), 0); + FileEntryRef File = FileMgr.getVirtualFileRef(SB->getBufferIdentifier(), + SB->getBufferSize(), 0); SourceMgr.setMainFileID( SourceMgr.createFileID(File, SourceLocation(), Kind)); SourceMgr.overrideFileContents(File, std::move(SB)); diff --git a/clang/test/CodeGenObjC/arc.ll b/clang/test/CodeGenObjC/arc.ll index 7b903d05cd178f..cfc88c3c7eb715 100644 --- a/clang/test/CodeGenObjC/arc.ll +++ b/clang/test/CodeGenObjC/arc.ll @@ -1,7 +1,5 @@ ; RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Os -emit-llvm -fobjc-arc -o - %s | FileCheck %s -target triple = "x86_64-apple-darwin10" - declare i8* @llvm.objc.retain(i8*) declare void @llvm.objc.release(i8*) diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp index c6d59d703d1732..ed0d99b9d19989 100644 --- a/clang/tools/c-index-test/core_main.cpp +++ b/clang/tools/c-index-test/core_main.cpp @@ -262,7 +262,7 @@ static bool printSourceSymbolsFromModule(StringRef modulePath, std::unique_ptr AU = ASTUnit::LoadFromASTFile( std::string(modulePath), *pchRdr, ASTUnit::LoadASTOnly, Diags, FileSystemOpts, /*UseDebugInfo=*/false, - /*OnlyLocalDecls=*/true, None, CaptureDiagsKind::None, + /*OnlyLocalDecls=*/true, CaptureDiagsKind::None, /*AllowASTWithCompilerErrors=*/true, /*UserFilesAreVolatile=*/false); if (!AU) { diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 95ff9aa35bfa1e..aa888a38004800 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -3475,7 +3475,7 @@ enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx, std::unique_ptr AU = ASTUnit::LoadFromASTFile( ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(), ASTUnit::LoadEverything, Diags, FileSystemOpts, /*UseDebugInfo=*/false, - CXXIdx->getOnlyLocalDecls(), None, CaptureDiagsKind::All, + CXXIdx->getOnlyLocalDecls(), CaptureDiagsKind::All, /*AllowASTWithCompilerErrors=*/true, /*UserFilesAreVolatile=*/true); *out_TU = MakeCXTranslationUnit(CXXIdx, std::move(AU)); diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp index 7ba0bf0c2e2f5a..0cb075ac632a29 100644 --- a/compiler-rt/lib/dfsan/dfsan_custom.cpp +++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -879,6 +880,26 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req, return ret; } +SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfsw_recvmsg( + int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label, + dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label) { + ssize_t ret = recvmsg(sockfd, msg, flags); + if (ret >= 0) { + dfsan_set_label(0, msg, sizeof(*msg)); + dfsan_set_label(0, msg->msg_name, msg->msg_namelen); + dfsan_set_label(0, msg->msg_control, msg->msg_controllen); + for (size_t remaining = ret, i = 0; remaining > 0; ++i) { + assert(i < msg->msg_iovlen); + struct iovec *iov = &msg->msg_iov[i]; + size_t written = remaining < iov->iov_len ? remaining : iov->iov_len; + dfsan_set_label(0, iov->iov_base, written); + remaining -= written; + } + } + *ret_label = 0; + return ret; +} + SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_socketpair(int domain, int type, int protocol, int sv[2], dfsan_label domain_label, dfsan_label type_label, @@ -892,6 +913,20 @@ __dfsw_socketpair(int domain, int type, int protocol, int sv[2], return ret; } +SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockopt( + int sockfd, int level, int optname, void *optval, socklen_t *optlen, + dfsan_label sockfd_label, dfsan_label level_label, + dfsan_label optname_label, dfsan_label optval_label, + dfsan_label optlen_label, dfsan_label *ret_label) { + int ret = getsockopt(sockfd, level, optname, optval, optlen); + if (ret != -1 && optval && optlen) { + dfsan_set_label(0, optlen, sizeof(*optlen)); + dfsan_set_label(0, optval, *optlen); + } + *ret_label = 0; + return ret; +} + // Type of the trampoline function passed to the custom version of // dfsan_set_write_callback. typedef void (*write_trampoline_t)( diff --git a/compiler-rt/lib/dfsan/done_abilist.txt b/compiler-rt/lib/dfsan/done_abilist.txt index bf874d262be97b..13513cbb0f23b2 100644 --- a/compiler-rt/lib/dfsan/done_abilist.txt +++ b/compiler-rt/lib/dfsan/done_abilist.txt @@ -116,6 +116,8 @@ fun:connect=discard fun:creat=discard fun:dladdr=discard fun:dlclose=discard +fun:epoll_create=discard +fun:epoll_create1=discard fun:epoll_ctl=discard fun:fclose=discard fun:feof=discard @@ -192,9 +194,11 @@ fun:get_current_dir_name=custom fun:gethostname=custom fun:getrlimit=custom fun:getrusage=custom +fun:getsockopt=custom fun:nanosleep=custom fun:pread=custom fun:read=custom +fun:recvmsg=custom fun:socketpair=custom fun:stat=custom fun:time=custom diff --git a/compiler-rt/lib/scudo/standalone/secondary.h b/compiler-rt/lib/scudo/standalone/secondary.h index eda88862cb0784..ff41bd3e07227c 100644 --- a/compiler-rt/lib/scudo/standalone/secondary.h +++ b/compiler-rt/lib/scudo/standalone/secondary.h @@ -31,7 +31,7 @@ struct Header { uptr BlockEnd; uptr MapBase; uptr MapSize; - MapPlatformData Data; + [[no_unique_address]] MapPlatformData Data; }; constexpr uptr getHeaderSize() { @@ -232,7 +232,7 @@ class MapAllocatorCache { uptr BlockEnd; uptr MapBase; uptr MapSize; - MapPlatformData Data; + [[no_unique_address]] MapPlatformData Data; u64 Time; }; diff --git a/compiler-rt/test/dfsan/custom.cpp b/compiler-rt/test/dfsan/custom.cpp index 087a684f51b97d..b57f172d7e4ca0 100644 --- a/compiler-rt/test/dfsan/custom.cpp +++ b/compiler-rt/test/dfsan/custom.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -336,6 +337,41 @@ void test_calloc() { free(crv); } +void test_recvmsg() { + int sockfds[2]; + int ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sockfds); + assert(ret != -1); + + char sbuf[] = "abcdefghijkl"; + struct iovec siovs[2] = {{&sbuf[0], 4}, {&sbuf[4], 4}}; + struct msghdr smsg = {}; + smsg.msg_iov = siovs; + smsg.msg_iovlen = 2; + + ssize_t sent = sendmsg(sockfds[0], &smsg, 0); + assert(sent > 0); + + char rbuf[128]; + struct iovec riovs[2] = {{&rbuf[0], 4}, {&rbuf[4], 4}}; + struct msghdr rmsg = {}; + rmsg.msg_iov = riovs; + rmsg.msg_iovlen = 2; + + dfsan_set_label(i_label, rbuf, sizeof(rbuf)); + dfsan_set_label(i_label, &rmsg, sizeof(rmsg)); + + ssize_t received = recvmsg(sockfds[1], &rmsg, 0); + assert(received == sent); + assert(memcmp(sbuf, rbuf, 8) == 0); + ASSERT_ZERO_LABEL(received); + ASSERT_READ_ZERO_LABEL(&rmsg, sizeof(rmsg)); + ASSERT_READ_ZERO_LABEL(&rbuf[0], 8); + ASSERT_READ_LABEL(&rbuf[8], 1, i_label); + + close(sockfds[0]); + close(sockfds[1]); +} + void test_read() { char buf[16]; dfsan_set_label(i_label, buf, 1); @@ -895,6 +931,27 @@ void test_socketpair() { ASSERT_READ_ZERO_LABEL(fd, sizeof(fd)); } +void test_getsockopt() { + int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); + assert(sockfd != -1); + + int optval[2] = {-1, -1}; + socklen_t optlen = sizeof(optval); + dfsan_set_label(i_label, &optval, sizeof(optval)); + dfsan_set_label(i_label, &optlen, sizeof(optlen)); + int ret = getsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen); + assert(ret != -1); + assert(optlen == sizeof(int)); + assert(optval[0] == 0); + assert(optval[1] == -1); + ASSERT_ZERO_LABEL(ret); + ASSERT_ZERO_LABEL(optlen); + ASSERT_ZERO_LABEL(optval[0]); + ASSERT_LABEL(optval[1], i_label); + + close(sockfd); +} + void test_write() { int fd = open("/dev/null", O_WRONLY); @@ -1077,6 +1134,7 @@ int main(void) { test_getpwuid_r(); test_getrlimit(); test_getrusage(); + test_getsockopt(); test_gettimeofday(); test_inet_pton(); test_localtime_r(); @@ -1089,6 +1147,7 @@ int main(void) { test_pread(); test_pthread_create(); test_read(); + test_recvmsg(); test_sched_getaffinity(); test_select(); test_sigaction(); diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index f289e66dc6d5e5..19964428050b01 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -883,8 +883,10 @@ ParsedDirectives ArgParser::parseDirectives(StringRef s) { tok.startswith_lower("-include:")) result.includes.push_back(tok.substr(strlen("/include:"))); else { - // Save non-null-terminated strings to make proper C strings. - bool HasNul = tok.data()[tok.size()] == '\0'; + // Copy substrings that are not valid C strings. The tokenizer may have + // already copied quoted arguments for us, so those do not need to be + // copied again. + bool HasNul = tok.end() != s.end() && tok.data()[tok.size()] == '\0'; rest.push_back(HasNul ? tok.data() : saver.save(tok).data()); } } diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 0254b54eca1d8e..c79578ce18fa51 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -598,6 +598,8 @@ def: J<"plugin-opt=lto-partitions=">, Alias, HelpText<"Alias for def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">; def: F<"plugin-opt=new-pass-manager">, Alias, HelpText<"Alias for --lto-new-pass-manager">; +def: F<"plugin-opt=no-new-pass-manager">, + Alias, HelpText<"Alias for --no-lto-new-pass-manager">; def: F<"plugin-opt=cs-profile-generate">, Alias, HelpText<"Alias for --lto-cs-profile-generate">; def: J<"plugin-opt=cs-profile-path=">, diff --git a/lld/test/ELF/lto/new-pass-manager.ll b/lld/test/ELF/lto/new-pass-manager.ll index 941235b486307a..6b6f6ce83cf00e 100644 --- a/lld/test/ELF/lto/new-pass-manager.ll +++ b/lld/test/ELF/lto/new-pass-manager.ll @@ -7,6 +7,7 @@ ; RUN: ld.lld --lto-new-pass-manager --plugin-opt=debug-pass-manager -o /dev/null %t.o 2>&1 | FileCheck %s ; RUN: ld.lld --lto-new-pass-manager --lto-debug-pass-manager -o /dev/null %t.o 2>&1 | FileCheck %s ; RUN: ld.lld --lto-new-pass-manager --no-lto-new-pass-manager --lto-debug-pass-manager -o /dev/null %t.o 2>&1 | FileCheck %s --check-prefix=LEGACY +; RUN: ld.lld --plugin-opt=no-new-pass-manager --plugin-opt=debug-pass-manager -o /dev/null %t.o 2>&1 | FileCheck %s --check-prefix=LEGACY ; CHECK: Starting llvm::Module pass manager run ; CHECK: Finished llvm::Module pass manager run diff --git a/lld/test/wasm/call-indirect.ll b/lld/test/wasm/call-indirect.ll index 84a84710f2bafe..4acc1edae4f2ff 100644 --- a/lld/test/wasm/call-indirect.ll +++ b/lld/test/wasm/call-indirect.ll @@ -156,4 +156,7 @@ define void @call_ptr(i64 (i64)* %arg) { ; CHECK-NEXT: GlobalNames: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: __stack_pointer +; CHECK-NEXT: DataSegmentNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .data ; CHECK-NEXT: ... diff --git a/lld/test/wasm/data-segment-merging.ll b/lld/test/wasm/data-segment-merging.ll index bc347d19357482..1dee1ccbda29a9 100644 --- a/lld/test/wasm/data-segment-merging.ll +++ b/lld/test/wasm/data-segment-merging.ll @@ -31,7 +31,9 @@ ; MERGE-NEXT: GlobalNames: ; MERGE-NEXT: - Index: 0 ; MERGE-NEXT: Name: __stack_pointer -; MERGE-NOT: - Index: +; MERGE-NEXT: DataSegmentNames: +; MERGE-NEXT: - Index: 0 +; MERGE-NEXT: Name: .rodata ; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.o ; RUN: obj2yaml %t.separate.wasm | FileCheck %s --check-prefix=SEPARATE @@ -71,7 +73,9 @@ ; SEPARATE-NEXT: GlobalNames: ; SEPARATE-NEXT: - Index: 0 ; SEPARATE-NEXT: Name: __stack_pointer -; SEPARATE-NOT: - Index: +; SEPARATE-NEXT: DataSegmentNames: +; SEPARATE-NEXT: - Index: 0 +; SEPARATE-NEXT: Name: .rodata ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 -o %t.merged.passive.wasm %t.passive.o ; RUN: obj2yaml %t.merged.passive.wasm | FileCheck %s --check-prefix=PASSIVE-MERGE diff --git a/lld/test/wasm/gc-sections.ll b/lld/test/wasm/gc-sections.ll index 8bac2fd078278a..de8298697bf12e 100644 --- a/lld/test/wasm/gc-sections.ll +++ b/lld/test/wasm/gc-sections.ll @@ -87,6 +87,9 @@ entry: ; CHECK-NEXT: Name: __stack_pointer ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: used_global +; CHECK-NEXT: DataSegmentNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .data ; CHECK-NEXT: ... ; RUN: wasm-ld -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm \ @@ -162,6 +165,9 @@ entry: ; NO-GC-NEXT: Name: unused_global ; NO-GC-NEXT: - Index: 2 ; NO-GC-NEXT: Name: used_global +; NO-GC-NEXT: DataSegmentNames: +; NO-GC-NEXT: - Index: 0 +; NO-GC-NEXT: Name: .data ; NO-GC-NEXT: ... ; RUN: not wasm-ld --gc-sections --relocatable -o %t1.no-gc.wasm %t.o 2>&1 | FileCheck %s -check-prefix=CHECK-ERROR diff --git a/lld/test/wasm/local-symbols.ll b/lld/test/wasm/local-symbols.ll index d0a520a950a29e..13c200d648e930 100644 --- a/lld/test/wasm/local-symbols.ll +++ b/lld/test/wasm/local-symbols.ll @@ -97,4 +97,7 @@ entry: ; CHECK-NEXT: GlobalNames: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: __stack_pointer +; CHECK-NEXT: DataSegmentNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .data ; CHECK-NEXT: ... diff --git a/lld/test/wasm/locals-duplicate.test b/lld/test/wasm/locals-duplicate.test index dc6b9c88be2965..07abb748538149 100644 --- a/lld/test/wasm/locals-duplicate.test +++ b/lld/test/wasm/locals-duplicate.test @@ -212,6 +212,9 @@ ; CHECK-NEXT: GlobalNames: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: __stack_pointer +; CHECK-NEXT: DataSegmentNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .data ; CHECK-NEXT: ... @@ -546,4 +549,11 @@ ; RELOC-NEXT: Name: get_func2B ; RELOC-NEXT: - Index: 17 ; RELOC-NEXT: Name: get_func3B +; RELOC-NEXT: DataSegmentNames: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Name: .data.colliding_global1 +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Name: .data.colliding_global2 +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Name: .data.colliding_global3 ; RELOC-NEXT: ... diff --git a/lld/test/wasm/map-file.s b/lld/test/wasm/map-file.s index e194662ea5d150..a5bd0160569523 100644 --- a/lld/test/wasm/map-file.s +++ b/lld/test/wasm/map-file.s @@ -40,7 +40,7 @@ somedata: # CHECK-NEXT: 400 5a 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata) # CHECK-NEXT: 400 5a 4 somedata # CHECK-NEXT: - 60 12 CUSTOM(.debug_info) -# CHECK-NEXT: - 72 2b CUSTOM(name) +# CHECK-NEXT: - 72 35 CUSTOM(name) # RUN: not wasm-ld %t1.o -o /dev/null -Map=/ 2>&1 \ # RUN: | FileCheck -check-prefix=FAIL %s diff --git a/lld/test/wasm/signature-mismatch.ll b/lld/test/wasm/signature-mismatch.ll index 3e42a74d0f058c..d5f95b0073c06d 100644 --- a/lld/test/wasm/signature-mismatch.ll +++ b/lld/test/wasm/signature-mismatch.ll @@ -55,6 +55,9 @@ declare i32 @ret32(i32, i64, i32) local_unnamed_addr ; YAML-NEXT: GlobalNames: ; YAML-NEXT: - Index: 0 ; YAML-NEXT: Name: __stack_pointer +; YAML-NEXT: DataSegmentNames: +; YAML-NEXT: - Index: 0 +; YAML-NEXT: Name: .data ; YAML-NEXT: ... ; RELOC: Name: linking diff --git a/lld/test/wasm/weak-symbols.s b/lld/test/wasm/weak-symbols.s index 41c8a1a38f55db..7557dfb5535b5f 100644 --- a/lld/test/wasm/weak-symbols.s +++ b/lld/test/wasm/weak-symbols.s @@ -116,4 +116,7 @@ _start: # CHECK-NEXT: GlobalNames: # CHECK-NEXT: - Index: 0 # CHECK-NEXT: Name: __stack_pointer +# CHECK-NEXT: DataSegmentNames: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: Name: .data # CHECK-NEXT: ... diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 3fdcc6252fd9ca..95a48528db9e56 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -562,6 +562,16 @@ unsigned NameSection::numNamedGlobals() const { return numNames; } +unsigned NameSection::numNamedDataSegments() const { + unsigned numNames = 0; + + for (const OutputSegment *s : segments) + if (!s->name.empty()) + ++numNames; + + return numNames; +} + // Create the custom "name" section containing debug symbol names. void NameSection::writeBody() { unsigned count = numNamedFunctions(); @@ -619,6 +629,19 @@ void NameSection::writeBody() { sub.writeTo(bodyOutputStream); } + + count = numNamedDataSegments(); + if (count) { + SubSection sub(WASM_NAMES_DATA_SEGMENT); + writeUleb128(sub.os, count, "name count"); + + for (OutputSegment *s : segments) { + writeUleb128(sub.os, s->index, "global index"); + writeStr(sub.os, s->name, "segment name"); + } + + sub.writeTo(bodyOutputStream); + } } void ProducersSection::addInfo(const WasmProducerInfo &info) { diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h index f9ec7f288dbd4b..56ba66ffc08d02 100644 --- a/lld/wasm/SyntheticSections.h +++ b/lld/wasm/SyntheticSections.h @@ -296,7 +296,9 @@ class LinkingSection : public SyntheticSection { // Create the custom "name" section containing debug symbol names. class NameSection : public SyntheticSection { public: - NameSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name") {} + NameSection(ArrayRef segments) + : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"), + segments(segments) {} bool isNeeded() const override { return !config->stripDebug && !config->stripAll && numNames() > 0; } @@ -304,6 +306,10 @@ class NameSection : public SyntheticSection { unsigned numNames() const { return numNamedGlobals() + numNamedFunctions(); } unsigned numNamedGlobals() const; unsigned numNamedFunctions() const; + unsigned numNamedDataSegments() const; + +protected: + ArrayRef segments; }; class ProducersSection : public SyntheticSection { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 851a6d36621010..dca6c260d429d7 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1210,7 +1210,7 @@ void Writer::createSyntheticSections() { out.elemSec = make(); out.dataCountSec = make(segments); out.linkingSec = make(initFunctions, segments); - out.nameSec = make(); + out.nameSec = make(segments); out.producersSec = make(); out.targetFeaturesSec = make(); } diff --git a/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp b/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp index 344bac8e0632ef..2655e4de9063ad 100644 --- a/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp +++ b/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp @@ -342,13 +342,6 @@ static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, } } - cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, - CFSTR("DBGArchitecture")); - if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { - if (CFCString::FileSystemRepresentation(cf_str, str)) - module_spec.GetArchitecture().SetTriple(str.c_str()); - } - std::string DBGBuildSourcePath; std::string DBGSourcePath; diff --git a/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py b/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py index 79a79056476b71..7055fa698382fb 100644 --- a/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py +++ b/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py @@ -85,7 +85,7 @@ def test_lc_note(self): 'fi', 'echo "$uuid"', '', - 'echo "DBGArchitecturex86_64"', + 'echo "DBGArchitecturei386"', 'echo "DBGDSYMPath$dsym"', 'echo "DBGSymbolRichExecutable$bin"', 'echo ""', diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index 760ddf5a23680a..371e9add880f6d 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -202,7 +202,8 @@ struct WasmSymbolInfo { enum class NameType { FUNCTION, - GLOBAL + GLOBAL, + DATA_SEGMENT, }; struct WasmDebugName { @@ -313,9 +314,10 @@ enum : uint8_t { // Kind codes used in the custom "name" section enum : unsigned { - WASM_NAMES_FUNCTION = 0x1, - WASM_NAMES_LOCAL = 0x2, - WASM_NAMES_GLOBAL = 0x7, + WASM_NAMES_FUNCTION = 1, + WASM_NAMES_LOCAL = 2, + WASM_NAMES_GLOBAL = 7, + WASM_NAMES_DATA_SEGMENT = 9, }; // Kind codes used in the custom "linking" section diff --git a/llvm/include/llvm/ObjectYAML/WasmYAML.h b/llvm/include/llvm/ObjectYAML/WasmYAML.h index 28cd56061a3cf1..80f1b4006205d0 100644 --- a/llvm/include/llvm/ObjectYAML/WasmYAML.h +++ b/llvm/include/llvm/ObjectYAML/WasmYAML.h @@ -222,6 +222,7 @@ struct NameSection : CustomSection { std::vector FunctionNames; std::vector GlobalNames; + std::vector DataSegmentNames; }; struct LinkingSection : CustomSection { diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 7c8abcbd76fa28..c9b13e4afb4e5b 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -357,6 +357,7 @@ Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) { Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { llvm::DenseSet SeenFunctions; llvm::DenseSet SeenGlobals; + llvm::DenseSet SeenSegments; if (FunctionTypes.size() && !SeenCodeSection) { return make_error("Names must come after code section", object_error::parse_failed); @@ -368,11 +369,13 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { const uint8_t *SubSectionEnd = Ctx.Ptr + Size; switch (Type) { case wasm::WASM_NAMES_FUNCTION: - case wasm::WASM_NAMES_GLOBAL: { + case wasm::WASM_NAMES_GLOBAL: + case wasm::WASM_NAMES_DATA_SEGMENT: { uint32_t Count = readVaruint32(Ctx); while (Count--) { uint32_t Index = readVaruint32(Ctx); StringRef Name = readString(Ctx); + wasm::NameType nameType = wasm::NameType::FUNCTION; if (Type == wasm::WASM_NAMES_FUNCTION) { if (!SeenFunctions.insert(Index).second) return make_error( @@ -383,18 +386,24 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { if (isDefinedFunctionIndex(Index)) getDefinedFunction(Index).DebugName = Name; - } else { + } else if (Type == wasm::WASM_NAMES_GLOBAL) { + nameType = wasm::NameType::GLOBAL; if (!SeenGlobals.insert(Index).second) return make_error("Global named more than once", object_error::parse_failed); if (!isValidGlobalIndex(Index) || Name.empty()) return make_error("Invalid name entry", object_error::parse_failed); + } else { + nameType = wasm::NameType::DATA_SEGMENT; + if (!SeenSegments.insert(Index).second) + return make_error( + "Segment named more than once", object_error::parse_failed); + if (Index > DataSegments.size()) + return make_error("Invalid named data segment", + object_error::parse_failed); } - wasm::NameType T = Type == wasm::WASM_NAMES_FUNCTION - ? wasm::NameType::FUNCTION - : wasm::NameType::GLOBAL; - DebugNames.push_back(wasm::WasmDebugName{T, Index, Name}); + DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name}); } break; } diff --git a/llvm/lib/ObjectYAML/WasmEmitter.cpp b/llvm/lib/ObjectYAML/WasmEmitter.cpp index 64498c82232bbf..d9f820baaaa38b 100644 --- a/llvm/lib/ObjectYAML/WasmEmitter.cpp +++ b/llvm/lib/ObjectYAML/WasmEmitter.cpp @@ -281,6 +281,19 @@ void WasmWriter::writeSectionContent(raw_ostream &OS, writeStringRef(NameEntry.Name, SubSection.getStream()); } + SubSection.done(); + } + if (Section.DataSegmentNames.size()) { + writeUint8(OS, wasm::WASM_NAMES_DATA_SEGMENT); + + SubSectionWriter SubSection(OS); + + encodeULEB128(Section.DataSegmentNames.size(), SubSection.getStream()); + for (const WasmYAML::NameEntry &NameEntry : Section.DataSegmentNames) { + encodeULEB128(NameEntry.Index, SubSection.getStream()); + writeStringRef(NameEntry.Name, SubSection.getStream()); + } + SubSection.done(); } } diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp index a6ad5c3e0b8dcc..69c4fd6cf4817d 100644 --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -62,6 +62,7 @@ static void sectionMapping(IO &IO, WasmYAML::NameSection &Section) { IO.mapRequired("Name", Section.Name); IO.mapOptional("FunctionNames", Section.FunctionNames); IO.mapOptional("GlobalNames", Section.GlobalNames); + IO.mapOptional("DataSegmentNames", Section.DataSegmentNames); } static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) { diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp index 56d97588df6ea3..22c32400ecbf6f 100644 --- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -4040,7 +4040,7 @@ bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, SMLoc ErrorLoc = IDLoc; if (ErrorInfo != ~0ULL) { if (ErrorInfo >= Operands.size()) { - return Error(getLoc(), "too few operands for instruction"); + return Error(IDLoc, "too few operands for instruction"); } ErrorLoc = ((AMDGPUOperand &)*Operands[ErrorInfo]).getStartLoc(); if (ErrorLoc == SMLoc()) @@ -5020,9 +5020,11 @@ bool AMDGPUAsmParser::ParseInstruction(ParseInstructionInfo &Info, while (!getLexer().is(AsmToken::EndOfStatement)) { Parser.Lex(); } + Parser.Lex(); return true; } } + Parser.Lex(); return false; } diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index de8c2f345fb5f9..a5cb078b2257e4 100644 --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -616,7 +616,7 @@ X86DAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const { // best of both worlds. if (U->getOpcode() == ISD::AND && Imm->getAPIntValue().getBitWidth() == 64 && - Imm->getAPIntValue().isIntN(32)) + Imm->getAPIntValue().isSignedIntN(32)) return false; // If this really a zext_inreg that can be represented with a movzx diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 53f30af8d38b22..5a77cc1f17fc0b 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -135,19 +135,24 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM, addBypassSlowDiv(64, 32); } - if (Subtarget.isTargetWindowsMSVC() || - Subtarget.isTargetWindowsItanium()) { - // Setup Windows compiler runtime calls. - setLibcallName(RTLIB::SDIV_I64, "_alldiv"); - setLibcallName(RTLIB::UDIV_I64, "_aulldiv"); - setLibcallName(RTLIB::SREM_I64, "_allrem"); - setLibcallName(RTLIB::UREM_I64, "_aullrem"); - setLibcallName(RTLIB::MUL_I64, "_allmul"); - setLibcallCallingConv(RTLIB::SDIV_I64, CallingConv::X86_StdCall); - setLibcallCallingConv(RTLIB::UDIV_I64, CallingConv::X86_StdCall); - setLibcallCallingConv(RTLIB::SREM_I64, CallingConv::X86_StdCall); - setLibcallCallingConv(RTLIB::UREM_I64, CallingConv::X86_StdCall); - setLibcallCallingConv(RTLIB::MUL_I64, CallingConv::X86_StdCall); + // Setup Windows compiler runtime calls. + if (Subtarget.isTargetWindowsMSVC() || Subtarget.isTargetWindowsItanium()) { + static const struct { + const RTLIB::Libcall Op; + const char * const Name; + const CallingConv::ID CC; + } LibraryCalls[] = { + { RTLIB::SDIV_I64, "_alldiv", CallingConv::X86_StdCall }, + { RTLIB::UDIV_I64, "_aulldiv", CallingConv::X86_StdCall }, + { RTLIB::SREM_I64, "_allrem", CallingConv::X86_StdCall }, + { RTLIB::UREM_I64, "_aullrem", CallingConv::X86_StdCall }, + { RTLIB::MUL_I64, "_allmul", CallingConv::X86_StdCall }, + }; + + for (const auto &LC : LibraryCalls) { + setLibcallName(LC.Op, LC.Name); + setLibcallCallingConv(LC.Op, LC.CC); + } } if (Subtarget.getTargetTriple().isOSMSVCRT()) { diff --git a/llvm/test/CodeGen/X86/pr48458.ll b/llvm/test/CodeGen/X86/pr48458.ll new file mode 100644 index 00000000000000..bca355961611b2 --- /dev/null +++ b/llvm/test/CodeGen/X86/pr48458.ll @@ -0,0 +1,17 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s + +define i1 @foo(i64* %0) { +; CHECK-LABEL: foo: +; CHECK: # %bb.0: # %top +; CHECK-NEXT: movq (%rdi), %rax +; CHECK-NEXT: andq $-2147483648, %rax # imm = 0x80000000 +; CHECK-NEXT: sete %al +; CHECK-NEXT: retq +top: + %1 = load i64, i64* %0, !range !0 + %2 = icmp ult i64 %1, 2147483648 + ret i1 %2 +} + +!0 = !{i64 0, i64 10000000000} diff --git a/llvm/test/MC/AMDGPU/exp-err.s b/llvm/test/MC/AMDGPU/exp-err.s index b650a78627dba4..ee83bef0c50bcf 100644 --- a/llvm/test/MC/AMDGPU/exp-err.s +++ b/llvm/test/MC/AMDGPU/exp-err.s @@ -53,7 +53,7 @@ exp , v3, v2, v1, v0 // GCN: :5: error: unknown token in expression exp -// GCN: :4: error: too few operands for instruction +// GCN: :1: error: too few operands for instruction exp mrt0 s0, v0, v0, v0 // GCN: 10: error: invalid operand for instruction diff --git a/llvm/test/MC/AMDGPU/gfx10_err_pos.s b/llvm/test/MC/AMDGPU/gfx10_err_pos.s index 8d0c3694b285d6..1d4e52d6c64ad5 100644 --- a/llvm/test/MC/AMDGPU/gfx10_err_pos.s +++ b/llvm/test/MC/AMDGPU/gfx10_err_pos.s @@ -992,12 +992,12 @@ s_getreg_b32 s2, hwreg(HW_REG_SHADER_CYCLES) tbuffer_store_format_xyzw v[1:4], off, ttmp[4:7] // CHECK: error: too few operands for instruction // CHECK-NEXT:{{^}}tbuffer_store_format_xyzw v[1:4], off, ttmp[4:7] -// CHECK-NEXT:{{^}} ^ +// CHECK-NEXT:{{^}}^ v_add_f32_e64 v0, v1 // CHECK: error: too few operands for instruction // CHECK-NEXT:{{^}}v_add_f32_e64 v0, v1 -// CHECK-NEXT:{{^}} ^ +// CHECK-NEXT:{{^}}^ //============================================================================== // too large value for expcnt diff --git a/llvm/test/MC/AMDGPU/round-trip.s b/llvm/test/MC/AMDGPU/round-trip.s new file mode 100644 index 00000000000000..eb355ea544e02b --- /dev/null +++ b/llvm/test/MC/AMDGPU/round-trip.s @@ -0,0 +1,13 @@ +# RUN: llvm-mc -preserve-comments -triple amdgcn-amd-amdhsa %s >%t-1.s +# RUN: llvm-mc -preserve-comments -triple amdgcn-amd-amdhsa %t-1.s >%t-2.s +# RUN: diff %t-1.s %t-2.s + +# Test that AMDGPU assembly round-trips when run through MC; the first +# transition from hand-written to "canonical" output may introduce some small +# differences, so we don't include the initial input in the comparison. + +.text + +# The AMDGPU asm parser didn't consume the end of statement +# consistently, which led to extra empty lines in the output. +s_nop 0 diff --git a/llvm/test/ThinLTO/X86/Inputs/distributed_import.ll b/llvm/test/ThinLTO/X86/Inputs/distributed_import.ll index 328603d20c46b1..d7d9bb6789af23 100644 --- a/llvm/test/ThinLTO/X86/Inputs/distributed_import.ll +++ b/llvm/test/ThinLTO/X86/Inputs/distributed_import.ll @@ -1,4 +1,5 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" @G = internal global i32 7 define i32 @g() { diff --git a/llvm/test/tools/gold/X86/Inputs/comdat.ll b/llvm/test/tools/gold/X86/Inputs/comdat.ll index e70b71815665a4..ca4bbb4bf81efd 100644 --- a/llvm/test/tools/gold/X86/Inputs/comdat.ll +++ b/llvm/test/tools/gold/X86/Inputs/comdat.ll @@ -1,4 +1,5 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" $c2 = comdat any $c1 = comdat any diff --git a/llvm/test/tools/gold/X86/Inputs/type-merge2.ll b/llvm/test/tools/gold/X86/Inputs/type-merge2.ll index 7cdea6e82f371d..7890c47a30040a 100644 --- a/llvm/test/tools/gold/X86/Inputs/type-merge2.ll +++ b/llvm/test/tools/gold/X86/Inputs/type-merge2.ll @@ -1,4 +1,5 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" %zed = type { i16 } define void @bar(%zed* %this) { diff --git a/llvm/test/tools/gold/X86/Inputs/visibility.ll b/llvm/test/tools/gold/X86/Inputs/visibility.ll index 42796a97bc8715..37442469aa7ee7 100644 --- a/llvm/test/tools/gold/X86/Inputs/visibility.ll +++ b/llvm/test/tools/gold/X86/Inputs/visibility.ll @@ -1,4 +1,5 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" define void @foo() { ret void diff --git a/llvm/test/tools/gold/X86/new-pm.ll b/llvm/test/tools/gold/X86/new-pm.ll index ee5e6ed53b135d..05c7883b1403fe 100644 --- a/llvm/test/tools/gold/X86/new-pm.ll +++ b/llvm/test/tools/gold/X86/new-pm.ll @@ -10,6 +10,12 @@ ; CHECK: Starting llvm::Module pass manager run +;; --plugin-opt=debug-pass-manager is a no-op for the legacy pass manager. +; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \ +; RUN: --plugin-opt=thinlto \ +; RUN: --plugin-opt=no-new-pass-manager --plugin-opt=debug-pass-manager \ +; RUN: -o /dev/null %t.o 2>&1 | count 0 + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp index adb77ca8219da0..b479f8922dc6d1 100644 --- a/llvm/tools/gold/gold-plugin.cpp +++ b/llvm/tools/gold/gold-plugin.cpp @@ -288,6 +288,8 @@ namespace options { cs_profile_path = std::string(opt); } else if (opt == "new-pass-manager") { new_pass_manager = true; + } else if (opt == "no-new-pass-manager") { + new_pass_manager = false; } else if (opt == "debug-pass-manager") { debug_pass_manager = true; } else if (opt == "whole-program-visibility") { diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp index 91855c30653d42..205ec1e0163856 100644 --- a/llvm/tools/obj2yaml/wasm2yaml.cpp +++ b/llvm/tools/obj2yaml/wasm2yaml.cpp @@ -70,9 +70,11 @@ WasmDumper::dumpCustomSection(const WasmSection &WasmSec) { NameEntry.Index = Name.Index; if (Name.Type == llvm::wasm::NameType::FUNCTION) { NameSec->FunctionNames.push_back(NameEntry); - } else { - assert(Name.Type == llvm::wasm::NameType::GLOBAL); + } else if (Name.Type == llvm::wasm::NameType::GLOBAL) { NameSec->GlobalNames.push_back(NameEntry); + } else { + assert(Name.Type == llvm::wasm::NameType::DATA_SEGMENT); + NameSec->DataSegmentNames.push_back(NameEntry); } } CustomSec = std::move(NameSec); diff --git a/mlir/include/mlir/Dialect/Shape/IR/Shape.h b/mlir/include/mlir/Dialect/Shape/IR/Shape.h index eab3c6f67ca083..db2862141ea915 100644 --- a/mlir/include/mlir/Dialect/Shape/IR/Shape.h +++ b/mlir/include/mlir/Dialect/Shape/IR/Shape.h @@ -31,18 +31,6 @@ namespace shape { /// Alias type for extent tensors. RankedTensorType getExtentTensorType(MLIRContext *ctx); -/// The component type corresponding to shape, element type and attribute. -class ComponentType : public Type::TypeBase { -public: - using Base::Base; -}; - -/// The element type of the shaped type. -class ElementType : public Type::TypeBase { -public: - using Base::Base; -}; - /// The shape descriptor type represents rank and dimension sizes. class ShapeType : public Type::TypeBase { public: diff --git a/mlir/include/mlir/Dialect/Shape/IR/ShapeBase.td b/mlir/include/mlir/Dialect/Shape/IR/ShapeBase.td index c9103a2b8b63e9..a7868e74c65fd7 100644 --- a/mlir/include/mlir/Dialect/Shape/IR/ShapeBase.td +++ b/mlir/include/mlir/Dialect/Shape/IR/ShapeBase.td @@ -39,29 +39,11 @@ def ShapeDialect : Dialect { let hasConstantMaterializer = 1; } -def Shape_ComponentType : DialectType()">, "component type">, - BuildableType<"$_builder.getType<::mlir::shape::ComponentType>()"> { - let typeDescription = [{ - `shape.component_type` represents the tuple of shape, element type and - attribute. - }]; -} - -def Shape_ElementType : DialectType()">, "element type">, - BuildableType<"$_builder.getType<::mlir::shape::ElementType>()"> { - let typeDescription = [{ - `shape.element_type` represents the element type of the ShapedType. It may - be unknown, error or regular element type supported by ShapedType. - }]; -} - def Shape_ShapeType : DialectType()">, "shape">, BuildableType<"$_builder.getType<::mlir::shape::ShapeType>()"> { let typeDescription = [{ - `shape.type` represents either an unranked shape, a ranked shape with + `shape.shape` represents either an unranked shape, a ranked shape with possibly unknown dimensions or an invalid shape. The rank is of type `shape.size` and, if rank is known, the extent is a 1D tensor of type `shape.size`. @@ -96,12 +78,12 @@ def Shape_ValueShapeType : DialectType())"> { let typeDescription = [{ The extent tensor is a tensor of rank one with arbitrarily many index - elements. Like `!shape.shape`, it is used to represent shapes with the - difference that it is guaranteed to be error-free. + elements (tensor). Like `!shape.shape`, it is used to represent + shapes with the difference that it is guaranteed to be error-free. }]; } diff --git a/mlir/include/mlir/Dialect/Shape/IR/ShapeOps.td b/mlir/include/mlir/Dialect/Shape/IR/ShapeOps.td index 552de7e78f9187..0cbb910e062c1a 100644 --- a/mlir/include/mlir/Dialect/Shape/IR/ShapeOps.td +++ b/mlir/include/mlir/Dialect/Shape/IR/ShapeOps.td @@ -34,7 +34,9 @@ def Shape_AddOp : Shape_Op<"add", [Commutative, NoSideEffect]> { Adds two sizes or indices. If either operand is an error it will be propagated to the result. The operands can be of type `size` or `index`. If at least one of the operands can hold an error, i.e. if it is of type `size`, - then also the result must be of type `size`. + the result must be of type `size`. If error propagation is not possible + because both operands are of type `index` then the result may be of type + `size` or `index`. }]; let arguments = (ins Shape_SizeOrIndexType:$lhs, Shape_SizeOrIndexType:$rhs); @@ -177,7 +179,7 @@ def Shape_FromExtentTensorOp : Shape_Op<"from_extent_tensor", [NoSideEffect]> { extents match the values of the elements. }]; - let arguments = (ins IndexTensor:$input); + let arguments = (ins 1DTensorOf<[Index]>:$input); let results = (outs Shape_ShapeType:$result); let assemblyFormat = "$input attr-dict `:` type($input)"; @@ -247,7 +249,7 @@ def Shape_GetExtentOp : Shape_Op<"get_extent", [NoSideEffect]> { let summary = "Gets the specified extent from a shape or extent tensor"; let description = [{ Gets the extent indexed by `dim` from the `shape` operand. If the shape is - an error then it returns an error size. + an error then it returns an invalid size. }]; let arguments = (ins Shape_ShapeOrExtentTensorType:$shape, Shape_SizeOrIndexType:$dim); @@ -289,7 +291,7 @@ def Shape_IndexToSizeOp : Shape_Op<"index_to_size", [NoSideEffect]> { } def Shape_JoinOp : Shape_Op<"join", [Commutative]> { - let summary = "Returns the least general shape.size of its operands"; + let summary = "Returns the least general shape.shape of its operands"; let description = [{ An operation that computes the least general shape of input operands. This effectively asserts that corresponding static dimensions are equal. @@ -327,9 +329,9 @@ def Shape_MulOp : Shape_Op<"mul", [Commutative, NoSideEffect]> { Multiplies two sizes or indices. If either operand is an error it will be propagated to the result. The operands can be of type `size` or `index`. If at least one of the operands can hold an error, i.e. if it is of type `size`, - then also the result must be of type `size`. If error propagation is not - possible because both operands are of type `index` then the result must also - be of type `index`. + the result must be of type `size`. If error propagation is not possible + because both operands are of type `index` then the result may be of type + `size` or `index`. }]; let arguments = (ins Shape_SizeOrIndexType:$lhs, Shape_SizeOrIndexType:$rhs); @@ -369,23 +371,22 @@ def Shape_ReduceOp : Shape_Op<"reduce", let summary = "Returns an expression reduced over a shape or extent tensor"; let description = [{ An operation that takes as input a shape or extent tensor, and a number of - initial values. This operation has a region/function that is applied - repeatedly for every extent of the input. Starting with the initial values, - the individual extents are then aggregated as defined by the associated - region. + initial values. This operation has a region that is applied repeatedly for + every extent of the input. Starting with the initial values, the individual + extents are then aggregated as defined by the associated region. Conceptually this op performs the following reduction: ``` res[] = init; for (int i = 0, i < shape.rank(); i++) { - res = fn(i, shape[i], res[0], ..., res[n]); + res = reduce(i, shape[i], res[0], ..., res[n]); } ``` - Where `fn` is provided by the user and the result of the reduce op is the - last computed output of the reduce function. As an example, computing the - number of elements can be defined as follows: + Where `reduce` represents the region attached and the result of the reduce + op is the last computed output of the reduce region. As an example, the + number of elements can be computed as follows: ```mlir func @reduce(%shape : !shape.shape, %init : !shape.size) -> !shape.size { @@ -669,13 +670,13 @@ def Shape_AssumingOp : Shape_Op<"assuming", } def Shape_AssumingYieldOp : Shape_Op<"assuming_yield", - [NoSideEffect, ReturnLike, Terminator]> { + [NoSideEffect, ReturnLike, Terminator, HasParent<"AssumingOp">]> { let summary = "Yield operation"; let description = [{ - This yield operation represents a return operation within the assert_and_exec - region. The operation takes variable number of operands and produces no - results. The operand number and types must match the return signature of - the region that contains the operation. + This yield operation represents a return operation within the + `shape.assuming` operation region. The operation takes variable number of + operands and produces no results. The operand number and types must match + the number and types of parent `shape.assuming` results. }]; let arguments = (ins Variadic:$operands); @@ -742,7 +743,7 @@ def Shape_ConstWitnessOp : Shape_Op<"const_witness", [ConstantLike, NoSideEffect ```mlir %0 = shape.const_shape [1,2,3] - %1 = shape.const_shape [1, 2, 3] + %1 = shape.const_shape [1,2,3] %w0 = shape.cstr_eq(%0, %1) // Can be folded to "const_witness true" %w1 = shape.const_witness true %w2 = shape.assuming_all(%w0, %w2) // Can be folded to "const_witness true" diff --git a/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp b/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp index 99e2e6ab07f27f..ca2d16e8de863d 100644 --- a/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp +++ b/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp @@ -43,6 +43,10 @@ Value Aliases::find(Value v) { if (!defOp) return v; + // Treat RegionBranchOpInterfaces like an allocate and don't try to follow + // the aliasing further. + if (isa(defOp)) + return v; if (isa(defOp)) return v; diff --git a/mlir/lib/Dialect/Shape/IR/Shape.cpp b/mlir/lib/Dialect/Shape/IR/Shape.cpp index 44f897cbf505b9..c71360cdaba543 100644 --- a/mlir/lib/Dialect/Shape/IR/Shape.cpp +++ b/mlir/lib/Dialect/Shape/IR/Shape.cpp @@ -31,10 +31,9 @@ RankedTensorType shape::getExtentTensorType(MLIRContext *ctx) { } static bool isErrorPropagationPossible(TypeRange operandTypes) { - for (Type ty : operandTypes) - if (ty.isa() || ty.isa() || ty.isa()) - return true; - return false; + return llvm::any_of(operandTypes, [](Type ty) { + return ty.isa(); + }); } static LogicalResult verifySizeOrIndexOp(Operation *op) { @@ -92,8 +91,7 @@ void ShapeDialect::initialize() { #define GET_OP_LIST #include "mlir/Dialect/Shape/IR/ShapeOps.cpp.inc" >(); - addTypes(); + addTypes(); addInterfaces(); // Allow unknown operations during prototyping and testing. As the dialect is // still evolving it makes it simple to start with an unregistered ops and @@ -123,10 +121,6 @@ Type ShapeDialect::parseType(DialectAsmParser &parser) const { if (parser.parseKeyword(&keyword)) return Type(); - if (keyword == "component") - return ComponentType::get(getContext()); - if (keyword == "element") - return ElementType::get(getContext()); if (keyword == "shape") return ShapeType::get(getContext()); if (keyword == "size") @@ -143,8 +137,6 @@ Type ShapeDialect::parseType(DialectAsmParser &parser) const { /// Print a type registered to this dialect. void ShapeDialect::printType(Type type, DialectAsmPrinter &os) const { TypeSwitch(type) - .Case([&](Type) { os << "component"; }) - .Case([&](Type) { os << "element"; }) .Case([&](Type) { os << "shape"; }) .Case([&](Type) { os << "size"; }) .Case([&](Type) { os << "value_shape"; }) diff --git a/openmp/runtime/src/dllexports b/openmp/runtime/src/dllexports index 6e41376a16b9dc..1c29ca90657a1c 100644 --- a/openmp/runtime/src/dllexports +++ b/openmp/runtime/src/dllexports @@ -371,6 +371,7 @@ kmpc_set_defaults 224 __kmpc_doacross_fini 264 __kmpc_taskloop 266 __kmpc_critical_with_hint 270 + __kmpc_taskloop_5 285 %endif kmpc_aligned_malloc 265 kmpc_set_disp_num_buffers 267 diff --git a/openmp/runtime/src/kmp.h b/openmp/runtime/src/kmp.h index e450b128a00597..64431a60aef302 100644 --- a/openmp/runtime/src/kmp.h +++ b/openmp/runtime/src/kmp.h @@ -3783,6 +3783,12 @@ KMP_EXPORT void __kmpc_taskloop(ident_t *loc, kmp_int32 gtid, kmp_task_t *task, kmp_uint64 *ub, kmp_int64 st, kmp_int32 nogroup, kmp_int32 sched, kmp_uint64 grainsize, void *task_dup); +KMP_EXPORT void __kmpc_taskloop_5(ident_t *loc, kmp_int32 gtid, + kmp_task_t *task, kmp_int32 if_val, + kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, + kmp_int32 nogroup, kmp_int32 sched, + kmp_uint64 grainsize, kmp_int32 modifier, + void *task_dup); KMP_EXPORT void *__kmpc_task_reduction_init(int gtid, int num_data, void *data); KMP_EXPORT void *__kmpc_taskred_init(int gtid, int num_data, void *data); KMP_EXPORT void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void *d); diff --git a/openmp/runtime/src/kmp_tasking.cpp b/openmp/runtime/src/kmp_tasking.cpp index 424576ed440f51..f95a92d872d440 100644 --- a/openmp/runtime/src/kmp_tasking.cpp +++ b/openmp/runtime/src/kmp_tasking.cpp @@ -4142,6 +4142,7 @@ class kmp_taskloop_bounds_t { // num_tasks Number of tasks to execute // grainsize Number of loop iterations per task // extras Number of chunks with grainsize+1 iterations +// last_chunk Reduction of grainsize for last task // tc Iterations count // task_dup Tasks duplication routine // codeptr_ra Return address for OMPT events @@ -4149,7 +4150,7 @@ void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, kmp_uint64 ub_glob, kmp_uint64 num_tasks, kmp_uint64 grainsize, kmp_uint64 extras, - kmp_uint64 tc, + kmp_int64 last_chunk, kmp_uint64 tc, #if OMPT_SUPPORT void *codeptr_ra, #endif @@ -4167,13 +4168,14 @@ void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task, kmp_task_t *next_task; kmp_int32 lastpriv = 0; - KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + extras); + KMP_DEBUG_ASSERT( + tc == num_tasks * grainsize + (last_chunk < 0 ? last_chunk : extras)); KMP_DEBUG_ASSERT(num_tasks > extras); KMP_DEBUG_ASSERT(num_tasks > 0); KA_TRACE(20, ("__kmp_taskloop_linear: T#%d: %lld tasks, grainsize %lld, " - "extras %lld, i=%lld,%lld(%d)%lld, dup %p\n", - gtid, num_tasks, grainsize, extras, lower, upper, ub_glob, st, - task_dup)); + "extras %lld, last_chunk %lld, i=%lld,%lld(%d)%lld, dup %p\n", + gtid, num_tasks, grainsize, extras, last_chunk, lower, upper, + ub_glob, st, task_dup)); // Launch num_tasks tasks, assign grainsize iterations each task for (i = 0; i < num_tasks; ++i) { @@ -4185,6 +4187,9 @@ void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task, --extras; // first extras iterations get bigger chunk (grainsize+1) } upper = lower + st * chunk_minus_1; + if (upper > *ub) { + upper = *ub; + } if (i == num_tasks - 1) { // schedule the last task, set lastprivate flag if needed if (st == 1) { // most common case @@ -4248,6 +4253,7 @@ typedef struct __taskloop_params { kmp_uint64 num_tasks; kmp_uint64 grainsize; kmp_uint64 extras; + kmp_int64 last_chunk; kmp_uint64 tc; kmp_uint64 num_t_min; #if OMPT_SUPPORT @@ -4257,7 +4263,8 @@ typedef struct __taskloop_params { void __kmp_taskloop_recur(ident_t *, int, kmp_task_t *, kmp_uint64 *, kmp_uint64 *, kmp_int64, kmp_uint64, kmp_uint64, - kmp_uint64, kmp_uint64, kmp_uint64, kmp_uint64, + kmp_uint64, kmp_uint64, kmp_int64, kmp_uint64, + kmp_uint64, #if OMPT_SUPPORT void *, #endif @@ -4277,6 +4284,7 @@ int __kmp_taskloop_task(int gtid, void *ptask) { kmp_uint64 num_tasks = p->num_tasks; kmp_uint64 grainsize = p->grainsize; kmp_uint64 extras = p->extras; + kmp_int64 last_chunk = p->last_chunk; kmp_uint64 tc = p->tc; kmp_uint64 num_t_min = p->num_t_min; #if OMPT_SUPPORT @@ -4285,22 +4293,23 @@ int __kmp_taskloop_task(int gtid, void *ptask) { #if KMP_DEBUG kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); KMP_DEBUG_ASSERT(task != NULL); - KA_TRACE(20, ("__kmp_taskloop_task: T#%d, task %p: %lld tasks, grainsize" - " %lld, extras %lld, i=%lld,%lld(%d), dup %p\n", - gtid, taskdata, num_tasks, grainsize, extras, *lb, *ub, st, - task_dup)); + KA_TRACE(20, + ("__kmp_taskloop_task: T#%d, task %p: %lld tasks, grainsize" + " %lld, extras %lld, last_chunk %lld, i=%lld,%lld(%d), dup %p\n", + gtid, taskdata, num_tasks, grainsize, extras, last_chunk, *lb, *ub, + st, task_dup)); #endif KMP_DEBUG_ASSERT(num_tasks * 2 + 1 > num_t_min); if (num_tasks > num_t_min) __kmp_taskloop_recur(NULL, gtid, task, lb, ub, st, ub_glob, num_tasks, - grainsize, extras, tc, num_t_min, + grainsize, extras, last_chunk, tc, num_t_min, #if OMPT_SUPPORT codeptr_ra, #endif task_dup); else __kmp_taskloop_linear(NULL, gtid, task, lb, ub, st, ub_glob, num_tasks, - grainsize, extras, tc, + grainsize, extras, last_chunk, tc, #if OMPT_SUPPORT codeptr_ra, #endif @@ -4323,6 +4332,7 @@ int __kmp_taskloop_task(int gtid, void *ptask) { // num_tasks Number of tasks to execute // grainsize Number of loop iterations per task // extras Number of chunks with grainsize+1 iterations +// last_chunk Reduction of grainsize for last task // tc Iterations count // num_t_min Threshold to launch tasks recursively // task_dup Tasks duplication routine @@ -4331,7 +4341,8 @@ void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, kmp_uint64 ub_glob, kmp_uint64 num_tasks, kmp_uint64 grainsize, kmp_uint64 extras, - kmp_uint64 tc, kmp_uint64 num_t_min, + kmp_int64 last_chunk, kmp_uint64 tc, + kmp_uint64 num_t_min, #if OMPT_SUPPORT void *codeptr_ra, #endif @@ -4339,10 +4350,11 @@ void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task, kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); KMP_DEBUG_ASSERT(task != NULL); KMP_DEBUG_ASSERT(num_tasks > num_t_min); - KA_TRACE(20, ("__kmp_taskloop_recur: T#%d, task %p: %lld tasks, grainsize" - " %lld, extras %lld, i=%lld,%lld(%d), dup %p\n", - gtid, taskdata, num_tasks, grainsize, extras, *lb, *ub, st, - task_dup)); + KA_TRACE(20, + ("__kmp_taskloop_recur: T#%d, task %p: %lld tasks, grainsize" + " %lld, extras %lld, last_chunk %lld, i=%lld,%lld(%d), dup %p\n", + gtid, taskdata, num_tasks, grainsize, extras, last_chunk, *lb, *ub, + st, task_dup)); p_task_dup_t ptask_dup = (p_task_dup_t)task_dup; kmp_uint64 lower = *lb; kmp_info_t *thread = __kmp_threads[gtid]; @@ -4353,16 +4365,23 @@ void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task, size_t upper_offset = (char *)ub - (char *)task; // remember offset of ub in the task structure - KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + extras); + KMP_DEBUG_ASSERT( + tc == num_tasks * grainsize + (last_chunk < 0 ? last_chunk : extras)); KMP_DEBUG_ASSERT(num_tasks > extras); KMP_DEBUG_ASSERT(num_tasks > 0); // split the loop in two halves kmp_uint64 lb1, ub0, tc0, tc1, ext0, ext1; + kmp_int64 last_chunk0 = 0, last_chunk1 = 0; kmp_uint64 gr_size0 = grainsize; kmp_uint64 n_tsk0 = num_tasks >> 1; // num_tasks/2 to execute kmp_uint64 n_tsk1 = num_tasks - n_tsk0; // to schedule as a task - if (n_tsk0 <= extras) { + if (last_chunk < 0) { + ext0 = ext1 = 0; + last_chunk1 = last_chunk; + tc0 = grainsize * n_tsk0; + tc1 = tc - tc0; + } else if (n_tsk0 <= extras) { gr_size0++; // integrate extras into grainsize ext0 = 0; // no extra iters in 1st half ext1 = extras - n_tsk0; // remaining extras @@ -4404,6 +4423,7 @@ void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task, p->num_tasks = n_tsk1; p->grainsize = grainsize; p->extras = ext1; + p->last_chunk = last_chunk1; p->tc = tc1; p->num_t_min = num_t_min; #if OMPT_SUPPORT @@ -4420,44 +4440,28 @@ void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task, // execute the 1st half of current subrange if (n_tsk0 > num_t_min) __kmp_taskloop_recur(loc, gtid, task, lb, ub, st, ub_glob, n_tsk0, gr_size0, - ext0, tc0, num_t_min, + ext0, last_chunk0, tc0, num_t_min, #if OMPT_SUPPORT codeptr_ra, #endif task_dup); else __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, n_tsk0, - gr_size0, ext0, tc0, + gr_size0, ext0, last_chunk0, tc0, #if OMPT_SUPPORT codeptr_ra, #endif task_dup); - KA_TRACE(40, ("__kmpc_taskloop_recur(exit): T#%d\n", gtid)); + KA_TRACE(40, ("__kmp_taskloop_recur(exit): T#%d\n", gtid)); } -/*! -@ingroup TASKING -@param loc Source location information -@param gtid Global thread ID -@param task Task structure -@param if_val Value of the if clause -@param lb Pointer to loop lower bound in task structure -@param ub Pointer to loop upper bound in task structure -@param st Loop stride -@param nogroup Flag, 1 if no taskgroup needs to be added, 0 otherwise -@param sched Schedule specified 0/1/2 for none/grainsize/num_tasks -@param grainsize Schedule value if specified -@param task_dup Tasks duplication routine - -Execute the taskloop construct. -*/ -void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, - kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, - int sched, kmp_uint64 grainsize, void *task_dup) { +static void __kmp_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, + kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, + int nogroup, int sched, kmp_uint64 grainsize, + int modifier, void *task_dup) { kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); KMP_DEBUG_ASSERT(task != NULL); - __kmp_assert_valid_gtid(gtid); if (nogroup == 0) { #if OMPT_SUPPORT && OMPT_OPTIONAL OMPT_STORE_RETURN_ADDRESS(gtid); @@ -4474,13 +4478,16 @@ void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, kmp_uint64 upper = task_bounds.get_ub(); kmp_uint64 ub_glob = upper; // global upper used to calc lastprivate flag kmp_uint64 num_tasks = 0, extras = 0; + kmp_int64 last_chunk = + 0; // reduce grainsize of last task by last_chunk in strict mode kmp_uint64 num_tasks_min = __kmp_taskloop_min_tasks; kmp_info_t *thread = __kmp_threads[gtid]; kmp_taskdata_t *current_task = thread->th.th_current_task; - KA_TRACE(20, ("__kmpc_taskloop: T#%d, task %p, lb %lld, ub %lld, st %lld, " - "grain %llu(%d), dup %p\n", - gtid, taskdata, lower, upper, st, grainsize, sched, task_dup)); + KA_TRACE(20, ("__kmp_taskloop: T#%d, task %p, lb %lld, ub %lld, st %lld, " + "grain %llu(%d, %d), dup %p\n", + gtid, taskdata, lower, upper, st, grainsize, sched, modifier, + task_dup)); // compute trip count if (st == 1) { // most common case @@ -4491,7 +4498,7 @@ void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, tc = (upper - lower) / st + 1; } if (tc == 0) { - KA_TRACE(20, ("__kmpc_taskloop(exit): T#%d zero-trip loop\n", gtid)); + KA_TRACE(20, ("__kmp_taskloop(exit): T#%d zero-trip loop\n", gtid)); // free the pattern task and exit __kmp_task_start(gtid, task, current_task); // do not execute anything for zero-trip loop @@ -4533,20 +4540,28 @@ void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, break; case 1: // grainsize provided if (grainsize > tc) { - num_tasks = 1; // too big grainsize requested, adjust values - grainsize = tc; + num_tasks = 1; + grainsize = tc; // too big grainsize requested, adjust values extras = 0; } else { - num_tasks = tc / grainsize; - // adjust grainsize for balanced distribution of iterations - grainsize = tc / num_tasks; - extras = tc % num_tasks; + if (modifier) { + num_tasks = (tc + grainsize - 1) / grainsize; + last_chunk = tc - (num_tasks * grainsize); + extras = 0; + } else { + num_tasks = tc / grainsize; + // adjust grainsize for balanced distribution of iterations + grainsize = tc / num_tasks; + extras = tc % num_tasks; + } } break; default: KMP_ASSERT2(0, "unknown scheduling of taskloop"); } - KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + extras); + + KMP_DEBUG_ASSERT( + tc == num_tasks * grainsize + (last_chunk < 0 ? last_chunk : extras)); KMP_DEBUG_ASSERT(num_tasks > extras); KMP_DEBUG_ASSERT(num_tasks > 0); // ========================================================================= @@ -4558,7 +4573,7 @@ void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, taskdata->td_flags.tiedness = TASK_TIED; // AC: serial task cannot be untied // always start serial tasks linearly __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, num_tasks, - grainsize, extras, tc, + grainsize, extras, last_chunk, tc, #if OMPT_SUPPORT OMPT_GET_RETURN_ADDRESS(0), #endif @@ -4566,21 +4581,23 @@ void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, // !taskdata->td_flags.native => currently force linear spawning of tasks // for GOMP_taskloop } else if (num_tasks > num_tasks_min && !taskdata->td_flags.native) { - KA_TRACE(20, ("__kmpc_taskloop: T#%d, go recursive: tc %llu, #tasks %llu" - "(%lld), grain %llu, extras %llu\n", - gtid, tc, num_tasks, num_tasks_min, grainsize, extras)); + KA_TRACE(20, ("__kmp_taskloop: T#%d, go recursive: tc %llu, #tasks %llu" + "(%lld), grain %llu, extras %llu, last_chunk %lld\n", + gtid, tc, num_tasks, num_tasks_min, grainsize, extras, + last_chunk)); __kmp_taskloop_recur(loc, gtid, task, lb, ub, st, ub_glob, num_tasks, - grainsize, extras, tc, num_tasks_min, + grainsize, extras, last_chunk, tc, num_tasks_min, #if OMPT_SUPPORT OMPT_GET_RETURN_ADDRESS(0), #endif task_dup); } else { - KA_TRACE(20, ("__kmpc_taskloop: T#%d, go linear: tc %llu, #tasks %llu" - "(%lld), grain %llu, extras %llu\n", - gtid, tc, num_tasks, num_tasks_min, grainsize, extras)); + KA_TRACE(20, ("__kmp_taskloop: T#%d, go linear: tc %llu, #tasks %llu" + "(%lld), grain %llu, extras %llu, last_chunk %lld\n", + gtid, tc, num_tasks, num_tasks_min, grainsize, extras, + last_chunk)); __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, num_tasks, - grainsize, extras, tc, + grainsize, extras, last_chunk, tc, #if OMPT_SUPPORT OMPT_GET_RETURN_ADDRESS(0), #endif @@ -4601,5 +4618,59 @@ void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, #endif __kmpc_end_taskgroup(loc, gtid); } + KA_TRACE(20, ("__kmp_taskloop(exit): T#%d\n", gtid)); +} + +/*! +@ingroup TASKING +@param loc Source location information +@param gtid Global thread ID +@param task Task structure +@param if_val Value of the if clause +@param lb Pointer to loop lower bound in task structure +@param ub Pointer to loop upper bound in task structure +@param st Loop stride +@param nogroup Flag, 1 if nogroup clause specified, 0 otherwise +@param sched Schedule specified 0/1/2 for none/grainsize/num_tasks +@param grainsize Schedule value if specified +@param task_dup Tasks duplication routine + +Execute the taskloop construct. +*/ +void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, + kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, + int sched, kmp_uint64 grainsize, void *task_dup) { + __kmp_assert_valid_gtid(gtid); + KA_TRACE(20, ("__kmpc_taskloop(enter): T#%d\n", gtid)); + __kmp_taskloop(loc, gtid, task, if_val, lb, ub, st, nogroup, sched, grainsize, + 0, task_dup); KA_TRACE(20, ("__kmpc_taskloop(exit): T#%d\n", gtid)); } + +/*! +@ingroup TASKING +@param loc Source location information +@param gtid Global thread ID +@param task Task structure +@param if_val Value of the if clause +@param lb Pointer to loop lower bound in task structure +@param ub Pointer to loop upper bound in task structure +@param st Loop stride +@param nogroup Flag, 1 if nogroup clause specified, 0 otherwise +@param sched Schedule specified 0/1/2 for none/grainsize/num_tasks +@param grainsize Schedule value if specified +@param modifer Modifier 'strict' for sched, 1 if present, 0 otherwise +@param task_dup Tasks duplication routine + +Execute the taskloop construct. +*/ +void __kmpc_taskloop_5(ident_t *loc, int gtid, kmp_task_t *task, int if_val, + kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, + int nogroup, int sched, kmp_uint64 grainsize, + int modifier, void *task_dup) { + __kmp_assert_valid_gtid(gtid); + KA_TRACE(20, ("__kmpc_taskloop_5(enter): T#%d\n", gtid)); + __kmp_taskloop(loc, gtid, task, if_val, lb, ub, st, nogroup, sched, grainsize, + modifier, task_dup); + KA_TRACE(20, ("__kmpc_taskloop_5(exit): T#%d\n", gtid)); +} diff --git a/openmp/runtime/test/tasking/kmp_taskloop_5.c b/openmp/runtime/test/tasking/kmp_taskloop_5.c new file mode 100644 index 00000000000000..aca0e7565213e9 --- /dev/null +++ b/openmp/runtime/test/tasking/kmp_taskloop_5.c @@ -0,0 +1,167 @@ +// RUN: %libomp-compile-and-run +// RUN: %libomp-compile && env KMP_TASKLOOP_MIN_TASKS=1 %libomp-run + +#include +#include +#include "omp_my_sleep.h" + +#define N 4 +#define ST 3 +#define UB 118 +#define LB 0 + +// globals +int counter; +int task_count; + +// Compiler-generated code (emulation) +typedef struct ident { + void* dummy; +} ident_t; + +typedef struct shar { + int *pcounter; + int *pj; + int *ptask_count; +} *pshareds; + +typedef struct task { + pshareds shareds; + int(* routine)(int,struct task*); + int part_id; + unsigned long long lb; // library always uses ULONG + unsigned long long ub; + int st; + int last; + int i; + int j; + int th; +} *ptask, kmp_task_t; + +typedef int(* task_entry_t)( int, ptask ); + +void +__task_dup_entry(ptask task_dst, ptask task_src, int lastpriv) +{ +// setup lastprivate flag + task_dst->last = lastpriv; +// could be constructor calls here... +} + +// OpenMP RTL interfaces +typedef unsigned long long kmp_uint64; +typedef long long kmp_int64; + +#ifdef __cplusplus +extern "C" { +#endif +void +__kmpc_taskloop_5(ident_t *loc, int gtid, kmp_task_t *task, int if_val, + kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, + int nogroup, int sched, kmp_int64 grainsize, int modifier, + void *task_dup); +ptask +__kmpc_omp_task_alloc(ident_t *loc, int gtid, int flags, + size_t sizeof_kmp_task_t, size_t sizeof_shareds, + task_entry_t task_entry); +void __kmpc_atomic_fixed4_add(void *id_ref, int gtid, int * lhs, int rhs); +int __kmpc_global_thread_num(void *id_ref); +#ifdef __cplusplus +} +#endif + +// User's code +int task_entry(int gtid, ptask task) +{ + pshareds pshar = task->shareds; + __kmpc_atomic_fixed4_add(NULL, gtid, pshar->ptask_count, 1); + + for (task->i = task->lb; task->i <= (int)task->ub; task->i += task->st) { + task->th = omp_get_thread_num(); + __kmpc_atomic_fixed4_add(NULL,gtid,pshar->pcounter,1); + task->j = task->i; + } + my_sleep( 0.1 ); // sleep 100 ms in order to allow other threads to steal tasks + if (task->last) { + *(pshar->pj) = task->j; // lastprivate + } + return 0; +} + +void task_loop(int sched_type, int sched_val, int modifier) +{ + int i, j, gtid = __kmpc_global_thread_num(NULL); + ptask task; + pshareds psh; + omp_set_dynamic(0); + counter = 0; + task_count = 0; + #pragma omp parallel num_threads(N) + { + #pragma omp master + { + int gtid = __kmpc_global_thread_num(NULL); + task = __kmpc_omp_task_alloc(NULL, gtid, 1, sizeof(struct task), + sizeof(struct shar), &task_entry); + psh = task->shareds; + psh->pcounter = &counter; + psh->ptask_count = &task_count; + psh->pj = &j; + task->lb = LB; + task->ub = UB; + task->st = ST; + + __kmpc_taskloop_5( + NULL, // location + gtid, // gtid + task, // task structure + 1, // if clause value + &task->lb, // lower bound + &task->ub, // upper bound + ST, // loop increment + 0, // 1 if nogroup specified + sched_type, // schedule type: 0-none, 1-grainsize, 2-num_tasks + sched_val, // schedule value (ignored for type 0) + modifier, // strict modifier + (void*)&__task_dup_entry // tasks duplication routine + ); + } // end master + } // end parallel +// check results + int tc; + if (ST == 1) { // most common case + tc = UB - LB + 1; + } else if (ST < 0) { + tc = (LB - UB) / (-ST) + 1; + } else { // ST > 0 + tc = (UB - LB) / ST + 1; + } + int count; + if (sched_type == 1) { + count = (sched_val > tc) ? 1 : (tc + sched_val - 1) / sched_val; + } else { + count = (sched_val > tc) ? tc : sched_val; + } + if (j != LB + (tc - 1) * ST) { + printf("Error in lastprivate, %d != %d\n", j, LB + (tc - 1) * ST); + exit(1); + } + if (counter != tc) { + printf("Error, counter %d != %d\n", counter, tc); + exit(1); + } + if (task_count != count) { + printf("Error, task count %d != %d\n", task_count, count); + exit(1); + } +} + +int main(int argc, char *argv[]) { + task_loop(1, 6, 1); // create 7 tasks + task_loop(2, 6, 1); // create 6 tasks + task_loop(1, 50, 1); // create 1 task + task_loop(2, 50, 1); // create 40 tasks + + printf("Test passed\n"); + return 0; +}