aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-12-17 20:41:09 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-12-17 20:41:09 +0000
commit312c0ed19cc5276a17bacf2120097bec4515b0f1 (patch)
treee6e4a4163840b73ba54bb0d3b70ee4899e4b7434
parentb1c73532ee8997fe5dfbeb7d223027bdf99758a0 (diff)
Vendor import of llvm-project main llvmorg-18-init-15088-gd14ee76181fb.vendor/llvm-project/llvmorg-18-init-15088-gd14ee76181fb
-rw-r--r--clang/include/clang-c/BuildSystem.h6
-rw-r--r--clang/include/clang/AST/Type.h3
-rw-r--r--clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def1
-rw-r--r--clang/include/clang/Basic/Attr.td22
-rw-r--r--clang/include/clang/Basic/AttrDocs.td73
-rw-r--r--clang/include/clang/Basic/BuiltinsAMDGPU.def18
-rw-r--r--clang/include/clang/Basic/BuiltinsNVPTX.def13
-rw-r--r--clang/include/clang/Basic/BuiltinsSystemZ.def26
-rw-r--r--clang/include/clang/Basic/BuiltinsX86.def30
-rw-r--r--clang/include/clang/Basic/Cuda.h7
-rw-r--r--clang/include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--clang/include/clang/Basic/DiagnosticLexKinds.td3
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--clang/include/clang/Basic/FPOptions.def1
-rw-r--r--clang/include/clang/Basic/Features.def2
-rw-r--r--clang/include/clang/Basic/IdentifierTable.h2
-rw-r--r--clang/include/clang/Basic/LangOptions.def2
-rw-r--r--clang/include/clang/Basic/LangOptions.h3
-rw-r--r--clang/include/clang/Basic/TargetBuiltins.h2
-rw-r--r--clang/include/clang/Basic/TargetInfo.h3
-rw-r--r--clang/include/clang/Basic/TokenKinds.def5
-rw-r--r--clang/include/clang/Basic/arm_sve.td78
-rw-r--r--clang/include/clang/Basic/arm_sve_sme_incl.td2
-rw-r--r--clang/include/clang/Driver/Options.td42
-rw-r--r--clang/include/clang/Parse/Parser.h4
-rw-r--r--clang/include/clang/Sema/Sema.h10
-rw-r--r--clang/include/clang/Serialization/ASTReader.h13
-rw-r--r--clang/include/clang/StaticAnalyzer/Checkers/Checkers.td17
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h4
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h4
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h53
-rw-r--r--clang/lib/APINotes/APINotesManager.cpp2
-rw-r--r--clang/lib/APINotes/APINotesYAMLCompiler.cpp2
-rw-r--r--clang/lib/ARCMigrate/ARCMT.cpp2
-rw-r--r--clang/lib/ARCMigrate/ObjCMT.cpp14
-rw-r--r--clang/lib/ARCMigrate/TransUnbridgedCasts.cpp2
-rw-r--r--clang/lib/ARCMigrate/TransformActions.cpp2
-rw-r--r--clang/lib/ARCMigrate/Transforms.cpp2
-rw-r--r--clang/lib/AST/ASTContext.cpp4
-rw-r--r--clang/lib/AST/Decl.cpp1
-rw-r--r--clang/lib/AST/DeclPrinter.cpp2
-rw-r--r--clang/lib/AST/ExprConstant.cpp14
-rw-r--r--clang/lib/AST/Interp/ByteCodeEmitter.cpp5
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.cpp256
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.h9
-rw-r--r--clang/lib/AST/Interp/Context.cpp5
-rw-r--r--clang/lib/AST/Interp/EvalEmitter.cpp21
-rw-r--r--clang/lib/AST/Interp/IntegralAP.h12
-rw-r--r--clang/lib/AST/Interp/Interp.cpp19
-rw-r--r--clang/lib/AST/Interp/Interp.h12
-rw-r--r--clang/lib/AST/Interp/InterpBuiltin.cpp67
-rw-r--r--clang/lib/AST/Interp/InterpFrame.cpp4
-rw-r--r--clang/lib/AST/Mangle.cpp2
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp10
-rw-r--r--clang/lib/AST/PrintfFormatString.cpp2
-rw-r--r--clang/lib/AST/RawCommentList.cpp4
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp4
-rw-r--r--clang/lib/AST/Stmt.cpp7
-rw-r--r--clang/lib/ASTMatchers/ASTMatchersInternal.cpp12
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Parser.cpp6
-rw-r--r--clang/lib/Analysis/BodyFarm.cpp4
-rw-r--r--clang/lib/Analysis/CallGraph.cpp2
-rw-r--r--clang/lib/Analysis/CalledOnceCheck.cpp2
-rw-r--r--clang/lib/Analysis/CocoaConventions.cpp11
-rw-r--r--clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp2
-rw-r--r--clang/lib/Analysis/RetainSummaryManager.cpp14
-rw-r--r--clang/lib/Analysis/UnsafeBufferUsage.cpp101
-rw-r--r--clang/lib/Basic/Attributes.cpp6
-rw-r--r--clang/lib/Basic/Cuda.cpp5
-rw-r--r--clang/lib/Basic/DiagnosticIDs.cpp2
-rw-r--r--clang/lib/Basic/IdentifierTable.cpp4
-rw-r--r--clang/lib/Basic/Module.cpp5
-rw-r--r--clang/lib/Basic/Sarif.cpp2
-rw-r--r--clang/lib/Basic/TargetInfo.cpp10
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp19
-rw-r--r--clang/lib/Basic/Targets/AMDGPU.cpp87
-rw-r--r--clang/lib/Basic/Targets/AMDGPU.h19
-rw-r--r--clang/lib/Basic/Targets/Mips.cpp2
-rw-r--r--clang/lib/Basic/Targets/NVPTX.cpp5
-rw-r--r--clang/lib/Basic/Targets/RISCV.cpp34
-rw-r--r--clang/lib/Basic/Warnings.cpp8
-rw-r--r--clang/lib/CodeGen/BackendUtil.cpp13
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp13
-rw-r--r--clang/lib/CodeGen/CGCUDANV.cpp88
-rw-r--r--clang/lib/CodeGen/CGCall.cpp2
-rw-r--r--clang/lib/CodeGen/CGCall.h11
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.cpp17
-rw-r--r--clang/lib/CodeGen/CGException.cpp6
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp4
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp166
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.cpp9
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.h2
-rw-r--r--clang/lib/CodeGen/CGObjCMac.cpp4
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp1
-rw-r--r--clang/lib/CodeGen/CGRecordLayoutBuilder.cpp2
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp2
-rw-r--r--clang/lib/CodeGen/CodeGenAction.cpp2
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp16
-rw-r--r--clang/lib/CodeGen/CoverageMappingGen.cpp4
-rw-r--r--clang/lib/CodeGen/Targets/SPIR.cpp6
-rw-r--r--clang/lib/CrossTU/CrossTranslationUnit.cpp2
-rw-r--r--clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp2
-rw-r--r--clang/lib/Driver/Distro.cpp12
-rw-r--r--clang/lib/Driver/Driver.cpp24
-rw-r--r--clang/lib/Driver/Job.cpp8
-rw-r--r--clang/lib/Driver/ToolChain.cpp4
-rw-r--r--clang/lib/Driver/ToolChains/AIX.cpp6
-rw-r--r--clang/lib/Driver/ToolChains/AMDGPU.cpp18
-rw-r--r--clang/lib/Driver/ToolChains/Arch/AArch64.cpp4
-rw-r--r--clang/lib/Driver/ToolChains/Arch/ARM.cpp18
-rw-r--r--clang/lib/Driver/ToolChains/Arch/RISCV.cpp9
-rw-r--r--clang/lib/Driver/ToolChains/Arch/X86.cpp10
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp173
-rw-r--r--clang/lib/Driver/ToolChains/CommonArgs.cpp145
-rw-r--r--clang/lib/Driver/ToolChains/Cuda.cpp8
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.cpp33
-rw-r--r--clang/lib/Driver/ToolChains/Flang.cpp16
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.cpp6
-rw-r--r--clang/lib/Driver/ToolChains/Hexagon.cpp8
-rw-r--r--clang/lib/Driver/ToolChains/Hurd.cpp4
-rw-r--r--clang/lib/Driver/ToolChains/MSP430.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/MSVC.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/MinGW.cpp6
-rw-r--r--clang/lib/Driver/ToolChains/PPCLinux.cpp4
-rw-r--r--clang/lib/Driver/ToolChains/Solaris.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/WebAssembly.cpp6
-rw-r--r--clang/lib/Edit/Commit.cpp2
-rw-r--r--clang/lib/Edit/RewriteObjCFoundationAPI.cpp6
-rw-r--r--clang/lib/ExtractAPI/ExtractAPIConsumer.cpp4
-rw-r--r--clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp2
-rw-r--r--clang/lib/Format/BreakableToken.cpp44
-rw-r--r--clang/lib/Format/ContinuationIndenter.cpp33
-rw-r--r--clang/lib/Format/Format.cpp26
-rw-r--r--clang/lib/Format/FormatToken.h10
-rw-r--r--clang/lib/Format/FormatTokenLexer.cpp8
-rw-r--r--clang/lib/Format/SortJavaScriptImports.cpp4
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp24
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp10
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp16
-rw-r--r--clang/lib/Frontend/DependencyGraph.cpp2
-rw-r--r--clang/lib/Frontend/Rewrite/InclusionRewriter.cpp2
-rw-r--r--clang/lib/Frontend/VerifyDiagnosticConsumer.cpp21
-rw-r--r--clang/lib/Headers/avx512bwintrin.h79
-rw-r--r--clang/lib/Headers/vecintrin.h43
-rw-r--r--clang/lib/Index/IndexSymbol.cpp2
-rw-r--r--clang/lib/IndexSerialization/SerializablePathCollection.cpp4
-rw-r--r--clang/lib/Lex/HeaderMap.cpp5
-rw-r--r--clang/lib/Lex/HeaderSearch.cpp32
-rw-r--r--clang/lib/Lex/InitHeaderSearch.cpp4
-rw-r--r--clang/lib/Lex/Lexer.cpp4
-rw-r--r--clang/lib/Lex/ModuleMap.cpp14
-rw-r--r--clang/lib/Lex/PPDirectives.cpp12
-rw-r--r--clang/lib/Lex/PPExpressions.cpp2
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp11
-rw-r--r--clang/lib/Parse/ParseDecl.cpp4
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp195
-rw-r--r--clang/lib/Parse/ParsePragma.cpp40
-rw-r--r--clang/lib/Parse/ParseStmt.cpp11
-rw-r--r--clang/lib/Parse/Parser.cpp5
-rw-r--r--clang/lib/Rewrite/Rewriter.cpp4
-rw-r--r--clang/lib/Sema/CodeCompleteConsumer.cpp11
-rw-r--r--clang/lib/Sema/HLSLExternalSemaSource.cpp25
-rw-r--r--clang/lib/Sema/Sema.cpp3
-rw-r--r--clang/lib/Sema/SemaAttr.cpp8
-rw-r--r--clang/lib/Sema/SemaChecking.cpp71
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp6
-rw-r--r--clang/lib/Sema/SemaDecl.cpp6
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp28
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp71
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp2
-rw-r--r--clang/lib/Sema/SemaExpr.cpp14
-rw-r--r--clang/lib/Sema/SemaInit.cpp183
-rw-r--r--clang/lib/Sema/SemaLambda.cpp3
-rw-r--r--clang/lib/Sema/SemaModule.cpp2
-rw-r--r--clang/lib/Sema/SemaRISCVVectorLookup.cpp18
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp30
-rw-r--r--clang/lib/Sema/SemaType.cpp17
-rw-r--r--clang/lib/Sema/TreeTransform.h2
-rw-r--r--clang/lib/Serialization/ASTReader.cpp38
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp21
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp106
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp156
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp36
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp10
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporter.cpp33
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugSuppression.cpp169
-rw-r--r--clang/lib/StaticAnalyzer/Core/CallEvent.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/CheckerContext.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp4
-rw-r--r--clang/lib/Support/RISCVVIntrinsicUtils.cpp2
-rw-r--r--clang/lib/Tooling/ASTDiff/ASTDiff.cpp2
-rw-r--r--clang/lib/Tooling/ArgumentsAdjusters.cpp14
-rw-r--r--clang/lib/Tooling/CompilationDatabase.cpp2
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp4
-rw-r--r--clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp6
-rw-r--r--clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp6
-rw-r--r--clang/lib/Tooling/Inclusions/HeaderIncludes.cpp18
-rw-r--r--clang/lib/Tooling/Refactoring/AtomicChange.cpp2
-rw-r--r--clang/lib/Tooling/Refactoring/Lookup.cpp14
-rw-r--r--clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp8
-rw-r--r--clang/lib/Tooling/Tooling.cpp8
-rw-r--r--clang/lib/Tooling/Transformer/SourceCode.cpp2
-rw-r--r--clang/tools/clang-repl/ClangRepl.cpp2
-rw-r--r--clang/tools/driver/driver.cpp4
-rw-r--r--clang/utils/TableGen/ASTTableGen.cpp2
-rw-r--r--clang/utils/TableGen/MveEmitter.cpp8
-rw-r--r--clang/utils/TableGen/NeonEmitter.cpp51
-rw-r--r--clang/utils/TableGen/SveEmitter.cpp13
-rw-r--r--clang/utils/TableGen/TableGen.cpp6
-rw-r--r--clang/utils/TableGen/TableGenBackends.h1
-rw-r--r--compiler-rt/include/profile/InstrProfData.inc17
-rw-r--r--compiler-rt/include/sanitizer/hwasan_interface.h4
-rw-r--r--compiler-rt/lib/asan/asan_fuchsia.cpp2
-rw-r--r--compiler-rt/lib/asan/asan_internal.h1
-rw-r--r--compiler-rt/lib/asan/asan_posix.cpp24
-rw-r--r--compiler-rt/lib/asan/asan_rtl.cpp51
-rw-r--r--compiler-rt/lib/asan/asan_win.cpp2
-rw-r--r--compiler-rt/lib/hwasan/hwasan.cpp2
-rw-r--r--compiler-rt/lib/hwasan/hwasan.h6
-rw-r--r--compiler-rt/lib/hwasan/hwasan_interface_internal.h3
-rw-r--r--compiler-rt/lib/hwasan/hwasan_linux.cpp16
-rw-r--r--compiler-rt/lib/hwasan/hwasan_thread.cpp1
-rw-r--r--compiler-rt/lib/lsan/lsan.cpp1
-rw-r--r--compiler-rt/lib/lsan/lsan.h1
-rw-r--r--compiler-rt/lib/lsan/lsan_common.cpp3
-rw-r--r--compiler-rt/lib/lsan/lsan_common.h4
-rw-r--r--compiler-rt/lib/lsan/lsan_fuchsia.cpp1
-rw-r--r--compiler-rt/lib/lsan/lsan_posix.cpp28
-rw-r--r--compiler-rt/lib/msan/msan.cpp1
-rw-r--r--compiler-rt/lib/msan/msan.h2
-rw-r--r--compiler-rt/lib/msan/msan_allocator.cpp4
-rw-r--r--compiler-rt/lib/msan/msan_allocator.h3
-rw-r--r--compiler-rt/lib/msan/msan_interceptors.cpp19
-rw-r--r--compiler-rt/lib/msan/msan_linux.cpp52
-rw-r--r--compiler-rt/lib/profile/InstrProfiling.h6
-rw-r--r--compiler-rt/lib/profile/InstrProfilingBuffer.c4
-rw-r--r--compiler-rt/lib/profile/InstrProfilingFile.c1
-rw-r--r--compiler-rt/lib/profile/InstrProfilingPlatformWindows.c3
-rw-r--r--compiler-rt/lib/scudo/standalone/common.h15
-rw-r--r--compiler-rt/lib/scudo/standalone/flags_parser.cpp18
-rw-r--r--compiler-rt/lib/scudo/standalone/primary32.h8
-rw-r--r--compiler-rt/lib/scudo/standalone/primary64.h8
-rw-r--r--compiler-rt/lib/scudo/standalone/secondary.h14
-rw-r--r--libcxx/include/__algorithm/find.h31
-rw-r--r--libcxx/include/__algorithm/find_segment_if.h62
-rw-r--r--libcxx/include/__chrono/day.h2
-rw-r--r--libcxx/include/__chrono/hh_mm_ss.h8
-rw-r--r--libcxx/include/__chrono/month.h2
-rw-r--r--libcxx/include/__chrono/monthday.h10
-rw-r--r--libcxx/include/__chrono/weekday.h8
-rw-r--r--libcxx/include/__chrono/year_month.h44
-rw-r--r--libcxx/include/__chrono/year_month_day.h2
-rw-r--r--libcxx/include/__mdspan/mdspan.h11
-rw-r--r--libcxx/include/__ranges/join_view.h138
-rw-r--r--libcxx/include/__ranges/lazy_split_view.h2
-rw-r--r--libcxx/include/__ranges/split_view.h2
-rw-r--r--libcxx/include/__ranges/take_view.h5
-rw-r--r--libcxx/include/__utility/as_lvalue.h37
-rw-r--r--libcxx/include/__variant/monostate.h14
-rw-r--r--libcxx/include/any4
-rw-r--r--libcxx/include/array5
-rw-r--r--libcxx/include/cmath6
-rw-r--r--libcxx/include/complex12
-rw-r--r--libcxx/include/cstddef14
-rw-r--r--libcxx/include/deque32
-rw-r--r--libcxx/include/mdspan7
-rw-r--r--libcxx/include/module.modulemap.in2
-rw-r--r--libcxx/include/regex8
-rw-r--r--libcxx/include/string283
-rw-r--r--libcxx/include/typeindex2
-rw-r--r--libcxx/include/utility1
-rw-r--r--libcxx/include/vector14
-rw-r--r--libcxx/modules/std.compat.cppm.in208
-rw-r--r--libcxx/modules/std.compat/cassert.inc12
-rw-r--r--libcxx/modules/std.compat/cctype.inc25
-rw-r--r--libcxx/modules/std.compat/cerrno.inc12
-rw-r--r--libcxx/modules/std.compat/cfenv.inc29
-rw-r--r--libcxx/modules/std.compat/cfloat.inc12
-rw-r--r--libcxx/modules/std.compat/cinttypes.inc25
-rw-r--r--libcxx/modules/std.compat/climits.inc12
-rw-r--r--libcxx/modules/std.compat/clocale.inc17
-rw-r--r--libcxx/modules/std.compat/cmath.inc268
-rw-r--r--libcxx/modules/std.compat/csetjmp.inc13
-rw-r--r--libcxx/modules/std.compat/csignal.inc17
-rw-r--r--libcxx/modules/std.compat/cstdarg.inc10
-rw-r--r--libcxx/modules/std.compat/cstddef.inc22
-rw-r--r--libcxx/modules/std.compat/cstdint.inc50
-rw-r--r--libcxx/modules/std.compat/cstdio.inc61
-rw-r--r--libcxx/modules/std.compat/cstdlib.inc72
-rw-r--r--libcxx/modules/std.compat/cstring.inc36
-rw-r--r--libcxx/modules/std.compat/ctime.inc28
-rw-r--r--libcxx/modules/std.compat/cuchar.inc28
-rw-r--r--libcxx/modules/std.compat/cwchar.inc80
-rw-r--r--libcxx/modules/std.compat/cwctype.inc35
-rw-r--r--libcxx/modules/std.cppm.in46
-rw-r--r--libcxx/modules/std/ranges.inc2
-rw-r--r--libcxx/modules/std/string.inc7
-rw-r--r--lld/COFF/Config.h4
-rw-r--r--lld/COFF/Driver.cpp118
-rw-r--r--lld/COFF/InputFiles.cpp4
-rw-r--r--lld/COFF/PDB.cpp2
-rw-r--r--lld/COFF/Symbols.h7
-rw-r--r--lld/COFF/Writer.cpp9
-rw-r--r--lld/ELF/Arch/ARM.cpp8
-rw-r--r--lld/ELF/Relocations.cpp4
-rw-r--r--lld/MachO/InputFiles.cpp2
-rw-r--r--lld/docs/WebAssembly.rst6
-rw-r--r--lld/docs/windows_support.rst11
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h3
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h3
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h3
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointResolverName.h3
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h3
-rw-r--r--lldb/include/lldb/Core/Module.h77
-rw-r--r--lldb/include/lldb/Core/ModuleList.h24
-rw-r--r--lldb/include/lldb/Core/ValueObject.h4
-rw-r--r--lldb/include/lldb/Host/Editline.h2
-rw-r--r--lldb/include/lldb/Interpreter/CommandCompletions.h3
-rw-r--r--lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h1
-rw-r--r--lldb/include/lldb/Symbol/CompilerDecl.h7
-rw-r--r--lldb/include/lldb/Symbol/CompilerDeclContext.h8
-rw-r--r--lldb/include/lldb/Symbol/CompilerType.h54
-rw-r--r--lldb/include/lldb/Symbol/SymbolFile.h29
-rw-r--r--lldb/include/lldb/Symbol/SymbolFileOnDemand.h13
-rw-r--r--lldb/include/lldb/Symbol/Type.h305
-rw-r--r--lldb/include/lldb/Symbol/TypeMap.h6
-rw-r--r--lldb/include/lldb/Symbol/TypeSystem.h24
-rw-r--r--lldb/include/lldb/Utility/CompletionRequest.h2
-rw-r--r--lldb/include/lldb/lldb-enumerations.h62
-rw-r--r--lldb/include/lldb/lldb-forward.h2
-rw-r--r--lldb/include/lldb/lldb-private-enumerations.h5
-rw-r--r--lldb/source/API/SBModule.cpp54
-rw-r--r--lldb/source/API/SBTarget.cpp38
-rw-r--r--lldb/source/Breakpoint/BreakpointResolver.cpp10
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverAddress.cpp5
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverFileLine.cpp7
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp5
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverName.cpp8
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverScripted.cpp7
-rw-r--r--lldb/source/Commands/CommandCompletions.cpp31
-rw-r--r--lldb/source/Commands/CommandObjectCommands.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectMemory.cpp25
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp51
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp102
-rw-r--r--lldb/source/Commands/CommandObjectType.cpp2
-rw-r--r--lldb/source/Commands/Options.td6
-rw-r--r--lldb/source/Core/IOHandlerCursesGUI.cpp2
-rw-r--r--lldb/source/Core/Mangled.cpp20
-rw-r--r--lldb/source/Core/Module.cpp96
-rw-r--r--lldb/source/Core/ModuleList.cpp37
-rw-r--r--lldb/source/Core/PluginManager.cpp4
-rw-r--r--lldb/source/Core/RichManglingContext.cpp2
-rw-r--r--lldb/source/Core/ValueObject.cpp13
-rw-r--r--lldb/source/DataFormatters/TypeFormat.cpp11
-rw-r--r--lldb/source/Expression/IRExecutionUnit.cpp4
-rw-r--r--lldb/source/Expression/REPL.cpp2
-rw-r--r--lldb/source/Host/common/Editline.cpp10
-rw-r--r--lldb/source/Host/common/Host.cpp2
-rw-r--r--lldb/source/Interpreter/CommandAlias.cpp2
-rw-r--r--lldb/source/Interpreter/OptionArgParser.cpp2
-rw-r--r--lldb/source/Interpreter/Options.cpp8
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp101
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp6
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp10
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp2
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp16
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp2
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp2
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp4
-rw-r--r--lldb/source/Plugins/Language/ObjC/NSDictionary.cpp2
-rw-r--r--lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp4
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp8
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp34
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp6
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp15
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp2
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp2
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp6
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp4
-rw-r--r--lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp9
-rw-r--r--lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h9
-rw-r--r--lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp23
-rw-r--r--lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h8
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp32
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp48
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h15
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp41
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp332
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h10
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp23
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h9
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp4
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp39
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h10
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp65
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h15
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp153
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h8
-rw-r--r--lldb/source/Symbol/CompilerDecl.cpp5
-rw-r--r--lldb/source/Symbol/CompilerDeclContext.cpp7
-rw-r--r--lldb/source/Symbol/CompilerType.cpp186
-rw-r--r--lldb/source/Symbol/ObjectFile.cpp10
-rw-r--r--lldb/source/Symbol/Symbol.cpp2
-rw-r--r--lldb/source/Symbol/SymbolFile.cpp11
-rw-r--r--lldb/source/Symbol/SymbolFileOnDemand.cpp23
-rw-r--r--lldb/source/Symbol/Symtab.cpp2
-rw-r--r--lldb/source/Symbol/Type.cpp146
-rw-r--r--lldb/source/Symbol/TypeMap.cpp14
-rw-r--r--lldb/source/Symbol/TypeSystem.cpp10
-rw-r--r--lldb/source/Symbol/Variable.cpp4
-rw-r--r--lldb/source/Target/Language.cpp10
-rw-r--r--lldb/source/Target/StackFrame.cpp22
-rw-r--r--lldb/source/Target/TargetList.cpp2
-rw-r--r--lldb/source/Utility/Args.cpp2
-rw-r--r--lldb/source/Utility/CompletionRequest.cpp4
-rw-r--r--lldb/source/Utility/FileSpec.cpp4
-rw-r--r--lldb/source/Utility/FileSpecList.cpp2
-rw-r--r--lldb/source/Utility/NameMatches.cpp4
-rw-r--r--lldb/source/Utility/StringExtractor.cpp2
-rw-r--r--lldb/source/Utility/TildeExpressionResolver.cpp4
-rw-r--r--lldb/source/Utility/XcodeSDK.cpp4
-rw-r--r--llvm/include/llvm-c/Core.h145
-rw-r--r--llvm/include/llvm-c/LLJIT.h2
-rw-r--r--llvm/include/llvm-c/LLJITUtils.h52
-rw-r--r--llvm/include/llvm-c/Types.h5
-rw-r--r--llvm/include/llvm/ADT/SmallString.h12
-rw-r--r--llvm/include/llvm/ADT/SparseBitVector.h2
-rw-r--r--llvm/include/llvm/ADT/StringRef.h12
-rw-r--r--llvm/include/llvm/Analysis/AliasAnalysis.h1
-rw-r--r--llvm/include/llvm/Analysis/AliasAnalysisEvaluator.h1
-rw-r--r--llvm/include/llvm/Analysis/AliasSetTracker.h2
-rw-r--r--llvm/include/llvm/Analysis/InstructionSimplify.h1
-rw-r--r--llvm/include/llvm/Analysis/LazyValueInfo.h4
-rw-r--r--llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h2
-rw-r--r--llvm/include/llvm/Analysis/TargetTransformInfo.h16
-rw-r--r--llvm/include/llvm/Analysis/TargetTransformInfoImpl.h6
-rw-r--r--llvm/include/llvm/BinaryFormat/ELF.h44
-rw-r--r--llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def4
-rw-r--r--llvm/include/llvm/BinaryFormat/Magic.h1
-rw-r--r--llvm/include/llvm/Bitcode/LLVMBitCodes.h1
-rw-r--r--llvm/include/llvm/CodeGen/AccelTable.h1
-rw-r--r--llvm/include/llvm/CodeGen/AntiDepBreaker.h1
-rw-r--r--llvm/include/llvm/CodeGen/AsmPrinter.h23
-rw-r--r--llvm/include/llvm/CodeGen/BasicTTIImpl.h19
-rw-r--r--llvm/include/llvm/CodeGen/CallingConvLower.h1
-rw-r--r--llvm/include/llvm/CodeGen/CodeGenPassBuilder.h42
-rw-r--r--llvm/include/llvm/CodeGen/ExpandMemCmp.h29
-rw-r--r--llvm/include/llvm/CodeGen/FunctionLoweringInfo.h1
-rw-r--r--llvm/include/llvm/CodeGen/GCMetadata.h40
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h2
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h423
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h436
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h1
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h5
-rw-r--r--llvm/include/llvm/CodeGen/IndirectBrExpand.h28
-rw-r--r--llvm/include/llvm/CodeGen/IndirectThunks.h4
-rw-r--r--llvm/include/llvm/CodeGen/InterleavedAccess.h34
-rw-r--r--llvm/include/llvm/CodeGen/InterleavedLoadCombine.h29
-rw-r--r--llvm/include/llvm/CodeGen/JMCInstrumenter.h23
-rw-r--r--llvm/include/llvm/CodeGen/MIRYamlMapping.h4
-rw-r--r--llvm/include/llvm/CodeGen/MachinePassManager.h16
-rw-r--r--llvm/include/llvm/CodeGen/MachinePassRegistry.def60
-rw-r--r--llvm/include/llvm/CodeGen/MacroFusion.h20
-rw-r--r--llvm/include/llvm/CodeGen/Passes.h6
-rw-r--r--llvm/include/llvm/CodeGen/SchedulerRegistry.h2
-rw-r--r--llvm/include/llvm/CodeGen/SelectOptimize.h34
-rw-r--r--llvm/include/llvm/CodeGen/SelectionDAGISel.h67
-rw-r--r--llvm/include/llvm/CodeGen/SjLjEHPrepare.h28
-rw-r--r--llvm/include/llvm/CodeGen/TargetInstrInfo.h13
-rw-r--r--llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h4
-rw-r--r--llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h2
-rw-r--r--llvm/include/llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h2
-rw-r--r--llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h16
-rw-r--r--llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h6
-rw-r--r--llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h13
-rw-r--r--llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h61
-rw-r--r--llvm/include/llvm/Frontend/HLSL/HLSLResource.h5
-rw-r--r--llvm/include/llvm/IR/Attributes.td3
-rw-r--r--llvm/include/llvm/IR/DebugInfo.h3
-rw-r--r--llvm/include/llvm/IR/DebugProgramInstruction.h5
-rw-r--r--llvm/include/llvm/IR/IntrinsicsAArch64.td21
-rw-r--r--llvm/include/llvm/IR/IntrinsicsAMDGPU.td72
-rw-r--r--llvm/include/llvm/IR/IntrinsicsRISCV.td1
-rw-r--r--llvm/include/llvm/IR/IntrinsicsRISCVXCV.td37
-rw-r--r--llvm/include/llvm/IR/IntrinsicsSystemZ.td28
-rw-r--r--llvm/include/llvm/InitializePasses.h4
-rw-r--r--llvm/include/llvm/LinkAllPasses.h5
-rw-r--r--llvm/include/llvm/MC/MCFragment.h4
-rw-r--r--llvm/include/llvm/MC/MCSectionCOFF.h2
-rw-r--r--llvm/include/llvm/ObjCopy/CommonConfig.h2
-rw-r--r--llvm/include/llvm/Object/ELF.h6
-rw-r--r--llvm/include/llvm/Object/ELFObjectFile.h22
-rw-r--r--llvm/include/llvm/Object/ELFTypes.h75
-rw-r--r--llvm/include/llvm/ObjectYAML/ELFYAML.h33
-rw-r--r--llvm/include/llvm/ObjectYAML/GOFFYAML.h49
-rw-r--r--llvm/include/llvm/ObjectYAML/ObjectYAML.h2
-rw-r--r--llvm/include/llvm/ObjectYAML/yaml2obj.h5
-rw-r--r--llvm/include/llvm/Passes/PassBuilder.h6
-rw-r--r--llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h270
-rw-r--r--llvm/include/llvm/ProfileData/InstrProf.h4
-rw-r--r--llvm/include/llvm/ProfileData/InstrProfCorrelator.h55
-rw-r--r--llvm/include/llvm/ProfileData/InstrProfData.inc17
-rw-r--r--llvm/include/llvm/ProfileData/InstrProfReader.h9
-rw-r--r--llvm/include/llvm/ProfileData/MemProf.h5
-rw-r--r--llvm/include/llvm/ProfileData/SampleProf.h2
-rw-r--r--llvm/include/llvm/Support/AMDGPUAddrSpace.h86
-rw-r--r--llvm/include/llvm/Support/AMDHSAKernelDescriptor.h12
-rw-r--r--llvm/include/llvm/Support/AutoConvert.h24
-rw-r--r--llvm/include/llvm/Support/LLVMDriver.h2
-rw-r--r--llvm/include/llvm/Support/SystemZ/zOSSupport.h47
-rw-r--r--llvm/include/llvm/Support/TargetOpcodes.def3
-rw-r--r--llvm/include/llvm/Support/TypeSize.h1
-rw-r--r--llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h2
-rw-r--r--llvm/include/llvm/Support/raw_ostream.h51
-rw-r--r--llvm/include/llvm/Target/CGPassBuilderOption.h12
-rw-r--r--llvm/include/llvm/Target/GenericOpcodes.td9
-rw-r--r--llvm/include/llvm/Target/TargetMachine.h2
-rw-r--r--llvm/include/llvm/Target/TargetSelectionDAG.td18
-rw-r--r--llvm/include/llvm/TargetParser/AArch64TargetParser.h5
-rw-r--r--llvm/include/llvm/TargetParser/ARMTargetParser.def2
-rw-r--r--llvm/include/llvm/Transforms/CFGuard.h13
-rw-r--r--llvm/include/llvm/Transforms/HipStdPar/HipStdPar.h1
-rw-r--r--llvm/include/llvm/Transforms/IPO/Attributor.h4
-rw-r--r--llvm/include/llvm/Transforms/IPO/BlockExtractor.h1
-rw-r--r--llvm/include/llvm/Transforms/IPO/EmbedBitcodePass.h1
-rw-r--r--llvm/include/llvm/Transforms/Instrumentation.h3
-rw-r--r--llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h161
-rw-r--r--llvm/include/llvm/Transforms/Instrumentation/MemProfiler.h2
-rw-r--r--llvm/include/llvm/Transforms/Scalar/Scalarizer.h1
-rw-r--r--llvm/include/llvm/Transforms/Scalar/SimpleLoopUnswitch.h1
-rw-r--r--llvm/include/llvm/Transforms/Utils/ValueMapper.h1
-rw-r--r--llvm/lib/Analysis/AliasAnalysis.cpp2
-rw-r--r--llvm/lib/Analysis/AliasSetTracker.cpp5
-rw-r--r--llvm/lib/Analysis/LazyValueInfo.cpp264
-rw-r--r--llvm/lib/Analysis/LoopAccessAnalysis.cpp11
-rw-r--r--llvm/lib/Analysis/LoopInfo.cpp2
-rw-r--r--llvm/lib/Analysis/ScalarEvolution.cpp6
-rw-r--r--llvm/lib/Analysis/TargetTransformInfo.cpp5
-rw-r--r--llvm/lib/Analysis/VFABIDemangling.cpp2
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp63
-rw-r--r--llvm/lib/AsmParser/LLLexer.cpp8
-rw-r--r--llvm/lib/BinaryFormat/Magic.cpp14
-rw-r--r--llvm/lib/Bitcode/Reader/BitcodeReader.cpp24
-rw-r--r--llvm/lib/Bitcode/Reader/MetadataLoader.cpp2
-rw-r--r--llvm/lib/Bitcode/Writer/BitcodeWriter.cpp2
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp137
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp6
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h1
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h1
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp10
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfFile.h1
-rw-r--r--llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp27
-rw-r--r--llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp2
-rw-r--r--llvm/lib/CodeGen/CodeGen.cpp4
-rw-r--r--llvm/lib/CodeGen/CodeGenPassBuilder.cpp4
-rw-r--r--llvm/lib/CodeGen/CodeGenPrepare.cpp45
-rw-r--r--llvm/lib/CodeGen/DwarfEHPrepare.cpp2
-rw-r--r--llvm/lib/CodeGen/ExpandMemCmp.cpp71
-rw-r--r--llvm/lib/CodeGen/GCMetadata.cpp113
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CallLowering.cpp7
-rw-r--r--llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp21
-rw-r--r--llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp22
-rw-r--r--llvm/lib/CodeGen/GlobalMerge.cpp3
-rw-r--r--llvm/lib/CodeGen/IndirectBrExpandPass.cpp71
-rw-r--r--llvm/lib/CodeGen/InterleavedAccessPass.cpp98
-rw-r--r--llvm/lib/CodeGen/InterleavedLoadCombinePass.cpp12
-rw-r--r--llvm/lib/CodeGen/JMCInstrumenter.cpp13
-rw-r--r--llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp55
-rw-r--r--llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h24
-rw-r--r--llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp4
-rw-r--r--llvm/lib/CodeGen/MIRParser/MILexer.cpp16
-rw-r--r--llvm/lib/CodeGen/MachinePassManager.cpp9
-rw-r--r--llvm/lib/CodeGen/MachinePipeliner.cpp8
-rw-r--r--llvm/lib/CodeGen/MachineScheduler.cpp12
-rw-r--r--llvm/lib/CodeGen/MachineSink.cpp21
-rw-r--r--llvm/lib/CodeGen/MachineStableHash.cpp1
-rw-r--r--llvm/lib/CodeGen/MachineVerifier.cpp23
-rw-r--r--llvm/lib/CodeGen/MacroFusion.cpp37
-rw-r--r--llvm/lib/CodeGen/RegAllocFast.cpp65
-rw-r--r--llvm/lib/CodeGen/RegisterCoalescer.cpp18
-rw-r--r--llvm/lib/CodeGen/SanitizerBinaryMetadata.cpp2
-rw-r--r--llvm/lib/CodeGen/SelectOptimize.cpp174
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp21
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp1
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp122
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h3
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp280
-rw-r--r--llvm/lib/CodeGen/SjLjEHPrepare.cpp67
-rw-r--r--llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp43
-rw-r--r--llvm/lib/CodeGen/TargetPassConfig.cpp25
-rw-r--r--llvm/lib/CodeGen/WinEHPrepare.cpp6
-rw-r--r--llvm/lib/DWARFLinker/DWARFLinker.cpp6
-rw-r--r--llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp6
-rw-r--r--llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp2
-rw-r--r--llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp10
-rw-r--r--llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp8
-rw-r--r--llvm/lib/DebugInfo/Symbolize/Symbolize.cpp20
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp4
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/Orc/Debugging/LLJITUtilsCBindings.cpp22
-rw-r--r--llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp6
-rw-r--r--llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/Orc/LLJIT.cpp111
-rw-r--r--llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp208
-rw-r--r--llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/Orc/Shared/ObjectFormats.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp3
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp52
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFAArch64.h2
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h2
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h2
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h2
-rw-r--r--llvm/lib/FileCheck/FileCheck.cpp32
-rw-r--r--llvm/lib/Frontend/HLSL/HLSLResource.cpp14
-rw-r--r--llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp11
-rw-r--r--llvm/lib/FuzzMutate/FuzzerCLI.cpp4
-rw-r--r--llvm/lib/IR/Attributes.cpp3
-rw-r--r--llvm/lib/IR/AutoUpgrade.cpp12
-rw-r--r--llvm/lib/IR/BasicBlock.cpp7
-rw-r--r--llvm/lib/IR/Core.cpp118
-rw-r--r--llvm/lib/IR/DebugInfo.cpp46
-rw-r--r--llvm/lib/IR/DebugProgramInstruction.cpp9
-rw-r--r--llvm/lib/IR/Function.cpp6
-rw-r--r--llvm/lib/IR/Instructions.cpp9
-rw-r--r--llvm/lib/IR/Mangler.cpp4
-rw-r--r--llvm/lib/IR/Operator.cpp4
-rw-r--r--llvm/lib/IR/PassInstrumentation.cpp3
-rw-r--r--llvm/lib/IR/Type.cpp2
-rw-r--r--llvm/lib/IR/Verifier.cpp16
-rw-r--r--llvm/lib/InterfaceStub/IFSHandler.cpp2
-rw-r--r--llvm/lib/LTO/LTOModule.cpp8
-rw-r--r--llvm/lib/Linker/IRMover.cpp2
-rw-r--r--llvm/lib/MC/ELFObjectWriter.cpp12
-rw-r--r--llvm/lib/MC/MCAsmStreamer.cpp6
-rw-r--r--llvm/lib/MC/MCContext.cpp10
-rw-r--r--llvm/lib/MC/MCDwarf.cpp2
-rw-r--r--llvm/lib/MC/MCParser/AsmLexer.cpp4
-rw-r--r--llvm/lib/MC/MCParser/AsmParser.cpp2
-rw-r--r--llvm/lib/MC/MCParser/COFFMasmParser.cpp2
-rw-r--r--llvm/lib/MC/MCParser/ELFAsmParser.cpp4
-rw-r--r--llvm/lib/MC/MCParser/MasmParser.cpp4
-rw-r--r--llvm/lib/MC/StringTableBuilder.cpp2
-rw-r--r--llvm/lib/MC/WasmObjectWriter.cpp12
-rw-r--r--llvm/lib/MC/WinCOFFObjectWriter.cpp2
-rw-r--r--llvm/lib/ObjCopy/COFF/COFFObjcopy.cpp2
-rw-r--r--llvm/lib/ObjCopy/ConfigManager.cpp12
-rw-r--r--llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp18
-rw-r--r--llvm/lib/ObjCopy/ELF/ELFObject.cpp31
-rw-r--r--llvm/lib/ObjCopy/ELF/ELFObject.h5
-rw-r--r--llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp1
-rw-r--r--llvm/lib/ObjCopy/MachO/MachOObject.cpp1
-rw-r--r--llvm/lib/ObjCopy/MachO/MachOObject.h4
-rw-r--r--llvm/lib/ObjCopy/MachO/MachOReader.cpp1
-rw-r--r--llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp4
-rw-r--r--llvm/lib/Object/Archive.cpp16
-rw-r--r--llvm/lib/Object/Binary.cpp1
-rw-r--r--llvm/lib/Object/COFFImportFile.cpp6
-rw-r--r--llvm/lib/Object/COFFModuleDefinition.cpp4
-rw-r--r--llvm/lib/Object/COFFObjectFile.cpp6
-rw-r--r--llvm/lib/Object/DXContainer.cpp2
-rw-r--r--llvm/lib/Object/ELF.cpp148
-rw-r--r--llvm/lib/Object/ELFObjectFile.cpp23
-rw-r--r--llvm/lib/Object/MachOObjectFile.cpp10
-rw-r--r--llvm/lib/Object/ModuleSymbolTable.cpp2
-rw-r--r--llvm/lib/Object/ObjectFile.cpp1
-rw-r--r--llvm/lib/Object/RecordStreamer.cpp2
-rw-r--r--llvm/lib/Object/WasmObjectFile.cpp2
-rw-r--r--llvm/lib/ObjectYAML/ELFEmitter.cpp72
-rw-r--r--llvm/lib/ObjectYAML/ELFYAML.cpp29
-rw-r--r--llvm/lib/ObjectYAML/GOFFEmitter.cpp282
-rw-r--r--llvm/lib/ObjectYAML/GOFFYAML.cpp46
-rw-r--r--llvm/lib/ObjectYAML/MachOEmitter.cpp1
-rw-r--r--llvm/lib/ObjectYAML/MachOYAML.cpp1
-rw-r--r--llvm/lib/ObjectYAML/ObjectYAML.cpp5
-rw-r--r--llvm/lib/ObjectYAML/yaml2obj.cpp2
-rw-r--r--llvm/lib/Option/ArgList.cpp4
-rw-r--r--llvm/lib/Option/OptTable.cpp29
-rw-r--r--llvm/lib/Passes/PassBuilder.cpp35
-rw-r--r--llvm/lib/Passes/PassBuilderPipelines.cpp4
-rw-r--r--llvm/lib/Passes/PassRegistry.def17
-rw-r--r--llvm/lib/Passes/StandardInstrumentations.cpp157
-rw-r--r--llvm/lib/ProfileData/Coverage/CoverageMapping.cpp354
-rw-r--r--llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp98
-rw-r--r--llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp17
-rw-r--r--llvm/lib/ProfileData/GCOV.cpp2
-rw-r--r--llvm/lib/ProfileData/InstrProf.cpp10
-rw-r--r--llvm/lib/ProfileData/InstrProfCorrelator.cpp121
-rw-r--r--llvm/lib/ProfileData/InstrProfReader.cpp17
-rw-r--r--llvm/lib/ProfileData/InstrProfWriter.cpp7
-rw-r--r--llvm/lib/ProfileData/ItaniumManglingCanonicalizer.cpp6
-rw-r--r--llvm/lib/ProfileData/SampleProfReader.cpp4
-rw-r--r--llvm/lib/ProfileData/SymbolRemappingReader.cpp2
-rw-r--r--llvm/lib/Remarks/YAMLRemarkParser.cpp2
-rw-r--r--llvm/lib/Support/AutoConvert.cpp73
-rw-r--r--llvm/lib/Support/CommandLine.cpp71
-rw-r--r--llvm/lib/Support/InitLLVM.cpp41
-rw-r--r--llvm/lib/Support/RISCVISAInfo.cpp8
-rw-r--r--llvm/lib/Support/SpecialCaseList.cpp11
-rw-r--r--llvm/lib/Support/Unix/Path.inc2
-rw-r--r--llvm/lib/Support/Unix/Process.inc4
-rw-r--r--llvm/lib/Support/Unix/Program.inc8
-rw-r--r--llvm/lib/Support/Windows/Path.inc4
-rw-r--r--llvm/lib/Support/raw_ostream.cpp167
-rw-r--r--llvm/lib/Target/AArch64/AArch64.td4
-rw-r--r--llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp207
-rw-r--r--llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp2
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp38
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.cpp15
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrGISel.td4
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.cpp29
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.h2
-rw-r--r--llvm/lib/Target/AArch64/AArch64SLSHardening.cpp2
-rw-r--r--llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td26
-rw-r--r--llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp4
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp63
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h1
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp7
-rw-r--r--llvm/lib/Target/AArch64/SVEInstrFormats.td13
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPU.h99
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPU.td33
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.h2
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp13
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp4
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp10
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUGISel.td5
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUGlobalISelDivergenceLowering.cpp68
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUHSAMetadataStreamer.h1
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp50
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h1
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp12
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h2
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp19
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td10
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp210
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h6
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUInstructions.td6
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp92
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp3
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPULibFunc.cpp2
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h1
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp127
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPURemoveIncompatibleFunctions.cpp36
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUSearchableTables.td6
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp4
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp21
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp2
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp17
-rw-r--r--llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp133
-rw-r--r--llvm/lib/Target/AMDGPU/BUFInstructions.td988
-rw-r--r--llvm/lib/Target/AMDGPU/DSInstructions.td313
-rw-r--r--llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp78
-rw-r--r--llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h1
-rw-r--r--llvm/lib/Target/AMDGPU/FLATInstructions.td316
-rw-r--r--llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp7
-rw-r--r--llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp4
-rw-r--r--llvm/lib/Target/AMDGPU/GCNProcessors.td4
-rw-r--r--llvm/lib/Target/AMDGPU/GCNSubtarget.h34
-rw-r--r--llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp12
-rw-r--r--llvm/lib/Target/AMDGPU/MCA/AMDGPUCustomBehaviour.cpp6
-rw-r--r--llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp46
-rw-r--r--llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp1
-rw-r--r--llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp15
-rw-r--r--llvm/lib/Target/AMDGPU/R600OpenCLImageTypeLoweringPass.cpp6
-rw-r--r--llvm/lib/Target/AMDGPU/SIDefines.h23
-rw-r--r--llvm/lib/Target/AMDGPU/SIFrameLowering.cpp4
-rw-r--r--llvm/lib/Target/AMDGPU/SIISelLowering.cpp413
-rw-r--r--llvm/lib/Target/AMDGPU/SIISelLowering.h2
-rw-r--r--llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp173
-rw-r--r--llvm/lib/Target/AMDGPU/SIInstrInfo.cpp233
-rw-r--r--llvm/lib/Target/AMDGPU/SIInstrInfo.h50
-rw-r--r--llvm/lib/Target/AMDGPU/SIInstrInfo.td23
-rw-r--r--llvm/lib/Target/AMDGPU/SIInstructions.td6
-rw-r--r--llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp90
-rw-r--r--llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp319
-rw-r--r--llvm/lib/Target/AMDGPU/SILowerI1Copies.h97
-rw-r--r--llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp7
-rw-r--r--llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h1
-rw-r--r--llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp12
-rw-r--r--llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.cpp22
-rw-r--r--llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h4
-rw-r--r--llvm/lib/Target/AMDGPU/SIProgramInfo.cpp41
-rw-r--r--llvm/lib/Target/AMDGPU/SIProgramInfo.h7
-rw-r--r--llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp15
-rw-r--r--llvm/lib/Target/AMDGPU/SIRegisterInfo.td2
-rw-r--r--llvm/lib/Target/AMDGPU/SISchedule.td36
-rw-r--r--llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp3
-rw-r--r--llvm/lib/Target/AMDGPU/SMInstructions.td114
-rw-r--r--llvm/lib/Target/AMDGPU/SOPInstructions.td175
-rw-r--r--llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp7
-rw-r--r--llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp56
-rw-r--r--llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h22
-rw-r--r--llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.cpp10
-rw-r--r--llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.h2
-rw-r--r--llvm/lib/Target/AMDGPU/VOP1Instructions.td410
-rw-r--r--llvm/lib/Target/AMDGPU/VOP2Instructions.td659
-rw-r--r--llvm/lib/Target/AMDGPU/VOP3Instructions.td390
-rw-r--r--llvm/lib/Target/AMDGPU/VOP3PInstructions.td172
-rw-r--r--llvm/lib/Target/AMDGPU/VOPCInstructions.td589
-rw-r--r--llvm/lib/Target/AMDGPU/VOPDInstructions.td140
-rw-r--r--llvm/lib/Target/AMDGPU/VOPInstructions.td412
-rw-r--r--llvm/lib/Target/ARM/ARM.td2
-rw-r--r--llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp13
-rw-r--r--llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp12
-rw-r--r--llvm/lib/Target/ARM/ARMMachineFunctionInfo.h26
-rw-r--r--llvm/lib/Target/ARM/ARMSLSHardening.cpp2
-rw-r--r--llvm/lib/Target/ARM/ARMSubtarget.h1
-rw-r--r--llvm/lib/Target/ARM/ARMTargetMachine.cpp25
-rw-r--r--llvm/lib/Target/ARM/ARMTargetMachine.h8
-rw-r--r--llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp2
-rw-r--r--llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp213
-rw-r--r--llvm/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp2
-rw-r--r--llvm/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp2
-rw-r--r--llvm/lib/Target/AVR/AVRAsmPrinter.cpp6
-rw-r--r--llvm/lib/Target/BPF/BPF.h7
-rw-r--r--llvm/lib/Target/BPF/BPF.td1
-rw-r--r--llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp12
-rw-r--r--llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp4
-rw-r--r--llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp14
-rw-r--r--llvm/lib/Target/BPF/BPFISelLowering.cpp26
-rw-r--r--llvm/lib/Target/BPF/BPFISelLowering.h2
-rw-r--r--llvm/lib/Target/BPF/BPFInstrInfo.td4
-rw-r--r--llvm/lib/Target/BPF/BPFPreserveDIType.cpp2
-rw-r--r--llvm/lib/Target/BPF/BPFSubtarget.cpp32
-rw-r--r--llvm/lib/Target/BPF/BPFSubtarget.h21
-rw-r--r--llvm/lib/Target/BPF/BPFTargetMachine.cpp31
-rw-r--r--llvm/lib/Target/BPF/BTFDebug.cpp6
-rw-r--r--llvm/lib/Target/BPF/GISel/BPFCallLowering.cpp46
-rw-r--r--llvm/lib/Target/BPF/GISel/BPFCallLowering.h39
-rw-r--r--llvm/lib/Target/BPF/GISel/BPFInstructionSelector.cpp93
-rw-r--r--llvm/lib/Target/BPF/GISel/BPFLegalizerInfo.cpp22
-rw-r--r--llvm/lib/Target/BPF/GISel/BPFLegalizerInfo.h28
-rw-r--r--llvm/lib/Target/BPF/GISel/BPFRegisterBankInfo.cpp25
-rw-r--r--llvm/lib/Target/BPF/GISel/BPFRegisterBankInfo.h39
-rw-r--r--llvm/lib/Target/BPF/GISel/BPFRegisterBanks.td15
-rw-r--r--llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h5
-rw-r--r--llvm/lib/Target/DirectX/DXILResource.cpp6
-rw-r--r--llvm/lib/Target/Hexagon/HexagonSubtarget.cpp6
-rw-r--r--llvm/lib/Target/Hexagon/HexagonTargetMachine.h2
-rw-r--r--llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp2
-rw-r--r--llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp2
-rw-r--r--llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp14
-rw-r--r--llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp4
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchISelLowering.h1
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td26
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td26
-rw-r--r--llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp42
-rw-r--r--llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp17
-rw-r--r--llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp23
-rw-r--r--llvm/lib/Target/M68k/GISel/M68kCallLowering.h17
-rw-r--r--llvm/lib/Target/M68k/M68kInstrData.td46
-rw-r--r--llvm/lib/Target/M68k/M68kInstrInfo.td10
-rw-r--r--llvm/lib/Target/M68k/M68kRegisterInfo.td5
-rw-r--r--llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp24
-rw-r--r--llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp6
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp6
-rw-r--r--llvm/lib/Target/Mips/MipsISelLowering.cpp2
-rw-r--r--llvm/lib/Target/NVPTX/NVPTX.td19
-rw-r--r--llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp4
-rw-r--r--llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp2
-rw-r--r--llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp68
-rw-r--r--llvm/lib/Target/NVPTX/NVPTXISelLowering.h5
-rw-r--r--llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp2
-rw-r--r--llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp7
-rw-r--r--llvm/lib/Target/NVPTX/NVPTXSubtarget.h17
-rw-r--r--llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp2
-rw-r--r--llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp5
-rw-r--r--llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp2
-rw-r--r--llvm/lib/Target/PowerPC/PPCRegisterInfo.td3
-rw-r--r--llvm/lib/Target/PowerPC/PPCTargetMachine.cpp4
-rw-r--r--llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp4
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp4
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp8
-rw-r--r--llvm/lib/Target/RISCV/RISCV.h5
-rw-r--r--llvm/lib/Target/RISCV/RISCVFeatures.td19
-rw-r--r--llvm/lib/Target/RISCV/RISCVISelLowering.cpp112
-rw-r--r--llvm/lib/Target/RISCV/RISCVISelLowering.h8
-rw-r--r--llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp132
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td48
-rw-r--r--llvm/lib/Target/RISCV/RISCVMacroFusion.cpp121
-rw-r--r--llvm/lib/Target/RISCV/RISCVProcessors.td2
-rw-r--r--llvm/lib/Target/RISCV/RISCVSubtarget.h6
-rw-r--r--llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp4
-rw-r--r--llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp2
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp16
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp34
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp4
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVUtils.cpp8
-rw-r--r--llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp2
-rw-r--r--llvm/lib/Target/SystemZ/SystemZCallingConv.td14
-rw-r--r--llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp70
-rw-r--r--llvm/lib/Target/SystemZ/SystemZISelLowering.cpp504
-rw-r--r--llvm/lib/Target/SystemZ/SystemZISelLowering.h23
-rw-r--r--llvm/lib/Target/SystemZ/SystemZInstrInfo.td4
-rw-r--r--llvm/lib/Target/SystemZ/SystemZInstrVector.td251
-rw-r--r--llvm/lib/Target/SystemZ/SystemZOperands.td91
-rw-r--r--llvm/lib/Target/SystemZ/SystemZOperators.td36
-rw-r--r--llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp55
-rw-r--r--llvm/lib/Target/SystemZ/SystemZRegisterInfo.td7
-rw-r--r--llvm/lib/Target/TargetMachine.cpp21
-rw-r--r--llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp34
-rw-r--r--llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp2
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp4
-rw-r--r--llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp71
-rw-r--r--llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp3
-rw-r--r--llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp48
-rw-r--r--llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp10
-rw-r--r--llvm/lib/Target/X86/MCTargetDesc/X86InstComments.cpp4
-rw-r--r--llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp4
-rw-r--r--llvm/lib/Target/X86/X86AsmPrinter.cpp82
-rw-r--r--llvm/lib/Target/X86/X86AsmPrinter.h5
-rw-r--r--llvm/lib/Target/X86/X86FastISel.cpp22
-rw-r--r--llvm/lib/Target/X86/X86FixupVectorConstants.cpp13
-rw-r--r--llvm/lib/Target/X86/X86ISelDAGToDAG.cpp24
-rw-r--r--llvm/lib/Target/X86/X86ISelLowering.cpp190
-rw-r--r--llvm/lib/Target/X86/X86InsertPrefetch.cpp2
-rw-r--r--llvm/lib/Target/X86/X86InstrAVX512.td78
-rw-r--r--llvm/lib/Target/X86/X86InstrInfo.cpp149
-rw-r--r--llvm/lib/Target/X86/X86InstrMisc.td24
-rw-r--r--llvm/lib/Target/X86/X86InstrSSE.td30
-rw-r--r--llvm/lib/Target/X86/X86LowerAMXIntrinsics.cpp4
-rw-r--r--llvm/lib/Target/X86/X86MCInstLower.cpp8
-rw-r--r--llvm/lib/Target/X86/X86RegisterInfo.cpp6
-rw-r--r--llvm/lib/Target/X86/X86ReplaceableInstrs.def2
-rw-r--r--llvm/lib/Target/X86/X86SchedAlderlakeP.td2
-rw-r--r--llvm/lib/Target/X86/X86SchedBroadwell.td4
-rw-r--r--llvm/lib/Target/X86/X86SchedHaswell.td4
-rw-r--r--llvm/lib/Target/X86/X86SchedIceLake.td44
-rw-r--r--llvm/lib/Target/X86/X86SchedSapphireRapids.td66
-rw-r--r--llvm/lib/Target/X86/X86SchedSkylakeClient.td4
-rw-r--r--llvm/lib/Target/X86/X86SchedSkylakeServer.td44
-rw-r--r--llvm/lib/Target/X86/X86ScheduleBdVer2.td2
-rw-r--r--llvm/lib/Target/X86/X86ScheduleBtVer2.td2
-rw-r--r--llvm/lib/Target/X86/X86ScheduleZnver1.td4
-rw-r--r--llvm/lib/Target/X86/X86ScheduleZnver2.td4
-rw-r--r--llvm/lib/Target/X86/X86ScheduleZnver4.td14
-rw-r--r--llvm/lib/Target/X86/X86Subtarget.cpp20
-rw-r--r--llvm/lib/Target/XCore/XCoreISelLowering.cpp2
-rw-r--r--llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp2
-rw-r--r--llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp8
-rw-r--r--llvm/lib/TargetParser/AArch64TargetParser.cpp4
-rw-r--r--llvm/lib/TargetParser/ARMTargetParser.cpp4
-rw-r--r--llvm/lib/TargetParser/ARMTargetParserCommon.cpp26
-rw-r--r--llvm/lib/TargetParser/CSKYTargetParser.cpp2
-rw-r--r--llvm/lib/TargetParser/Host.cpp18
-rw-r--r--llvm/lib/TargetParser/Triple.cpp29
-rw-r--r--llvm/lib/TextAPI/Symbol.cpp10
-rw-r--r--llvm/lib/TextAPI/Target.cpp2
-rw-r--r--llvm/lib/TextAPI/TextStub.cpp18
-rw-r--r--llvm/lib/Transforms/CFGuard/CFGuard.cpp85
-rw-r--r--llvm/lib/Transforms/Coroutines/CoroFrame.cpp194
-rw-r--r--llvm/lib/Transforms/Coroutines/CoroInternal.h16
-rw-r--r--llvm/lib/Transforms/Coroutines/CoroSplit.cpp35
-rw-r--r--llvm/lib/Transforms/IPO/AttributorAttributes.cpp44
-rw-r--r--llvm/lib/Transforms/IPO/FunctionImport.cpp279
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp35
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp20
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp58
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineInternal.h1
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp23
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp45
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp3
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp11
-rw-r--r--llvm/lib/Transforms/InstCombine/InstructionCombining.cpp31
-rw-r--r--llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp2
-rw-r--r--llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp410
-rw-r--r--llvm/lib/Transforms/Instrumentation/Instrumentation.cpp15
-rw-r--r--llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp5
-rw-r--r--llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp6
-rw-r--r--llvm/lib/Transforms/Scalar/ConstantHoisting.cpp3
-rw-r--r--llvm/lib/Transforms/Scalar/ConstraintElimination.cpp67
-rw-r--r--llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp32
-rw-r--r--llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp2
-rw-r--r--llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp1
-rw-r--r--llvm/lib/Transforms/Scalar/LICM.cpp19
-rw-r--r--llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp5
-rw-r--r--llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp7
-rw-r--r--llvm/lib/Transforms/Scalar/SCCP.cpp1
-rw-r--r--llvm/lib/Transforms/Scalar/SROA.cpp86
-rw-r--r--llvm/lib/Transforms/Utils/BasicBlockUtils.cpp14
-rw-r--r--llvm/lib/Transforms/Utils/CodeExtractor.cpp1
-rw-r--r--llvm/lib/Transforms/Utils/Local.cpp112
-rw-r--r--llvm/lib/Transforms/Utils/LoopRotationUtils.cpp5
-rw-r--r--llvm/lib/Transforms/Utils/LowerSwitch.cpp4
-rw-r--r--llvm/lib/Transforms/Utils/MemoryOpRemark.cpp11
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyCFG.cpp1
-rw-r--r--llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp1
-rw-r--r--llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp10
-rw-r--r--llvm/lib/Transforms/Vectorize/VPlan.cpp17
-rw-r--r--llvm/lib/Transforms/Vectorize/VPlanAnalysis.h3
-rw-r--r--llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp4
-rw-r--r--llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp13
-rw-r--r--llvm/lib/Transforms/Vectorize/VPlanTransforms.h2
-rw-r--r--llvm/lib/Transforms/Vectorize/VPlanValue.h13
-rw-r--r--llvm/tools/llc/llc.cpp6
-rw-r--r--llvm/tools/lli/lli.cpp2
-rw-r--r--llvm/tools/llvm-ar/llvm-ar.cpp4
-rw-r--r--llvm/tools/llvm-as/llvm-as.cpp2
-rw-r--r--llvm/tools/llvm-cov/CodeCoverage.cpp58
-rw-r--r--llvm/tools/llvm-cov/CoverageExporterJson.cpp44
-rw-r--r--llvm/tools/llvm-cov/CoverageReport.cpp49
-rw-r--r--llvm/tools/llvm-cov/CoverageSummaryInfo.cpp23
-rw-r--r--llvm/tools/llvm-cov/CoverageSummaryInfo.h50
-rw-r--r--llvm/tools/llvm-cov/CoverageViewOptions.h2
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageView.cpp14
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageView.h28
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp54
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewHTML.h3
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewText.cpp51
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewText.h3
-rw-r--r--llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp28
-rw-r--r--llvm/tools/llvm-diff/llvm-diff.cpp3
-rw-r--r--llvm/tools/llvm-dis/llvm-dis.cpp2
-rw-r--r--llvm/tools/llvm-dwarfutil/DebugInfoLinker.h2
-rw-r--r--llvm/tools/llvm-nm/llvm-nm.cpp14
-rw-r--r--llvm/tools/llvm-objcopy/ObjcopyOptions.cpp31
-rw-r--r--llvm/tools/llvm-objcopy/ObjcopyOpts.td12
-rw-r--r--llvm/tools/llvm-objdump/COFFDump.cpp2
-rw-r--r--llvm/tools/llvm-objdump/MachODump.cpp4
-rw-r--r--llvm/tools/llvm-objdump/SourcePrinter.cpp2
-rw-r--r--llvm/tools/llvm-objdump/llvm-objdump.cpp2
-rw-r--r--llvm/tools/llvm-profdata/llvm-profdata.cpp31
-rw-r--r--llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp2
-rw-r--r--llvm/tools/llvm-readobj/COFFDumper.cpp2
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp29
-rw-r--r--llvm/tools/llvm-readobj/ObjDumper.cpp1
-rw-r--r--llvm/tools/llvm-readobj/Win64EHDumper.cpp2
-rw-r--r--llvm/tools/llvm-stress/llvm-stress.cpp2
-rw-r--r--llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp52
-rw-r--r--llvm/tools/opt/opt.cpp12
-rw-r--r--llvm/utils/TableGen/DAGISelMatcher.cpp4
-rw-r--r--llvm/utils/TableGen/DAGISelMatcher.h330
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherEmitter.cpp131
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherGen.cpp15
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherOpt.cpp24
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp86
-rw-r--r--llvm/utils/TableGen/GlobalISelMatchTable.cpp541
-rw-r--r--llvm/utils/TableGen/GlobalISelMatchTable.h46
-rw-r--r--llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp9
-rw-r--r--llvm/utils/TableGen/X86DisassemblerTables.cpp8
-rw-r--r--llvm/utils/TableGen/X86FoldTablesEmitter.cpp9
-rw-r--r--llvm/utils/TableGen/X86RecognizableInstr.cpp9
-rw-r--r--llvm/utils/split-file/split-file.cpp4
-rw-r--r--openmp/runtime/src/kmp.h16
-rw-r--r--openmp/runtime/src/kmp_ftn_entry.h18
-rw-r--r--openmp/runtime/src/kmp_gsupport.cpp9
-rw-r--r--openmp/runtime/src/kmp_os.h15
-rw-r--r--openmp/runtime/src/kmp_platform.h20
-rw-r--r--openmp/runtime/src/kmp_runtime.cpp60
-rw-r--r--openmp/runtime/src/kmp_utility.cpp2
-rw-r--r--openmp/runtime/src/kmp_utils.h55
-rw-r--r--openmp/runtime/src/z_Linux_asm.S22
-rw-r--r--openmp/runtime/src/z_Linux_util.cpp18
1071 files changed, 23492 insertions, 9686 deletions
diff --git a/clang/include/clang-c/BuildSystem.h b/clang/include/clang-c/BuildSystem.h
index 296e61247cef..57e16af20a70 100644
--- a/clang/include/clang-c/BuildSystem.h
+++ b/clang/include/clang-c/BuildSystem.h
@@ -95,7 +95,7 @@ CINDEX_LINKAGE void clang_free(void *buffer);
CINDEX_LINKAGE void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay);
/**
- * Object encapsulating information about a module.map file.
+ * Object encapsulating information about a module.modulemap file.
*/
typedef struct CXModuleMapDescriptorImpl *CXModuleMapDescriptor;
@@ -109,7 +109,7 @@ CINDEX_LINKAGE CXModuleMapDescriptor
clang_ModuleMapDescriptor_create(unsigned options);
/**
- * Sets the framework module name that the module.map describes.
+ * Sets the framework module name that the module.modulemap describes.
* \returns 0 for success, non-zero to indicate an error.
*/
CINDEX_LINKAGE enum CXErrorCode
@@ -117,7 +117,7 @@ clang_ModuleMapDescriptor_setFrameworkModuleName(CXModuleMapDescriptor,
const char *name);
/**
- * Sets the umbrella header name that the module.map describes.
+ * Sets the umbrella header name that the module.modulemap describes.
* \returns 0 for success, non-zero to indicate an error.
*/
CINDEX_LINKAGE enum CXErrorCode
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index b14184afe584..b3ae66e6e769 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -36,6 +36,7 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/iterator_range.h"
@@ -7514,7 +7515,7 @@ inline const Type *Type::getPointeeOrArrayElementType() const {
/// spaces into a diagnostic with <<.
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
LangAS AS) {
- PD.AddTaggedVal(static_cast<std::underlying_type_t<LangAS>>(AS),
+ PD.AddTaggedVal(llvm::to_underlying(AS),
DiagnosticsEngine::ArgumentKind::ak_addrspace);
return PD;
}
diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178b..757ee452ced7 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified Pointer Context
FIXABLE_GADGET(UPCStandalonePointer)
FIXABLE_GADGET(UPCPreIncrement) // '++Ptr' in an Unspecified Pointer Context
+FIXABLE_GADGET(UUCAddAssign) // 'Ptr += n' in an Unspecified Untyped Context
FIXABLE_GADGET(PointerAssignment)
FIXABLE_GADGET(PointerInit)
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index b0a8ef10c500..2b57058d3f1c 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -455,6 +455,9 @@ def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch6
def TargetELF : TargetSpec {
let ObjectFormats = ["ELF"];
}
+def TargetELFOrMachO : TargetSpec {
+ let ObjectFormats = ["ELF", "MachO"];
+}
def TargetSupportsInitPriority : TargetSpec {
let CustomCode = [{ !Target.getTriple().isOSzOS() }];
@@ -1665,7 +1668,7 @@ def IBOutletCollection : InheritableAttr {
let Documentation = [Undocumented];
}
-def IFunc : Attr, TargetSpecificAttr<TargetELF> {
+def IFunc : Attr, TargetSpecificAttr<TargetELFOrMachO> {
let Spellings = [GCC<"ifunc">];
let Args = [StringArgument<"Resolver">];
let Subjects = SubjectList<[Function]>;
@@ -2212,7 +2215,8 @@ def NotTailCalled : InheritableAttr {
def : MutualExclusions<[AlwaysInline, NotTailCalled]>;
def NoStackProtector : InheritableAttr {
- let Spellings = [Clang<"no_stack_protector">, Declspec<"safebuffers">];
+ let Spellings = [Clang<"no_stack_protector">, CXX11<"gnu", "no_stack_protector">,
+ C23<"gnu", "no_stack_protector">, Declspec<"safebuffers">];
let Subjects = SubjectList<[Function]>;
let Documentation = [NoStackProtectorDocs];
let SimpleHandler = 1;
@@ -2792,9 +2796,10 @@ def SwiftAsyncError : InheritableAttr {
let Documentation = [SwiftAsyncErrorDocs];
}
-def Suppress : StmtAttr {
- let Spellings = [CXX11<"gsl", "suppress">];
+def Suppress : DeclOrStmtAttr {
+ let Spellings = [CXX11<"gsl", "suppress">, Clang<"suppress">];
let Args = [VariadicStringArgument<"DiagnosticIdentifiers">];
+ let Accessors = [Accessor<"isGSL", [CXX11<"gsl", "suppress">]>];
let Documentation = [SuppressDocs];
}
@@ -2878,7 +2883,7 @@ def Target : InheritableAttr {
for (auto &Feature : AttrFeatures) {
Feature = Feature.trim();
- if (Feature.startswith("arch="))
+ if (Feature.starts_with("arch="))
return Feature.drop_front(sizeof("arch=") - 1);
}
return "";
@@ -2896,8 +2901,8 @@ def Target : InheritableAttr {
for (auto &Feature : AttrFeatures) {
Feature = Feature.trim();
- if (!Feature.startswith("no-") && !Feature.startswith("arch=") &&
- !Feature.startswith("fpmath=") && !Feature.startswith("tune="))
+ if (!Feature.starts_with("no-") && !Feature.starts_with("arch=") &&
+ !Feature.starts_with("fpmath=") && !Feature.starts_with("tune="))
Out.push_back(Feature);
}
}
@@ -4258,7 +4263,8 @@ def HLSLResource : InheritableAttr {
"StructuredBuffer", "CBuffer", "Sampler",
"TBuffer", "RTAccelerationStructure",
"FeedbackTexture2D", "FeedbackTexture2DArray"],
- /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>
+ /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>,
+ DefaultBoolArgument<"isROV", /*default=*/0>
];
let Documentation = [InternalOnly];
}
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 1a98196834ce..90041fa8dbb3 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -5267,7 +5267,74 @@ the ``int`` parameter is the one that represents the error.
def SuppressDocs : Documentation {
let Category = DocCatStmt;
let Content = [{
-The ``[[gsl::suppress]]`` attribute suppresses specific
+The ``suppress`` attribute suppresses unwanted warnings coming from static
+analysis tools such as the Clang Static Analyzer. The tool will not report
+any issues in source code annotated with the attribute.
+
+The attribute cannot be used to suppress traditional Clang warnings, because
+many such warnings are emitted before the attribute is fully parsed.
+Consider using ``#pragma clang diagnostic`` to control such diagnostics,
+as described in `Controlling Diagnostics via Pragmas
+<https://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas>`_.
+
+The ``suppress`` attribute can be placed on an individual statement in order to
+suppress warnings about undesirable behavior occurring at that statement:
+
+.. code-block:: c++
+
+ int foo() {
+ int *x = nullptr;
+ ...
+ [[clang::suppress]]
+ return *x; // null pointer dereference warning suppressed here
+ }
+
+Putting the attribute on a compound statement suppresses all warnings in scope:
+
+.. code-block:: c++
+
+ int foo() {
+ [[clang::suppress]] {
+ int *x = nullptr;
+ ...
+ return *x; // warnings suppressed in the entire scope
+ }
+ }
+
+Some static analysis warnings are accompanied by one or more notes, and the
+line of code against which the warning is emitted isn't necessarily the best
+for suppression purposes. In such cases the tools are allowed to implement
+additional ways to suppress specific warnings based on the attribute attached
+to a note location.
+
+For example, the Clang Static Analyzer suppresses memory leak warnings when
+the suppression attribute is placed at the allocation site (highlited by
+a "note: memory is allocated"), which may be different from the line of code
+at which the program "loses track" of the pointer (where the warning
+is ultimately emitted):
+
+.. code-block:: c
+
+ int bar1(bool coin_flip) {
+ __attribute__((suppress))
+ int *result = (int *)malloc(sizeof(int));
+ if (coin_flip)
+ return 1; // warning about this leak path is suppressed
+
+ return *result; // warning about this leak path is also suppressed
+ }
+
+ int bar2(bool coin_flip) {
+ int *result = (int *)malloc(sizeof(int));
+ if (coin_flip)
+ return 1; // leak warning on this path NOT suppressed
+
+ __attribute__((suppress))
+ return *result; // leak warning is suppressed only on this path
+ }
+
+
+When written as ``[[gsl::suppress]]``, this attribute suppresses specific
clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable
way. The attribute can be attached to declarations, statements, and at
namespace scope.
@@ -5468,7 +5535,9 @@ considered inline.
Not all targets support this attribute. ELF target support depends on both the
linker and runtime linker, and is available in at least lld 4.0 and later,
binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later.
-Non-ELF targets currently do not support this attribute.
+Mach-O targets support it, but with slightly different semantics: the resolver
+is run at first call, instead of at load time by the runtime linker. Targets
+other than ELF and Mach-O currently do not support this attribute.
}];
}
diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def
index 8b59b3790d7b..e562ef04a301 100644
--- a/clang/include/clang/Basic/BuiltinsAMDGPU.def
+++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def
@@ -406,5 +406,23 @@ TARGET_BUILTIN(__builtin_amdgcn_cvt_pk_fp8_f32, "iffiIb", "nc", "fp8-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_bf8_f32, "ifiiIi", "nc", "fp8-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_fp8_f32, "ifiiIi", "nc", "fp8-insts")
+//===----------------------------------------------------------------------===//
+// GFX12+ only builtins.
+//===----------------------------------------------------------------------===//
+
+TARGET_BUILTIN(__builtin_amdgcn_permlane16_var, "UiUiUiUiIbIb", "nc", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_permlanex16_var, "UiUiUiUiIbIb", "nc", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal, "vIi", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_var, "vi", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_wait, "vIs", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_isfirst, "bIi", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_isfirst_var, "bi", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_init, "vii", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_join, "vi", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_wakeup_barrier, "vi", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_leave, "b", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_get_barrier_state, "Uii", "n", "gfx12-insts")
+
+
#undef BUILTIN
#undef TARGET_BUILTIN
diff --git a/clang/include/clang/Basic/BuiltinsNVPTX.def b/clang/include/clang/Basic/BuiltinsNVPTX.def
index d74a7d1e55dd..0f2e8260143b 100644
--- a/clang/include/clang/Basic/BuiltinsNVPTX.def
+++ b/clang/include/clang/Basic/BuiltinsNVPTX.def
@@ -26,7 +26,9 @@
#pragma push_macro("SM_87")
#pragma push_macro("SM_89")
#pragma push_macro("SM_90")
-#define SM_90 "sm_90"
+#pragma push_macro("SM_90a")
+#define SM_90a "sm_90a"
+#define SM_90 "sm_90|" SM_90a
#define SM_89 "sm_89|" SM_90
#define SM_87 "sm_87|" SM_89
#define SM_86 "sm_86|" SM_87
@@ -56,7 +58,11 @@
#pragma push_macro("PTX78")
#pragma push_macro("PTX80")
#pragma push_macro("PTX81")
-#define PTX81 "ptx81"
+#pragma push_macro("PTX82")
+#pragma push_macro("PTX83")
+#define PTX83 "ptx83"
+#define PTX82 "ptx82|" PTX83
+#define PTX81 "ptx81|" PTX82
#define PTX80 "ptx80|" PTX81
#define PTX78 "ptx78|" PTX80
#define PTX77 "ptx77|" PTX78
@@ -1055,6 +1061,7 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78))
#pragma pop_macro("SM_87")
#pragma pop_macro("SM_89")
#pragma pop_macro("SM_90")
+#pragma pop_macro("SM_90a")
#pragma pop_macro("PTX42")
#pragma pop_macro("PTX60")
#pragma pop_macro("PTX61")
@@ -1072,3 +1079,5 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78))
#pragma pop_macro("PTX78")
#pragma pop_macro("PTX80")
#pragma pop_macro("PTX81")
+#pragma pop_macro("PTX82")
+#pragma pop_macro("PTX83")
diff --git a/clang/include/clang/Basic/BuiltinsSystemZ.def b/clang/include/clang/Basic/BuiltinsSystemZ.def
index 4cfc52ae4216..f0c0ebfa622a 100644
--- a/clang/include/clang/Basic/BuiltinsSystemZ.def
+++ b/clang/include/clang/Basic/BuiltinsSystemZ.def
@@ -64,14 +64,14 @@ TARGET_BUILTIN(__builtin_s390_vupllh, "V4UiV8Us", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vupllf, "V2ULLiV4Ui", "nc", "vector")
// Vector integer instructions (chapter 22 of the PoP)
-TARGET_BUILTIN(__builtin_s390_vaq, "V16UcV16UcV16Uc", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vacq, "V16UcV16UcV16UcV16Uc", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vaq, "SLLLiSLLLiSLLLi", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vacq, "ULLLiULLLiULLLiULLLi", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vaccb, "V16UcV16UcV16Uc", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vacch, "V8UsV8UsV8Us", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vaccf, "V4UiV4UiV4Ui", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vaccg, "V2ULLiV2ULLiV2ULLi", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vaccq, "V16UcV16UcV16Uc", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vacccq, "V16UcV16UcV16UcV16Uc", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vaccq, "ULLLiULLLiULLLi", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vacccq, "ULLLiULLLiULLLiULLLi", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vavgb, "V16ScV16ScV16Sc", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vavgh, "V8SsV8SsV8Ss", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vavgf, "V4SiV4SiV4Si", "nc", "vector")
@@ -116,11 +116,11 @@ TARGET_BUILTIN(__builtin_s390_verllvg, "V2ULLiV2ULLiV2ULLi", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vgfmb, "V8UsV16UcV16Uc", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vgfmh, "V4UiV8UsV8Us", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vgfmf, "V2ULLiV4UiV4Ui", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vgfmg, "V16UcV2ULLiV2ULLi", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vgfmg, "ULLLiV2ULLiV2ULLi", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vgfmab, "V8UsV16UcV16UcV8Us", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vgfmah, "V4UiV8UsV8UsV4Ui", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vgfmaf, "V2ULLiV4UiV4UiV2ULLi", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vgfmag, "V16UcV2ULLiV2ULLiV16Uc", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vgfmag, "ULLLiV2ULLiV2ULLiULLLi", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vmahb, "V16ScV16ScV16ScV16Sc", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vmahh, "V8SsV8SsV8SsV8Ss", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vmahf, "V4SiV4SiV4SiV4Si", "nc", "vector")
@@ -161,14 +161,14 @@ TARGET_BUILTIN(__builtin_s390_vpopctb, "V16UcV16Uc", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vpopcth, "V8UsV8Us", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vpopctf, "V4UiV4Ui", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vpopctg, "V2ULLiV2ULLi", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vsq, "V16UcV16UcV16Uc", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vsbcbiq, "V16UcV16UcV16UcV16Uc", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vsbiq, "V16UcV16UcV16UcV16Uc", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vsq, "SLLLiSLLLiSLLLi", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vsbcbiq, "ULLLiULLLiULLLiULLLi", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vsbiq, "ULLLiULLLiULLLiULLLi", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vscbib, "V16UcV16UcV16Uc", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vscbih, "V8UsV8UsV8Us", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vscbif, "V4UiV4UiV4Ui", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vscbig, "V2ULLiV2ULLiV2ULLi", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vscbiq, "V16UcV16UcV16Uc", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vscbiq, "ULLLiULLLiULLLi", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vsl, "V16UcV16UcV16Uc", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vslb, "V16UcV16UcV16Uc", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vsldb, "V16UcV16UcV16UcIi", "nc", "vector")
@@ -180,8 +180,8 @@ TARGET_BUILTIN(__builtin_s390_vsumb, "V4UiV16UcV16Uc", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vsumh, "V4UiV8UsV8Us", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vsumgh, "V2ULLiV8UsV8Us", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vsumgf, "V2ULLiV4UiV4Ui", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vsumqf, "V16UcV4UiV4Ui", "nc", "vector")
-TARGET_BUILTIN(__builtin_s390_vsumqg, "V16UcV2ULLiV2ULLi", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vsumqf, "ULLLiV4UiV4Ui", "nc", "vector")
+TARGET_BUILTIN(__builtin_s390_vsumqg, "ULLLiV2ULLiV2ULLi", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vtm, "iV16UcV16Uc", "nc", "vector")
// Vector string instructions (chapter 23 of the PoP)
@@ -256,7 +256,7 @@ TARGET_BUILTIN(__builtin_s390_vftcidb, "V2SLLiV2dIii*", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vlrlr, "V16ScUivC*", "", "vector-enhancements-1")
TARGET_BUILTIN(__builtin_s390_vstrlr, "vV16ScUiv*", "", "vector-enhancements-1")
TARGET_BUILTIN(__builtin_s390_vbperm, "V2ULLiV16UcV16Uc", "nc", "vector-enhancements-1")
-TARGET_BUILTIN(__builtin_s390_vmslg, "V16UcV2ULLiV2ULLiV16UcIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vmslg, "ULLLiV2ULLiV2ULLiULLLiIi", "nc", "vector-enhancements-1")
TARGET_BUILTIN(__builtin_s390_vfmaxdb, "V2dV2dV2dIi", "nc", "vector-enhancements-1")
TARGET_BUILTIN(__builtin_s390_vfmindb, "V2dV2dV2dIi", "nc", "vector-enhancements-1")
TARGET_BUILTIN(__builtin_s390_vfnmadb, "V2dV2dV2dV2d", "nc", "vector-enhancements-1")
diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def
index e4802f8ab1c1..60b752ad4854 100644
--- a/clang/include/clang/Basic/BuiltinsX86.def
+++ b/clang/include/clang/Basic/BuiltinsX86.def
@@ -979,7 +979,7 @@ TARGET_BUILTIN(__builtin_ia32_scatterpfqps, "vUcV8Oiv*IiIi", "nV:512:", "avx512p
TARGET_BUILTIN(__builtin_ia32_knotqi, "UcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_knothi, "UsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_knotsi, "UiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_knotdi, "UOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_knotdi, "UOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_cmpb128_mask, "UsV16cV16cIiUs", "ncV:128:", "avx512vl,avx512bw")
TARGET_BUILTIN(__builtin_ia32_cmpd128_mask, "UcV4iV4iIiUc", "ncV:128:", "avx512vl")
@@ -1349,7 +1349,7 @@ TARGET_BUILTIN(__builtin_ia32_vpmadd52luq128, "V2OiV2OiV2OiV2Oi", "ncV:128:", "a
TARGET_BUILTIN(__builtin_ia32_vpmadd52luq256, "V4OiV4OiV4OiV4Oi", "ncV:256:", "avx512ifma,avx512vl|avxifma")
TARGET_BUILTIN(__builtin_ia32_vcomisd, "iV2dV2dIiIi", "ncV:128:", "avx512f")
TARGET_BUILTIN(__builtin_ia32_vcomiss, "iV4fV4fIiIi", "ncV:128:", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_kunpckdi, "UOiUOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kunpckdi, "UOiUOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kunpcksi, "UiUiUi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_loaddquhi512_mask, "V32sV32sC*V32sUi", "nV:512:", "avx512bw,evex512")
TARGET_BUILTIN(__builtin_ia32_loaddquqi512_mask, "V64cV64cC*V64cUOi", "nV:512:", "avx512bw,evex512")
@@ -1665,56 +1665,56 @@ TARGET_BUILTIN(__builtin_ia32_fpclassss_mask, "UcV4fIiUc", "ncV:128:", "avx512dq
TARGET_BUILTIN(__builtin_ia32_kaddqi, "UcUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kaddhi, "UsUsUs", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kaddsi, "UiUiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kadddi, "UOiUOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kadddi, "UOiUOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kandqi, "UcUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kandhi, "UsUsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kandsi, "UiUiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kanddi, "UOiUOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kanddi, "UOiUOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kandnqi, "UcUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kandnhi, "UsUsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kandnsi, "UiUiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kandndi, "UOiUOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kandndi, "UOiUOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_korqi, "UcUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_korhi, "UsUsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_korsi, "UiUiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kordi, "UOiUOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kordi, "UOiUOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kortestcqi, "iUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kortestzqi, "iUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kortestchi, "iUsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kortestzhi, "iUsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kortestcsi, "iUiUi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kortestzsi, "iUiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kortestcdi, "iUOiUOi", "nc", "avx512bw,evex512")
-TARGET_BUILTIN(__builtin_ia32_kortestzdi, "iUOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kortestcdi, "iUOiUOi", "nc", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_kortestzdi, "iUOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_ktestcqi, "iUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_ktestzqi, "iUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_ktestchi, "iUsUs", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_ktestzhi, "iUsUs", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_ktestcsi, "iUiUi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_ktestzsi, "iUiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_ktestcdi, "iUOiUOi", "nc", "avx512bw,evex512")
-TARGET_BUILTIN(__builtin_ia32_ktestzdi, "iUOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_ktestcdi, "iUOiUOi", "nc", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_ktestzdi, "iUOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kunpckhi, "UsUsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kxnorqi, "UcUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kxnorhi, "UsUsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kxnorsi, "UiUiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kxnordi, "UOiUOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kxnordi, "UOiUOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kxorqi, "UcUcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kxorhi, "UsUsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kxorsi, "UiUiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kxordi, "UOiUOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kxordi, "UOiUOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kshiftliqi, "UcUcIUi", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kshiftlihi, "UsUsIUi", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kshiftlisi, "UiUiIUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kshiftlidi, "UOiUOiIUi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kshiftlidi, "UOiUOiIUi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kshiftriqi, "UcUcIUi", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kshiftrihi, "UsUsIUi", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kshiftrisi, "UiUiIUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kshiftridi, "UOiUOiIUi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kshiftridi, "UOiUOiIUi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_kmovb, "UcUc", "nc", "avx512dq")
TARGET_BUILTIN(__builtin_ia32_kmovw, "UsUs", "nc", "avx512f")
TARGET_BUILTIN(__builtin_ia32_kmovd, "UiUi", "nc", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_kmovq, "UOiUOi", "nc", "avx512bw,evex512")
+TARGET_BUILTIN(__builtin_ia32_kmovq, "UOiUOi", "nc", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_palignr512, "V64cV64cV64cIi", "ncV:512:", "avx512bw,evex512")
TARGET_BUILTIN(__builtin_ia32_dbpsadbw128, "V8sV16cV16cIi", "ncV:128:", "avx512bw,avx512vl")
TARGET_BUILTIN(__builtin_ia32_dbpsadbw256, "V16sV32cV32cIi", "ncV:256:", "avx512bw,avx512vl")
diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h
index 2d912bdbbd1b..916cb4b7ef34 100644
--- a/clang/include/clang/Basic/Cuda.h
+++ b/clang/include/clang/Basic/Cuda.h
@@ -39,9 +39,11 @@ enum class CudaVersion {
CUDA_118,
CUDA_120,
CUDA_121,
- FULLY_SUPPORTED = CUDA_118,
+ CUDA_122,
+ CUDA_123,
+ FULLY_SUPPORTED = CUDA_123,
PARTIALLY_SUPPORTED =
- CUDA_121, // Partially supported. Proceed with a warning.
+ CUDA_123, // Partially supported. Proceed with a warning.
NEW = 10000, // Too new. Issue a warning, but allow using it.
};
const char *CudaVersionToString(CudaVersion V);
@@ -71,6 +73,7 @@ enum class CudaArch {
SM_87,
SM_89,
SM_90,
+ SM_90a,
GFX600,
GFX601,
GFX602,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index caee2dc6daad..80b5680b94f6 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -40,6 +40,7 @@ def : DiagGroup<"auto-import">;
def FrameworkHdrQuotedInclude : DiagGroup<"quoted-include-in-framework-header">;
def FrameworkIncludePrivateFromPublic :
DiagGroup<"framework-include-private-from-public">;
+def DeprecatedModuleDotMap : DiagGroup<"deprecated-module-dot-map">;
def FrameworkHdrAtImport : DiagGroup<"atimport-in-framework-header">;
def CXX14BinaryLiteral : DiagGroup<"c++14-binary-literal">;
def CXXPre14CompatBinaryLiteral : DiagGroup<"c++98-c++11-compat-binary-literal">;
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 564ca48cc32a..75ca2fa16d34 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -884,6 +884,9 @@ def warn_quoted_include_in_framework_header : Warning<
def warn_framework_include_private_from_public : Warning<
"public framework header includes private framework header '%0'"
>, InGroup<FrameworkIncludePrivateFromPublic>;
+def warn_deprecated_module_dot_map : Warning<
+ "'%0' as a module map name is deprecated, rename it to %select{module.modulemap|module.private.modulemap}1%select{| in the 'Modules' directory of the framework}2">,
+ InGroup<DeprecatedModuleDotMap>;
def remark_pp_include_directive_modular_translation : Remark<
"treating #%select{include|import|include_next|__include_macros}0 as an "
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 28d95ca9b138..c8e32a63684f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1669,6 +1669,8 @@ def err_qualified_friend_def : Error<
"friend function definition cannot be qualified with '%0'">;
def err_friend_def_in_local_class : Error<
"friend function cannot be defined in a local class">;
+def err_friend_specialization_def : Error<
+ "friend function specialization cannot be defined">;
def err_friend_not_first_in_declaration : Error<
"'friend' must appear first in a non-function declaration">;
def err_using_decl_friend : Error<
@@ -8727,7 +8729,7 @@ def err_atomic_op_needs_atomic_int : Error<
"address argument to atomic operation must be a pointer to "
"%select{|atomic }0integer (%1 invalid)">;
def warn_atomic_op_has_invalid_memory_order : Warning<
- "memory order argument to atomic operation is invalid">,
+ "%select{|success |failure }0memory order argument to atomic operation is invalid">,
InGroup<DiagGroup<"atomic-memory-ordering">>;
def err_atomic_op_has_invalid_synch_scope : Error<
"synchronization scope argument to atomic operation is invalid">;
@@ -12000,7 +12002,7 @@ def warn_tcb_enforcement_violation : Warning<
// RISC-V builtin required extension warning
def err_riscv_builtin_requires_extension : Error<
- "builtin requires%select{| at least one of the following extensions to be enabled}0: %1">;
+ "builtin requires%select{| at least one of the following extensions}0: %1">;
def err_riscv_builtin_invalid_lmul : Error<
"LMUL argument must be in the range [0,3] or [5,7]">;
def err_riscv_type_requires_extension : Error<
diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def
index 5b923a1944e5..79f04c89c9fe 100644
--- a/clang/include/clang/Basic/FPOptions.def
+++ b/clang/include/clang/Basic/FPOptions.def
@@ -28,4 +28,5 @@ OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc)
OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod)
OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, Float16ExcessPrecision)
OPTION(MathErrno, bool, 1, BFloat16ExcessPrecision)
+OPTION(ComplexRange, LangOptions::ComplexRangeKind, 2, MathErrno)
#undef OPTION
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index df1eff8cbcc9..06efac0cf1ab 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -104,6 +104,7 @@ FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
FEATURE(swiftasynccc,
PP.getTargetInfo().checkCallingConvention(CC_SwiftAsync) ==
clang::TargetInfo::CCCR_OK)
+FEATURE(pragma_stdc_cx_limited_range, true)
// Objective-C features
FEATURE(objc_arr, LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
FEATURE(objc_arc, LangOpts.ObjCAutoRefCount)
@@ -281,7 +282,6 @@ EXTENSION(matrix_types_scalar_division, true)
EXTENSION(cxx_attributes_on_using_declarations, LangOpts.CPlusPlus11)
EXTENSION(datasizeof, LangOpts.CPlusPlus)
-FEATURE(builtin_headers_in_system_modules, LangOpts.BuiltinHeadersInSystemModules)
FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVTables)
// CUDA/HIP Features
diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index 0898e7d39dd7..1ac182d4fce2 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -511,7 +511,7 @@ public:
/// function(<#int x#>);
/// \endcode
bool isEditorPlaceholder() const {
- return getName().startswith("<#") && getName().endswith("#>");
+ return getName().starts_with("<#") && getName().ends_with("#>");
}
/// Determine whether \p this is a name reserved for the implementation (C99
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index c3d5399905a3..152d9f65f86d 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -220,6 +220,8 @@ BENIGN_LANGOPT(NoSignedZero , 1, 0, "Permit Floating Point optimization wit
BENIGN_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal")
BENIGN_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation")
+ENUM_LANGOPT(ComplexRange, ComplexRangeKind, 2, CX_Full, "Enable use of range reduction for complex arithmetics.")
+
BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control")
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index c4979b9a38c0..9f986fce2d44 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -392,6 +392,8 @@ public:
IncompleteOnly = 3,
};
+ enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran };
+
public:
/// The used language standard.
LangStandard::Kind LangStd;
@@ -741,6 +743,7 @@ public:
setAllowFEnvAccess(true);
else
setAllowFEnvAccess(LangOptions::FPM_Off);
+ setComplexRange(LO.getComplexRange());
}
bool allowFPContractWithinStatement() const {
diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index 8f7881abf26f..c9f9cbec7493 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -309,7 +309,7 @@ namespace clang {
bool isTupleSet() const { return Flags & IsTupleSet; }
bool isReadZA() const { return Flags & IsReadZA; }
bool isWriteZA() const { return Flags & IsWriteZA; }
-
+ bool isReductionQV() const { return Flags & IsReductionQV; }
uint64_t getBits() const { return Flags; }
bool isFlagSet(uint64_t Flag) const { return Flags & Flag; }
};
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 41f3c2e403cb..aa0f5023104a 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -266,7 +266,6 @@ protected:
LLVM_PREFERRED_TYPE(bool)
unsigned AllowAMDGPUUnsafeFPAtomics : 1;
- LLVM_PREFERRED_TYPE(bool)
unsigned ARMCDECoprocMask : 8;
unsigned MaxOpenCLWorkGroupSize;
@@ -1424,6 +1423,8 @@ public:
/// Identify whether this target supports IFuncs.
bool supportsIFunc() const {
+ if (getTriple().isOSBinFormatMachO())
+ return true;
return getTriple().isOSBinFormatELF() &&
((getTriple().isOSLinux() && !getTriple().isMusl()) ||
getTriple().isOSFreeBSD());
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 5f9915d21022..3f0e1e1a7d45 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -911,6 +911,11 @@ PRAGMA_ANNOTATION(pragma_fenv_access_ms)
// handles them.
PRAGMA_ANNOTATION(pragma_fenv_round)
+// Annotation for #pragma STDC CX_LIMITED_RANGE
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+PRAGMA_ANNOTATION(pragma_cx_limited_range)
+
// Annotation for #pragma float_control
// The lexer produces these so that they only take effect when the parser
// handles them.
diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td
index 85656c00c5b3..55fd35c3b6c2 100644
--- a/clang/include/clang/Basic/arm_sve.td
+++ b/clang/include/clang/Basic/arm_sve.td
@@ -1935,17 +1935,41 @@ def SVBGRP : SInst<"svbgrp[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sv
def SVBGRP_N : SInst<"svbgrp[_n_{d}]", "dda", "UcUsUiUl", MergeNone, "aarch64_sve_bgrp_x">;
}
+let TargetGuard = "sve2p1|sme" in {
+def SVPSEL_B : SInst<"svpsel_lane_b8", "PPPm", "Pc", MergeNone, "", [IsStreamingCompatible], []>;
+def SVPSEL_H : SInst<"svpsel_lane_b16", "PPPm", "Ps", MergeNone, "", [IsStreamingCompatible], []>;
+def SVPSEL_S : SInst<"svpsel_lane_b32", "PPPm", "Pi", MergeNone, "", [IsStreamingCompatible], []>;
+def SVPSEL_D : SInst<"svpsel_lane_b64", "PPPm", "Pl", MergeNone, "", [IsStreamingCompatible], []>;
+def SVPSEL_COUNT_ALIAS_B : SInst<"svpsel_lane_c8", "}}Pm", "Pc", MergeNone, "", [IsStreamingCompatible], []>;
+def SVPSEL_COUNT_ALIAS_H : SInst<"svpsel_lane_c16", "}}Pm", "Ps", MergeNone, "", [IsStreamingCompatible], []>;
+def SVPSEL_COUNT_ALIAS_S : SInst<"svpsel_lane_c32", "}}Pm", "Pi", MergeNone, "", [IsStreamingCompatible], []>;
+def SVPSEL_COUNT_ALIAS_D : SInst<"svpsel_lane_c64", "}}Pm", "Pl", MergeNone, "", [IsStreamingCompatible], []>;
+}
+
+// Standalone sve2.1 builtins
let TargetGuard = "sve2p1" in {
-def SVFCLAMP : SInst<"svclamp[_{d}]", "dddd", "hfd", MergeNone, "aarch64_sve_fclamp", [], []>;
+def SVORQV : SInst<"svorqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_orqv", [IsReductionQV]>;
+def SVEORQV : SInst<"sveorqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorqv", [IsReductionQV]>;
+def SVADDQV : SInst<"svaddqv[_{d}]", "{Pd", "hfdcsilUcUsUiUl", MergeNone, "aarch64_sve_addqv", [IsReductionQV]>;
+def SVANDQV : SInst<"svandqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_andqv", [IsReductionQV]>;
+def SVSMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "csil", MergeNone, "aarch64_sve_smaxqv", [IsReductionQV]>;
+def SVUMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "UcUsUiUl", MergeNone, "aarch64_sve_umaxqv", [IsReductionQV]>;
+def SVSMINQV : SInst<"svminqv[_{d}]", "{Pd", "csil", MergeNone, "aarch64_sve_sminqv", [IsReductionQV]>;
+def SVUMINQV : SInst<"svminqv[_{d}]", "{Pd", "UcUsUiUl", MergeNone, "aarch64_sve_uminqv", [IsReductionQV]>;
-def SVPEXT_SINGLE : SInst<"svpext_lane_{d}", "P}i", "QcQsQiQl", MergeNone, "aarch64_sve_pext", [], [ImmCheck<1, ImmCheck0_3>]>;
-def SVPEXT_X2 : SInst<"svpext_lane_{d}_x2", "2.P}i", "QcQsQiQl", MergeNone, "aarch64_sve_pext_x2", [], [ImmCheck<1, ImmCheck0_1>]>;
+def SVFMAXNMQV: SInst<"svmaxnmqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fmaxnmqv", [IsReductionQV]>;
+def SVFMINNMQV: SInst<"svminnmqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fminnmqv", [IsReductionQV]>;
+def SVFMAXQV: SInst<"svmaxqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fmaxqv", [IsReductionQV]>;
+def SVFMINQV: SInst<"svminqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fminqv", [IsReductionQV]>;
+}
-def SVPSEL_COUNT_ALIAS_B : SInst<"svpsel_lane_c8", "}}Pm", "Pc", MergeNone, "", [], []>;
-def SVPSEL_COUNT_ALIAS_H : SInst<"svpsel_lane_c16", "}}Pm", "Ps", MergeNone, "", [], []>;
-def SVPSEL_COUNT_ALIAS_S : SInst<"svpsel_lane_c32", "}}Pm", "Pi", MergeNone, "", [], []>;
-def SVPSEL_COUNT_ALIAS_D : SInst<"svpsel_lane_c64", "}}Pm", "Pl", MergeNone, "", [], []>;
+let TargetGuard = "sve2p1|sme2" in {
+//FIXME: Replace IsStreamingCompatible with IsStreamingOrHasSVE2p1 when available
+def SVPEXT_SINGLE : SInst<"svpext_lane_{d}", "P}i", "QcQsQiQl", MergeNone, "aarch64_sve_pext", [IsStreamingCompatible], [ImmCheck<1, ImmCheck0_3>]>;
+def SVPEXT_X2 : SInst<"svpext_lane_{d}_x2", "2.P}i", "QcQsQiQl", MergeNone, "aarch64_sve_pext_x2", [IsStreamingCompatible], [ImmCheck<1, ImmCheck0_1>]>;
+}
+let TargetGuard = "sve2p1" in {
def SVWHILEGE_COUNT : SInst<"svwhilege_{d}", "}lli", "QcQsQiQl", MergeNone, "aarch64_sve_whilege_{d}", [IsOverloadNone], [ImmCheck<2, ImmCheck2_4_Mul2>]>;
def SVWHILEGT_COUNT : SInst<"svwhilegt_{d}", "}lli", "QcQsQiQl", MergeNone, "aarch64_sve_whilegt_{d}", [IsOverloadNone], [ImmCheck<2, ImmCheck2_4_Mul2>]>;
def SVWHILELE_COUNT : SInst<"svwhilele_{d}", "}lli", "QcQsQiQl", MergeNone, "aarch64_sve_whilele_{d}", [IsOverloadNone], [ImmCheck<2, ImmCheck2_4_Mul2>]>;
@@ -2045,13 +2069,6 @@ let TargetGuard = "sve2p1" in {
def SVSCLAMP : SInst<"svclamp[_{d}]", "dddd", "csil", MergeNone, "aarch64_sve_sclamp", [], []>;
def SVUCLAMP : SInst<"svclamp[_{d}]", "dddd", "UcUsUiUl", MergeNone, "aarch64_sve_uclamp", [], []>;
-def SVPSEL_B : SInst<"svpsel_lane_b8", "PPPm", "Pc", MergeNone, "", [], []>;
-def SVPSEL_H : SInst<"svpsel_lane_b16", "PPPm", "Ps", MergeNone, "", [], []>;
-def SVPSEL_S : SInst<"svpsel_lane_b32", "PPPm", "Pi", MergeNone, "", [], []>;
-def SVPSEL_D : SInst<"svpsel_lane_b64", "PPPm", "Pl", MergeNone, "", [], []>;
-
-def SVCNTP_COUNT : SInst<"svcntp_{d}", "n}i", "QcQsQiQl", MergeNone, "aarch64_sve_cntp_{d}", [IsOverloadNone], [ImmCheck<1, ImmCheck2_4_Mul2>]>;
-
defm SVREVD : SInstZPZ<"svrevd", "csilUcUsUiUl", "aarch64_sve_revd">;
}
@@ -2060,6 +2077,9 @@ let TargetGuard = "sve2p1|sme2" in {
def SVPTRUE_COUNT : SInst<"svptrue_{d}", "}v", "QcQsQiQl", MergeNone, "aarch64_sve_ptrue_{d}", [IsOverloadNone, IsStreamingCompatible], []>;
def SVPFALSE_COUNT_ALIAS : SInst<"svpfalse_c", "}v", "", MergeNone, "", [IsOverloadNone, IsStreamingCompatible]>;
+
+ def SVFCLAMP : SInst<"svclamp[_{d}]", "dddd", "hfd", MergeNone, "aarch64_sve_fclamp", [IsStreamingCompatible], []>;
+ def SVCNTP_COUNT : SInst<"svcntp_{d}", "n}i", "QcQsQiQl", MergeNone, "aarch64_sve_cntp_{d}", [IsOverloadNone, IsStreamingCompatible], [ImmCheck<1, ImmCheck2_4_Mul2>]>;
}
let TargetGuard = "sve2p1,b16b16" in {
@@ -2164,6 +2184,21 @@ let TargetGuard = "sme2" in {
def REINTERPRET_SVBOOL_TO_SVCOUNT : Inst<"svreinterpret[_c]", "}P", "Pc", MergeNone, "", [IsStreamingCompatible], []>;
def REINTERPRET_SVCOUNT_TO_SVBOOL : Inst<"svreinterpret[_b]", "P}", "Pc", MergeNone, "", [IsStreamingCompatible], []>;
+
+ // SQDMULH
+ def SVSQDMULH_SINGLE_X2 : SInst<"svqdmulh[_single_{d}_x2]", "22d", "csil", MergeNone, "aarch64_sve_sqdmulh_single_vgx2", [IsStreaming], []>;
+ def SVSQDMULH_SINGLE_X4 : SInst<"svqdmulh[_single_{d}_x4]", "44d", "csil", MergeNone, "aarch64_sve_sqdmulh_single_vgx4", [IsStreaming], []>;
+ def SVSQDMULH_X2 : SInst<"svqdmulh[_{d}_x2]", "222", "csil", MergeNone, "aarch64_sve_sqdmulh_vgx2", [IsStreaming], []>;
+ def SVSQDMULH_X4 : SInst<"svqdmulh[_{d}_x4]", "444", "csil", MergeNone, "aarch64_sve_sqdmulh_vgx4", [IsStreaming], []>;
+}
+
+let TargetGuard = "sve2p1|sme2" in {
+ // SQRSHRN / UQRSHRN
+ def SVQRSHRN_X2 : SInst<"svqrshrn[_n]_{0}[_{d}_x2]", "h2i", "i", MergeNone, "aarch64_sve_sqrshrn_x2", [IsStreamingCompatible], [ImmCheck<1, ImmCheck1_16>]>;
+ def SVUQRSHRN_X2 : SInst<"svqrshrn[_n]_{0}[_{d}_x2]", "e2i", "Ui", MergeNone, "aarch64_sve_uqrshrn_x2", [IsStreamingCompatible], [ImmCheck<1, ImmCheck1_16>]>;
+
+ // SQRSHRUN
+ def SVSQRSHRUN_X2 : SInst<"svqrshrun[_n]_{0}[_{d}_x2]", "e2i", "i", MergeNone, "aarch64_sve_sqrshrun_x2", [IsStreamingCompatible], [ImmCheck<1, ImmCheck1_16>]>;
}
let TargetGuard = "sve2p1" in {
@@ -2245,11 +2280,13 @@ let TargetGuard = "sme2" in {
//
// Multi-vector saturating extract narrow and interleave
//
-let TargetGuard = "sme2" in {
+let TargetGuard = "sme2|sve2p1" in {
def SVQCVTN_S16_S32_X2 : SInst<"svqcvtn_s16[_{d}_x2]", "h2.d", "i", MergeNone, "aarch64_sve_sqcvtn_x2", [IsStreamingCompatible], []>;
def SVQCVTN_U16_U32_X2 : SInst<"svqcvtn_u16[_{d}_x2]", "e2.d", "Ui", MergeNone, "aarch64_sve_uqcvtn_x2", [IsStreamingCompatible], []>;
def SVQCVTN_U16_S32_X2 : SInst<"svqcvtn_u16[_{d}_x2]", "e2.d", "i", MergeNone, "aarch64_sve_sqcvtun_x2", [IsStreamingCompatible], []>;
+}
+let TargetGuard = "sme2" in {
def SVQCVTN_S8_S32_X4 : SInst<"svqcvtn_s8[_{d}_x4]", "q4.d", "i", MergeNone, "aarch64_sve_sqcvtn_x4", [IsStreaming], []>;
def SVQCVTN_U8_U32_X4 : SInst<"svqcvtn_u8[_{d}_x4]", "b4.d", "Ui", MergeNone, "aarch64_sve_uqcvtn_x4", [IsStreaming], []>;
def SVQCVTN_U8_S32_X4 : SInst<"svqcvtn_u8[_{d}_x4]", "b4.d", "i", MergeNone, "aarch64_sve_sqcvtun_x4", [IsStreaming], []>;
@@ -2258,3 +2295,14 @@ let TargetGuard = "sme2" in {
def SVQCVTN_U16_U64_X4 : SInst<"svqcvtn_u16[_{d}_x4]", "b4.d", "Ul", MergeNone, "aarch64_sve_uqcvtn_x4", [IsStreaming], []>;
def SVQCVTN_U16_S64_X4 : SInst<"svqcvtn_u16[_{d}_x4]", "b4.d", "l", MergeNone, "aarch64_sve_sqcvtun_x4", [IsStreaming], []>;
}
+
+//
+// Multi-vector unpack
+//
+
+let TargetGuard = "sme2" in {
+ def SVSUNPK_X2 : SInst<"svunpk_{d}[_{1}_x2]", "2h", "sil", MergeNone, "aarch64_sve_sunpk_x2", [IsStreaming], []>;
+ def SVUUNPK_X2 : SInst<"svunpk_{d}[_{1}_x2]", "2h", "UsUiUl", MergeNone, "aarch64_sve_uunpk_x2", [IsStreaming], []>;
+ def SVSUNPK_X4 : SInst<"svunpk_{d}[_{3}_x4]", "42.h", "sil", MergeNone, "aarch64_sve_sunpk_x4", [IsStreaming], []>;
+ def SVUUNPK_X4 : SInst<"svunpk_{d}[_{3}_x4]", "42.h", "UsUiUl", MergeNone, "aarch64_sve_uunpk_x4", [IsStreaming], []>;
+}
diff --git a/clang/include/clang/Basic/arm_sve_sme_incl.td b/clang/include/clang/Basic/arm_sve_sme_incl.td
index 040ce95a57de..0dba8493bad2 100644
--- a/clang/include/clang/Basic/arm_sve_sme_incl.td
+++ b/clang/include/clang/Basic/arm_sve_sme_incl.td
@@ -129,6 +129,7 @@
// Z: const pointer to uint64_t
// Prototype modifiers added for SVE2p1
+// {: 128b vector
// }: svcount_t
class MergeType<int val, string suffix=""> {
@@ -225,6 +226,7 @@ def IsSharedZA : FlagType<0x8000000000>;
def IsPreservesZA : FlagType<0x10000000000>;
def IsReadZA : FlagType<0x20000000000>;
def IsWriteZA : FlagType<0x40000000000>;
+def IsReductionQV : FlagType<0x80000000000>;
// These must be kept in sync with the flags in include/clang/Basic/TargetBuiltins.h
class ImmCheckType<int val> {
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index b959fd20fe41..1b02087425b7 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1010,6 +1010,30 @@ defm offload_uniform_block : BoolFOption<"offload-uniform-block",
NegFlag<SetFalse, [], [ClangOption, CC1Option], "Don't assume">,
BothFlags<[], [ClangOption], " that kernels are launched with uniform block sizes (default true for CUDA/HIP and false otherwise)">>;
+def fcx_limited_range : Joined<["-"], "fcx-limited-range">,
+ Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Basic algebraic expansions of complex arithmetic operations "
+ "involving are enabled.">;
+
+def fno_cx_limited_range : Joined<["-"], "fno-cx-limited-range">,
+ Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Basic algebraic expansions of complex arithmetic operations "
+ "involving are disabled.">;
+
+def fcx_fortran_rules : Joined<["-"], "fcx-fortran-rules">,
+ Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Range reduction is enabled for complex arithmetic operations.">;
+
+def fno_cx_fortran_rules : Joined<["-"], "fno-cx-fortran-rules">,
+ Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Range reduction is disabled for complex arithmetic operations.">;
+
+def complex_range_EQ : Joined<["-"], "complex-range=">, Group<f_Group>,
+ Visibility<[CC1Option]>,
+ Values<"full,limited,fortran">, NormalizedValuesScope<"LangOptions">,
+ NormalizedValues<["CX_Full", "CX_Limited", "CX_Fortran"]>,
+ MarshallingInfoEnum<LangOpts<"ComplexRange">, "CX_Full">;
+
// OpenCL-only Options
def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>,
Visibility<[ClangOption, CC1Option]>,
@@ -2872,9 +2896,11 @@ defm asm_blocks : BoolFOption<"asm-blocks",
LangOpts<"AsmBlocks">, Default<fms_extensions.KeyPath>,
PosFlag<SetTrue, [], [ClangOption, CC1Option]>,
NegFlag<SetFalse>>;
-def fms_volatile : Flag<["-"], "fms-volatile">, Group<f_Group>,
- Visibility<[ClangOption, CC1Option]>,
- MarshallingInfoFlag<LangOpts<"MSVolatile">>;
+defm ms_volatile : BoolFOption<"ms-volatile",
+ LangOpts<"MSVolatile">, DefaultFalse,
+ PosFlag<SetTrue, [], [ClangOption, CC1Option],
+ "Volatile loads and stores have acquire and release semantics">,
+ NegFlag<SetFalse>>;
def fmsc_version : Joined<["-"], "fmsc-version=">, Group<f_Group>,
Visibility<[ClangOption, CLOption]>,
HelpText<"Microsoft compiler version number to report in _MSC_VER (0 = don't define it (default))">;
@@ -6354,6 +6380,12 @@ def J : JoinedOrSeparate<["-"], "J">,
Group<gfortran_Group>,
Alias<module_dir>;
+let Visibility = [FlangOption] in {
+def no_fortran_main : Flag<["-"], "fno-fortran-main">,
+ Visibility<[FlangOption]>, Group<f_Group>,
+ HelpText<"Do not include Fortran_main.a (provided by Flang) when linking">;
+} // let Visibility = [ FlangOption ]
+
//===----------------------------------------------------------------------===//
// FC1 Options
//===----------------------------------------------------------------------===//
@@ -8187,7 +8219,7 @@ def _SLASH_winsysroot : CLJoinedOrSeparate<"winsysroot">,
HelpText<"Same as \"/diasdkdir <dir>/DIA SDK\" /vctoolsdir <dir>/VC/Tools/MSVC/<vctoolsversion> \"/winsdkdir <dir>/Windows Kits/10\"">,
MetaVarName<"<dir>">;
def _SLASH_volatile_iso : Option<["/", "-"], "volatile:iso", KIND_FLAG>,
- Group<_SLASH_volatile_Group>, Flags<[NoXarchOption]>, Visibility<[CLOption]>,
+ Visibility<[CLOption]>, Alias<fno_ms_volatile>,
HelpText<"Volatile loads and stores have standard semantics">;
def _SLASH_vmb : CLFlag<"vmb">,
HelpText<"Use a best-case representation method for member pointers">;
@@ -8202,7 +8234,7 @@ def _SLASH_vmv : CLFlag<"vmv">,
HelpText<"Set the default most-general representation to "
"virtual inheritance">;
def _SLASH_volatile_ms : Option<["/", "-"], "volatile:ms", KIND_FLAG>,
- Group<_SLASH_volatile_Group>, Flags<[NoXarchOption]>, Visibility<[CLOption]>,
+ Visibility<[CLOption]>, Alias<fms_volatile>,
HelpText<"Volatile loads and stores have acquire and release semantics">;
def _SLASH_clang : CLJoined<"clang:">,
HelpText<"Pass <arg> to the clang driver">, MetaVarName<"<arg>">;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 066349823516..2dbe090bd093 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -770,6 +770,10 @@ private:
void HandlePragmaFEnvRound();
/// Handle the annotation token produced for
+ /// #pragma STDC CX_LIMITED_RANGE...
+ void HandlePragmaCXLimitedRange();
+
+ /// Handle the annotation token produced for
/// #pragma float_control
void HandlePragmaFloatControl();
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f45e0a7d3d52..20228da15ade 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2102,7 +2102,7 @@ public:
SourceLocation AttrLoc);
CodeAlignAttr *BuildCodeAlignAttr(const AttributeCommonInfo &CI, Expr *E);
- bool CheckRebuiltCodeAlignStmtAttributes(ArrayRef<const Attr *> Attrs);
+ bool CheckRebuiltStmtAttributes(ArrayRef<const Attr *> Attrs);
bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc);
@@ -7311,8 +7311,7 @@ public:
/// ActOnLambdaExpr - This is called when the body of a lambda expression
/// was successfully completed.
- ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
- Scope *CurScope);
+ ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body);
/// Does copying/destroying the captured variable have side effects?
bool CaptureHasSideEffects(const sema::Capture &From);
@@ -11023,6 +11022,11 @@ public:
/// \#pragma STDC FENV_ACCESS
void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled);
+ /// ActOnPragmaCXLimitedRange - Called on well formed
+ /// \#pragma STDC CX_LIMITED_RANGE
+ void ActOnPragmaCXLimitedRange(SourceLocation Loc,
+ LangOptions::ComplexRangeKind Range);
+
/// Called on well formed '\#pragma clang fp' that has option 'exceptions'.
void ActOnPragmaFPExceptions(SourceLocation Loc,
LangOptions::FPExceptionModeKind);
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 7eefdca6815c..59358e77edb0 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -1424,7 +1424,7 @@ private:
RecordLocation TypeCursorForIndex(unsigned Index);
void LoadedDecl(unsigned Index, Decl *D);
Decl *ReadDeclRecord(serialization::DeclID ID);
- void markIncompleteDeclChain(Decl *Canon);
+ void markIncompleteDeclChain(Decl *D);
/// Returns the most recent declaration of a declaration (which must be
/// of a redeclarable kind) that is either local or has already been loaded
@@ -2093,7 +2093,7 @@ public:
SmallVectorImpl<std::pair<Selector, SourceLocation>> &Sels) override;
void ReadWeakUndeclaredIdentifiers(
- SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo>> &WI) override;
+ SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo>> &WeakIDs) override;
void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) override;
@@ -2203,7 +2203,7 @@ public:
/// Retrieve the global selector ID that corresponds to this
/// the local selector ID in a given module.
- serialization::SelectorID getGlobalSelectorID(ModuleFile &F,
+ serialization::SelectorID getGlobalSelectorID(ModuleFile &M,
unsigned LocalID) const;
/// Read the contents of a CXXCtorInitializer array.
@@ -2415,12 +2415,7 @@ public:
BitsUnpacker(BitsUnpacker &&) = delete;
BitsUnpacker operator=(const BitsUnpacker &) = delete;
BitsUnpacker operator=(BitsUnpacker &&) = delete;
- ~BitsUnpacker() {
-#ifndef NDEBUG
- while (isValid())
- assert(!getNextBit() && "There are unprocessed bits!");
-#endif
- }
+ ~BitsUnpacker() = default;
void updateValue(uint32_t V) {
Value = V;
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 1d224786372e..e7774e5a9392 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -36,6 +36,7 @@ def CoreAlpha : Package<"core">, ParentPackage<Alpha>;
// Note: OptIn is *not* intended for checkers that are too noisy to be on by
// default. Such checkers belong in the alpha package.
def OptIn : Package<"optin">;
+def CoreOptIn : Package<"core">, ParentPackage<OptIn>;
// In the Portability package reside checkers for finding code that relies on
// implementation-defined behavior. Such checks are wanted for cross-platform
@@ -440,6 +441,18 @@ def UndefinedNewArraySizeChecker : Checker<"NewArraySize">,
} // end "core.uninitialized"
//===----------------------------------------------------------------------===//
+// Optin checkers for core language features
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = CoreOptIn in {
+
+def EnumCastOutOfRangeChecker : Checker<"EnumCastOutOfRange">,
+ HelpText<"Check integer to enumeration casts for out of range values">,
+ Documentation<HasDocumentation>;
+
+} // end "optin.core"
+
+//===----------------------------------------------------------------------===//
// Unix API checkers.
//===----------------------------------------------------------------------===//
@@ -774,10 +787,6 @@ def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">,
"destructor in their base class">,
Documentation<HasDocumentation>;
-def EnumCastOutOfRangeChecker : Checker<"EnumCastOutOfRange">,
- HelpText<"Check integer to enumeration casts for out of range values">,
- Documentation<HasDocumentation>;
-
def IteratorModeling : Checker<"IteratorModeling">,
HelpText<"Models iterators of C++ containers">,
Dependencies<[ContainerModeling]>,
diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index a947bd086702..276d11e80a5b 100644
--- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -409,8 +409,8 @@ AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental) {
};
std::vector<StringRef> Checkers;
for (StringRef CheckerName : StaticAnalyzerCheckerNames) {
- if (!CheckerName.startswith("debug.") &&
- (IncludeExperimental || !CheckerName.startswith("alpha.")))
+ if (!CheckerName.starts_with("debug.") &&
+ (IncludeExperimental || !CheckerName.starts_with("alpha.")))
Checkers.push_back(CheckerName);
}
return Checkers;
diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 8956552e7bfc..e762f7548e0b 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -19,6 +19,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
@@ -594,6 +595,9 @@ private:
/// A vector of BugReports for tracking the allocated pointers and cleanup.
std::vector<BugReportEquivClass *> EQClassesVector;
+ /// User-provided in-code suppressions.
+ BugSuppression UserSuppressions;
+
public:
BugReporter(BugReporterData &d);
virtual ~BugReporter();
diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h
new file mode 100644
index 000000000000..4fd81b627519
--- /dev/null
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h
@@ -0,0 +1,53 @@
+//===- BugSuppression.h - Suppression interface -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines BugSuppression, a simple interface class encapsulating
+// all user provided in-code suppressions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_SUPPRESSION_H
+#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_SUPPRESSION_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+class Decl;
+
+namespace ento {
+class BugReport;
+class PathDiagnosticLocation;
+
+class BugSuppression {
+public:
+ using DiagnosticIdentifierList = llvm::ArrayRef<llvm::StringRef>;
+
+ /// Return true if the given bug report was explicitly suppressed by the user.
+ bool isSuppressed(const BugReport &);
+
+ /// Return true if the bug reported at the given location was explicitly
+ /// suppressed by the user.
+ bool isSuppressed(const PathDiagnosticLocation &Location,
+ const Decl *DeclWithIssue,
+ DiagnosticIdentifierList DiagnosticIdentification);
+
+private:
+ // Overly pessimistic number, to be honest.
+ static constexpr unsigned EXPECTED_NUMBER_OF_SUPPRESSIONS = 8;
+ using CachedRanges =
+ llvm::SmallVector<SourceRange, EXPECTED_NUMBER_OF_SUPPRESSIONS>;
+
+ llvm::DenseMap<const Decl *, CachedRanges> CachedSuppressionLocations;
+};
+
+} // end namespace ento
+} // end namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_SUPPRESSION_H
diff --git a/clang/lib/APINotes/APINotesManager.cpp b/clang/lib/APINotes/APINotesManager.cpp
index ec1fb3ffa961..a921c8b9fce3 100644
--- a/clang/lib/APINotes/APINotesManager.cpp
+++ b/clang/lib/APINotes/APINotesManager.cpp
@@ -198,7 +198,7 @@ static void checkPrivateAPINotesName(DiagnosticsEngine &Diags,
StringRef RealFileName =
llvm::sys::path::filename(File->tryGetRealPathName());
StringRef RealStem = llvm::sys::path::stem(RealFileName);
- if (RealStem.endswith("_private"))
+ if (RealStem.ends_with("_private"))
return;
unsigned DiagID = diag::warn_apinotes_private_case;
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index 4dfd01dae05f..57d6da7a1775 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -745,7 +745,7 @@ public:
convertCommonEntity(M, MI, M.Selector);
// Check if the selector ends with ':' to determine if it takes arguments.
- bool takesArguments = M.Selector.endswith(":");
+ bool takesArguments = M.Selector.ends_with(":");
// Split the selector into pieces.
llvm::SmallVector<StringRef, 4> Args;
diff --git a/clang/lib/ARCMigrate/ARCMT.cpp b/clang/lib/ARCMigrate/ARCMT.cpp
index 8e398977dcd6..b410d5f3b42a 100644
--- a/clang/lib/ARCMigrate/ARCMT.cpp
+++ b/clang/lib/ARCMigrate/ARCMT.cpp
@@ -201,7 +201,7 @@ createInvocationForMigration(CompilerInvocation &origCI,
for (std::vector<std::string>::iterator
I = CInvok->getDiagnosticOpts().Warnings.begin(),
E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) {
- if (!StringRef(*I).startswith("error"))
+ if (!StringRef(*I).starts_with("error"))
WarnOpts.push_back(*I);
}
WarnOpts.push_back("error=arc-unsafe-retained-assign");
diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp
index 5a25c88c65f6..ed363a46a200 100644
--- a/clang/lib/ARCMigrate/ObjCMT.cpp
+++ b/clang/lib/ARCMigrate/ObjCMT.cpp
@@ -562,7 +562,7 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D) {
if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D)) {
StringRef Name = CatDecl->getName();
- return Name.endswith("Deprecated");
+ return Name.ends_with("Deprecated");
}
return false;
}
@@ -1176,12 +1176,12 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
if (!SetterMethod) {
// try a different naming convention for getter: isXxxxx
StringRef getterNameString = getterName->getName();
- bool IsPrefix = getterNameString.startswith("is");
+ bool IsPrefix = getterNameString.starts_with("is");
// Note that we don't want to change an isXXX method of retainable object
// type to property (readonly or otherwise).
if (IsPrefix && GRT->isObjCRetainableType())
return false;
- if (IsPrefix || getterNameString.startswith("get")) {
+ if (IsPrefix || getterNameString.starts_with("get")) {
LengthOfPrefix = (IsPrefix ? 2 : 3);
const char *CGetterName = getterNameString.data() + LengthOfPrefix;
// Make sure that first character after "is" or "get" prefix can
@@ -1320,11 +1320,11 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) {
StringRef STRefMethodName(MethodName);
size_t len = 0;
- if (STRefMethodName.startswith("standard"))
+ if (STRefMethodName.starts_with("standard"))
len = strlen("standard");
- else if (STRefMethodName.startswith("shared"))
+ else if (STRefMethodName.starts_with("shared"))
len = strlen("shared");
- else if (STRefMethodName.startswith("default"))
+ else if (STRefMethodName.starts_with("default"))
len = strlen("default");
else
return;
@@ -1341,7 +1341,7 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
StringRef LoweredMethodName(MethodName);
std::string StringLoweredMethodName = LoweredMethodName.lower();
LoweredMethodName = StringLoweredMethodName;
- if (!LoweredMethodName.startswith(ClassNamePostfix))
+ if (!LoweredMethodName.starts_with(ClassNamePostfix))
return;
if (OIT_Family == OIT_ReturnsSelf)
ReplaceWithClasstype(*this, OM);
diff --git a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
index 40220a2eef49..1e6354f71e29 100644
--- a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -146,7 +146,7 @@ private:
ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
FD->getIdentifier()->getName())) {
StringRef fname = FD->getIdentifier()->getName();
- if (fname.endswith("Retain") || fname.contains("Create") ||
+ if (fname.ends_with("Retain") || fname.contains("Create") ||
fname.contains("Copy")) {
// Do not migrate to couple of bridge transfer casts which
// cancel each other out. Leave it unchanged so error gets user
diff --git a/clang/lib/ARCMigrate/TransformActions.cpp b/clang/lib/ARCMigrate/TransformActions.cpp
index bd5c79356867..6bc6fed1a903 100644
--- a/clang/lib/ARCMigrate/TransformActions.cpp
+++ b/clang/lib/ARCMigrate/TransformActions.cpp
@@ -431,7 +431,7 @@ bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) {
if (invalidTemp)
return false;
- return file.substr(locInfo.second).startswith(text);
+ return file.substr(locInfo.second).starts_with(text);
}
void TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) {
diff --git a/clang/lib/ARCMigrate/Transforms.cpp b/clang/lib/ARCMigrate/Transforms.cpp
index 90b2b32b6b1b..2808e35135dc 100644
--- a/clang/lib/ARCMigrate/Transforms.cpp
+++ b/clang/lib/ARCMigrate/Transforms.cpp
@@ -95,7 +95,7 @@ bool trans::isPlusOne(const Expr *E) {
ento::cocoa::isRefType(callE->getType(), "CF",
FD->getIdentifier()->getName())) {
StringRef fname = FD->getIdentifier()->getName();
- if (fname.endswith("Retain") || fname.contains("Create") ||
+ if (fname.ends_with("Retain") || fname.contains("Create") ||
fname.contains("Copy"))
return true;
}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index e877f903b34c..0395b3e47ab6 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -8223,7 +8223,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
// Another legacy compatibility encoding. Some ObjC qualifier and type
// combinations need to be rearranged.
// Rewrite "in const" from "nr" to "rn"
- if (StringRef(S).endswith("nr"))
+ if (StringRef(S).ends_with("nr"))
S.replace(S.end()-2, S.end(), "rn");
}
@@ -13519,7 +13519,7 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
Target->getTargetOpts().FeaturesAsWritten.begin(),
Target->getTargetOpts().FeaturesAsWritten.end());
} else {
- if (VersionStr.startswith("arch="))
+ if (VersionStr.starts_with("arch="))
TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
else if (VersionStr != "default")
Features.push_back((StringRef{"+"} + VersionStr).str());
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index c5c2edf1bfe3..527ea6042daa 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4150,6 +4150,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C,
assert(TSK != TSK_Undeclared &&
"Must specify the type of function template specialization");
assert((TemplateOrSpecialization.isNull() ||
+ getFriendObjectKind() != FOK_None ||
TSK == TSK_ExplicitSpecialization) &&
"Member specialization must be an explicit specialization");
FunctionTemplateSpecializationInfo *Info =
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 30a26d518386..24da6f2ef32b 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -1728,7 +1728,7 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
std::string TypeStr = PDecl->getASTContext().getUnqualifiedObjCPointerType(T).
getAsString(Policy);
Out << ' ' << TypeStr;
- if (!StringRef(TypeStr).endswith("*"))
+ if (!StringRef(TypeStr).ends_with("*"))
Out << ' ';
Out << *PDecl;
if (Policy.PolishForDeclaration)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f035c1419f4c..f6aeee1a4e93 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -8514,14 +8514,24 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
return false;
if (auto *FD = Info.CurrentCall->LambdaCaptureFields.lookup(VD)) {
+ const auto *MD = cast<CXXMethodDecl>(Info.CurrentCall->Callee);
+
+ // Static lambda function call operators can't have captures. We already
+ // diagnosed this, so bail out here.
+ if (MD->isStatic()) {
+ assert(Info.CurrentCall->This == nullptr &&
+ "This should not be set for a static call operator");
+ return false;
+ }
+
// Start with 'Result' referring to the complete closure object...
- if (auto *MD = cast<CXXMethodDecl>(Info.CurrentCall->Callee);
- MD->isExplicitObjectMemberFunction()) {
+ if (MD->isExplicitObjectMemberFunction()) {
APValue *RefValue =
Info.getParamSlot(Info.CurrentCall->Arguments, MD->getParamDecl(0));
Result.setFrom(Info.Ctx, *RefValue);
} else
Result = *Info.CurrentCall->This;
+
// ... then update it to refer to the field of the closure object
// that represents the capture.
if (!HandleLValueMember(Info, E, Result, FD))
diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
index 89b7708c0c2a..045263447cbc 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -61,6 +61,11 @@ ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
MD->getParent()->getCaptureFields(LC, LTC);
for (auto Cap : LC) {
+ // Static lambdas cannot have any captures. If this one does,
+ // it has already been diagnosed and we can only ignore it.
+ if (MD->isStatic())
+ return nullptr;
+
unsigned Offset = R->getField(Cap.second)->Offset;
this->LambdaCaptures[Cap.first] = {
Offset, Cap.second->getType()->isReferenceType()};
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index f7f8e6c73d84..e6b3097a80d8 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -222,6 +222,64 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitNE(PtrT, CE);
}
+ case CK_IntegralComplexToBoolean:
+ case CK_FloatingComplexToBoolean: {
+ std::optional<PrimType> ElemT =
+ classifyComplexElementType(SubExpr->getType());
+ if (!ElemT)
+ return false;
+ // We emit the expression (__real(E) != 0 || __imag(E) != 0)
+ // for us, that means (bool)E[0] || (bool)E[1]
+ if (!this->visit(SubExpr))
+ return false;
+ if (!this->emitConstUint8(0, CE))
+ return false;
+ if (!this->emitArrayElemPtrUint8(CE))
+ return false;
+ if (!this->emitLoadPop(*ElemT, CE))
+ return false;
+ if (*ElemT == PT_Float) {
+ if (!this->emitCastFloatingIntegral(PT_Bool, CE))
+ return false;
+ } else {
+ if (!this->emitCast(*ElemT, PT_Bool, CE))
+ return false;
+ }
+
+ // We now have the bool value of E[0] on the stack.
+ LabelTy LabelTrue = this->getLabel();
+ if (!this->jumpTrue(LabelTrue))
+ return false;
+
+ if (!this->emitConstUint8(1, CE))
+ return false;
+ if (!this->emitArrayElemPtrPopUint8(CE))
+ return false;
+ if (!this->emitLoadPop(*ElemT, CE))
+ return false;
+ if (*ElemT == PT_Float) {
+ if (!this->emitCastFloatingIntegral(PT_Bool, CE))
+ return false;
+ } else {
+ if (!this->emitCast(*ElemT, PT_Bool, CE))
+ return false;
+ }
+ // Leave the boolean value of E[1] on the stack.
+ LabelTy EndLabel = this->getLabel();
+ this->jump(EndLabel);
+
+ this->emitLabel(LabelTrue);
+ if (!this->emitPopPtr(CE))
+ return false;
+ if (!this->emitConstBool(true, CE))
+ return false;
+
+ this->fallthrough(EndLabel);
+ this->emitLabel(EndLabel);
+
+ return true;
+ }
+
case CK_ToVoid:
return discard(SubExpr);
@@ -258,6 +316,9 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
if (BO->isLogicalOp())
return this->VisitLogicalBinOp(BO);
+ if (BO->getType()->isAnyComplexType())
+ return this->VisitComplexBinOp(BO);
+
const Expr *LHS = BO->getLHS();
const Expr *RHS = BO->getRHS();
@@ -501,6 +562,107 @@ bool ByteCodeExprGen<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {
}
template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
+ assert(Initializing);
+
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
+ PrimType LHSElemT = *this->classifyComplexElementType(LHS->getType());
+ PrimType RHSElemT = *this->classifyComplexElementType(RHS->getType());
+
+ unsigned LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false);
+ unsigned RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false);
+ unsigned ResultOffset = ~0u;
+ if (!this->DiscardResult)
+ ResultOffset = this->allocateLocalPrimitive(E, PT_Ptr, true, false);
+
+ assert(LHSElemT == RHSElemT);
+
+ // Save result pointer in ResultOffset
+ if (!this->DiscardResult) {
+ if (!this->emitDupPtr(E))
+ return false;
+ if (!this->emitSetLocal(PT_Ptr, ResultOffset, E))
+ return false;
+ }
+
+ // Evaluate LHS and save value to LHSOffset.
+ if (!this->visit(LHS))
+ return false;
+ if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
+ return false;
+
+ // Same with RHS.
+ if (!this->visit(RHS))
+ return false;
+ if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
+ return false;
+
+ // Now we can get pointers to the LHS and RHS from the offsets above.
+ BinaryOperatorKind Op = E->getOpcode();
+ for (unsigned ElemIndex = 0; ElemIndex != 2; ++ElemIndex) {
+ // Result pointer for the store later.
+ if (!this->DiscardResult) {
+ if (!this->emitGetLocal(PT_Ptr, ResultOffset, E))
+ return false;
+ }
+
+ if (!this->emitGetLocal(PT_Ptr, LHSOffset, E))
+ return false;
+ if (!this->emitConstUint8(ElemIndex, E))
+ return false;
+ if (!this->emitArrayElemPtrPopUint8(E))
+ return false;
+ if (!this->emitLoadPop(LHSElemT, E))
+ return false;
+
+ if (!this->emitGetLocal(PT_Ptr, RHSOffset, E))
+ return false;
+ if (!this->emitConstUint8(ElemIndex, E))
+ return false;
+ if (!this->emitArrayElemPtrPopUint8(E))
+ return false;
+ if (!this->emitLoadPop(RHSElemT, E))
+ return false;
+
+ // The actual operation.
+ switch (Op) {
+ case BO_Add:
+ if (LHSElemT == PT_Float) {
+ if (!this->emitAddf(getRoundingMode(E), E))
+ return false;
+ } else {
+ if (!this->emitAdd(LHSElemT, E))
+ return false;
+ }
+ break;
+ case BO_Sub:
+ if (LHSElemT == PT_Float) {
+ if (!this->emitSubf(getRoundingMode(E), E))
+ return false;
+ } else {
+ if (!this->emitSub(LHSElemT, E))
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ if (!this->DiscardResult) {
+ // Initialize array element with the value we just computed.
+ if (!this->emitInitElemPop(LHSElemT, ElemIndex, E))
+ return false;
+ } else {
+ if (!this->emitPop(LHSElemT, E))
+ return false;
+ }
+ }
+ return true;
+}
+
+template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
QualType QT = E->getType();
@@ -671,6 +833,32 @@ bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
return true;
}
+ if (T->isAnyComplexType()) {
+ unsigned NumInits = E->getNumInits();
+ QualType ElemQT = E->getType()->getAs<ComplexType>()->getElementType();
+ PrimType ElemT = classifyPrim(ElemQT);
+ if (NumInits == 0) {
+ // Zero-initialize both elements.
+ for (unsigned I = 0; I < 2; ++I) {
+ if (!this->visitZeroInitializer(ElemT, ElemQT, E))
+ return false;
+ if (!this->emitInitElem(ElemT, I, E))
+ return false;
+ }
+ } else if (NumInits == 2) {
+ unsigned InitIndex = 0;
+ for (const Expr *Init : E->inits()) {
+ if (!this->visit(Init))
+ return false;
+
+ if (!this->emitInitElem(ElemT, InitIndex, E))
+ return false;
+ ++InitIndex;
+ }
+ }
+ return true;
+ }
+
return false;
}
@@ -1647,7 +1835,8 @@ template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
return this->discard(E);
// Create local variable to hold the return value.
- if (!E->isGLValue() && !classify(E->getType())) {
+ if (!E->isGLValue() && !E->getType()->isAnyComplexType() &&
+ !classify(E->getType())) {
std::optional<unsigned> LocalIndex = allocateLocal(E, /*IsExtended=*/true);
if (!LocalIndex)
return false;
@@ -1833,6 +2022,9 @@ bool ByteCodeExprGen<Emitter>::dereference(
return Indirect(*T);
}
+ if (LV->getType()->isAnyComplexType())
+ return visit(LV);
+
return false;
}
@@ -2092,15 +2284,33 @@ const Function *ByteCodeExprGen<Emitter>::getFunction(const FunctionDecl *FD) {
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *E) {
ExprScope<Emitter> RootScope(this);
- if (!visit(E))
- return false;
-
- if (E->getType()->isVoidType())
+ // Void expressions.
+ if (E->getType()->isVoidType()) {
+ if (!visit(E))
+ return false;
return this->emitRetVoid(E);
+ }
- if (std::optional<PrimType> T = classify(E))
+ // Expressions with a primitive return type.
+ if (std::optional<PrimType> T = classify(E)) {
+ if (!visit(E))
+ return false;
return this->emitRet(*T, E);
- return this->emitRetValue(E);
+ }
+
+ // Expressions with a composite return type.
+ // For us, that means everything we don't
+ // have a PrimType for.
+ if (std::optional<unsigned> LocalOffset = this->allocateLocal(E)) {
+ if (!this->visitLocalInitializer(E, *LocalOffset))
+ return false;
+
+ if (!this->emitGetPtrLocal(*LocalOffset, E))
+ return false;
+ return this->emitRetValue(E);
+ }
+
+ return false;
}
/// Toplevel visitDecl().
@@ -2550,8 +2760,36 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
if (!this->visit(SubExpr))
return false;
return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E);
- case UO_Real: // __real x
- case UO_Imag: // __imag x
+ case UO_Real: { // __real x
+ assert(!T);
+ if (!this->visit(SubExpr))
+ return false;
+ if (!this->emitConstUint8(0, E))
+ return false;
+ if (!this->emitArrayElemPtrPopUint8(E))
+ return false;
+
+ // Since our _Complex implementation does not map to a primitive type,
+ // we sometimes have to do the lvalue-to-rvalue conversion here manually.
+ if (!SubExpr->isLValue())
+ return this->emitLoadPop(classifyPrim(E->getType()), E);
+ return true;
+ }
+ case UO_Imag: { // __imag x
+ assert(!T);
+ if (!this->visit(SubExpr))
+ return false;
+ if (!this->emitConstUint8(1, E))
+ return false;
+ if (!this->emitArrayElemPtrPopUint8(E))
+ return false;
+
+ // Since our _Complex implementation does not map to a primitive type,
+ // we sometimes have to do the lvalue-to-rvalue conversion here manually.
+ if (!SubExpr->isLValue())
+ return this->emitLoadPop(classifyPrim(E->getType()), E);
+ return true;
+ }
case UO_Extension:
return this->delegate(SubExpr);
case UO_Coawait:
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index bc1d5d11a115..bbb13e97e725 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -65,6 +65,7 @@ public:
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitLogicalBinOp(const BinaryOperator *E);
bool VisitPointerArithBinOp(const BinaryOperator *E);
+ bool VisitComplexBinOp(const BinaryOperator *E);
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
bool VisitCallExpr(const CallExpr *E);
bool VisitBuiltinCallExpr(const CallExpr *E);
@@ -285,6 +286,14 @@ private:
}
bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);
+ std::optional<PrimType> classifyComplexElementType(QualType T) const {
+ assert(T->isAnyComplexType());
+
+ QualType ElemType = T->getAs<ComplexType>()->getElementType();
+
+ return this->classify(ElemType);
+ }
+
bool emitRecordDestruction(const Descriptor *Desc);
unsigned collectBaseOffset(const RecordType *BaseType,
const RecordType *DerivedType);
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index cb96e56fb5e1..17abb7163583 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -92,6 +92,9 @@ std::optional<PrimType> Context::classify(QualType T) const {
if (T->isBooleanType())
return PT_Bool;
+ if (T->isAnyComplexType())
+ return std::nullopt;
+
if (T->isSignedIntegerOrEnumerationType()) {
switch (Ctx.getIntWidth(T)) {
case 64:
@@ -168,7 +171,7 @@ bool Context::Run(State &Parent, const Function *Func, APValue &Result) {
}
// State gets destroyed here, so the Stk.clear() below doesn't accidentally
- // remove values the State's destructor might accedd.
+ // remove values the State's destructor might access.
}
Stk.clear();
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index 9bc42057c5f5..0ff0bde8fd17 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -208,6 +208,27 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
}
return Ok;
}
+
+ // Complex types.
+ if (const auto *CT = Ty->getAs<ComplexType>()) {
+ QualType ElemTy = CT->getElementType();
+ std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
+ assert(ElemT);
+
+ if (ElemTy->isIntegerType()) {
+ INT_TYPE_SWITCH(*ElemT, {
+ auto V1 = Ptr.atIndex(0).deref<T>();
+ auto V2 = Ptr.atIndex(1).deref<T>();
+ Result = APValue(V1.toAPSInt(), V2.toAPSInt());
+ return true;
+ });
+ } else if (ElemTy->isFloatingType()) {
+ Result = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
+ Ptr.atIndex(1).deref<Floating>().getAPFloat());
+ return true;
+ }
+ return false;
+ }
llvm_unreachable("invalid value to return");
};
diff --git a/clang/lib/AST/Interp/IntegralAP.h b/clang/lib/AST/Interp/IntegralAP.h
index 9019f32e6cef..d5f46409d231 100644
--- a/clang/lib/AST/Interp/IntegralAP.h
+++ b/clang/lib/AST/Interp/IntegralAP.h
@@ -182,17 +182,13 @@ public:
}
static bool increment(IntegralAP A, IntegralAP *R) {
- // FIXME: Implement.
- assert(false);
- *R = IntegralAP(A.V - 1);
- return false;
+ IntegralAP<Signed> One(1, A.bitWidth());
+ return add(A, One, A.bitWidth() + 1, R);
}
static bool decrement(IntegralAP A, IntegralAP *R) {
- // FIXME: Implement.
- assert(false);
- *R = IntegralAP(A.V - 1);
- return false;
+ IntegralAP<Signed> One(1, A.bitWidth());
+ return sub(A, One, A.bitWidth() + 1, R);
}
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 13b77e9a8772..a82d1c3c7c62 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -350,11 +350,6 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
}
if (!F->isConstexpr()) {
- // Don't emit anything if we're checking for a potential constant
- // expression. That will happen later when actually executing.
- if (S.checkingPotentialConstantExpression())
- return false;
-
const SourceLocation &Loc = S.Current->getLocation(OpPC);
if (S.getLangOpts().CPlusPlus11) {
const FunctionDecl *DiagDecl = F->getDecl();
@@ -371,13 +366,21 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
// FIXME: If DiagDecl is an implicitly-declared special member function
// or an inheriting constructor, we should be much more explicit about why
// it's not constexpr.
- if (CD && CD->isInheritingConstructor())
+ if (CD && CD->isInheritingConstructor()) {
S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
<< CD->getInheritedConstructor().getConstructor()->getParent();
- else
+ S.Note(DiagDecl->getLocation(), diag::note_declared_at);
+ } else {
+ // Don't emit anything if the function isn't defined and we're checking
+ // for a constant expression. It might be defined at the point we're
+ // actually calling it.
+ if (!DiagDecl->isDefined() && S.checkingPotentialConstantExpression())
+ return false;
+
S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
<< DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
- S.Note(DiagDecl->getLocation(), diag::note_declared_at);
+ S.Note(DiagDecl->getLocation(), diag::note_declared_at);
+ }
} else {
S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
}
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 4f7778bdd2ff..a240d74d6342 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1619,7 +1619,11 @@ bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
QualType Type = E->getType();
S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
- return S.noteUndefinedBehavior();
+ if (S.noteUndefinedBehavior()) {
+ S.Stk.push<T>(T(Result));
+ return true;
+ }
+ return false;
}
S.Stk.push<T>(T(Result));
@@ -1822,10 +1826,12 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
/// Just takes a pointer and checks if its' an incomplete
/// array type.
inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
- const Pointer &Ptr = S.Stk.peek<Pointer>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!Ptr.isUnknownSizeArray())
+ if (!Ptr.isUnknownSizeArray()) {
+ S.Stk.push<Pointer>(Ptr.atIndex(0));
return true;
+ }
const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp
index 4384ace6b6be..b55b1569a259 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -579,6 +579,40 @@ static bool interp__builtin_expect(InterpState &S, CodePtr OpPC,
return true;
}
+/// rotateleft(value, amount)
+static bool interp__builtin_rotate(InterpState &S, CodePtr OpPC,
+ const InterpFrame *Frame,
+ const Function *Func, const CallExpr *Call,
+ bool Right) {
+ PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+ assert(ArgT == *S.getContext().classify(Call->getArg(1)->getType()));
+
+ APSInt Amount = peekToAPSInt(S.Stk, ArgT);
+ APSInt Value = peekToAPSInt(S.Stk, ArgT, align(primSize(ArgT)) * 2);
+
+ APSInt Result;
+ if (Right)
+ Result = APSInt(Value.rotr(Amount.urem(Value.getBitWidth())),
+ /*IsUnsigned=*/true);
+ else // Left.
+ Result = APSInt(Value.rotl(Amount.urem(Value.getBitWidth())),
+ /*IsUnsigned=*/true);
+
+ pushAPSInt(S, Result);
+ return true;
+}
+
+static bool interp__builtin_ffs(InterpState &S, CodePtr OpPC,
+ const InterpFrame *Frame, const Function *Func,
+ const CallExpr *Call) {
+ PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+ APSInt Value = peekToAPSInt(S.Stk, ArgT);
+
+ uint64_t N = Value.countr_zero();
+ pushInt(S, N == Value.getBitWidth() ? 0 : N + 1);
+ return true;
+}
+
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
InterpFrame *Frame = S.Current;
@@ -754,6 +788,39 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;
+ case Builtin::BI__builtin_rotateleft8:
+ case Builtin::BI__builtin_rotateleft16:
+ case Builtin::BI__builtin_rotateleft32:
+ case Builtin::BI__builtin_rotateleft64:
+ case Builtin::BI_rotl8: // Microsoft variants of rotate left
+ case Builtin::BI_rotl16:
+ case Builtin::BI_rotl:
+ case Builtin::BI_lrotl:
+ case Builtin::BI_rotl64:
+ if (!interp__builtin_rotate(S, OpPC, Frame, F, Call, /*Right=*/false))
+ return false;
+ break;
+
+ case Builtin::BI__builtin_rotateright8:
+ case Builtin::BI__builtin_rotateright16:
+ case Builtin::BI__builtin_rotateright32:
+ case Builtin::BI__builtin_rotateright64:
+ case Builtin::BI_rotr8: // Microsoft variants of rotate right
+ case Builtin::BI_rotr16:
+ case Builtin::BI_rotr:
+ case Builtin::BI_lrotr:
+ case Builtin::BI_rotr64:
+ if (!interp__builtin_rotate(S, OpPC, Frame, F, Call, /*Right=*/true))
+ return false;
+ break;
+
+ case Builtin::BI__builtin_ffs:
+ case Builtin::BI__builtin_ffsl:
+ case Builtin::BI__builtin_ffsll:
+ if (!interp__builtin_ffs(S, OpPC, Frame, F, Call))
+ return false;
+ break;
+
default:
return false;
}
diff --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp
index b06923114c7a..d460d7ea3710 100644
--- a/clang/lib/AST/Interp/InterpFrame.cpp
+++ b/clang/lib/AST/Interp/InterpFrame.cpp
@@ -228,7 +228,7 @@ Pointer InterpFrame::getParamPointer(unsigned Off) {
SourceInfo InterpFrame::getSource(CodePtr PC) const {
// Implicitly created functions don't have any code we could point at,
// so return the call site.
- if (Func && Func->getDecl()->isImplicit() && Caller)
+ if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
return Caller->getSource(RetPC);
return S.getSource(Func, PC);
@@ -243,7 +243,7 @@ SourceLocation InterpFrame::getLocation(CodePtr PC) const {
}
SourceRange InterpFrame::getRange(CodePtr PC) const {
- if (Func && Func->getDecl()->isImplicit() && Caller)
+ if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
return Caller->getRange(RetPC);
return S.getRange(Func, PC);
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 64c971912a91..d3a6b61fd2be 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -147,7 +147,7 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
// If the label isn't literal, or if this is an alias for an LLVM intrinsic,
// do not add a "\01" prefix.
- if (!ALA->getIsLiteralLabel() || ALA->getLabel().startswith("llvm.")) {
+ if (!ALA->getIsLiteralLabel() || ALA->getLabel().starts_with("llvm.")) {
Out << ALA->getLabel();
return;
}
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 50ab6ea59be9..8346ad87b409 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -63,7 +63,7 @@ struct msvc_hashing_ostream : public llvm::raw_svector_ostream {
: llvm::raw_svector_ostream(Buffer), OS(OS) {}
~msvc_hashing_ostream() override {
StringRef MangledName = str();
- bool StartsWithEscape = MangledName.startswith("\01");
+ bool StartsWithEscape = MangledName.starts_with("\01");
if (StartsWithEscape)
MangledName = MangledName.drop_front(1);
if (MangledName.size() < 4096) {
@@ -3809,14 +3809,14 @@ void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator(
llvm::raw_svector_ostream Stream(VFTableMangling);
mangleCXXVFTable(Derived, BasePath, Stream);
- if (VFTableMangling.startswith("??@")) {
- assert(VFTableMangling.endswith("@"));
+ if (VFTableMangling.starts_with("??@")) {
+ assert(VFTableMangling.ends_with("@"));
Out << VFTableMangling << "??_R4@";
return;
}
- assert(VFTableMangling.startswith("??_7") ||
- VFTableMangling.startswith("??_S"));
+ assert(VFTableMangling.starts_with("??_7") ||
+ VFTableMangling.starts_with("??_S"));
Out << "??_R4" << VFTableMangling.str().drop_front(4);
}
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index f0b9d0ecaf23..3b09ca40bd2a 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -140,7 +140,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
// Set the privacy flag if the privacy annotation in the
// comma-delimited segment is at least as strict as the privacy
// annotations in previous comma-delimited segments.
- if (MatchedStr.startswith("mask")) {
+ if (MatchedStr.starts_with("mask")) {
StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);
unsigned Size = MaskType.size();
if (Warn && (Size == 0 || Size > 8))
diff --git a/clang/lib/AST/RawCommentList.cpp b/clang/lib/AST/RawCommentList.cpp
index c3beb2322888..dffa007b6588 100644
--- a/clang/lib/AST/RawCommentList.cpp
+++ b/clang/lib/AST/RawCommentList.cpp
@@ -141,8 +141,8 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR,
Kind = K.first;
IsTrailingComment |= K.second;
- IsAlmostTrailingComment = RawText.startswith("//<") ||
- RawText.startswith("/*<");
+ IsAlmostTrailingComment =
+ RawText.starts_with("//<") || RawText.starts_with("/*<");
} else {
Kind = RCK_Merged;
IsTrailingComment =
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index a51c8b938f41..706991f4fb50 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2942,8 +2942,8 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
}
if (!FoundBase) {
- if (MDCUsesEBO && BaseDecl->isEmpty()) {
- assert(BaseLayout.getNonVirtualSize() == CharUnits::Zero());
+ if (MDCUsesEBO && BaseDecl->isEmpty() &&
+ (BaseLayout.getNonVirtualSize() == CharUnits::Zero())) {
BaseOffset = CharUnits::Zero();
} else {
// Otherwise, lay the base out at the end of the MDC.
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index c31fb48a2add..afd05881cb16 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -811,11 +811,12 @@ std::string MSAsmStmt::generateAsmString(const ASTContext &C) const {
StringRef Instruction = Pieces[I];
// For vex/vex2/vex3/evex masm style prefix, convert it to att style
// since we don't support masm style prefix in backend.
- if (Instruction.startswith("vex "))
+ if (Instruction.starts_with("vex "))
MSAsmString += '{' + Instruction.substr(0, 3).str() + '}' +
Instruction.substr(3).str();
- else if (Instruction.startswith("vex2 ") ||
- Instruction.startswith("vex3 ") || Instruction.startswith("evex "))
+ else if (Instruction.starts_with("vex2 ") ||
+ Instruction.starts_with("vex3 ") ||
+ Instruction.starts_with("evex "))
MSAsmString += '{' + Instruction.substr(0, 4).str() + '}' +
Instruction.substr(4).str();
else
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 435bbdeda220..8ed213ca2ce0 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -480,11 +480,11 @@ HasNameMatcher::HasNameMatcher(std::vector<std::string> N)
static bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) {
StringRef Name = FullName;
- if (!Name.endswith(Suffix))
+ if (!Name.ends_with(Suffix))
return false;
Name = Name.drop_back(Suffix.size());
if (!Name.empty()) {
- if (!Name.endswith("::"))
+ if (!Name.ends_with("::"))
return false;
Name = Name.drop_back(2);
}
@@ -530,7 +530,7 @@ public:
PatternSet(ArrayRef<std::string> Names) {
Patterns.reserve(Names.size());
for (StringRef Name : Names)
- Patterns.push_back({Name, Name.startswith("::")});
+ Patterns.push_back({Name, Name.starts_with("::")});
}
/// Consumes the name suffix from each pattern in the set and removes the ones
@@ -652,11 +652,11 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const {
const StringRef FullName = OS.str();
for (const StringRef Pattern : Names) {
- if (Pattern.startswith("::")) {
+ if (Pattern.starts_with("::")) {
if (FullName == Pattern)
return true;
- } else if (FullName.endswith(Pattern) &&
- FullName.drop_back(Pattern.size()).endswith("::")) {
+ } else if (FullName.ends_with(Pattern) &&
+ FullName.drop_back(Pattern.size()).ends_with("::")) {
return true;
}
}
diff --git a/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/clang/lib/ASTMatchers/Dynamic/Parser.cpp
index 33a10fe838a6..27096a83b8dd 100644
--- a/clang/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -187,10 +187,10 @@ private:
break;
++TokenLength;
}
- if (TokenLength == 4 && Code.startswith("true")) {
+ if (TokenLength == 4 && Code.starts_with("true")) {
Result.Kind = TokenInfo::TK_Literal;
Result.Value = true;
- } else if (TokenLength == 5 && Code.startswith("false")) {
+ } else if (TokenLength == 5 && Code.starts_with("false")) {
Result.Kind = TokenInfo::TK_Literal;
Result.Value = false;
} else {
@@ -737,7 +737,7 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
// Completions minus the prefix.
void Parser::addCompletion(const TokenInfo &CompToken,
const MatcherCompletion& Completion) {
- if (StringRef(Completion.TypedText).startswith(CompToken.Text) &&
+ if (StringRef(Completion.TypedText).starts_with(CompToken.Text) &&
Completion.Specificity > 0) {
Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),
Completion.MatcherDecl, Completion.Specificity);
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index 13ec9b65c9f0..127e843d4ead 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -726,8 +726,8 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
FF = nullptr;
break;
}
- } else if (Name.startswith("OSAtomicCompareAndSwap") ||
- Name.startswith("objc_atomicCompareAndSwap")) {
+ } else if (Name.starts_with("OSAtomicCompareAndSwap") ||
+ Name.starts_with("objc_atomicCompareAndSwap")) {
FF = create_OSAtomicCompareAndSwap;
} else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) {
FF = create_call_once;
diff --git a/clang/lib/Analysis/CallGraph.cpp b/clang/lib/Analysis/CallGraph.cpp
index 59cc939b6fd1..f892980ed313 100644
--- a/clang/lib/Analysis/CallGraph.cpp
+++ b/clang/lib/Analysis/CallGraph.cpp
@@ -168,7 +168,7 @@ bool CallGraph::includeCalleeInGraph(const Decl *D) {
return false;
IdentifierInfo *II = FD->getIdentifier();
- if (II && II->getName().startswith("__inline"))
+ if (II && II->getName().starts_with("__inline"))
return false;
}
diff --git a/clang/lib/Analysis/CalledOnceCheck.cpp b/clang/lib/Analysis/CalledOnceCheck.cpp
index 5b4fc24b6f0e..04c5f6aa9c74 100644
--- a/clang/lib/Analysis/CalledOnceCheck.cpp
+++ b/clang/lib/Analysis/CalledOnceCheck.cpp
@@ -973,7 +973,7 @@ private:
/// Return true if the given name has conventional suffixes.
static bool hasConventionalSuffix(llvm::StringRef Name) {
return llvm::any_of(CONVENTIONAL_SUFFIXES, [Name](llvm::StringRef Suffix) {
- return Name.endswith(Suffix);
+ return Name.ends_with(Suffix);
});
}
diff --git a/clang/lib/Analysis/CocoaConventions.cpp b/clang/lib/Analysis/CocoaConventions.cpp
index 571d72e1a841..836859c22345 100644
--- a/clang/lib/Analysis/CocoaConventions.cpp
+++ b/clang/lib/Analysis/CocoaConventions.cpp
@@ -26,10 +26,10 @@ bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
// Recursively walk the typedef stack, allowing typedefs of reference types.
while (const TypedefType *TD = RetTy->getAs<TypedefType>()) {
StringRef TDName = TD->getDecl()->getIdentifier()->getName();
- if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
+ if (TDName.starts_with(Prefix) && TDName.ends_with("Ref"))
return true;
// XPC unfortunately uses CF-style function names, but aren't CF types.
- if (TDName.startswith("xpc_"))
+ if (TDName.starts_with("xpc_"))
return false;
RetTy = TD->getDecl()->getUnderlyingType();
}
@@ -43,7 +43,7 @@ bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
return false;
// Does the name start with the prefix?
- return Name.startswith(Prefix);
+ return Name.starts_with(Prefix);
}
/// Returns true when the passed-in type is a CF-style reference-counted
@@ -127,10 +127,9 @@ bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
// Scan for *lowercase* 'reate' or 'opy', followed by no lowercase
// character.
StringRef suffix = functionName.substr(it - start);
- if (suffix.startswith("reate")) {
+ if (suffix.starts_with("reate")) {
it += 5;
- }
- else if (suffix.startswith("opy")) {
+ } else if (suffix.starts_with("opy")) {
it += 3;
} else {
// Keep scanning.
diff --git a/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp
index f49087ababc4..5ac71e1d6bf6 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp
@@ -43,7 +43,7 @@ bool isCheckLikeMethod(llvm::SmallDenseSet<const CXXMethodDecl *> &CheckDecls,
return false;
for (const CXXMethodDecl *M : ParentClass->methods())
- if (M->getDeclName().isIdentifier() && M->getName().endswith("Check"))
+ if (M->getDeclName().isIdentifier() && M->getName().ends_with("Check"))
CheckDecls.insert(M);
}
diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp
index 4cbeb0c35b6f..6f50d95b179f 100644
--- a/clang/lib/Analysis/RetainSummaryManager.cpp
+++ b/clang/lib/Analysis/RetainSummaryManager.cpp
@@ -174,7 +174,7 @@ static bool isOSObjectPtr(QualType QT) {
}
static bool isISLObjectRef(QualType Ty) {
- return StringRef(Ty.getAsString()).startswith("isl_");
+ return StringRef(Ty.getAsString()).starts_with("isl_");
}
static bool isOSIteratorSubclass(const Decl *D) {
@@ -255,13 +255,13 @@ RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD,
// TODO: Add support for the slightly common *Matching(table) idiom.
// Cf. IOService::nameMatching() etc. - these function have an unusual
// contract of returning at +0 or +1 depending on their last argument.
- if (FName.endswith("Matching")) {
+ if (FName.ends_with("Matching")) {
return getPersistentStopSummary();
}
// All objects returned with functions *not* starting with 'get',
// or iterators, are returned at +1.
- if ((!FName.startswith("get") && !FName.startswith("Get")) ||
+ if ((!FName.starts_with("get") && !FName.starts_with("Get")) ||
isOSIteratorSubclass(PD)) {
return getOSSummaryCreateRule(FD);
} else {
@@ -392,9 +392,9 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
return getPersistentSummary(RetEffect::MakeNoRet(),
ScratchArgs,
ArgEffect(DoNothing), ArgEffect(DoNothing));
- } else if (FName.startswith("NSLog")) {
+ } else if (FName.starts_with("NSLog")) {
return getDoNothingSummary();
- } else if (FName.startswith("NS") && FName.contains("Insert")) {
+ } else if (FName.starts_with("NS") && FName.contains("Insert")) {
// Allowlist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
// be deallocated by NSMapRemove.
ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
@@ -453,9 +453,9 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
// Check for release functions, the only kind of functions that we care
// about that don't return a pointer type.
- if (FName.startswith("CG") || FName.startswith("CF")) {
+ if (FName.starts_with("CG") || FName.starts_with("CF")) {
// Test for 'CGCF'.
- FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
+ FName = FName.substr(FName.starts_with("CGCF") ? 4 : 2);
if (isRelease(FD, FName))
return getUnarySummary(FT, DecRef);
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290..70eec1cee57f 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,46 @@ public:
}
};
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+ static constexpr const char *const UUCAddAssignTag =
+ "PointerAddAssignUnderUUC";
+ static constexpr const char *const OffsetTag = "Offset";
+
+ const BinaryOperator *Node; // the `Ptr += n` node
+ const Expr *Offset = nullptr;
+
+public:
+ UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+ : FixableGadget(Kind::UUCAddAssign),
+ Node(Result.Nodes.getNodeAs<BinaryOperator>(UUCAddAssignTag)),
+ Offset(Result.Nodes.getNodeAs<Expr>(OffsetTag)) {
+ assert(Node != nullptr && "Expecting a non-null matching result");
+ }
+
+ static bool classof(const Gadget *G) {
+ return G->getKind() == Kind::UUCAddAssign;
+ }
+
+ static Matcher matcher() {
+ return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+ binaryOperator(hasOperatorName("+="),
+ hasLHS(declRefExpr(toSupportedVariable())),
+ hasRHS(expr().bind(OffsetTag)))
+ .bind(UUCAddAssignTag)))));
+ }
+
+ virtual std::optional<FixItList> getFixits(const Strategy &S) const override;
+
+ virtual const Stmt *getBaseStmt() const override { return Node; }
+
+ virtual DeclUseList getClaimedVarUseSites() const override {
+ return {dyn_cast<DeclRefExpr>(Node->getLHS())};
+ }
+};
+
// Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
// ptr)`:
class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1312,6 +1352,16 @@ PointerInitGadget::getFixits(const Strategy &S) const {
return std::nullopt;
}
+static bool isNonNegativeIntegerExpr(const Expr *Expr, const VarDecl *VD,
+ const ASTContext &Ctx) {
+ if (auto ConstVal = Expr->getIntegerConstantExpr(Ctx)) {
+ if (ConstVal->isNegative())
+ return false;
+ } else if (!Expr->getType()->isUnsignedIntegerType())
+ return false;
+ return true;
+}
+
std::optional<FixItList>
ULCArraySubscriptGadget::getFixits(const Strategy &S) const {
if (const auto *DRE =
@@ -1319,14 +1369,12 @@ ULCArraySubscriptGadget::getFixits(const Strategy &S) const {
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
switch (S.lookup(VD)) {
case Strategy::Kind::Span: {
+
// If the index has a negative constant value, we give up as no valid
// fix-it can be generated:
const ASTContext &Ctx = // FIXME: we need ASTContext to be passed in!
VD->getASTContext();
- if (auto ConstVal = Node->getIdx()->getIntegerConstantExpr(Ctx)) {
- if (ConstVal->isNegative())
- return std::nullopt;
- } else if (!Node->getIdx()->getType()->isUnsignedIntegerType())
+ if (!isNonNegativeIntegerExpr(Node->getIdx(), VD, Ctx))
return std::nullopt;
// no-op is a good fix-it, otherwise
return FixItList{};
@@ -1405,10 +1453,8 @@ static std::optional<SourceLocation> getPastLoc(const NodeTy *Node,
const LangOptions &LangOpts) {
SourceLocation Loc =
Lexer::getLocForEndOfToken(Node->getEndLoc(), 0, SM, LangOpts);
-
if (Loc.isValid())
return Loc;
-
return std::nullopt;
}
@@ -1488,7 +1534,7 @@ static bool hasUnsupportedSpecifiers(const VarDecl *VD,
// returned by this function is the last location of the last token.
static SourceRange getSourceRangeToTokenEnd(const Decl *D,
const SourceManager &SM,
- LangOptions LangOpts) {
+ const LangOptions &LangOpts) {
SourceLocation Begin = D->getBeginLoc();
SourceLocation
End = // `D->getEndLoc` should always return the starting location of the
@@ -1766,6 +1812,47 @@ fixUPCAddressofArraySubscriptWithSpan(const UnaryOperator *Node) {
FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
}
+std::optional<FixItList>
+UUCAddAssignGadget::getFixits(const Strategy &S) const {
+ DeclUseList DREs = getClaimedVarUseSites();
+
+ if (DREs.size() != 1)
+ return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
+ if (S.lookup(VD) == Strategy::Kind::Span) {
+ FixItList Fixes;
+
+ const Stmt *AddAssignNode = getBaseStmt();
+ StringRef varName = VD->getName();
+ const ASTContext &Ctx = VD->getASTContext();
+
+ if (!isNonNegativeIntegerExpr(Offset, VD, Ctx))
+ return std::nullopt;
+
+ // To transform UUC(p += n) to UUC(p = p.subspan(..)):
+ bool NotParenExpr =
+ (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
+ std::string SS = varName.str() + " = " + varName.str() + ".subspan";
+ if (NotParenExpr)
+ SS += "(";
+
+ std::optional<SourceLocation> AddAssignLocation = getEndCharLoc(
+ AddAssignNode, Ctx.getSourceManager(), Ctx.getLangOpts());
+ if (!AddAssignLocation)
+ return std::nullopt;
+
+ Fixes.push_back(FixItHint::CreateReplacement(
+ SourceRange(AddAssignNode->getBeginLoc(), Node->getOperatorLoc()),
+ SS));
+ if (NotParenExpr)
+ Fixes.push_back(FixItHint::CreateInsertion(
+ Offset->getEndLoc().getLocWithOffset(1), ")"));
+ return Fixes;
+ }
+ }
+ return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
std::optional<FixItList> UPCPreIncrementGadget::getFixits(const Strategy &S) const {
DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index bb495216ca93..44a4f1890d39 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -33,7 +33,7 @@ int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
const TargetInfo &Target, const LangOptions &LangOpts) {
StringRef Name = Attr->getName();
// Normalize the attribute name, __foo__ becomes foo.
- if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
+ if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__"))
Name = Name.substr(2, Name.size() - 4);
// Normalize the scope name, but only for gnu and clang attributes.
@@ -103,8 +103,8 @@ static StringRef normalizeAttrName(const IdentifierInfo *Name,
(NormalizedScopeName.empty() || NormalizedScopeName == "gnu" ||
NormalizedScopeName == "clang"));
StringRef AttrName = Name->getName();
- if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") &&
- AttrName.endswith("__"))
+ if (ShouldNormalize && AttrName.size() >= 4 && AttrName.starts_with("__") &&
+ AttrName.ends_with("__"))
AttrName = AttrName.slice(2, AttrName.size() - 2);
return AttrName;
diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp
index 65840b9f2025..1b1da6a1356f 100644
--- a/clang/lib/Basic/Cuda.cpp
+++ b/clang/lib/Basic/Cuda.cpp
@@ -39,6 +39,8 @@ static const CudaVersionMapEntry CudaNameVersionMap[] = {
CUDA_ENTRY(11, 8),
CUDA_ENTRY(12, 0),
CUDA_ENTRY(12, 1),
+ CUDA_ENTRY(12, 2),
+ CUDA_ENTRY(12, 3),
{"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits<int>::max())},
{"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone.
};
@@ -93,6 +95,7 @@ static const CudaArchToStringMap arch_names[] = {
SM(87), // Jetson/Drive AGX Orin
SM(89), // Ada Lovelace
SM(90), // Hopper
+ SM(90a), // Hopper
GFX(600), // gfx600
GFX(601), // gfx601
GFX(602), // gfx602
@@ -209,6 +212,8 @@ CudaVersion MinVersionForCudaArch(CudaArch A) {
case CudaArch::SM_89:
case CudaArch::SM_90:
return CudaVersion::CUDA_118;
+ case CudaArch::SM_90a:
+ return CudaVersion::CUDA_120;
default:
llvm_unreachable("invalid enum");
}
diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp
index e5667d57f8cf..6c7bd50eefb7 100644
--- a/clang/lib/Basic/DiagnosticIDs.cpp
+++ b/clang/lib/Basic/DiagnosticIDs.cpp
@@ -853,5 +853,5 @@ bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
unsigned cat = getCategoryNumberForDiag(DiagID);
- return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
+ return DiagnosticIDs::getCategoryNameFromID(cat).starts_with("ARC ");
}
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 38150d1640d7..5902c6dc3ce0 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -604,7 +604,7 @@ LLVM_DUMP_METHOD void Selector::dump() const { print(llvm::errs()); }
static bool startsWithWord(StringRef name, StringRef word) {
if (name.size() < word.size()) return false;
return ((name.size() == word.size() || !isLowercase(name[word.size()])) &&
- name.startswith(word));
+ name.starts_with(word));
}
ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
@@ -742,7 +742,7 @@ SelectorTable::constructSetterSelector(IdentifierTable &Idents,
std::string SelectorTable::getPropertyNameFromSetterSelector(Selector Sel) {
StringRef Name = Sel.getNameForSlot(0);
- assert(Name.startswith("set") && "invalid setter name");
+ assert(Name.starts_with("set") && "invalid setter name");
return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str();
}
diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp
index e4ac1abf12a7..925217431d4d 100644
--- a/clang/lib/Basic/Module.cpp
+++ b/clang/lib/Basic/Module.cpp
@@ -89,7 +89,7 @@ static bool isPlatformEnvironment(const TargetInfo &Target, StringRef Feature) {
// where both are valid examples of the same platform+environment but in the
// variant (2) the simulator is hardcoded as part of the platform name. Both
// forms above should match for "iossimulator" requirement.
- if (Target.getTriple().isOSDarwin() && PlatformEnv.endswith("simulator"))
+ if (Target.getTriple().isOSDarwin() && PlatformEnv.ends_with("simulator"))
return PlatformEnv == Feature || CmpPlatformEnv(PlatformEnv, Feature);
return PlatformEnv == Feature;
@@ -166,7 +166,8 @@ bool Module::isForBuilding(const LangOptions &LangOpts) const {
// for either.
if (!LangOpts.isCompilingModule() && getTopLevelModule()->IsFramework &&
CurrentModule == LangOpts.ModuleName &&
- !CurrentModule.endswith("_Private") && TopLevelName.endswith("_Private"))
+ !CurrentModule.ends_with("_Private") &&
+ TopLevelName.ends_with("_Private"))
TopLevelName = TopLevelName.drop_back(8);
return TopLevelName == CurrentModule;
diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp
index 3476103cc39d..1cae7b937bc6 100644
--- a/clang/lib/Basic/Sarif.cpp
+++ b/clang/lib/Basic/Sarif.cpp
@@ -74,7 +74,7 @@ static std::string fileNameToURI(StringRef Filename) {
// Get the root name to see if it has a URI authority.
StringRef Root = sys::path::root_name(Filename);
- if (Root.startswith("//")) {
+ if (Root.starts_with("//")) {
// There is an authority, so add it to the URI.
Ret += Root.drop_front(2).str();
} else if (!Root.empty()) {
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 6cd5d618a4ac..96b3ad9ba2f2 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -551,26 +551,26 @@ ParsedTargetAttr TargetInfo::parseTargetAttr(StringRef Features) const {
// TODO: Support the fpmath option. It will require checking
// overall feature validity for the function with the rest of the
// attributes on the function.
- if (Feature.startswith("fpmath="))
+ if (Feature.starts_with("fpmath="))
continue;
- if (Feature.startswith("branch-protection=")) {
+ if (Feature.starts_with("branch-protection=")) {
Ret.BranchProtection = Feature.split('=').second.trim();
continue;
}
// While we're here iterating check for a different target cpu.
- if (Feature.startswith("arch=")) {
+ if (Feature.starts_with("arch=")) {
if (!Ret.CPU.empty())
Ret.Duplicate = "arch=";
else
Ret.CPU = Feature.split("=").second.trim();
- } else if (Feature.startswith("tune=")) {
+ } else if (Feature.starts_with("tune=")) {
if (!Ret.Tune.empty())
Ret.Duplicate = "tune=";
else
Ret.Tune = Feature.split("=").second.trim();
- } else if (Feature.startswith("no-"))
+ } else if (Feature.starts_with("no-"))
Ret.Features.push_back("-" + Feature.split("-").second.str());
else
Ret.Features.push_back("+" + Feature.str());
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index c31f2e0bee54..def16c032c86 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -574,11 +574,12 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
else if (*ArchInfo == llvm::AArch64::ARMV9_5A)
getTargetDefinesARMV95A(Opts, Builder);
- // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work.
+ // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8|16) builtins work.
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16");
// Allow detection of fast FMA support.
Builder.defineMacro("__FP_FAST_FMA", "1");
@@ -1061,7 +1062,7 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
else
// Pushing the original feature string to give a sema error later on
// when they get checked.
- if (Feature.startswith("no"))
+ if (Feature.starts_with("no"))
Features.push_back("-" + Feature.drop_front(2).str());
else
Features.push_back("+" + Feature.str());
@@ -1070,15 +1071,15 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
for (auto &Feature : AttrFeatures) {
Feature = Feature.trim();
- if (Feature.startswith("fpmath="))
+ if (Feature.starts_with("fpmath="))
continue;
- if (Feature.startswith("branch-protection=")) {
+ if (Feature.starts_with("branch-protection=")) {
Ret.BranchProtection = Feature.split('=').second.trim();
continue;
}
- if (Feature.startswith("arch=")) {
+ if (Feature.starts_with("arch=")) {
if (FoundArch)
Ret.Duplicate = "arch=";
FoundArch = true;
@@ -1094,7 +1095,7 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
Ret.Features.push_back(AI->ArchFeature.str());
// Add any extra features, after the +
SplitAndAddFeatures(Split.second, Ret.Features);
- } else if (Feature.startswith("cpu=")) {
+ } else if (Feature.starts_with("cpu=")) {
if (!Ret.CPU.empty())
Ret.Duplicate = "cpu=";
else {
@@ -1105,14 +1106,14 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
Ret.CPU = Split.first;
SplitAndAddFeatures(Split.second, Ret.Features);
}
- } else if (Feature.startswith("tune=")) {
+ } else if (Feature.starts_with("tune=")) {
if (!Ret.Tune.empty())
Ret.Duplicate = "tune=";
else
Ret.Tune = Feature.split("=").second.trim();
- } else if (Feature.startswith("+")) {
+ } else if (Feature.starts_with("+")) {
SplitAndAddFeatures(Feature, Ret.Features);
- } else if (Feature.startswith("no-")) {
+ } else if (Feature.starts_with("no-")) {
StringRef FeatureName =
llvm::AArch64::getArchExtFeature(Feature.split("-").second);
if (!FeatureName.empty())
diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp
index 409ae32ab424..6f3a4908623d 100644
--- a/clang/lib/Basic/Targets/AMDGPU.cpp
+++ b/clang/lib/Basic/Targets/AMDGPU.cpp
@@ -32,55 +32,56 @@ static const char *const DataLayoutStringR600 =
static const char *const DataLayoutStringAMDGCN =
"e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32"
- "-p7:160:256:256:32-p8:128:128-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
+ "-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:"
+ "32-v48:64-v96:128"
"-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1"
- "-ni:7:8";
+ "-ni:7:8:9";
const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = {
- Generic, // Default
- Global, // opencl_global
- Local, // opencl_local
- Constant, // opencl_constant
- Private, // opencl_private
- Generic, // opencl_generic
- Global, // opencl_global_device
- Global, // opencl_global_host
- Global, // cuda_device
- Constant, // cuda_constant
- Local, // cuda_shared
- Global, // sycl_global
- Global, // sycl_global_device
- Global, // sycl_global_host
- Local, // sycl_local
- Private, // sycl_private
- Generic, // ptr32_sptr
- Generic, // ptr32_uptr
- Generic, // ptr64
- Generic, // hlsl_groupshared
+ llvm::AMDGPUAS::FLAT_ADDRESS, // Default
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // opencl_global
+ llvm::AMDGPUAS::LOCAL_ADDRESS, // opencl_local
+ llvm::AMDGPUAS::CONSTANT_ADDRESS, // opencl_constant
+ llvm::AMDGPUAS::PRIVATE_ADDRESS, // opencl_private
+ llvm::AMDGPUAS::FLAT_ADDRESS, // opencl_generic
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // opencl_global_device
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // opencl_global_host
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // cuda_device
+ llvm::AMDGPUAS::CONSTANT_ADDRESS, // cuda_constant
+ llvm::AMDGPUAS::LOCAL_ADDRESS, // cuda_shared
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // sycl_global
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // sycl_global_device
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // sycl_global_host
+ llvm::AMDGPUAS::LOCAL_ADDRESS, // sycl_local
+ llvm::AMDGPUAS::PRIVATE_ADDRESS, // sycl_private
+ llvm::AMDGPUAS::FLAT_ADDRESS, // ptr32_sptr
+ llvm::AMDGPUAS::FLAT_ADDRESS, // ptr32_uptr
+ llvm::AMDGPUAS::FLAT_ADDRESS, // ptr64
+ llvm::AMDGPUAS::FLAT_ADDRESS, // hlsl_groupshared
};
const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
- Private, // Default
- Global, // opencl_global
- Local, // opencl_local
- Constant, // opencl_constant
- Private, // opencl_private
- Generic, // opencl_generic
- Global, // opencl_global_device
- Global, // opencl_global_host
- Global, // cuda_device
- Constant, // cuda_constant
- Local, // cuda_shared
+ llvm::AMDGPUAS::PRIVATE_ADDRESS, // Default
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // opencl_global
+ llvm::AMDGPUAS::LOCAL_ADDRESS, // opencl_local
+ llvm::AMDGPUAS::CONSTANT_ADDRESS, // opencl_constant
+ llvm::AMDGPUAS::PRIVATE_ADDRESS, // opencl_private
+ llvm::AMDGPUAS::FLAT_ADDRESS, // opencl_generic
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // opencl_global_device
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // opencl_global_host
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // cuda_device
+ llvm::AMDGPUAS::CONSTANT_ADDRESS, // cuda_constant
+ llvm::AMDGPUAS::LOCAL_ADDRESS, // cuda_shared
// SYCL address space values for this map are dummy
- Generic, // sycl_global
- Generic, // sycl_global_device
- Generic, // sycl_global_host
- Generic, // sycl_local
- Generic, // sycl_private
- Generic, // ptr32_sptr
- Generic, // ptr32_uptr
- Generic, // ptr64
- Generic, // hlsl_groupshared
+ llvm::AMDGPUAS::FLAT_ADDRESS, // sycl_global
+ llvm::AMDGPUAS::FLAT_ADDRESS, // sycl_global_device
+ llvm::AMDGPUAS::FLAT_ADDRESS, // sycl_global_host
+ llvm::AMDGPUAS::FLAT_ADDRESS, // sycl_local
+ llvm::AMDGPUAS::FLAT_ADDRESS, // sycl_private
+ llvm::AMDGPUAS::FLAT_ADDRESS, // ptr32_sptr
+ llvm::AMDGPUAS::FLAT_ADDRESS, // ptr32_uptr
+ llvm::AMDGPUAS::FLAT_ADDRESS, // ptr64
+ llvm::AMDGPUAS::FLAT_ADDRESS, // hlsl_groupshared
};
} // namespace targets
@@ -279,7 +280,7 @@ void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro(Twine("__") + Twine(CanonName) + Twine("__"));
// Emit macros for gfx family e.g. gfx906 -> __GFX9__, gfx1030 -> __GFX10___
if (isAMDGCN(getTriple())) {
- assert(CanonName.startswith("gfx") && "Invalid amdgcn canonical name");
+ assert(CanonName.starts_with("gfx") && "Invalid amdgcn canonical name");
Builder.defineMacro(Twine("__") + Twine(CanonName.drop_back(2).upper()) +
Twine("__"));
}
diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h
index 300d9691d8a0..1819ba544ccf 100644
--- a/clang/lib/Basic/Targets/AMDGPU.h
+++ b/clang/lib/Basic/Targets/AMDGPU.h
@@ -17,6 +17,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/AMDGPUAddrSpace.h"
#include "llvm/Support/Compiler.h"
#include "llvm/TargetParser/TargetParser.h"
#include "llvm/TargetParser/Triple.h"
@@ -29,13 +30,6 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
static const char *const GCCRegNames[];
- enum AddrSpace {
- Generic = 0,
- Global = 1,
- Local = 3,
- Constant = 4,
- Private = 5
- };
static const LangASMap AMDGPUDefIsGenMap;
static const LangASMap AMDGPUDefIsPrivMap;
@@ -106,7 +100,8 @@ public:
return 32;
unsigned TargetAS = getTargetAddressSpace(AS);
- if (TargetAS == Private || TargetAS == Local)
+ if (TargetAS == llvm::AMDGPUAS::PRIVATE_ADDRESS ||
+ TargetAS == llvm::AMDGPUAS::LOCAL_ADDRESS)
return 32;
return 64;
@@ -376,7 +371,7 @@ public:
}
std::optional<LangAS> getConstantAddressSpace() const override {
- return getLangASFromTargetAS(Constant);
+ return getLangASFromTargetAS(llvm::AMDGPUAS::CONSTANT_ADDRESS);
}
const llvm::omp::GV &getGridValue() const override {
@@ -392,7 +387,7 @@ public:
/// \returns Target specific vtbl ptr address space.
unsigned getVtblPtrAddressSpace() const override {
- return static_cast<unsigned>(Constant);
+ return static_cast<unsigned>(llvm::AMDGPUAS::CONSTANT_ADDRESS);
}
/// \returns If a target requires an address within a target specific address
@@ -405,9 +400,9 @@ public:
getDWARFAddressSpace(unsigned AddressSpace) const override {
const unsigned DWARF_Private = 1;
const unsigned DWARF_Local = 2;
- if (AddressSpace == Private) {
+ if (AddressSpace == llvm::AMDGPUAS::PRIVATE_ADDRESS) {
return DWARF_Private;
- } else if (AddressSpace == Local) {
+ } else if (AddressSpace == llvm::AMDGPUAS::LOCAL_ADDRESS) {
return DWARF_Local;
} else {
return std::nullopt;
diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp
index bc90d1b93d53..3a65f53c5248 100644
--- a/clang/lib/Basic/Targets/Mips.cpp
+++ b/clang/lib/Basic/Targets/Mips.cpp
@@ -196,7 +196,7 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts,
else
Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper());
- if (StringRef(CPU).startswith("octeon"))
+ if (StringRef(CPU).starts_with("octeon"))
Builder.defineMacro("__OCTEON__");
if (CPU != "mips1") {
diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp
index 3a4a75b0348f..c0b5db795e27 100644
--- a/clang/lib/Basic/Targets/NVPTX.cpp
+++ b/clang/lib/Basic/Targets/NVPTX.cpp
@@ -42,7 +42,7 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
PTXVersion = 32;
for (const StringRef Feature : Opts.FeaturesAsWritten) {
int PTXV;
- if (!Feature.startswith("+ptx") ||
+ if (!Feature.starts_with("+ptx") ||
Feature.drop_front(4).getAsInteger(10, PTXV))
continue;
PTXVersion = PTXV; // TODO: should it be max(PTXVersion, PTXV)?
@@ -262,11 +262,14 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts,
case CudaArch::SM_89:
return "890";
case CudaArch::SM_90:
+ case CudaArch::SM_90a:
return "900";
}
llvm_unreachable("unhandled CudaArch");
}();
Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode);
+ if (GPU == CudaArch::SM_90a)
+ Builder.defineMacro("__CUDA_ARCH_FEAT_SM90_ALL", "1");
}
}
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index 13f934e99472..60a4e0ed69c3 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -131,7 +131,7 @@ static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__riscv");
- bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
+ bool Is64Bit = getTriple().isRISCV64();
Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
StringRef CodeModel = getTargetOpts().CodeModel;
unsigned FLen = ISAInfo->getFLen();
@@ -281,7 +281,7 @@ bool RISCVTargetInfo::initFeatureMap(
unsigned XLen = 32;
- if (getTriple().getArch() == llvm::Triple::riscv64) {
+ if (getTriple().isRISCV64()) {
Features["64bit"] = true;
XLen = 64;
} else {
@@ -304,11 +304,18 @@ bool RISCVTargetInfo::initFeatureMap(
// RISCVISAInfo makes implications for ISA features
std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();
- // Add non-ISA features like `relax` and `save-restore` back
- for (const std::string &Feature : NewFeaturesVec)
- if (!llvm::is_contained(ImpliedFeatures, Feature))
- ImpliedFeatures.push_back(Feature);
+ // parseFeatures normalizes the feature set by dropping any explicit
+ // negatives, and non-extension features. We need to preserve the later
+ // for correctness and want to preserve the former for consistency.
+ for (auto &Feature : NewFeaturesVec) {
+ StringRef ExtName = Feature;
+ assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
+ ExtName = ExtName.drop_front(1); // Drop '+' or '-'
+ if (!llvm::is_contained(ImpliedFeatures, ("+" + ExtName).str()) &&
+ !llvm::is_contained(ImpliedFeatures, ("-" + ExtName).str()))
+ ImpliedFeatures.push_back(Feature);
+ }
return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures);
}
@@ -336,7 +343,7 @@ RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
/// Return true if has this feature, need to sync with handleTargetFeatures.
bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
- bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
+ bool Is64Bit = getTriple().isRISCV64();
auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
.Case("riscv", true)
.Case("riscv32", !Is64Bit)
@@ -347,10 +354,7 @@ bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
if (Result)
return *Result;
- if (ISAInfo->isSupportedExtensionFeature(Feature))
- return ISAInfo->hasExtension(Feature);
-
- return false;
+ return ISAInfo->hasExtension(Feature);
}
/// Perform initialization based on the user configured set of features.
@@ -430,14 +434,14 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
Feature = Feature.trim();
StringRef AttrString = Feature.split("=").second.trim();
- if (Feature.startswith("arch=")) {
+ if (Feature.starts_with("arch=")) {
// Override last features
Ret.Features.clear();
if (FoundArch)
Ret.Duplicate = "arch=";
FoundArch = true;
- if (AttrString.startswith("+")) {
+ if (AttrString.starts_with("+")) {
// EXTENSION like arch=+v,+zbb
SmallVector<StringRef, 1> Exts;
AttrString.split(Exts, ",");
@@ -457,7 +461,7 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
// full-arch-string like arch=rv64gcv
handleFullArchString(AttrString, Ret.Features);
}
- } else if (Feature.startswith("cpu=")) {
+ } else if (Feature.starts_with("cpu=")) {
if (!Ret.CPU.empty())
Ret.Duplicate = "cpu=";
@@ -471,7 +475,7 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
handleFullArchString(MarchFromCPU, Ret.Features);
}
}
- } else if (Feature.startswith("tune=")) {
+ } else if (Feature.starts_with("tune=")) {
if (!Ret.Tune.empty())
Ret.Duplicate = "tune=";
diff --git a/clang/lib/Basic/Warnings.cpp b/clang/lib/Basic/Warnings.cpp
index cc8c138233ca..cb23d844ef8f 100644
--- a/clang/lib/Basic/Warnings.cpp
+++ b/clang/lib/Basic/Warnings.cpp
@@ -97,7 +97,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
// Check to see if this warning starts with "no-", if so, this is a
// negative form of the option.
bool isPositive = true;
- if (Opt.startswith("no-")) {
+ if (Opt.starts_with("no-")) {
isPositive = false;
Opt = Opt.substr(3);
}
@@ -133,7 +133,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
// table. It also has the "specifier" form of -Werror=foo. GCC supports
// the deprecated -Werror-implicit-function-declaration which is used by
// a few projects.
- if (Opt.startswith("error")) {
+ if (Opt.starts_with("error")) {
StringRef Specifier;
if (Opt.size() > 5) { // Specifier must be present.
if (Opt[5] != '=' &&
@@ -162,7 +162,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
}
// -Wfatal-errors is yet another special case.
- if (Opt.startswith("fatal-errors")) {
+ if (Opt.starts_with("fatal-errors")) {
StringRef Specifier;
if (Opt.size() != 12) {
if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {
@@ -204,7 +204,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
// Check to see if this warning starts with "no-", if so, this is a
// negative form of the option.
- bool IsPositive = !Opt.startswith("no-");
+ bool IsPositive = !Opt.starts_with("no-");
if (!IsPositive) Opt = Opt.substr(3);
auto Severity = IsPositive ? diag::Severity::Remark
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 8c666e2cb463..7d16de33763a 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -45,6 +45,7 @@
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/StandardInstrumentations.h"
+#include "llvm/ProfileData/InstrProfCorrelator.h"
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -102,17 +103,21 @@ static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP(
"sanitizer-early-opt-ep", cl::Optional,
cl::desc("Insert sanitizers on OptimizerEarlyEP."), cl::init(false));
+extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;
+
// Re-link builtin bitcodes after optimization
cl::opt<bool> ClRelinkBuiltinBitcodePostop(
"relink-builtin-bitcode-postop", cl::Optional,
cl::desc("Re-link builtin bitcodes after optimization."), cl::init(false));
-}
+} // namespace llvm
namespace {
// Default filename used for profile generation.
std::string getDefaultProfileGenName() {
- return DebugInfoCorrelate ? "default_%m.proflite" : "default_%m.profraw";
+ return DebugInfoCorrelate || ProfileCorrelate != InstrProfCorrelator::NONE
+ ? "default_%m.proflite"
+ : "default_%m.profraw";
}
class EmitAssemblyHelper {
@@ -204,7 +209,7 @@ public:
void EmitAssembly(BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS,
BackendConsumer *BC);
};
-}
+} // namespace
static SanitizerCoverageOptions
getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) {
@@ -982,7 +987,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
getInstrProfOptions(CodeGenOpts, LangOpts))
PB.registerPipelineStartEPCallback(
[Options](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(InstrProfiling(*Options, false));
+ MPM.addPass(InstrProfilingLoweringPass(*Options, false));
});
// TODO: Consider passing the MemoryProfileOutput to the pass builder via
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 83d0a72aac54..3327866d2b96 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3410,9 +3410,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
{ Src0->getType(), Src1->getType() });
return RValue::get(Builder.CreateCall(F, { Src0, Src1 }));
}
+ case Builtin::BI__builtin_frexpl: {
+ // Linux PPC will not be adding additional PPCDoubleDouble support.
+ // WIP to switch default to IEEE long double. Will emit libcall for
+ // frexpl instead of legalizing this type in the BE.
+ if (&getTarget().getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble())
+ break;
+ LLVM_FALLTHROUGH;
+ }
case Builtin::BI__builtin_frexp:
case Builtin::BI__builtin_frexpf:
- case Builtin::BI__builtin_frexpl:
case Builtin::BI__builtin_frexpf128:
case Builtin::BI__builtin_frexpf16:
return RValue::get(emitFrexpBuiltin(*this, E, Intrinsic::frexp));
@@ -9985,6 +9992,10 @@ CodeGenFunction::getSVEOverloadTypes(const SVETypeFlags &TypeFlags,
if (TypeFlags.isOverloadCvt())
return {Ops[0]->getType(), Ops.back()->getType()};
+ if (TypeFlags.isReductionQV() && !ResultType->isScalableTy() &&
+ ResultType->isVectorTy())
+ return {ResultType, Ops[1]->getType()};
+
assert(TypeFlags.isOverloadDefault() && "Unexpected value for overloads");
return {DefaultType};
}
diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp
index 520b0c4f1176..353370f1d761 100644
--- a/clang/lib/CodeGen/CGCUDANV.cpp
+++ b/clang/lib/CodeGen/CGCUDANV.cpp
@@ -39,7 +39,7 @@ class CGNVCUDARuntime : public CGCUDARuntime {
private:
llvm::IntegerType *IntTy, *SizeTy;
llvm::Type *VoidTy;
- llvm::PointerType *CharPtrTy, *VoidPtrTy, *VoidPtrPtrTy;
+ llvm::PointerType *PtrTy;
/// Convenience reference to LLVM Context
llvm::LLVMContext &Context;
@@ -232,15 +232,12 @@ CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM)
VoidTy = CGM.VoidTy;
Zeros[0] = llvm::ConstantInt::get(SizeTy, 0);
Zeros[1] = Zeros[0];
-
- CharPtrTy = CGM.UnqualPtrTy;
- VoidPtrTy = CGM.UnqualPtrTy;
- VoidPtrPtrTy = CGM.UnqualPtrTy;
+ PtrTy = CGM.UnqualPtrTy;
}
llvm::FunctionCallee CGNVCUDARuntime::getSetupArgumentFn() const {
// cudaError_t cudaSetupArgument(void *, size_t, size_t)
- llvm::Type *Params[] = {VoidPtrTy, SizeTy, SizeTy};
+ llvm::Type *Params[] = {PtrTy, SizeTy, SizeTy};
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(IntTy, Params, false),
addPrefixToName("SetupArgument"));
@@ -250,24 +247,24 @@ llvm::FunctionCallee CGNVCUDARuntime::getLaunchFn() const {
if (CGM.getLangOpts().HIP) {
// hipError_t hipLaunchByPtr(char *);
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, CharPtrTy, false), "hipLaunchByPtr");
+ llvm::FunctionType::get(IntTy, PtrTy, false), "hipLaunchByPtr");
}
// cudaError_t cudaLaunch(char *);
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, CharPtrTy, false), "cudaLaunch");
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(IntTy, PtrTy, false),
+ "cudaLaunch");
}
llvm::FunctionType *CGNVCUDARuntime::getRegisterGlobalsFnTy() const {
- return llvm::FunctionType::get(VoidTy, VoidPtrPtrTy, false);
+ return llvm::FunctionType::get(VoidTy, PtrTy, false);
}
llvm::FunctionType *CGNVCUDARuntime::getCallbackFnTy() const {
- return llvm::FunctionType::get(VoidTy, VoidPtrTy, false);
+ return llvm::FunctionType::get(VoidTy, PtrTy, false);
}
llvm::FunctionType *CGNVCUDARuntime::getRegisterLinkedBinaryFnTy() const {
- llvm::Type *Params[] = {llvm::PointerType::getUnqual(Context), VoidPtrTy,
- VoidPtrTy, llvm::PointerType::getUnqual(Context)};
+ llvm::Type *Params[] = {llvm::PointerType::getUnqual(Context), PtrTy, PtrTy,
+ llvm::PointerType::getUnqual(Context)};
return llvm::FunctionType::get(VoidTy, Params, false);
}
@@ -330,15 +327,15 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
// args, allocate a single pointer so we still have a valid pointer to the
// argument array that we can pass to runtime, even if it will be unused.
Address KernelArgs = CGF.CreateTempAlloca(
- VoidPtrTy, CharUnits::fromQuantity(16), "kernel_args",
+ PtrTy, CharUnits::fromQuantity(16), "kernel_args",
llvm::ConstantInt::get(SizeTy, std::max<size_t>(1, Args.size())));
// Store pointers to the arguments in a locally allocated launch_args.
for (unsigned i = 0; i < Args.size(); ++i) {
llvm::Value* VarPtr = CGF.GetAddrOfLocalVar(Args[i]).getPointer();
- llvm::Value *VoidVarPtr = CGF.Builder.CreatePointerCast(VarPtr, VoidPtrTy);
+ llvm::Value *VoidVarPtr = CGF.Builder.CreatePointerCast(VarPtr, PtrTy);
CGF.Builder.CreateDefaultAlignedStore(
VoidVarPtr,
- CGF.Builder.CreateConstGEP1_32(VoidPtrTy, KernelArgs.getPointer(), i));
+ CGF.Builder.CreateConstGEP1_32(PtrTy, KernelArgs.getPointer(), i));
}
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("setup.end");
@@ -386,8 +383,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
CGF.CreateMemTemp(Dim3Ty, CharUnits::fromQuantity(8), "block_dim");
Address ShmemSize =
CGF.CreateTempAlloca(SizeTy, CGM.getSizeAlign(), "shmem_size");
- Address Stream =
- CGF.CreateTempAlloca(VoidPtrTy, CGM.getPointerAlign(), "stream");
+ Address Stream = CGF.CreateTempAlloca(PtrTy, CGM.getPointerAlign(), "stream");
llvm::FunctionCallee cudaPopConfigFn = CGM.CreateRuntimeFunction(
llvm::FunctionType::get(IntTy,
{/*gridDim=*/GridDim.getType(),
@@ -402,8 +398,8 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
ShmemSize.getPointer(), Stream.getPointer()});
// Emit the call to cudaLaunch
- llvm::Value *Kernel = CGF.Builder.CreatePointerCast(
- KernelHandles[CGF.CurFn->getName()], VoidPtrTy);
+ llvm::Value *Kernel =
+ CGF.Builder.CreatePointerCast(KernelHandles[CGF.CurFn->getName()], PtrTy);
CallArgList LaunchKernelArgs;
LaunchKernelArgs.add(RValue::get(Kernel),
cudaLaunchKernelFD->getParamDecl(0)->getType());
@@ -443,7 +439,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyLegacy(CodeGenFunction &CGF,
Offset = Offset.alignTo(TInfo.Align);
llvm::Value *Args[] = {
CGF.Builder.CreatePointerCast(CGF.GetAddrOfLocalVar(A).getPointer(),
- VoidPtrTy),
+ PtrTy),
llvm::ConstantInt::get(SizeTy, TInfo.Width.getQuantity()),
llvm::ConstantInt::get(SizeTy, Offset.getQuantity()),
};
@@ -458,8 +454,8 @@ void CGNVCUDARuntime::emitDeviceStubBodyLegacy(CodeGenFunction &CGF,
// Emit the call to cudaLaunch
llvm::FunctionCallee cudaLaunchFn = getLaunchFn();
- llvm::Value *Arg = CGF.Builder.CreatePointerCast(
- KernelHandles[CGF.CurFn->getName()], CharPtrTy);
+ llvm::Value *Arg =
+ CGF.Builder.CreatePointerCast(KernelHandles[CGF.CurFn->getName()], PtrTy);
CGF.EmitRuntimeCallOrInvoke(cudaLaunchFn, Arg);
CGF.EmitBranch(EndBlock);
@@ -537,11 +533,8 @@ llvm::Function *CGNVCUDARuntime::makeRegisterGlobalsFn() {
// void __cudaRegisterFunction(void **, const char *, char *, const char *,
// int, uint3*, uint3*, dim3*, dim3*, int*)
llvm::Type *RegisterFuncParams[] = {
- VoidPtrPtrTy, CharPtrTy,
- CharPtrTy, CharPtrTy,
- IntTy, VoidPtrTy,
- VoidPtrTy, VoidPtrTy,
- VoidPtrTy, llvm::PointerType::getUnqual(Context)};
+ PtrTy, PtrTy, PtrTy, PtrTy, IntTy,
+ PtrTy, PtrTy, PtrTy, PtrTy, llvm::PointerType::getUnqual(Context)};
llvm::FunctionCallee RegisterFunc = CGM.CreateRuntimeFunction(
llvm::FunctionType::get(IntTy, RegisterFuncParams, false),
addUnderscoredPrefixToName("RegisterFunction"));
@@ -553,7 +546,7 @@ llvm::Function *CGNVCUDARuntime::makeRegisterGlobalsFn() {
for (auto &&I : EmittedKernels) {
llvm::Constant *KernelName =
makeConstantString(getDeviceSideName(cast<NamedDecl>(I.D)));
- llvm::Constant *NullPtr = llvm::ConstantPointerNull::get(VoidPtrTy);
+ llvm::Constant *NullPtr = llvm::ConstantPointerNull::get(PtrTy);
llvm::Value *Args[] = {
&GpuBinaryHandlePtr,
KernelHandles[I.Kernel->getName()],
@@ -576,16 +569,15 @@ llvm::Function *CGNVCUDARuntime::makeRegisterGlobalsFn() {
// void __cudaRegisterVar(void **, char *, char *, const char *,
// int, int, int, int)
- llvm::Type *RegisterVarParams[] = {VoidPtrPtrTy, CharPtrTy, CharPtrTy,
- CharPtrTy, IntTy, VarSizeTy,
- IntTy, IntTy};
+ llvm::Type *RegisterVarParams[] = {PtrTy, PtrTy, PtrTy, PtrTy,
+ IntTy, VarSizeTy, IntTy, IntTy};
llvm::FunctionCallee RegisterVar = CGM.CreateRuntimeFunction(
llvm::FunctionType::get(VoidTy, RegisterVarParams, false),
addUnderscoredPrefixToName("RegisterVar"));
// void __hipRegisterManagedVar(void **, char *, char *, const char *,
// size_t, unsigned)
- llvm::Type *RegisterManagedVarParams[] = {VoidPtrPtrTy, CharPtrTy, CharPtrTy,
- CharPtrTy, VarSizeTy, IntTy};
+ llvm::Type *RegisterManagedVarParams[] = {PtrTy, PtrTy, PtrTy,
+ PtrTy, VarSizeTy, IntTy};
llvm::FunctionCallee RegisterManagedVar = CGM.CreateRuntimeFunction(
llvm::FunctionType::get(VoidTy, RegisterManagedVarParams, false),
addUnderscoredPrefixToName("RegisterManagedVar"));
@@ -593,16 +585,13 @@ llvm::Function *CGNVCUDARuntime::makeRegisterGlobalsFn() {
// const void **, const char *, int, int);
llvm::FunctionCallee RegisterSurf = CGM.CreateRuntimeFunction(
llvm::FunctionType::get(
- VoidTy, {VoidPtrPtrTy, VoidPtrTy, CharPtrTy, CharPtrTy, IntTy, IntTy},
- false),
+ VoidTy, {PtrTy, PtrTy, PtrTy, PtrTy, IntTy, IntTy}, false),
addUnderscoredPrefixToName("RegisterSurface"));
// void __cudaRegisterTexture(void **, const struct textureReference *,
// const void **, const char *, int, int, int)
llvm::FunctionCallee RegisterTex = CGM.CreateRuntimeFunction(
llvm::FunctionType::get(
- VoidTy,
- {VoidPtrPtrTy, VoidPtrTy, CharPtrTy, CharPtrTy, IntTy, IntTy, IntTy},
- false),
+ VoidTy, {PtrTy, PtrTy, PtrTy, PtrTy, IntTy, IntTy, IntTy}, false),
addUnderscoredPrefixToName("RegisterTexture"));
for (auto &&Info : DeviceVars) {
llvm::GlobalVariable *Var = Info.Var;
@@ -713,11 +702,11 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
// void ** __{cuda|hip}RegisterFatBinary(void *);
llvm::FunctionCallee RegisterFatbinFunc = CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(VoidPtrPtrTy, VoidPtrTy, false),
+ llvm::FunctionType::get(PtrTy, PtrTy, false),
addUnderscoredPrefixToName("RegisterFatBinary"));
// struct { int magic, int version, void * gpu_binary, void * dont_care };
llvm::StructType *FatbinWrapperTy =
- llvm::StructType::get(IntTy, IntTy, VoidPtrTy, VoidPtrTy);
+ llvm::StructType::get(IntTy, IntTy, PtrTy, PtrTy);
// Register GPU binary with the CUDA runtime, store returned handle in a
// global variable and save a reference in GpuBinaryHandle to be cleaned up
@@ -813,7 +802,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
// Data.
Values.add(FatBinStr);
// Unused in fatbin v1.
- Values.add(llvm::ConstantPointerNull::get(VoidPtrTy));
+ Values.add(llvm::ConstantPointerNull::get(PtrTy));
llvm::GlobalVariable *FatbinWrapper = Values.finishAndCreateGlobal(
addUnderscoredPrefixToName("_fatbin_wrapper"), CGM.getPointerAlign(),
/*constant*/ true);
@@ -836,9 +825,8 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
// The name, size, and initialization pattern of this variable is part
// of HIP ABI.
GpuBinaryHandle = new llvm::GlobalVariable(
- TheModule, VoidPtrPtrTy, /*isConstant=*/false,
- Linkage,
- /*Initializer=*/llvm::ConstantPointerNull::get(VoidPtrPtrTy),
+ TheModule, PtrTy, /*isConstant=*/false, Linkage,
+ /*Initializer=*/llvm::ConstantPointerNull::get(PtrTy),
"__hip_gpubin_handle");
if (Linkage == llvm::GlobalValue::LinkOnceAnyLinkage)
GpuBinaryHandle->setComdat(
@@ -848,7 +836,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
if (Linkage != llvm::GlobalValue::InternalLinkage)
GpuBinaryHandle->setVisibility(llvm::GlobalValue::HiddenVisibility);
Address GpuBinaryAddr(
- GpuBinaryHandle, VoidPtrPtrTy,
+ GpuBinaryHandle, PtrTy,
CharUnits::fromQuantity(GpuBinaryHandle->getAlignment()));
{
auto *HandleValue = CtorBuilder.CreateLoad(GpuBinaryAddr);
@@ -880,8 +868,8 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
llvm::CallInst *RegisterFatbinCall =
CtorBuilder.CreateCall(RegisterFatbinFunc, FatbinWrapper);
GpuBinaryHandle = new llvm::GlobalVariable(
- TheModule, VoidPtrPtrTy, false, llvm::GlobalValue::InternalLinkage,
- llvm::ConstantPointerNull::get(VoidPtrPtrTy), "__cuda_gpubin_handle");
+ TheModule, PtrTy, false, llvm::GlobalValue::InternalLinkage,
+ llvm::ConstantPointerNull::get(PtrTy), "__cuda_gpubin_handle");
GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getAsAlign());
CtorBuilder.CreateAlignedStore(RegisterFatbinCall, GpuBinaryHandle,
CGM.getPointerAlign());
@@ -895,7 +883,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
CudaFeature::CUDA_USES_FATBIN_REGISTER_END)) {
// void __cudaRegisterFatBinaryEnd(void **);
llvm::FunctionCallee RegisterFatbinEndFunc = CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(VoidTy, VoidPtrPtrTy, false),
+ llvm::FunctionType::get(VoidTy, PtrTy, false),
"__cudaRegisterFatBinaryEnd");
CtorBuilder.CreateCall(RegisterFatbinEndFunc, RegisterFatbinCall);
}
@@ -967,7 +955,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleDtorFunction() {
// void __cudaUnregisterFatBinary(void ** handle);
llvm::FunctionCallee UnregisterFatbinFunc = CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(VoidTy, VoidPtrPtrTy, false),
+ llvm::FunctionType::get(VoidTy, PtrTy, false),
addUnderscoredPrefixToName("UnregisterFatBinary"));
llvm::Function *ModuleDtorFunc = llvm::Function::Create(
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index a24aeea7ae32..51a43b5f85b3 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5609,7 +5609,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
EmitBlock(Cont);
}
if (CI->getCalledFunction() && CI->getCalledFunction()->hasName() &&
- CI->getCalledFunction()->getName().startswith("_Z4sqrt")) {
+ CI->getCalledFunction()->getName().starts_with("_Z4sqrt")) {
SetSqrtFPAccuracy(CI);
}
if (callOrInvoke)
diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h
index aee86a3242fd..1c0d15dc932a 100644
--- a/clang/lib/CodeGen/CGCall.h
+++ b/clang/lib/CodeGen/CGCall.h
@@ -20,6 +20,7 @@
#include "clang/AST/CanonicalType.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/Type.h"
+#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/IR/Value.h"
namespace llvm {
@@ -406,15 +407,13 @@ enum class FnInfoOpts {
};
inline FnInfoOpts operator|(FnInfoOpts A, FnInfoOpts B) {
- return static_cast<FnInfoOpts>(
- static_cast<std::underlying_type_t<FnInfoOpts>>(A) |
- static_cast<std::underlying_type_t<FnInfoOpts>>(B));
+ return static_cast<FnInfoOpts>(llvm::to_underlying(A) |
+ llvm::to_underlying(B));
}
inline FnInfoOpts operator&(FnInfoOpts A, FnInfoOpts B) {
- return static_cast<FnInfoOpts>(
- static_cast<std::underlying_type_t<FnInfoOpts>>(A) &
- static_cast<std::underlying_type_t<FnInfoOpts>>(B));
+ return static_cast<FnInfoOpts>(llvm::to_underlying(A) &
+ llvm::to_underlying(B));
}
inline FnInfoOpts operator|=(FnInfoOpts A, FnInfoOpts B) {
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 7cf661994a29..236d53bee4e8 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -554,14 +554,16 @@ void CGDebugInfo::CreateCompileUnit() {
// If the main file name provided is identical to the input file name, and
// if the input file is a preprocessed source, use the module name for
// debug info. The module name comes from the name specified in the first
- // linemarker if the input is a preprocessed source.
+ // linemarker if the input is a preprocessed source. In this case we don't
+ // know the content to compute a checksum.
if (MainFile->getName() == MainFileName &&
FrontendOptions::getInputKindForExtension(
MainFile->getName().rsplit('.').second)
- .isPreprocessed())
+ .isPreprocessed()) {
MainFileName = CGM.getModule().getName().str();
-
- CSKind = computeChecksum(SM.getMainFileID(), Checksum);
+ } else {
+ CSKind = computeChecksum(SM.getMainFileID(), Checksum);
+ }
}
llvm::dwarf::SourceLanguage LangTag;
@@ -635,7 +637,8 @@ void CGDebugInfo::CreateCompileUnit() {
Sysroot = CGM.getHeaderSearchOpts().Sysroot;
auto B = llvm::sys::path::rbegin(Sysroot);
auto E = llvm::sys::path::rend(Sysroot);
- auto It = std::find_if(B, E, [](auto SDK) { return SDK.endswith(".sdk"); });
+ auto It =
+ std::find_if(B, E, [](auto SDK) { return SDK.ends_with(".sdk"); });
if (It != E)
SDK = *It;
}
@@ -2883,7 +2886,7 @@ llvm::DIModule *CGDebugInfo::getOrCreateModuleRef(ASTSourceDescriptor Mod,
// clang::Module object, but it won't actually be built or imported; it will
// be textual.
if (CreateSkeletonCU && IsRootModule && Mod.getASTFile().empty() && M)
- assert(StringRef(M->Name).startswith(CGM.getLangOpts().ModuleName) &&
+ assert(StringRef(M->Name).starts_with(CGM.getLangOpts().ModuleName) &&
"clang module without ASTFile must be specified by -fmodule-name");
// Return a StringRef to the remapped Path.
@@ -4247,7 +4250,7 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc,
Flags |= llvm::DINode::FlagPrototyped;
}
- if (Name.startswith("\01"))
+ if (Name.starts_with("\01"))
Name = Name.substr(1);
assert((!D || !isa<VarDecl>(D) ||
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index bae8babb8efe..0d507da5c1ba 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -277,7 +277,7 @@ static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) {
if (llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Val))
// ObjC EH selector entries are always global variables with
// names starting like this.
- if (GV->getName().startswith("OBJC_EHTYPE"))
+ if (GV->getName().starts_with("OBJC_EHTYPE"))
return false;
} else {
// Check if any of the filter values have the ObjC prefix.
@@ -288,7 +288,7 @@ static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) {
cast<llvm::GlobalVariable>((*II)->stripPointerCasts()))
// ObjC EH selector entries are always global variables with
// names starting like this.
- if (GV->getName().startswith("OBJC_EHTYPE"))
+ if (GV->getName().starts_with("OBJC_EHTYPE"))
return false;
}
}
@@ -1917,7 +1917,7 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
const VarDecl *D = cast<VarDecl>(I.first);
if (isa<ImplicitParamDecl>(D) &&
D->getType() == getContext().VoidPtrTy) {
- assert(D->getName().startswith("frame_pointer"));
+ assert(D->getName().starts_with("frame_pointer"));
FramePtrAddrAlloca = cast<llvm::AllocaInst>(I.second.getPointer());
break;
}
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 69cf7f76be9a..ed9aaa28c257 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -431,7 +431,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF,
/// Helper method to check if the underlying ABI is AAPCS
static bool isAAPCS(const TargetInfo &TargetInfo) {
- return TargetInfo.getABI().startswith("aapcs");
+ return TargetInfo.getABI().starts_with("aapcs");
}
LValue CodeGenFunction::
@@ -3156,7 +3156,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
auto SL = E->getFunctionName();
assert(SL != nullptr && "No StringLiteral name in PredefinedExpr");
StringRef FnName = CurFn->getName();
- if (FnName.startswith("\01"))
+ if (FnName.starts_with("\01"))
FnName = FnName.substr(1);
StringRef NameItems[] = {
PredefinedExpr::getIdentKindName(E->getIdentKind()), FnName};
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index f3cbd1d0451e..e532794b71bd 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -275,6 +275,10 @@ public:
ComplexPairTy EmitBinSub(const BinOpInfo &Op);
ComplexPairTy EmitBinMul(const BinOpInfo &Op);
ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
+ ComplexPairTy EmitAlgebraicDiv(llvm::Value *A, llvm::Value *B, llvm::Value *C,
+ llvm::Value *D);
+ ComplexPairTy EmitRangeReductionDiv(llvm::Value *A, llvm::Value *B,
+ llvm::Value *C, llvm::Value *D);
ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName,
const BinOpInfo &Op);
@@ -781,6 +785,10 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
ResR = Builder.CreateFSub(AC, BD, "mul_r");
ResI = Builder.CreateFAdd(AD, BC, "mul_i");
+ if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited ||
+ Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran)
+ return ComplexPairTy(ResR, ResI);
+
// Emit the test for the real part becoming NaN and create a branch to
// handle it. We test for NaN by comparing the number to itself.
Value *IsRNaN = Builder.CreateFCmpUNO(ResR, ResR, "isnan_cmp");
@@ -846,23 +854,139 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
return ComplexPairTy(ResR, ResI);
}
+ComplexPairTy ComplexExprEmitter::EmitAlgebraicDiv(llvm::Value *LHSr,
+ llvm::Value *LHSi,
+ llvm::Value *RHSr,
+ llvm::Value *RHSi) {
+ // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
+ llvm::Value *DSTr, *DSTi;
+
+ llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
+ llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
+ llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd
+
+ llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
+ llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
+ llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd
+
+ llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
+ llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
+ llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad
+
+ DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
+ DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
+ return ComplexPairTy(DSTr, DSTi);
+}
+
+// EmitFAbs - Emit a call to @llvm.fabs.
+static llvm::Value *EmitllvmFAbs(CodeGenFunction &CGF, llvm::Value *Value) {
+ llvm::Function *Func =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Value->getType());
+ llvm::Value *Call = CGF.Builder.CreateCall(Func, Value);
+ return Call;
+}
+
+// EmitRangeReductionDiv - Implements Smith's algorithm for complex division.
+// SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962).
+ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
+ llvm::Value *LHSi,
+ llvm::Value *RHSr,
+ llvm::Value *RHSi) {
+ // (a + ib) / (c + id) = (e + if)
+ llvm::Value *FAbsRHSr = EmitllvmFAbs(CGF, RHSr); // |c|
+ llvm::Value *FAbsRHSi = EmitllvmFAbs(CGF, RHSi); // |d|
+ // |c| >= |d|
+ llvm::Value *IsR = Builder.CreateFCmpUGT(FAbsRHSr, FAbsRHSi, "abs_cmp");
+
+ llvm::BasicBlock *TrueBB =
+ CGF.createBasicBlock("abs_rhsr_greater_or_equal_abs_rhsi");
+ llvm::BasicBlock *FalseBB =
+ CGF.createBasicBlock("abs_rhsr_less_than_abs_rhsi");
+ llvm::BasicBlock *ContBB = CGF.createBasicBlock("complex_div");
+ Builder.CreateCondBr(IsR, TrueBB, FalseBB);
+
+ CGF.EmitBlock(TrueBB);
+ // abs(c) >= abs(d)
+ // r = d/c
+ // tmp = c + rd
+ // e = (a + br)/tmp
+ // f = (b - ar)/tmp
+ llvm::Value *DdC = Builder.CreateFDiv(RHSi, RHSr); // r=d/c
+
+ llvm::Value *RD = Builder.CreateFMul(DdC, RHSi); // rd
+ llvm::Value *CpRD = Builder.CreateFAdd(RHSr, RD); // tmp=c+rd
+
+ llvm::Value *T3 = Builder.CreateFMul(LHSi, DdC); // br
+ llvm::Value *T4 = Builder.CreateFAdd(LHSr, T3); // a+br
+ llvm::Value *DSTTr = Builder.CreateFDiv(T4, CpRD); // (a+br)/tmp
+
+ llvm::Value *T5 = Builder.CreateFMul(LHSr, DdC); // ar
+ llvm::Value *T6 = Builder.CreateFSub(LHSi, T5); // b-ar
+ llvm::Value *DSTTi = Builder.CreateFDiv(T6, CpRD); // (b-ar)/tmp
+ Builder.CreateBr(ContBB);
+
+ CGF.EmitBlock(FalseBB);
+ // abs(c) < abs(d)
+ // r = c/d
+ // tmp = d + rc
+ // e = (ar + b)/tmp
+ // f = (br - a)/tmp
+ llvm::Value *CdD = Builder.CreateFDiv(RHSr, RHSi); // r=c/d
+
+ llvm::Value *RC = Builder.CreateFMul(CdD, RHSr); // rc
+ llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC); // tmp=d+rc
+
+ llvm::Value *T7 = Builder.CreateFMul(LHSr, RC); // ar
+ llvm::Value *T8 = Builder.CreateFAdd(T7, LHSi); // ar+b
+ llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC); // (ar+b)/tmp
+
+ llvm::Value *T9 = Builder.CreateFMul(LHSi, CdD); // br
+ llvm::Value *T10 = Builder.CreateFSub(T9, LHSr); // br-a
+ llvm::Value *DSTFi = Builder.CreateFDiv(T10, DpRC); // (br-a)/tmp
+ Builder.CreateBr(ContBB);
+
+ // Phi together the computation paths.
+ CGF.EmitBlock(ContBB);
+ llvm::PHINode *VALr = Builder.CreatePHI(DSTTr->getType(), 2);
+ VALr->addIncoming(DSTTr, TrueBB);
+ VALr->addIncoming(DSTFr, FalseBB);
+ llvm::PHINode *VALi = Builder.CreatePHI(DSTTi->getType(), 2);
+ VALi->addIncoming(DSTTi, TrueBB);
+ VALi->addIncoming(DSTFi, FalseBB);
+ return ComplexPairTy(VALr, VALi);
+}
+
// See C11 Annex G.5.1 for the semantics of multiplicative operators on complex
// typed values.
ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
-
llvm::Value *DSTr, *DSTi;
if (LHSr->getType()->isFloatingPointTy()) {
- // If we have a complex operand on the RHS and FastMath is not allowed, we
- // delegate to a libcall to handle all of the complexities and minimize
- // underflow/overflow cases. When FastMath is allowed we construct the
- // divide inline using the same algorithm as for integer operands.
- //
- // FIXME: We would be able to avoid the libcall in many places if we
- // supported imaginary types in addition to complex types.
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
- if (RHSi && !CGF.getLangOpts().FastMath) {
+ if (!RHSi) {
+ assert(LHSi && "Can have at most one non-complex operand!");
+
+ DSTr = Builder.CreateFDiv(LHSr, RHSr);
+ DSTi = Builder.CreateFDiv(LHSi, RHSr);
+ return ComplexPairTy(DSTr, DSTi);
+ }
+ llvm::Value *OrigLHSi = LHSi;
+ if (!LHSi)
+ LHSi = llvm::Constant::getNullValue(RHSi->getType());
+ if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran)
+ return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi);
+ else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited)
+ return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
+ else if (!CGF.getLangOpts().FastMath) {
+ LHSi = OrigLHSi;
+ // If we have a complex operand on the RHS and FastMath is not allowed, we
+ // delegate to a libcall to handle all of the complexities and minimize
+ // underflow/overflow cases. When FastMath is allowed we construct the
+ // divide inline using the same algorithm as for integer operands.
+ //
+ // FIXME: We would be able to avoid the libcall in many places if we
+ // supported imaginary types in addition to complex types.
BinOpInfo LibCallOp = Op;
// If LHS was a real, supply a null imaginary part.
if (!LHSi)
@@ -884,30 +1008,8 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
case llvm::Type::FP128TyID:
return EmitComplexBinOpLibCall("__divtc3", LibCallOp);
}
- } else if (RHSi) {
- if (!LHSi)
- LHSi = llvm::Constant::getNullValue(RHSi->getType());
-
- // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
- llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
- llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
- llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd
-
- llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
- llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
- llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd
-
- llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
- llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
- llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad
-
- DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
- DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
} else {
- assert(LHSi && "Can have at most one non-complex operand!");
-
- DSTr = Builder.CreateFDiv(LHSr, RHSr);
- DSTi = Builder.CreateFDiv(LHSi, RHSr);
+ return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
}
} else {
assert(Op.LHS.second && Op.RHS.second &&
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index c239bc17ef26..3e8a40e7540b 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -184,7 +184,8 @@ void CGHLSLRuntime::finishCodeGen() {
: llvm::hlsl::ResourceKind::TBuffer;
std::string TyName =
Buf.Name.str() + (Buf.IsCBuffer ? ".cb." : ".tb.") + "ty";
- addBufferResourceAnnotation(GV, TyName, RC, RK, Buf.Binding);
+ addBufferResourceAnnotation(GV, TyName, RC, RK, /*IsROV=*/false,
+ Buf.Binding);
}
}
@@ -196,6 +197,7 @@ void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::StringRef TyName,
llvm::hlsl::ResourceClass RC,
llvm::hlsl::ResourceKind RK,
+ bool IsROV,
BufferResBinding &Binding) {
llvm::Module &M = CGM.getModule();
@@ -219,7 +221,7 @@ void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
"ResourceMD must have been set by the switch above.");
llvm::hlsl::FrontendResource Res(
- GV, TyName, RK, Binding.Reg.value_or(UINT_MAX), Binding.Space);
+ GV, TyName, RK, IsROV, Binding.Reg.value_or(UINT_MAX), Binding.Space);
ResourceMD->addOperand(Res.getMetadata());
}
@@ -236,10 +238,11 @@ void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
llvm::hlsl::ResourceClass RC = Attr->getResourceClass();
llvm::hlsl::ResourceKind RK = Attr->getResourceKind();
+ bool IsROV = Attr->getIsROV();
QualType QT(Ty, 0);
BufferResBinding Binding(D->getAttr<HLSLResourceBindingAttr>());
- addBufferResourceAnnotation(GV, QT.getAsString(), RC, RK, Binding);
+ addBufferResourceAnnotation(GV, QT.getAsString(), RC, RK, IsROV, Binding);
}
CGHLSLRuntime::BufferResBinding::BufferResBinding(
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 67413fbd4a78..bb500cb5c979 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -92,7 +92,7 @@ private:
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::StringRef TyName,
llvm::hlsl::ResourceClass RC,
- llvm::hlsl::ResourceKind RK,
+ llvm::hlsl::ResourceKind RK, bool IsROV,
BufferResBinding &Binding);
void addConstant(VarDecl *D, Buffer &CB);
void addBufferDecls(const DeclContext *DC, Buffer &CB);
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index ba52b23be018..517f7cddebc1 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -1850,7 +1850,7 @@ static bool hasObjCExceptionAttribute(ASTContext &Context,
static llvm::GlobalValue::LinkageTypes
getLinkageTypeForObjCMetadata(CodeGenModule &CGM, StringRef Section) {
if (CGM.getTriple().isOSBinFormatMachO() &&
- (Section.empty() || Section.startswith("__DATA")))
+ (Section.empty() || Section.starts_with("__DATA")))
return llvm::GlobalValue::InternalLinkage;
return llvm::GlobalValue::PrivateLinkage;
}
@@ -6162,7 +6162,7 @@ void CGObjCNonFragileABIMac::AddModuleClassList(
// Section name is obtained by calling GetSectionName, which returns
// sections in the __DATA segment on MachO.
assert((!CGM.getTriple().isOSBinFormatMachO() ||
- SectionName.startswith("__DATA")) &&
+ SectionName.starts_with("__DATA")) &&
"SectionName expected to start with __DATA on MachO");
llvm::GlobalVariable *GV = new llvm::GlobalVariable(
CGM.getModule(), Init->getType(), false,
diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
index 293ccaa3413c..299ee1460b3d 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
@@ -3483,6 +3483,7 @@ void CGOpenMPRuntimeGPU::processRequiresDirective(
case CudaArch::SM_87:
case CudaArch::SM_89:
case CudaArch::SM_90:
+ case CudaArch::SM_90a:
case CudaArch::GFX600:
case CudaArch::GFX601:
case CudaArch::GFX602:
diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index cbfa79e10bfe..868ef810f3c4 100644
--- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -111,7 +111,7 @@ struct CGRecordLowering {
/// Helper function to check if we are targeting AAPCS.
bool isAAPCS() const {
- return Context.getTargetInfo().getABI().startswith("aapcs");
+ return Context.getTargetInfo().getABI().starts_with("aapcs");
}
/// Helper function to check if the target machine is BigEndian.
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index a5cb80640641..0f79a2e861d2 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -2548,7 +2548,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
ResultRegQualTys.push_back(QTy);
ResultRegDests.push_back(Dest);
- bool IsFlagReg = llvm::StringRef(OutputConstraint).startswith("{@cc");
+ bool IsFlagReg = llvm::StringRef(OutputConstraint).starts_with("{@cc");
ResultRegIsFlagReg.push_back(IsFlagReg);
llvm::Type *Ty = ConvertTypeForMem(QTy);
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index bb6b1a3bc228..753a8fd74fa6 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -1139,7 +1139,7 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) {
// Strip off a leading diagnostic code if there is one.
StringRef Msg = Err.getMessage();
- if (Msg.startswith("error: "))
+ if (Msg.starts_with("error: "))
Msg = Msg.substr(7);
unsigned DiagID =
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index b931a81bc008..7ad26ace328a 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -225,9 +225,9 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
StringRef ABIStr = Target.getABI();
unsigned XLen = Target.getPointerWidth(LangAS::Default);
unsigned ABIFLen = 0;
- if (ABIStr.endswith("f"))
+ if (ABIStr.ends_with("f"))
ABIFLen = 32;
- else if (ABIStr.endswith("d"))
+ else if (ABIStr.ends_with("d"))
ABIFLen = 64;
return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen);
}
@@ -308,9 +308,9 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
case llvm::Triple::loongarch64: {
StringRef ABIStr = Target.getABI();
unsigned ABIFRLen = 0;
- if (ABIStr.endswith("f"))
+ if (ABIStr.ends_with("f"))
ABIFRLen = 32;
- else if (ABIStr.endswith("d"))
+ else if (ABIStr.ends_with("d"))
ABIFRLen = 64;
return createLoongArchTargetCodeGenInfo(
CGM, Target.getPointerWidth(LangAS::Default), ABIFRLen);
@@ -1715,7 +1715,7 @@ static void AppendTargetMangling(const CodeGenModule &CGM,
llvm::sort(Info.Features, [&Target](StringRef LHS, StringRef RHS) {
// Multiversioning doesn't allow "no-${feature}", so we can
// only have "+" prefixes here.
- assert(LHS.startswith("+") && RHS.startswith("+") &&
+ assert(LHS.starts_with("+") && RHS.starts_with("+") &&
"Features should always have a prefix.");
return Target.multiVersionSortPriority(LHS.substr(1)) >
Target.multiVersionSortPriority(RHS.substr(1));
@@ -1769,7 +1769,7 @@ static void AppendTargetClonesMangling(const CodeGenModule &CGM,
} else {
Out << '.';
StringRef FeatureStr = Attr->getFeatureStr(VersionIndex);
- if (FeatureStr.startswith("arch="))
+ if (FeatureStr.starts_with("arch="))
Out << "arch_" << FeatureStr.substr(sizeof("arch=") - 1);
else
Out << FeatureStr;
@@ -3828,7 +3828,7 @@ namespace {
if (!BuiltinID || !BI.isLibFunction(BuiltinID))
return false;
StringRef BuiltinName = BI.getName(BuiltinID);
- if (BuiltinName.startswith("__builtin_") &&
+ if (BuiltinName.starts_with("__builtin_") &&
Name == BuiltinName.slice(strlen("__builtin_"), StringRef::npos)) {
return true;
}
@@ -4164,7 +4164,7 @@ void CodeGenModule::emitMultiVersionFunctions() {
Feature.push_back(CurFeat.trim());
}
} else {
- if (Version.startswith("arch="))
+ if (Version.starts_with("arch="))
Architecture = Version.drop_front(sizeof("arch=") - 1);
else if (Version != "default")
Feature.push_back(Version);
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index b16358ee117a..56411e2240e5 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1623,8 +1623,12 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
OS << "Gap,";
break;
case CounterMappingRegion::BranchRegion:
+ case CounterMappingRegion::MCDCBranchRegion:
OS << "Branch,";
break;
+ case CounterMappingRegion::MCDCDecisionRegion:
+ OS << "Decision,";
+ break;
}
OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 8bacba65617e..cf068cbc4fcd 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -146,14 +146,14 @@ static llvm::Type *getSPIRVImageType(llvm::LLVMContext &Ctx, StringRef BaseType,
// Choose the dimension of the image--this corresponds to the Dim enum in
// SPIR-V (first integer parameter of OpTypeImage).
- if (OpenCLName.startswith("image2d"))
+ if (OpenCLName.starts_with("image2d"))
IntParams[0] = 1; // 1D
- else if (OpenCLName.startswith("image3d"))
+ else if (OpenCLName.starts_with("image3d"))
IntParams[0] = 2; // 2D
else if (OpenCLName == "image1d_buffer")
IntParams[0] = 5; // Buffer
else
- assert(OpenCLName.startswith("image1d") && "Unknown image type");
+ assert(OpenCLName.starts_with("image1d") && "Unknown image type");
// Set the other integer parameters of OpTypeImage if necessary. Note that the
// OpenCL image types don't provide any information for the Sampled or
diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index 540c22d07865..94c10e50d7d0 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -551,7 +551,7 @@ CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) {
// Normalize by removing relative path components.
llvm::sys::path::remove_dots(Path, /*remove_dot_dot*/ true, PathStyle);
- if (Path.endswith(".ast"))
+ if (Path.ends_with(".ast"))
return loadFromDump(Path);
else
return loadFromSource(Path);
diff --git a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
index 9b3d2571f29f..beca9586988b 100644
--- a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
+++ b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
@@ -14,7 +14,6 @@
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include <atomic>
#include <condition_variable>
@@ -25,6 +24,7 @@
#include <vector>
#include <fcntl.h>
+#include <limits.h>
#include <optional>
#include <sys/epoll.h>
#include <sys/inotify.h>
diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp
index 36f828f8cae2..a7e7f169dc14 100644
--- a/clang/lib/Driver/Distro.cpp
+++ b/clang/lib/Driver/Distro.cpp
@@ -34,7 +34,7 @@ static Distro::DistroType DetectOsRelease(llvm::vfs::FileSystem &VFS) {
// Obviously this can be improved a lot.
for (StringRef Line : Lines)
- if (Version == Distro::UnknownDistro && Line.startswith("ID="))
+ if (Version == Distro::UnknownDistro && Line.starts_with("ID="))
Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(3))
.Case("alpine", Distro::AlpineLinux)
.Case("fedora", Distro::Fedora)
@@ -60,7 +60,7 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) {
for (StringRef Line : Lines)
if (Version == Distro::UnknownDistro &&
- Line.startswith("DISTRIB_CODENAME="))
+ Line.starts_with("DISTRIB_CODENAME="))
Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17))
.Case("hardy", Distro::UbuntuHardy)
.Case("intrepid", Distro::UbuntuIntrepid)
@@ -119,10 +119,10 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
if (File) {
StringRef Data = File.get()->getBuffer();
- if (Data.startswith("Fedora release"))
+ if (Data.starts_with("Fedora release"))
return Distro::Fedora;
- if (Data.startswith("Red Hat Enterprise Linux") ||
- Data.startswith("CentOS") || Data.startswith("Scientific Linux")) {
+ if (Data.starts_with("Red Hat Enterprise Linux") ||
+ Data.starts_with("CentOS") || Data.starts_with("Scientific Linux")) {
if (Data.contains("release 7"))
return Distro::RHEL7;
else if (Data.contains("release 6"))
@@ -182,7 +182,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
SmallVector<StringRef, 8> Lines;
Data.split(Lines, "\n");
for (const StringRef &Line : Lines) {
- if (!Line.trim().startswith("VERSION"))
+ if (!Line.trim().starts_with("VERSION"))
continue;
std::pair<StringRef, StringRef> SplitLine = Line.split('=');
// Old versions have split VERSION and PATCHLEVEL
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index e241706b9082..ff95c899c5f3 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -1451,7 +1451,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
case llvm::Triple::aarch64_32:
- if (TC.getTriple().getEnvironmentName().startswith("eabi")) {
+ if (TC.getTriple().getEnvironmentName().starts_with("eabi")) {
Diag(diag::warn_target_unrecognized_env)
<< TargetTriple
<< (TC.getTriple().getArchName().str() + "-none-elf");
@@ -1522,7 +1522,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
// (or /Library/Logs/DiagnosticReports for root) and has the filename pattern
// clang-<VERSION>_<YYYY-MM-DD-HHMMSS>_<hostname>.crash.
path::home_directory(CrashDiagDir);
- if (CrashDiagDir.startswith("/var/root"))
+ if (CrashDiagDir.starts_with("/var/root"))
CrashDiagDir = "/";
path::append(CrashDiagDir, "Library/Logs/DiagnosticReports");
int PID =
@@ -1540,7 +1540,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
for (fs::directory_iterator File(CrashDiagDir, EC), FileEnd;
File != FileEnd && !EC; File.increment(EC)) {
StringRef FileName = path::filename(File->path());
- if (!FileName.startswith(Name))
+ if (!FileName.starts_with(Name))
continue;
if (fs::status(File->path(), FileStatus))
continue;
@@ -1551,7 +1551,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
// The first line should start with "Process:", otherwise this isn't a real
// .crash file.
StringRef Data = CrashFile.get()->getBuffer();
- if (!Data.startswith("Process:"))
+ if (!Data.starts_with("Process:"))
continue;
// Parse parent process pid line, e.g: "Parent Process: clang-4.0 [79141]"
size_t ParentProcPos = Data.find("Parent Process:");
@@ -1780,7 +1780,7 @@ void Driver::generateCompilationDiagnostics(
ReproCrashFilename = TempFile;
llvm::sys::path::replace_extension(ReproCrashFilename, ".crash");
}
- if (StringRef(TempFile).endswith(".cache")) {
+ if (StringRef(TempFile).ends_with(".cache")) {
// In some cases (modules) we'll dump extra data to help with reproducing
// the crash into a directory next to the output.
VFS = llvm::sys::path::filename(TempFile);
@@ -2001,7 +2001,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const {
// Distinguish "--autocomplete=-someflag" and "--autocomplete=-someflag,"
// because the latter indicates that the user put space before pushing tab
// which should end up in a file completion.
- const bool HasSpace = PassedFlags.endswith(",");
+ const bool HasSpace = PassedFlags.ends_with(",");
// Parse PassedFlags by "," as all the command-line flags are passed to this
// function separated by ","
@@ -2041,7 +2041,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const {
// When flag ends with '=' and there was no value completion, return empty
// string and fall back to the file autocompletion.
- if (SuggestedCompletions.empty() && !Cur.endswith("=")) {
+ if (SuggestedCompletions.empty() && !Cur.ends_with("=")) {
// If the flag is in the form of "--autocomplete=-foo",
// we were requested to print out all option names that start with "-foo".
// For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only".
@@ -2053,7 +2053,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const {
// TODO: Find a good way to add them to OptTable instead and them remove
// this code.
for (StringRef S : DiagnosticIDs::getDiagnosticFlags())
- if (S.startswith(Cur))
+ if (S.starts_with(Cur))
SuggestedCompletions.push_back(std::string(S));
}
@@ -2535,7 +2535,7 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
// so we can't downgrade diagnostics for `/GR-` from an error to a warning
// in cc mode. (We can in cl mode because cl.exe itself only warns on
// unknown flags.)
- if (IsCLMode() && Ty == types::TY_Object && !Value.startswith("/"))
+ if (IsCLMode() && Ty == types::TY_Object && !Value.starts_with("/"))
return true;
Diag(clang::diag::err_drv_no_such_file) << Value;
@@ -6565,7 +6565,7 @@ llvm::StringRef clang::driver::getDriverMode(StringRef ProgName,
getDriverOptTable().getOption(options::OPT_driver_mode).getPrefixedName();
llvm::StringRef Opt;
for (StringRef Arg : Args) {
- if (!Arg.startswith(OptName))
+ if (!Arg.starts_with(OptName))
continue;
Opt = Arg;
}
@@ -6606,7 +6606,7 @@ llvm::Error driver::expandResponseFiles(SmallVectorImpl<const char *> &Args,
else
Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
- if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).startswith("-cc1"))
+ if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).starts_with("-cc1"))
MarkEOLs = false;
llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer);
@@ -6620,7 +6620,7 @@ llvm::Error driver::expandResponseFiles(SmallVectorImpl<const char *> &Args,
// If -cc1 came from a response file, remove the EOL sentinels.
auto FirstArg = llvm::find_if(llvm::drop_begin(Args),
[](const char *A) { return A != nullptr; });
- if (FirstArg != Args.end() && StringRef(*FirstArg).startswith("-cc1")) {
+ if (FirstArg != Args.end() && StringRef(*FirstArg).starts_with("-cc1")) {
// If -cc1 came from a response file, remove the EOL sentinels.
if (MarkEOLs) {
auto newEnd = std::remove(Args.begin(), Args.end(), nullptr);
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index 203400440f9f..a6c1581be796 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -95,10 +95,10 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum,
// These flags are treated as a single argument (e.g., -F<Dir>).
StringRef FlagRef(Flag);
- IsInclude = FlagRef.startswith("-F") || FlagRef.startswith("-I");
+ IsInclude = FlagRef.starts_with("-F") || FlagRef.starts_with("-I");
if (IsInclude)
return !HaveCrashVFS;
- if (FlagRef.startswith("-fmodules-cache-path="))
+ if (FlagRef.starts_with("-fmodules-cache-path="))
return true;
SkipNum = 0;
@@ -185,8 +185,8 @@ rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx,
SmallString<128> NewInc;
if (NumArgs == 1) {
StringRef FlagRef(Args[Idx + NumArgs - 1]);
- assert((FlagRef.startswith("-F") || FlagRef.startswith("-I")) &&
- "Expecting -I or -F");
+ assert((FlagRef.starts_with("-F") || FlagRef.starts_with("-I")) &&
+ "Expecting -I or -F");
StringRef Inc = FlagRef.slice(2, StringRef::npos);
if (getAbsPath(Inc, NewInc)) {
SmallString<128> NewArg(FlagRef.slice(0, 2));
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index ab19166f18c2..96a57927339a 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -315,7 +315,7 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
for (const auto &DS : DriverSuffixes) {
StringRef Suffix(DS.Suffix);
- if (ProgName.endswith(Suffix)) {
+ if (ProgName.ends_with(Suffix)) {
Pos = ProgName.size() - Suffix.size();
return &DS;
}
@@ -345,7 +345,7 @@ static const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) {
// added via -target as implicit first argument.
const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos);
- if (!DS && ProgName.endswith(".exe")) {
+ if (!DS && ProgName.ends_with(".exe")) {
// Try again after stripping the executable suffix:
// clang++.exe -> clang++
ProgName = ProgName.drop_back(StringRef(".exe").size());
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp
index aed8734b2bab..f9670ea6f251 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -88,7 +88,7 @@ static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) {
for (size_t i = 0, Size = CmdArgs.size(); i < Size; ++i) {
llvm::StringRef ArgString(CmdArgs[i]);
- if (ArgString.startswith("-bE:") || ArgString.startswith("-bexport:") ||
+ if (ArgString.starts_with("-bE:") || ArgString.starts_with("-bexport:") ||
ArgString == "-bexpall" || ArgString == "-bexpfull")
return true;
@@ -96,8 +96,8 @@ static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) {
if (ArgString == "-b" && i + 1 < Size) {
++i;
llvm::StringRef ArgNextString(CmdArgs[i]);
- if (ArgNextString.startswith("E:") ||
- ArgNextString.startswith("export:") || ArgNextString == "expall" ||
+ if (ArgNextString.starts_with("E:") ||
+ ArgNextString.starts_with("export:") || ArgNextString == "expall" ||
ArgNextString == "expfull")
return true;
}
diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index cad206ea4df1..56f06fc5fccb 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -49,7 +49,7 @@ RocmInstallationDetector::findSPACKPackage(const Candidate &Cand,
FileEnd;
File != FileEnd && !EC; File.increment(EC)) {
llvm::StringRef FileName = llvm::sys::path::filename(File->path());
- if (FileName.startswith(Prefix)) {
+ if (FileName.starts_with(Prefix)) {
SubDirs.push_back(FileName);
if (SubDirs.size() > 1)
break;
@@ -84,13 +84,13 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
!EC && LI != LE; LI = LI.increment(EC)) {
StringRef FilePath = LI->path();
StringRef FileName = llvm::sys::path::filename(FilePath);
- if (!FileName.endswith(Suffix))
+ if (!FileName.ends_with(Suffix))
continue;
StringRef BaseName;
- if (FileName.endswith(Suffix2))
+ if (FileName.ends_with(Suffix2))
BaseName = FileName.drop_back(Suffix2.size());
- else if (FileName.endswith(Suffix))
+ else if (FileName.ends_with(Suffix))
BaseName = FileName.drop_back(Suffix.size());
const StringRef ABIVersionPrefix = "oclc_abi_version_";
@@ -124,7 +124,7 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
WavefrontSize64.On = FilePath;
} else if (BaseName == "oclc_wavefrontsize64_off") {
WavefrontSize64.Off = FilePath;
- } else if (BaseName.startswith(ABIVersionPrefix)) {
+ } else if (BaseName.starts_with(ABIVersionPrefix)) {
unsigned ABIVersionNumber;
if (BaseName.drop_front(ABIVersionPrefix.size())
.getAsInteger(/*Redex=*/0, ABIVersionNumber))
@@ -134,7 +134,7 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
// Process all bitcode filenames that look like
// ocl_isa_version_XXX.amdgcn.bc
const StringRef DeviceLibPrefix = "oclc_isa_version_";
- if (!BaseName.startswith(DeviceLibPrefix))
+ if (!BaseName.starts_with(DeviceLibPrefix))
continue;
StringRef IsaVersionNumber =
@@ -230,7 +230,7 @@ RocmInstallationDetector::getInstallationPathCandidates() {
// <rocm_root>/llvm-amdgpu-<rocm_release_string>-<hash>/bin directory.
// We only consider the parent directory of llvm-amdgpu package as ROCm
// installation candidate for SPACK.
- if (ParentName.startswith("llvm-amdgpu-")) {
+ if (ParentName.starts_with("llvm-amdgpu-")) {
auto SPACKPostfix =
ParentName.drop_front(strlen("llvm-amdgpu-")).split('-');
auto SPACKReleaseStr = SPACKPostfix.first;
@@ -243,7 +243,7 @@ RocmInstallationDetector::getInstallationPathCandidates() {
// Some versions of the rocm llvm package install to /opt/rocm/llvm/bin
// Some versions of the aomp package install to /opt/rocm/aomp/bin
- if (ParentName == "llvm" || ParentName.startswith("aomp"))
+ if (ParentName == "llvm" || ParentName.starts_with("aomp"))
ParentDir = llvm::sys::path::parent_path(ParentDir);
return Candidate(ParentDir.str(), /*StrictChecking=*/true);
@@ -292,7 +292,7 @@ RocmInstallationDetector::getInstallationPathCandidates() {
FileEnd;
File != FileEnd && !EC; File.increment(EC)) {
llvm::StringRef FileName = llvm::sys::path::filename(File->path());
- if (!FileName.startswith("rocm-"))
+ if (!FileName.starts_with("rocm-"))
continue;
if (LatestROCm.empty()) {
LatestROCm = FileName.str();
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
index 097258b16924..912df79417ae 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -228,7 +228,7 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
if (MtuneLowerCase == "native")
MtuneLowerCase = std::string(llvm::sys::getHostCPUName());
if (MtuneLowerCase == "cyclone" ||
- StringRef(MtuneLowerCase).startswith("apple")) {
+ StringRef(MtuneLowerCase).starts_with("apple")) {
Features.push_back("+zcm");
Features.push_back("+zcz");
}
@@ -262,7 +262,7 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
for (const auto *A :
Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler))
for (StringRef Value : A->getValues())
- if (Value.startswith("-march="))
+ if (Value.starts_with("-march="))
WaMArch = Value.substr(7);
// Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or
// "-Xassembler -march" is detected. Otherwise it may return false
diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
index f1d7aeb555f8..25470db2b6ce 100644
--- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -67,9 +67,9 @@ void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch,
// Use getValues because -Wa can have multiple arguments
// e.g. -Wa,-mcpu=foo,-mcpu=bar
for (StringRef Value : A->getValues()) {
- if (Value.startswith("-mcpu="))
+ if (Value.starts_with("-mcpu="))
CPU = Value.substr(6);
- if (Value.startswith("-march="))
+ if (Value.starts_with("-march="))
Arch = Value.substr(7);
}
}
@@ -285,9 +285,9 @@ void arm::setArchNameInTriple(const Driver &D, const ArgList &Args,
// There is no assembler equivalent of -mno-thumb, -marm, or -mno-arm.
if (Value == "-mthumb")
IsThumb = true;
- else if (Value.startswith("-march="))
+ else if (Value.starts_with("-march="))
WaMArch = Value.substr(7);
- else if (Value.startswith("-mcpu="))
+ else if (Value.starts_with("-mcpu="))
WaMCPU = Value.substr(6);
}
}
@@ -528,13 +528,13 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
// We use getValues here because you can have many options per -Wa
// We will keep the last one we find for each of these
for (StringRef Value : A->getValues()) {
- if (Value.startswith("-mfpu=")) {
+ if (Value.starts_with("-mfpu=")) {
WaFPU = std::make_pair(A, Value.substr(6));
- } else if (Value.startswith("-mcpu=")) {
+ } else if (Value.starts_with("-mcpu=")) {
WaCPU = std::make_pair(A, Value.substr(6));
- } else if (Value.startswith("-mhwdiv=")) {
+ } else if (Value.starts_with("-mhwdiv=")) {
WaHDiv = std::make_pair(A, Value.substr(8));
- } else if (Value.startswith("-march=")) {
+ } else if (Value.starts_with("-march=")) {
WaArch = std::make_pair(A, Value.substr(7));
}
}
@@ -796,7 +796,7 @@ fp16_fml_fallthrough:
// Propagate frame-chain model selection
if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) {
StringRef FrameChainOption = A->getValue();
- if (FrameChainOption.startswith("aapcs"))
+ if (FrameChainOption.starts_with("aapcs"))
Features.push_back("+aapcs-frame-chain");
if (FrameChainOption == "aapcs+leaf")
Features.push_back("+aapcs-frame-chain-leaf");
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
index 5d990ba78e5c..0b696111e7d7 100644
--- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -171,13 +171,8 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("-save-restore");
// -mno-unaligned-access is default, unless -munaligned-access is specified.
- if (const Arg *A = Args.getLastArg(options::OPT_munaligned_access,
- options::OPT_mno_unaligned_access)) {
- if (A->getOption().matches(options::OPT_munaligned_access))
- Features.push_back("+fast-unaligned-access");
- else
- Features.push_back("-fast-unaligned-access");
- }
+ AddTargetFeature(Args, Features, options::OPT_munaligned_access,
+ options::OPT_mno_unaligned_access, "fast-unaligned-access");
// Now add any that the user explicitly requested on the command line,
// which may override the defaults.
diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp
index 3e51b2b5ce86..fef0522aaf45 100644
--- a/clang/lib/Driver/ToolChains/Arch/X86.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp
@@ -234,15 +234,15 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
A->claim();
// Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
+ assert(Name.starts_with("m") && "Invalid feature name.");
Name = Name.substr(1);
- bool IsNegative = Name.startswith("no-");
+ bool IsNegative = Name.starts_with("no-");
if (IsNegative)
Name = Name.substr(3);
#ifndef NDEBUG
- assert(Name.startswith("avx10.") && "Invalid AVX10 feature name.");
+ assert(Name.starts_with("avx10.") && "Invalid AVX10 feature name.");
StringRef Version, Width;
std::tie(Version, Width) = Name.substr(6).split('-');
assert(Version == "1" && "Invalid AVX10 feature name.");
@@ -260,7 +260,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
A->claim();
// Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
+ assert(Name.starts_with("m") && "Invalid feature name.");
Name = Name.substr(1);
// Replace -mgeneral-regs-only with -x87, -mmx, -sse
@@ -269,7 +269,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
continue;
}
- bool IsNegative = Name.startswith("no-");
+ bool IsNegative = Name.starts_with("no-");
if (A->getOption().matches(options::OPT_mapx_features_EQ) ||
A->getOption().matches(options::OPT_mno_apx_features_EQ)) {
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index eb26bfade47b..de9fd5eaa1e0 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -223,7 +223,7 @@ static void ParseMRecip(const Driver &D, const ArgList &Args,
for (unsigned i = 0; i != NumOptions; ++i) {
StringRef Val = A->getValue(i);
- bool IsDisabled = Val.startswith(DisabledPrefixIn);
+ bool IsDisabled = Val.starts_with(DisabledPrefixIn);
// Ignore the disablement token for string matching.
if (IsDisabled)
Val = Val.substr(1);
@@ -433,7 +433,7 @@ static void addDebugObjectName(const ArgList &Args, ArgStringList &CmdArgs,
const char *OutputFileName) {
// No need to generate a value for -object-file-name if it was provided.
for (auto *Arg : Args.filtered(options::OPT_Xclang))
- if (StringRef(Arg->getValue()).startswith("-object-file-name"))
+ if (StringRef(Arg->getValue()).starts_with("-object-file-name"))
return;
if (Args.hasArg(options::OPT_object_file_name_EQ))
@@ -940,7 +940,7 @@ static void handleAMDGPUCodeObjectVersionOptions(const Driver &D,
static bool hasClangPchSignature(const Driver &D, StringRef Path) {
if (llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MemBuf =
D.getVFS().getBufferForFile(Path))
- return (*MemBuf)->getBuffer().startswith("CPCH");
+ return (*MemBuf)->getBuffer().starts_with("CPCH");
return false;
}
@@ -1715,7 +1715,7 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") ||
Val.equals("2048+")) {
unsigned Bits = 0;
- if (Val.endswith("+"))
+ if (Val.ends_with("+"))
Val = Val.substr(0, Val.size() - 1);
else {
bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid;
@@ -2503,7 +2503,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
case llvm::Triple::thumbeb:
case llvm::Triple::arm:
case llvm::Triple::armeb:
- if (Value.startswith("-mimplicit-it=")) {
+ if (Value.starts_with("-mimplicit-it=")) {
// Only store the value; the last value set takes effect.
ImplicitIt = Value.split("=").second;
if (CheckARMImplicitITArg(ImplicitIt))
@@ -2528,12 +2528,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
CmdArgs.push_back("-use-tcc-in-div");
continue;
}
- if (Value.startswith("-msoft-float")) {
+ if (Value.starts_with("-msoft-float")) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+soft-float");
continue;
}
- if (Value.startswith("-mhard-float")) {
+ if (Value.starts_with("-mhard-float")) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("-soft-float");
continue;
@@ -2570,8 +2570,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
CmdArgs.push_back("-massembler-no-warn");
} else if (Value == "--noexecstack") {
UseNoExecStack = true;
- } else if (Value.startswith("-compress-debug-sections") ||
- Value.startswith("--compress-debug-sections") ||
+ } else if (Value.starts_with("-compress-debug-sections") ||
+ Value.starts_with("--compress-debug-sections") ||
Value == "-nocompress-debug-sections" ||
Value == "--nocompress-debug-sections") {
CmdArgs.push_back(Value.data());
@@ -2581,13 +2581,13 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
} else if (Value == "-mrelax-relocations=no" ||
Value == "--mrelax-relocations=no") {
UseRelaxRelocations = false;
- } else if (Value.startswith("-I")) {
+ } else if (Value.starts_with("-I")) {
CmdArgs.push_back(Value.data());
// We need to consume the next argument if the current arg is a plain
// -I. The next arg will be the include directory.
if (Value == "-I")
TakeNextArg = true;
- } else if (Value.startswith("-gdwarf-")) {
+ } else if (Value.starts_with("-gdwarf-")) {
// "-gdwarf-N" options are not cc1as options.
unsigned DwarfVersion = DwarfVersionNum(Value);
if (DwarfVersion == 0) { // Send it onward, and let cc1as complain.
@@ -2597,30 +2597,30 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
llvm::codegenoptions::DebugInfoConstructor,
DwarfVersion, llvm::DebuggerKind::Default);
}
- } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") ||
- Value.startswith("-mhwdiv") || Value.startswith("-march")) {
+ } else if (Value.starts_with("-mcpu") || Value.starts_with("-mfpu") ||
+ Value.starts_with("-mhwdiv") || Value.starts_with("-march")) {
// Do nothing, we'll validate it later.
} else if (Value == "-defsym") {
- if (A->getNumValues() != 2) {
- D.Diag(diag::err_drv_defsym_invalid_format) << Value;
- break;
- }
- const char *S = A->getValue(1);
- auto Pair = StringRef(S).split('=');
- auto Sym = Pair.first;
- auto SVal = Pair.second;
-
- if (Sym.empty() || SVal.empty()) {
- D.Diag(diag::err_drv_defsym_invalid_format) << S;
- break;
- }
- int64_t IVal;
- if (SVal.getAsInteger(0, IVal)) {
- D.Diag(diag::err_drv_defsym_invalid_symval) << SVal;
- break;
- }
- CmdArgs.push_back(Value.data());
- TakeNextArg = true;
+ if (A->getNumValues() != 2) {
+ D.Diag(diag::err_drv_defsym_invalid_format) << Value;
+ break;
+ }
+ const char *S = A->getValue(1);
+ auto Pair = StringRef(S).split('=');
+ auto Sym = Pair.first;
+ auto SVal = Pair.second;
+
+ if (Sym.empty() || SVal.empty()) {
+ D.Diag(diag::err_drv_defsym_invalid_format) << S;
+ break;
+ }
+ int64_t IVal;
+ if (SVal.getAsInteger(0, IVal)) {
+ D.Diag(diag::err_drv_defsym_invalid_symval) << SVal;
+ break;
+ }
+ CmdArgs.push_back(Value.data());
+ TakeNextArg = true;
} else if (Value == "-fdebug-compilation-dir") {
CmdArgs.push_back("-fdebug-compilation-dir");
TakeNextArg = true;
@@ -2660,6 +2660,35 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
}
}
+static StringRef EnumComplexRangeToStr(LangOptions::ComplexRangeKind Range) {
+ StringRef RangeStr = "";
+ switch (Range) {
+ case LangOptions::ComplexRangeKind::CX_Limited:
+ return "-fcx-limited-range";
+ break;
+ case LangOptions::ComplexRangeKind::CX_Fortran:
+ return "-fcx-fortran-rules";
+ break;
+ default:
+ return RangeStr;
+ break;
+ }
+}
+
+static void EmitComplexRangeDiag(const Driver &D,
+ LangOptions::ComplexRangeKind Range1,
+ LangOptions::ComplexRangeKind Range2) {
+ if (Range1 != LangOptions::ComplexRangeKind::CX_Full)
+ D.Diag(clang::diag::warn_drv_overriding_option)
+ << EnumComplexRangeToStr(Range1) << EnumComplexRangeToStr(Range2);
+}
+
+static std::string RenderComplexRangeOption(std::string Range) {
+ std::string ComplexRangeStr = "-complex-range=";
+ ComplexRangeStr += Range;
+ return ComplexRangeStr;
+}
+
static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
bool OFastEnabled, const ArgList &Args,
ArgStringList &CmdArgs,
@@ -2706,6 +2735,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
bool StrictFPModel = false;
StringRef Float16ExcessPrecision = "";
StringRef BFloat16ExcessPrecision = "";
+ LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_Full;
if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
@@ -2718,6 +2748,28 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
switch (optID) {
default:
break;
+ case options::OPT_fcx_limited_range: {
+ EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Limited);
+ Range = LangOptions::ComplexRangeKind::CX_Limited;
+ std::string ComplexRangeStr = RenderComplexRangeOption("limited");
+ if (!ComplexRangeStr.empty())
+ CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
+ break;
+ }
+ case options::OPT_fno_cx_limited_range:
+ Range = LangOptions::ComplexRangeKind::CX_Full;
+ break;
+ case options::OPT_fcx_fortran_rules: {
+ EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Fortran);
+ Range = LangOptions::ComplexRangeKind::CX_Fortran;
+ std::string ComplexRangeStr = RenderComplexRangeOption("fortran");
+ if (!ComplexRangeStr.empty())
+ CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
+ break;
+ }
+ case options::OPT_fno_cx_fortran_rules:
+ Range = LangOptions::ComplexRangeKind::CX_Full;
+ break;
case options::OPT_ffp_model_EQ: {
// If -ffp-model= is seen, reset to fno-fast-math
HonorINFs = true;
@@ -2772,7 +2824,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << Val;
break;
- }
+ }
}
switch (optID) {
@@ -2971,7 +3023,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (!OFastEnabled)
continue;
[[fallthrough]];
- case options::OPT_ffast_math:
+ case options::OPT_ffast_math: {
HonorINFs = false;
HonorNaNs = false;
MathErrno = false;
@@ -2985,7 +3037,13 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// If fast-math is set then set the fp-contract mode to fast.
FPContract = "fast";
SeenUnsafeMathModeOption = true;
+ // ffast-math enables fortran rules for complex multiplication and
+ // division.
+ std::string ComplexRangeStr = RenderComplexRangeOption("limited");
+ if (!ComplexRangeStr.empty())
+ CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
break;
+ }
case options::OPT_fno_fast_math:
HonorINFs = true;
HonorNaNs = true;
@@ -3139,6 +3197,15 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow,
options::OPT_fstrict_float_cast_overflow, false))
CmdArgs.push_back("-fno-strict-float-cast-overflow");
+
+ if (const Arg *A = Args.getLastArg(options::OPT_fcx_limited_range))
+ CmdArgs.push_back("-fcx-limited-range");
+ if (const Arg *A = Args.getLastArg(options::OPT_fcx_fortran_rules))
+ CmdArgs.push_back("-fcx-fortran-rules");
+ if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_limited_range))
+ CmdArgs.push_back("-fno-cx-limited-range");
+ if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_fortran_rules))
+ CmdArgs.push_back("-fno-cx-fortran-rules");
}
static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
@@ -3264,7 +3331,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
// --param ssp-buffer-size=
for (const Arg *A : Args.filtered(options::OPT__param)) {
StringRef Str(A->getValue());
- if (Str.startswith("ssp-buffer-size=")) {
+ if (Str.starts_with("ssp-buffer-size=")) {
if (StackProtectorLevel) {
CmdArgs.push_back("-stack-protector-buffer-size");
// FIXME: Verify the argument is a valid integer.
@@ -5548,6 +5615,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_auto_import);
}
+ if (Args.hasFlag(options::OPT_fms_volatile, options::OPT_fno_ms_volatile,
+ Triple.isX86() && D.IsCLMode()))
+ CmdArgs.push_back("-fms-volatile");
+
// Non-PIC code defaults to -fdirect-access-external-data while PIC code
// defaults to -fno-direct-access-external-data. Pass the option if different
// from the default.
@@ -5815,7 +5886,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StringRef Val = A->getValue();
if (Triple.isX86() && Triple.isOSBinFormatELF()) {
if (Val != "all" && Val != "labels" && Val != "none" &&
- !Val.startswith("list="))
+ !Val.starts_with("list="))
D.Diag(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
else
@@ -7880,18 +7951,6 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
CmdArgs.push_back("-P");
}
- unsigned VolatileOptionID;
- if (getToolChain().getTriple().isX86())
- VolatileOptionID = options::OPT__SLASH_volatile_ms;
- else
- VolatileOptionID = options::OPT__SLASH_volatile_iso;
-
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group))
- VolatileOptionID = A->getOption().getID();
-
- if (VolatileOptionID == options::OPT__SLASH_volatile_ms)
- CmdArgs.push_back("-fms-volatile");
-
if (Args.hasFlag(options::OPT__SLASH_Zc_dllexportInlines_,
options::OPT__SLASH_Zc_dllexportInlines,
false)) {
@@ -8323,14 +8382,14 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
continue;
auto &JArgs = J.getArguments();
for (unsigned I = 0; I < JArgs.size(); ++I) {
- if (StringRef(JArgs[I]).startswith("-object-file-name=") &&
+ if (StringRef(JArgs[I]).starts_with("-object-file-name=") &&
Output.isFilename()) {
- ArgStringList NewArgs(JArgs.begin(), JArgs.begin() + I);
- addDebugObjectName(Args, NewArgs, DebugCompilationDir,
- Output.getFilename());
- NewArgs.append(JArgs.begin() + I + 1, JArgs.end());
- J.replaceArguments(NewArgs);
- break;
+ ArgStringList NewArgs(JArgs.begin(), JArgs.begin() + I);
+ addDebugObjectName(Args, NewArgs, DebugCompilationDir,
+ Output.getFilename());
+ NewArgs.append(JArgs.begin() + I + 1, JArgs.end());
+ J.replaceArguments(NewArgs);
+ break;
}
}
}
@@ -8594,7 +8653,7 @@ void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA,
getTargetFeatures(TC->getDriver(), TC->getTriple(), TCArgs, Features,
false);
llvm::copy_if(Features, std::back_inserter(FeatureArgs),
- [](StringRef Arg) { return !Arg.startswith("-target"); });
+ [](StringRef Arg) { return !Arg.starts_with("-target"); });
if (TC->getTriple().isAMDGPU()) {
for (StringRef Feature : llvm::split(Arch.split(':').second, ':')) {
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 51b336216c56..45901ee7157f 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -303,7 +303,7 @@ void tools::handleTargetFeaturesGroup(const Driver &D,
A->claim();
// Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
+ assert(Name.starts_with("m") && "Invalid feature name.");
Name = Name.substr(1);
auto Proc = getCPUName(D, Args, Triple);
@@ -317,7 +317,7 @@ void tools::handleTargetFeaturesGroup(const Driver &D,
continue;
}
- bool IsNegative = Name.startswith("no-");
+ bool IsNegative = Name.starts_with("no-");
if (IsNegative)
Name = Name.substr(3);
@@ -1116,60 +1116,91 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
return true;
}
-void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) {
- // These are handled earlier on Windows by telling the frontend driver to add
- // the correct libraries to link against as dependents in the object file.
- if (!TC.getTriple().isKnownWindowsMSVCEnvironment()) {
- // The --whole-archive option needs to be part of the link line to
- // make sure that the main() function from Fortran_main.a is pulled
- // in by the linker. Determine if --whole-archive is active when
- // flang will try to link Fortran_main.a. If it is, don't add the
- // --whole-archive flag to the link line. If it's not, add a proper
- // --whole-archive/--no-whole-archive bracket to the link line.
- bool WholeArchiveActive = false;
- for (auto *Arg : Args.filtered(options::OPT_Wl_COMMA))
- if (Arg)
- for (StringRef ArgValue : Arg->getValues()) {
- if (ArgValue == "--whole-archive")
- WholeArchiveActive = true;
- if (ArgValue == "--no-whole-archive")
- WholeArchiveActive = false;
- }
+/// Determines if --whole-archive is active in the list of arguments.
+static bool isWholeArchivePresent(const ArgList &Args) {
+ bool WholeArchiveActive = false;
+ for (auto *Arg : Args.filtered(options::OPT_Wl_COMMA)) {
+ if (Arg) {
+ for (StringRef ArgValue : Arg->getValues()) {
+ if (ArgValue == "--whole-archive")
+ WholeArchiveActive = true;
+ if (ArgValue == "--no-whole-archive")
+ WholeArchiveActive = false;
+ }
+ }
+ }
+
+ return WholeArchiveActive;
+}
+
+/// Add Fortran runtime libs for MSVC
+static void addFortranRuntimeLibsMSVC(const ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) {
+ unsigned RTOptionID = options::OPT__SLASH_MT;
+ if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {
+ RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue())
+ .Case("static", options::OPT__SLASH_MT)
+ .Case("static_dbg", options::OPT__SLASH_MTd)
+ .Case("dll", options::OPT__SLASH_MD)
+ .Case("dll_dbg", options::OPT__SLASH_MDd)
+ .Default(options::OPT__SLASH_MT);
+ }
+ switch (RTOptionID) {
+ case options::OPT__SLASH_MT:
+ CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static.lib");
+ break;
+ case options::OPT__SLASH_MTd:
+ CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static_dbg.lib");
+ break;
+ case options::OPT__SLASH_MD:
+ CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic.lib");
+ break;
+ case options::OPT__SLASH_MDd:
+ CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic_dbg.lib");
+ break;
+ }
+}
+
+// Add FortranMain runtime lib
+static void addFortranMain(const ToolChain &TC, const ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) {
+ // 1. MSVC
+ if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
+ addFortranRuntimeLibsMSVC(Args, CmdArgs);
+ return;
+ }
- if (!WholeArchiveActive)
- CmdArgs.push_back("--whole-archive");
+ // 2. GNU and similar
+ // The --whole-archive option needs to be part of the link line to make
+ // sure that the main() function from Fortran_main.a is pulled in by the
+ // linker. However, it shouldn't be used if it's already active.
+ // TODO: Find an equivalent of `--whole-archive` for Darwin.
+ if (!isWholeArchivePresent(Args) && !TC.getTriple().isMacOSX()) {
+ CmdArgs.push_back("--whole-archive");
CmdArgs.push_back("-lFortran_main");
- if (!WholeArchiveActive)
- CmdArgs.push_back("--no-whole-archive");
+ CmdArgs.push_back("--no-whole-archive");
+ return;
+ }
+
+ CmdArgs.push_back("-lFortran_main");
+}
- // Perform regular linkage of the remaining runtime libraries.
+/// Add Fortran runtime libs
+void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) {
+ // 1. Link FortranMain
+ // FortranMain depends on FortranRuntime, so needs to be listed first. If
+ // -fno-fortran-main has been passed, skip linking Fortran_main.a
+ if (!Args.hasArg(options::OPT_no_fortran_main))
+ addFortranMain(TC, Args, CmdArgs);
+
+ // 2. Link FortranRuntime and FortranDecimal
+ // These are handled earlier on Windows by telling the frontend driver to
+ // add the correct libraries to link against as dependents in the object
+ // file.
+ if (!TC.getTriple().isKnownWindowsMSVCEnvironment()) {
CmdArgs.push_back("-lFortranRuntime");
CmdArgs.push_back("-lFortranDecimal");
- } else {
- unsigned RTOptionID = options::OPT__SLASH_MT;
- if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {
- RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue())
- .Case("static", options::OPT__SLASH_MT)
- .Case("static_dbg", options::OPT__SLASH_MTd)
- .Case("dll", options::OPT__SLASH_MD)
- .Case("dll_dbg", options::OPT__SLASH_MDd)
- .Default(options::OPT__SLASH_MT);
- }
- switch (RTOptionID) {
- case options::OPT__SLASH_MT:
- CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static.lib");
- break;
- case options::OPT__SLASH_MTd:
- CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static_dbg.lib");
- break;
- case options::OPT__SLASH_MD:
- CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic.lib");
- break;
- case options::OPT__SLASH_MDd:
- CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic_dbg.lib");
- break;
- }
}
}
@@ -2330,20 +2361,20 @@ static void GetSDLFromOffloadArchive(
llvm::Triple Triple(D.getTargetTriple());
bool IsMSVC = Triple.isWindowsMSVCEnvironment();
auto Ext = IsMSVC ? ".lib" : ".a";
- if (!Lib.startswith(":") && !Lib.startswith("-l")) {
+ if (!Lib.starts_with(":") && !Lib.starts_with("-l")) {
if (llvm::sys::fs::exists(Lib)) {
ArchiveOfBundles = Lib;
FoundAOB = true;
}
} else {
- if (Lib.startswith("-l"))
+ if (Lib.starts_with("-l"))
Lib = Lib.drop_front(2);
for (auto LPath : LibraryPaths) {
ArchiveOfBundles.clear();
- auto LibFile =
- (Lib.startswith(":") ? Lib.drop_front()
- : IsMSVC ? Lib + Ext : "lib" + Lib + Ext)
- .str();
+ auto LibFile = (Lib.starts_with(":") ? Lib.drop_front()
+ : IsMSVC ? Lib + Ext
+ : "lib" + Lib + Ext)
+ .str();
for (auto Prefix : {"/libdevice/", "/"}) {
auto AOB = Twine(LPath + Prefix + LibFile).str();
if (llvm::sys::fs::exists(AOB)) {
diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp
index e95ff98e6c94..f7a208575cb0 100644
--- a/clang/lib/Driver/ToolChains/Cuda.cpp
+++ b/clang/lib/Driver/ToolChains/Cuda.cpp
@@ -78,6 +78,10 @@ CudaVersion getCudaVersion(uint32_t raw_version) {
return CudaVersion::CUDA_120;
if (raw_version < 12020)
return CudaVersion::CUDA_121;
+ if (raw_version < 12030)
+ return CudaVersion::CUDA_122;
+ if (raw_version < 12040)
+ return CudaVersion::CUDA_123;
return CudaVersion::NEW;
}
@@ -234,7 +238,7 @@ CudaInstallationDetector::CudaInstallationDetector(
// Process all bitcode filenames that look like
// libdevice.compute_XX.YY.bc
const StringRef LibDeviceName = "libdevice.";
- if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc")))
+ if (!(FileName.starts_with(LibDeviceName) && FileName.ends_with(".bc")))
continue;
StringRef GpuArch = FileName.slice(
LibDeviceName.size(), FileName.find('.', LibDeviceName.size()));
@@ -671,6 +675,8 @@ void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
case CudaVersion::CUDA_##CUDA_VER: \
PtxFeature = "+ptx" #PTX_VER; \
break;
+ CASE_CUDA_VERSION(123, 83);
+ CASE_CUDA_VERSION(122, 82);
CASE_CUDA_VERSION(121, 81);
CASE_CUDA_VERSION(120, 80);
CASE_CUDA_VERSION(118, 78);
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index f09bc27d7d2c..65846cace461 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1010,13 +1010,13 @@ static const char *ArmMachOArchNameCPU(StringRef CPU) {
// FIXME: Make sure this MachO triple mangling is really necessary.
// ARMv5* normalises to ARMv5.
- if (Arch.startswith("armv5"))
+ if (Arch.starts_with("armv5"))
Arch = Arch.substr(0, 5);
// ARMv6*, except ARMv6M, normalises to ARMv6.
- else if (Arch.startswith("armv6") && !Arch.endswith("6m"))
+ else if (Arch.starts_with("armv6") && !Arch.ends_with("6m"))
Arch = Arch.substr(0, 5);
// ARMv7A normalises to ARMv7.
- else if (Arch.endswith("v7a"))
+ else if (Arch.ends_with("v7a"))
Arch = Arch.substr(0, 5);
return Arch.data();
}
@@ -1281,7 +1281,7 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
// rpaths. This is currently true from this place, but we need to be
// careful if this function is ever called before user's rpaths are emitted.
if (Opts & RLO_AddRPath) {
- assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library");
+ assert(DarwinLibName.ends_with(".dylib") && "must be a dynamic library");
// Add @executable_path to rpath to support having the dylib copied with
// the executable.
@@ -1319,8 +1319,8 @@ StringRef Darwin::getSDKName(StringRef isysroot) {
auto EndSDK = llvm::sys::path::rend(isysroot);
for (auto IT = BeginSDK; IT != EndSDK; ++IT) {
StringRef SDK = *IT;
- if (SDK.endswith(".sdk"))
- return SDK.slice(0, SDK.size() - 4);
+ if (SDK.ends_with(".sdk"))
+ return SDK.slice(0, SDK.size() - 4);
}
return "";
}
@@ -1959,22 +1959,23 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args,
auto CreatePlatformFromSDKName =
[&](StringRef SDK) -> std::optional<DarwinPlatform> {
- if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator"))
+ if (SDK.starts_with("iPhoneOS") || SDK.starts_with("iPhoneSimulator"))
return DarwinPlatform::createFromSDK(
Darwin::IPhoneOS, Version,
- /*IsSimulator=*/SDK.startswith("iPhoneSimulator"));
- else if (SDK.startswith("MacOSX"))
+ /*IsSimulator=*/SDK.starts_with("iPhoneSimulator"));
+ else if (SDK.starts_with("MacOSX"))
return DarwinPlatform::createFromSDK(Darwin::MacOS,
getSystemOrSDKMacOSVersion(Version));
- else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator"))
+ else if (SDK.starts_with("WatchOS") || SDK.starts_with("WatchSimulator"))
return DarwinPlatform::createFromSDK(
Darwin::WatchOS, Version,
- /*IsSimulator=*/SDK.startswith("WatchSimulator"));
- else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator"))
+ /*IsSimulator=*/SDK.starts_with("WatchSimulator"));
+ else if (SDK.starts_with("AppleTVOS") ||
+ SDK.starts_with("AppleTVSimulator"))
return DarwinPlatform::createFromSDK(
Darwin::TvOS, Version,
- /*IsSimulator=*/SDK.startswith("AppleTVSimulator"));
- else if (SDK.startswith("DriverKit"))
+ /*IsSimulator=*/SDK.starts_with("AppleTVSimulator"));
+ else if (SDK.starts_with("DriverKit"))
return DarwinPlatform::createFromSDK(Darwin::DriverKit, Version);
return std::nullopt;
};
@@ -2339,8 +2340,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (SDK.size() > 0) {
size_t StartVer = SDK.find_first_of("0123456789");
StringRef SDKName = SDK.slice(0, StartVer);
- if (!SDKName.startswith(getPlatformFamily()) &&
- !dropSDKNamePrefix(SDKName).startswith(getPlatformFamily()))
+ if (!SDKName.starts_with(getPlatformFamily()) &&
+ !dropSDKNamePrefix(SDKName).starts_with(getPlatformFamily()))
getDriver().Diag(diag::warn_incompatible_sysroot)
<< SDKName << getPlatformFamily();
}
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 9b21fe952af7..41eaad3bbad0 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -182,7 +182,7 @@ void Flang::AddAArch64TargetArgs(const ArgList &Args,
Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") ||
Val.equals("2048+")) {
unsigned Bits = 0;
- if (Val.endswith("+"))
+ if (Val.ends_with("+"))
Val = Val.substr(0, Val.size() - 1);
else {
[[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits);
@@ -231,6 +231,8 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
assert(TC.getTriple().isKnownWindowsMSVCEnvironment() &&
"can only add VS runtime library on Windows!");
+ // if -fno-fortran-main has been passed, skip linking Fortran_main.a
+ bool LinkFortranMain = !Args.hasArg(options::OPT_no_fortran_main);
if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins")));
@@ -248,7 +250,8 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
case options::OPT__SLASH_MT:
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("--dependent-lib=libcmt");
- CmdArgs.push_back("--dependent-lib=Fortran_main.static.lib");
+ if (LinkFortranMain)
+ CmdArgs.push_back("--dependent-lib=Fortran_main.static.lib");
CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib");
CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib");
break;
@@ -256,7 +259,8 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("--dependent-lib=libcmtd");
- CmdArgs.push_back("--dependent-lib=Fortran_main.static_dbg.lib");
+ if (LinkFortranMain)
+ CmdArgs.push_back("--dependent-lib=Fortran_main.static_dbg.lib");
CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib");
CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib");
break;
@@ -264,7 +268,8 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("-D_DLL");
CmdArgs.push_back("--dependent-lib=msvcrt");
- CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic.lib");
+ if (LinkFortranMain)
+ CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic.lib");
CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib");
CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib");
break;
@@ -273,7 +278,8 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("-D_DLL");
CmdArgs.push_back("--dependent-lib=msvcrtd");
- CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib");
+ if (LinkFortranMain)
+ CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib");
CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib");
CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib");
break;
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index b875991844ff..835215a83c40 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -1084,7 +1084,7 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
std::vector<std::string> Dirs({"/include"});
- if (StringRef(M.includeSuffix()).startswith("/uclibc"))
+ if (StringRef(M.includeSuffix()).starts_with("/uclibc"))
Dirs.push_back(
"/../../../../mips-linux-gnu/libc/uclibc/usr/include");
else
@@ -1288,7 +1288,7 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
std::vector<std::string> Dirs({"/include"});
- if (StringRef(M.includeSuffix()).startswith("/uclibc"))
+ if (StringRef(M.includeSuffix()).starts_with("/uclibc"))
Dirs.push_back("/../../../../sysroot/uclibc/usr/include");
else
Dirs.push_back("/../../../../sysroot/usr/include");
@@ -3055,7 +3055,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D,
// the cross. Note that GCC does include some of these directories in some
// configurations but this seems somewhere between questionable and simply
// a bug.
- if (StringRef(LibPath).startswith(SysRoot))
+ if (StringRef(LibPath).starts_with(SysRoot))
addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths);
}
}
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index d0ff7d0c1310..6a2a105bee32 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -54,11 +54,11 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
auto makeFeature = [&Args](Twine T, bool Enable) -> StringRef {
const std::string &S = T.str();
StringRef Opt(S);
- if (Opt.endswith("="))
+ if (Opt.ends_with("="))
Opt = Opt.drop_back(1);
- if (Opt.startswith("mno-"))
+ if (Opt.starts_with("mno-"))
Opt = Opt.drop_front(4);
- else if (Opt.startswith("m"))
+ else if (Opt.starts_with("m"))
Opt = Opt.drop_front(1);
return Args.MakeArgString(Twine(Enable ? "+" : "-") + Twine(Opt));
};
@@ -801,7 +801,7 @@ StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
CpuArg = A;
StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
- if (CPU.startswith("hexagon"))
+ if (CPU.starts_with("hexagon"))
return CPU.substr(sizeof("hexagon") - 1);
return CPU;
}
diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp
index 2dfc90ef37f7..7a4c2bb7ede1 100644
--- a/clang/lib/Driver/ToolChains/Hurd.cpp
+++ b/clang/lib/Driver/ToolChains/Hurd.cpp
@@ -92,7 +92,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// those searched.
// FIXME: It's not clear whether we should use the driver's installed
// directory ('Dir' below) or the ResourceDir.
- if (StringRef(D.Dir).startswith(SysRoot)) {
+ if (StringRef(D.Dir).starts_with(SysRoot)) {
addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths);
addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths);
}
@@ -110,7 +110,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// searched.
// FIXME: It's not clear whether we should use the driver's installed
// directory ('Dir' below) or the ResourceDir.
- if (StringRef(D.Dir).startswith(SysRoot))
+ if (StringRef(D.Dir).starts_with(SysRoot))
addPathIfExists(D, D.Dir + "/../lib", Paths);
addPathIfExists(D, SysRoot + "/lib", Paths);
diff --git a/clang/lib/Driver/ToolChains/MSP430.cpp b/clang/lib/Driver/ToolChains/MSP430.cpp
index b28d5e45706c..8dc23521f400 100644
--- a/clang/lib/Driver/ToolChains/MSP430.cpp
+++ b/clang/lib/Driver/ToolChains/MSP430.cpp
@@ -166,7 +166,7 @@ void MSP430ToolChain::addClangTargetOptions(const ArgList &DriverArgs,
return;
const StringRef MCU = MCUArg->getValue();
- if (MCU.startswith("msp430i")) {
+ if (MCU.starts_with("msp430i")) {
// 'i' should be in lower case as it's defined in TI MSP430-GCC headers
CC1Args.push_back(DriverArgs.MakeArgString(
"-D__MSP430i" + MCU.drop_front(7).upper() + "__"));
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 6d925555b7bb..8e1e95173836 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -302,7 +302,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (A.getOption().matches(options::OPT_l)) {
StringRef Lib = A.getValue();
const char *LinkLibArg;
- if (Lib.endswith(".lib"))
+ if (Lib.ends_with(".lib"))
LinkLibArg = Args.MakeArgString(Lib);
else
LinkLibArg = Args.MakeArgString(Lib + ".lib");
diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp
index 5d7f8675daf8..65512f16357d 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -86,9 +86,9 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args,
CmdArgs.push_back("-lmoldname");
CmdArgs.push_back("-lmingwex");
for (auto Lib : Args.getAllArgValues(options::OPT_l))
- if (StringRef(Lib).startswith("msvcr") ||
- StringRef(Lib).startswith("ucrt") ||
- StringRef(Lib).startswith("crtdll"))
+ if (StringRef(Lib).starts_with("msvcr") ||
+ StringRef(Lib).starts_with("ucrt") ||
+ StringRef(Lib).starts_with("crtdll"))
return;
CmdArgs.push_back("-lmsvcrt");
}
diff --git a/clang/lib/Driver/ToolChains/PPCLinux.cpp b/clang/lib/Driver/ToolChains/PPCLinux.cpp
index bdbecaef6040..0ed0f91ad166 100644
--- a/clang/lib/Driver/ToolChains/PPCLinux.cpp
+++ b/clang/lib/Driver/ToolChains/PPCLinux.cpp
@@ -31,10 +31,10 @@ static bool GlibcSupportsFloat128(const std::string &Linker) {
// Since glibc 2.34, the installed .so file is not symlink anymore. But we can
// still safely assume it's newer than 2.32.
- if (LinkerName.startswith("ld64.so"))
+ if (LinkerName.starts_with("ld64.so"))
return true;
- if (!LinkerName.startswith("ld-2."))
+ if (!LinkerName.starts_with("ld-2."))
return false;
unsigned Minor = (LinkerName[5] - '0') * 10 + (LinkerName[6] - '0');
if (Minor < 32)
diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp
index 485730da7df1..9a9792d019d5 100644
--- a/clang/lib/Driver/ToolChains/Solaris.cpp
+++ b/clang/lib/Driver/ToolChains/Solaris.cpp
@@ -328,7 +328,7 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
// If we are currently running Clang inside of the requested system root,
// add its parent library path to those searched.
- if (StringRef(D.Dir).startswith(D.SysRoot))
+ if (StringRef(D.Dir).starts_with(D.SysRoot))
addPathIfExists(D, D.Dir + "/../lib", Paths);
addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths);
diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index f04018179a5d..57f4600727ec 100644
--- a/clang/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -143,7 +143,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// When optimizing, if wasm-opt is available, run it.
std::string WasmOptPath;
- if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ if (Args.getLastArg(options::OPT_O_Group)) {
WasmOptPath = ToolChain.GetProgramPath("wasm-opt");
if (WasmOptPath == "wasm-opt") {
WasmOptPath = {};
@@ -328,7 +328,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) {
StringRef Opt = A->getValue(0);
- if (Opt.startswith("-emscripten-cxx-exceptions-allowed")) {
+ if (Opt.starts_with("-emscripten-cxx-exceptions-allowed")) {
// '-mllvm -emscripten-cxx-exceptions-allowed' should be used with
// '-mllvm -enable-emscripten-cxx-exceptions'
bool EmEHArgExists = false;
@@ -355,7 +355,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
}
}
- if (Opt.startswith("-wasm-enable-sjlj")) {
+ if (Opt.starts_with("-wasm-enable-sjlj")) {
// '-mllvm -wasm-enable-sjlj' is not compatible with
// '-mno-exception-handling'
if (DriverArgs.hasFlag(options::OPT_mno_exception_handing,
diff --git a/clang/lib/Edit/Commit.cpp b/clang/lib/Edit/Commit.cpp
index 7c5aea6e5069..6e785e866666 100644
--- a/clang/lib/Edit/Commit.cpp
+++ b/clang/lib/Edit/Commit.cpp
@@ -334,7 +334,7 @@ bool Commit::canReplaceText(SourceLocation loc, StringRef text,
return false;
Len = text.size();
- return file.substr(Offs.getOffset()).startswith(text);
+ return file.substr(Offs.getOffset()).starts_with(text);
}
bool Commit::isAtStartOfMacroExpansion(SourceLocation loc,
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index adb34eba4970..d5bf553e2412 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -697,7 +697,7 @@ static bool getLiteralInfo(SourceRange literalRange,
struct Suff {
static bool has(StringRef suff, StringRef &text) {
- if (text.endswith(suff)) {
+ if (text.ends_with(suff)) {
text = text.substr(0, text.size()-suff.size());
return true;
}
@@ -739,9 +739,9 @@ static bool getLiteralInfo(SourceRange literalRange,
Info.F = UpperF ? "F" : "f";
Info.Hex = Info.Octal = false;
- if (text.startswith("0x"))
+ if (text.starts_with("0x"))
Info.Hex = true;
- else if (!isFloat && !isIntZero && text.startswith("0"))
+ else if (!isFloat && !isIntZero && text.starts_with("0"))
Info.Octal = true;
SourceLocation B = literalRange.getBegin();
diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
index fe282dfb19e8..fd62d841197d 100644
--- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -105,10 +105,10 @@ std::optional<std::string> getRelativeIncludeName(const CompilerInstance &CI,
// Special case Apple .sdk folders since the search path is typically a
// symlink like `iPhoneSimulator14.5.sdk` while the file is instead
// located in `iPhoneSimulator.sdk` (the real folder).
- if (NI->endswith(".sdk") && DI->endswith(".sdk")) {
+ if (NI->ends_with(".sdk") && DI->ends_with(".sdk")) {
StringRef NBasename = path::stem(*NI);
StringRef DBasename = path::stem(*DI);
- if (DBasename.startswith(NBasename))
+ if (DBasename.starts_with(NBasename))
continue;
}
diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index d9675b0c94de..53b22297ee0e 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -743,7 +743,7 @@ bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
// Filter out symbols prefixed with an underscored as they are understood to
// be symbols clients should not use.
- if (Record.Name.startswith("_"))
+ if (Record.Name.starts_with("_"))
return true;
return false;
diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp
index 954eeb9a6f24..473908e8fee3 100644
--- a/clang/lib/Format/BreakableToken.cpp
+++ b/clang/lib/Format/BreakableToken.cpp
@@ -55,7 +55,7 @@ static StringRef getLineCommentIndentPrefix(StringRef Comment,
}));
for (StringRef KnownPrefix : KnownPrefixes) {
- if (Comment.startswith(KnownPrefix)) {
+ if (Comment.starts_with(KnownPrefix)) {
const auto PrefixLength =
Comment.find_first_not_of(' ', KnownPrefix.size());
return Comment.substr(0, PrefixLength);
@@ -220,8 +220,8 @@ bool switchesFormatting(const FormatToken &Token) {
assert((Token.is(TT_BlockComment) || Token.is(TT_LineComment)) &&
"formatting regions are switched by comment tokens");
StringRef Content = Token.TokenText.substr(2).ltrim();
- return Content.startswith("clang-format on") ||
- Content.startswith("clang-format off");
+ return Content.starts_with("clang-format on") ||
+ Content.starts_with("clang-format off");
}
unsigned
@@ -271,7 +271,7 @@ BreakableStringLiteral::BreakableStringLiteral(
: BreakableToken(Tok, InPPDirective, Encoding, Style),
StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix),
UnbreakableTailLength(UnbreakableTailLength) {
- assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix));
+ assert(Tok.TokenText.starts_with(Prefix) && Tok.TokenText.ends_with(Postfix));
Line = Tok.TokenText.substr(
Prefix.size(), Tok.TokenText.size() - Prefix.size() - Postfix.size());
}
@@ -454,7 +454,7 @@ static bool mayReflowContent(StringRef Content) {
bool hasSpecialMeaningPrefix = false;
for (StringRef Prefix :
{"@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) {
- if (Content.startswith(Prefix)) {
+ if (Content.starts_with(Prefix)) {
hasSpecialMeaningPrefix = true;
break;
}
@@ -471,7 +471,7 @@ static bool mayReflowContent(StringRef Content) {
// characters and either the first or second character must be
// non-punctuation.
return Content.size() >= 2 && !hasSpecialMeaningPrefix &&
- !Content.endswith("\\") &&
+ !Content.ends_with("\\") &&
// Note that this is UTF-8 safe, since if isPunctuation(Content[0]) is
// true, then the first code point must be 1 byte long.
(!isPunctuation(Content[0]) || !isPunctuation(Content[1]));
@@ -488,7 +488,7 @@ BreakableBlockComment::BreakableBlockComment(
"block comment section must start with a block comment");
StringRef TokenText(Tok.TokenText);
- assert(TokenText.startswith("/*") && TokenText.endswith("*/"));
+ assert(TokenText.starts_with("/*") && TokenText.ends_with("*/"));
TokenText.substr(2, TokenText.size() - 4)
.split(Lines, UseCRLF ? "\r\n" : "\n");
@@ -511,7 +511,7 @@ BreakableBlockComment::BreakableBlockComment(
// /*
// ** blah blah blah
// */
- if (Lines.size() >= 2 && Content[1].startswith("**") &&
+ if (Lines.size() >= 2 && Content[1].starts_with("**") &&
static_cast<unsigned>(ContentColumn[1]) == StartColumn) {
DecorationColumn = StartColumn;
}
@@ -531,10 +531,10 @@ BreakableBlockComment::BreakableBlockComment(
// If the last line is empty, the closing "*/" will have a star.
if (Text.empty())
break;
- } else if (!Text.empty() && Decoration.startswith(Text)) {
+ } else if (!Text.empty() && Decoration.starts_with(Text)) {
continue;
}
- while (!Text.startswith(Decoration))
+ while (!Text.starts_with(Decoration))
Decoration = Decoration.drop_back(1);
}
@@ -562,13 +562,13 @@ BreakableBlockComment::BreakableBlockComment(
// The last line excludes the star if LastLineNeedsDecoration is false.
// For all other lines, adjust the line to exclude the star and
// (optionally) the first whitespace.
- unsigned DecorationSize = Decoration.startswith(Content[i])
+ unsigned DecorationSize = Decoration.starts_with(Content[i])
? Content[i].size()
: Decoration.size();
if (DecorationSize)
ContentColumn[i] = DecorationColumn + DecorationSize;
Content[i] = Content[i].substr(DecorationSize);
- if (!Decoration.startswith(Content[i])) {
+ if (!Decoration.starts_with(Content[i])) {
IndentAtLineBreak =
std::min<int>(IndentAtLineBreak, std::max(0, ContentColumn[i]));
}
@@ -577,10 +577,10 @@ BreakableBlockComment::BreakableBlockComment(
// Detect a multiline jsdoc comment and set DelimitersOnNewline in that case.
if (Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) {
- if ((Lines[0] == "*" || Lines[0].startswith("* ")) && Lines.size() > 1) {
+ if ((Lines[0] == "*" || Lines[0].starts_with("* ")) && Lines.size() > 1) {
// This is a multiline jsdoc comment.
DelimitersOnNewline = true;
- } else if (Lines[0].startswith("* ") && Lines.size() == 1) {
+ } else if (Lines[0].starts_with("* ") && Lines.size() == 1) {
// Detect a long single-line comment, like:
// /** long long long */
// Below, '2' is the width of '*/'.
@@ -612,7 +612,7 @@ BreakableToken::Split BreakableBlockComment::getSplit(
return Split(StringRef::npos, 0);
return getCommentSplit(Content[LineIndex].substr(TailOffset),
ContentStartColumn, ColumnLimit, Style.TabWidth,
- Encoding, Style, Decoration.endswith("*"));
+ Encoding, Style, Decoration.ends_with("*"));
}
void BreakableBlockComment::adjustWhitespace(unsigned LineIndex,
@@ -623,7 +623,7 @@ void BreakableBlockComment::adjustWhitespace(unsigned LineIndex,
// trimming the trailing whitespace. The backslash will be re-added later when
// inserting a line break.
size_t EndOfPreviousLine = Lines[LineIndex - 1].size();
- if (InPPDirective && Lines[LineIndex - 1].endswith("\\"))
+ if (InPPDirective && Lines[LineIndex - 1].ends_with("\\"))
--EndOfPreviousLine;
// Calculate the end of the non-whitespace text in the previous line.
@@ -672,7 +672,7 @@ unsigned BreakableBlockComment::getRemainingLength(unsigned LineIndex,
// We never need a decoration when breaking just the trailing "*/" postfix.
bool HasRemainingText = Offset < Content[LineIndex].size();
if (!HasRemainingText) {
- bool HasDecoration = Lines[LineIndex].ltrim().startswith(Decoration);
+ bool HasDecoration = Lines[LineIndex].ltrim().starts_with(Decoration);
if (HasDecoration)
LineLength -= Decoration.size();
}
@@ -700,7 +700,7 @@ unsigned BreakableBlockComment::getContentIndent(unsigned LineIndex) const {
// /** line 0 */
// is "* line 0", so we need to skip over the decoration in that case.
StringRef ContentWithNoDecoration = Content[LineIndex];
- if (LineIndex == 0 && ContentWithNoDecoration.startswith("*"))
+ if (LineIndex == 0 && ContentWithNoDecoration.starts_with("*"))
ContentWithNoDecoration = ContentWithNoDecoration.substr(1).ltrim(Blanks);
StringRef FirstWord = ContentWithNoDecoration.substr(
0, ContentWithNoDecoration.find_first_of(Blanks));
@@ -853,7 +853,7 @@ bool BreakableBlockComment::mayReflow(
// Content[LineIndex] may exclude the indent after the '*' decoration. In that
// case, we compute the start of the comment pragma manually.
StringRef IndentContent = Content[LineIndex];
- if (Lines[LineIndex].ltrim(Blanks).startswith("*"))
+ if (Lines[LineIndex].ltrim(Blanks).starts_with("*"))
IndentContent = Lines[LineIndex].ltrim(Blanks).substr(1);
return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
@@ -876,7 +876,7 @@ BreakableLineCommentSection::BreakableLineCommentSection(
CurrentTok = CurrentTok->Next) {
LastLineTok = LineTok;
StringRef TokenText(CurrentTok->TokenText);
- assert((TokenText.startswith("//") || TokenText.startswith("#")) &&
+ assert((TokenText.starts_with("//") || TokenText.starts_with("#")) &&
"unsupported line comment prefix, '//' and '#' are supported");
size_t FirstLineIndex = Lines.size();
TokenText.split(Lines, "\n");
@@ -913,7 +913,7 @@ BreakableLineCommentSection::BreakableLineCommentSection(
// #########
// # section
// #########
- if (FirstCommentChar == '#' && !TokenText.startswith("#"))
+ if (FirstCommentChar == '#' && !TokenText.starts_with("#"))
return false;
return FirstCommentChar == '\\' || isPunctuation(FirstCommentChar) ||
isHorizontalWhitespace(FirstCommentChar);
@@ -1152,7 +1152,7 @@ bool BreakableLineCommentSection::mayReflow(
// Line comments have the indent as part of the prefix, so we need to
// recompute the start of the line.
StringRef IndentContent = Content[LineIndex];
- if (Lines[LineIndex].startswith("//"))
+ if (Lines[LineIndex].starts_with("//"))
IndentContent = Lines[LineIndex].substr(2);
// FIXME: Decide whether we want to reflow non-regular indents:
// Currently, we only reflow when the OriginalPrefix[LineIndex] matches the
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 9e4e939503df..bd319f21b05f 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -161,7 +161,7 @@ static bool opensProtoMessageField(const FormatToken &LessTok,
// string. For example, the delimiter of R"deli(cont)deli" is deli.
static std::optional<StringRef> getRawStringDelimiter(StringRef TokenText) {
if (TokenText.size() < 5 // The smallest raw string possible is 'R"()"'.
- || !TokenText.startswith("R\"") || !TokenText.endswith("\"")) {
+ || !TokenText.starts_with("R\"") || !TokenText.ends_with("\"")) {
return std::nullopt;
}
@@ -177,7 +177,7 @@ static std::optional<StringRef> getRawStringDelimiter(StringRef TokenText) {
size_t RParenPos = TokenText.size() - Delimiter.size() - 2;
if (TokenText[RParenPos] != ')')
return std::nullopt;
- if (!TokenText.substr(RParenPos + 1).startswith(Delimiter))
+ if (!TokenText.substr(RParenPos + 1).starts_with(Delimiter))
return std::nullopt;
return Delimiter;
}
@@ -608,7 +608,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
if (Current.is(tok::lessless) &&
((Previous.is(tok::identifier) && Previous.TokenText == "endl") ||
- (Previous.Tok.isLiteral() && (Previous.TokenText.endswith("\\n\"") ||
+ (Previous.Tok.isLiteral() && (Previous.TokenText.ends_with("\\n\"") ||
Previous.TokenText == "\'\\n\'")))) {
return true;
}
@@ -2293,12 +2293,13 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
if (Style.isVerilog() || Style.Language == FormatStyle::LK_Java ||
Style.isJavaScript() || Style.isCSharp()) {
BreakableStringLiteralUsingOperators::QuoteStyleType QuoteStyle;
- if (Style.isJavaScript() && Text.startswith("'") && Text.endswith("'")) {
+ if (Style.isJavaScript() && Text.starts_with("'") &&
+ Text.ends_with("'")) {
QuoteStyle = BreakableStringLiteralUsingOperators::SingleQuotes;
- } else if (Style.isCSharp() && Text.startswith("@\"") &&
- Text.endswith("\"")) {
+ } else if (Style.isCSharp() && Text.starts_with("@\"") &&
+ Text.ends_with("\"")) {
QuoteStyle = BreakableStringLiteralUsingOperators::AtDoubleQuotes;
- } else if (Text.startswith("\"") && Text.endswith("\"")) {
+ } else if (Text.starts_with("\"") && Text.ends_with("\"")) {
QuoteStyle = BreakableStringLiteralUsingOperators::DoubleQuotes;
} else {
return nullptr;
@@ -2315,12 +2316,14 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
// FIXME: Store Prefix and Suffix (or PrefixLength and SuffixLength to
// reduce the overhead) for each FormatToken, which is a string, so that we
// don't run multiple checks here on the hot path.
- if ((Text.endswith(Postfix = "\"") &&
- (Text.startswith(Prefix = "@\"") || Text.startswith(Prefix = "\"") ||
- Text.startswith(Prefix = "u\"") || Text.startswith(Prefix = "U\"") ||
- Text.startswith(Prefix = "u8\"") ||
- Text.startswith(Prefix = "L\""))) ||
- (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) {
+ if ((Text.ends_with(Postfix = "\"") &&
+ (Text.starts_with(Prefix = "@\"") || Text.starts_with(Prefix = "\"") ||
+ Text.starts_with(Prefix = "u\"") ||
+ Text.starts_with(Prefix = "U\"") ||
+ Text.starts_with(Prefix = "u8\"") ||
+ Text.starts_with(Prefix = "L\""))) ||
+ (Text.starts_with(Prefix = "_T(\"") &&
+ Text.ends_with(Postfix = "\")"))) {
return std::make_unique<BreakableStringLiteral>(
Current, StartColumn, Prefix, Postfix, UnbreakableTailLength,
State.Line->InPPDirective, Encoding, Style);
@@ -2342,7 +2345,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
bool RegularComments = [&]() {
for (const FormatToken *T = &Current; T && T->is(TT_LineComment);
T = T->Next) {
- if (!(T->TokenText.startswith("//") || T->TokenText.startswith("#")))
+ if (!(T->TokenText.starts_with("//") || T->TokenText.starts_with("#")))
return false;
}
return true;
@@ -2754,7 +2757,7 @@ bool ContinuationIndenter::nextIsMultilineString(const LineState &State) {
// We never consider raw string literals "multiline" for the purpose of
// AlwaysBreakBeforeMultilineStrings implementation as they are special-cased
// (see TokenAnnotator::mustBreakBefore().
- if (Current.TokenText.startswith("R\""))
+ if (Current.TokenText.starts_with("R\""))
return false;
if (Current.IsMultiline)
return true;
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 8feee7457fc3..668e959a9416 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -2346,9 +2346,9 @@ private:
// NB: testing for not starting with a double quote to avoid
// breaking `template strings`.
(Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
- !Input.startswith("\"")) ||
+ !Input.starts_with("\"")) ||
(Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
- !Input.startswith("\'"))) {
+ !Input.starts_with("\'"))) {
continue;
}
@@ -2932,7 +2932,7 @@ private:
};
for (auto *Line : AnnotatedLines) {
- if (Line->First && (Line->First->TokenText.startswith("#") ||
+ if (Line->First && (Line->First->TokenText.starts_with("#") ||
Line->First->TokenText == "__pragma" ||
Line->First->TokenText == "_Pragma")) {
continue;
@@ -3217,7 +3217,7 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
Style.IncludeStyle.IncludeBlocks ==
tooling::IncludeStyle::IBS_Regroup);
- bool MergeWithNextLine = Trimmed.endswith("\\");
+ bool MergeWithNextLine = Trimmed.ends_with("\\");
if (!FormattingOff && !MergeWithNextLine) {
if (tooling::HeaderIncludes::IncludeRegex.match(Line, &Matches)) {
StringRef IncludeName = Matches[2];
@@ -3243,7 +3243,7 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code,
Replaces, Cursor);
IncludesInBlock.clear();
- if (Trimmed.startswith("#pragma hdrstop")) // Precompiled headers.
+ if (Trimmed.starts_with("#pragma hdrstop")) // Precompiled headers.
FirstIncludeBlock = true;
else
FirstIncludeBlock = false;
@@ -3271,7 +3271,7 @@ static unsigned findJavaImportGroup(const FormatStyle &Style,
unsigned LongestMatchLength = 0;
for (unsigned I = 0; I < Style.JavaImportGroups.size(); I++) {
const std::string &GroupPrefix = Style.JavaImportGroups[I];
- if (ImportIdentifier.startswith(GroupPrefix) &&
+ if (ImportIdentifier.starts_with(GroupPrefix) &&
GroupPrefix.length() > LongestMatchLength) {
LongestMatchIndex = I;
LongestMatchLength = GroupPrefix.length();
@@ -3426,7 +3426,7 @@ bool isMpegTS(StringRef Code) {
return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
}
-bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); }
+bool isLikelyXml(StringRef Code) { return Code.ltrim().starts_with("<"); }
tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
@@ -3538,7 +3538,7 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
for (const auto &Header : HeadersToDelete) {
tooling::Replacements Replaces =
- Includes.remove(Header.trim("\"<>"), Header.startswith("<"));
+ Includes.remove(Header.trim("\"<>"), Header.starts_with("<"));
for (const auto &R : Replaces) {
auto Err = Result.add(R);
if (Err) {
@@ -3560,7 +3560,7 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
(void)Matched;
auto IncludeName = Matches[2];
auto Replace =
- Includes.insert(IncludeName.trim("\"<>"), IncludeName.startswith("<"),
+ Includes.insert(IncludeName.trim("\"<>"), IncludeName.starts_with("<"),
tooling::IncludeDirective::Include);
if (Replace) {
auto Err = Result.add(*Replace);
@@ -3882,14 +3882,14 @@ const char *StyleOptionHelpDescription =
" --style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
- if (FileName.endswith(".java"))
+ if (FileName.ends_with(".java"))
return FormatStyle::LK_Java;
if (FileName.ends_with_insensitive(".js") ||
FileName.ends_with_insensitive(".mjs") ||
FileName.ends_with_insensitive(".ts")) {
return FormatStyle::LK_JavaScript; // (module) JavaScript or TypeScript.
}
- if (FileName.endswith(".m") || FileName.endswith(".mm"))
+ if (FileName.ends_with(".m") || FileName.ends_with(".mm"))
return FormatStyle::LK_ObjC;
if (FileName.ends_with_insensitive(".proto") ||
FileName.ends_with_insensitive(".protodevel")) {
@@ -3963,7 +3963,7 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
llvm::SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 1>
ChildFormatTextToApply;
- if (StyleName.startswith("{")) {
+ if (StyleName.starts_with("{")) {
// Parse YAML/JSON style from the command line.
StringRef Source = "<command-line>";
if (std::error_code ec =
@@ -4123,7 +4123,7 @@ static bool isClangFormatOnOff(StringRef Comment, bool On) {
static const char ClangFormatOff[] = "// clang-format off";
const unsigned Size = (On ? sizeof ClangFormatOn : sizeof ClangFormatOff) - 1;
- return Comment.startswith(On ? ClangFormatOn : ClangFormatOff) &&
+ return Comment.starts_with(On ? ClangFormatOn : ClangFormatOff) &&
(Comment.size() == Size || Comment[Size] == ':');
}
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 14a3c21ba44e..3f9664f8f78a 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -667,7 +667,7 @@ public:
/// Returns whether \p Tok is ([{ or an opening < of a template or in
/// protos.
bool opensScope() const {
- if (is(TT_TemplateString) && TokenText.endswith("${"))
+ if (is(TT_TemplateString) && TokenText.ends_with("${"))
return true;
if (is(TT_DictLiteral) && is(tok::less))
return true;
@@ -677,7 +677,7 @@ public:
/// Returns whether \p Tok is )]} or a closing > of a template or in
/// protos.
bool closesScope() const {
- if (is(TT_TemplateString) && TokenText.startswith("}"))
+ if (is(TT_TemplateString) && TokenText.starts_with("}"))
return true;
if (is(TT_DictLiteral) && is(tok::greater))
return true;
@@ -743,9 +743,9 @@ public:
if (isNot(tok::string_literal))
return false;
StringRef Content = TokenText;
- if (Content.startswith("\"") || Content.startswith("'"))
+ if (Content.starts_with("\"") || Content.starts_with("'"))
Content = Content.drop_front(1);
- if (Content.endswith("\"") || Content.endswith("'"))
+ if (Content.ends_with("\"") || Content.ends_with("'"))
Content = Content.drop_back(1);
Content = Content.trim();
return Content.size() > 1 &&
@@ -1823,7 +1823,7 @@ private:
};
inline bool isLineComment(const FormatToken &FormatTok) {
- return FormatTok.is(tok::comment) && !FormatTok.TokenText.startswith("/*");
+ return FormatTok.is(tok::comment) && !FormatTok.TokenText.starts_with("/*");
}
// Checks if \p FormatTok is a line comment that continues the line comment
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index e4e32e2671df..61430282c6f8 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -711,12 +711,12 @@ void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
bool Verbatim = false;
bool Interpolated = false;
- if (TokenText.startswith(R"($@")") || TokenText.startswith(R"(@$")")) {
+ if (TokenText.starts_with(R"($@")") || TokenText.starts_with(R"(@$")")) {
Verbatim = true;
Interpolated = true;
- } else if (TokenText.startswith(R"(@")")) {
+ } else if (TokenText.starts_with(R"(@")")) {
Verbatim = true;
- } else if (TokenText.startswith(R"($")")) {
+ } else if (TokenText.starts_with(R"($")")) {
Interpolated = true;
}
@@ -1110,7 +1110,7 @@ FormatToken *FormatTokenLexer::getNextToken() {
// the comment token at the backslash, and resets the lexer to restart behind
// the backslash.
if ((Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) &&
- FormatTok->is(tok::comment) && FormatTok->TokenText.startswith("//")) {
+ FormatTok->is(tok::comment) && FormatTok->TokenText.starts_with("//")) {
size_t BackslashPos = FormatTok->TokenText.find('\\');
while (BackslashPos != StringRef::npos) {
if (BackslashPos + 1 < FormatTok->TokenText.size() &&
diff --git a/clang/lib/Format/SortJavaScriptImports.cpp b/clang/lib/Format/SortJavaScriptImports.cpp
index 8c6722e91534..1a6a1b19e702 100644
--- a/clang/lib/Format/SortJavaScriptImports.cpp
+++ b/clang/lib/Format/SortJavaScriptImports.cpp
@@ -468,10 +468,10 @@ private:
// URL = TokenText without the quotes.
Reference.URL =
Current->TokenText.substr(1, Current->TokenText.size() - 2);
- if (Reference.URL.startswith("..")) {
+ if (Reference.URL.starts_with("..")) {
Reference.Category =
JsModuleReference::ReferenceCategory::RELATIVE_PARENT;
- } else if (Reference.URL.startswith(".")) {
+ } else if (Reference.URL.starts_with(".")) {
Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
} else {
Reference.Category = JsModuleReference::ReferenceCategory::ABSOLUTE;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index eaccb5881ca3..f3551af34243 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -164,6 +164,10 @@ private:
TT_OverloadedOperatorLParen))) {
return false;
}
+ if (Previous.Previous->is(tok::kw_operator) &&
+ CurrentToken->is(tok::l_paren)) {
+ return false;
+ }
}
FormatToken *Left = CurrentToken->Previous;
@@ -1307,7 +1311,7 @@ private:
if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator, tok::comma,
tok::star, tok::arrow, tok::amp, tok::ampamp) ||
// User defined literal.
- Previous->TokenText.startswith("\"\"")) {
+ Previous->TokenText.starts_with("\"\"")) {
Previous->setType(TT_OverloadedOperator);
if (CurrentToken->isOneOf(tok::less, tok::greater))
break;
@@ -1466,7 +1470,7 @@ private:
// Mark tokens up to the trailing line comments as implicit string
// literals.
if (CurrentToken->isNot(tok::comment) &&
- !CurrentToken->TokenText.startswith("//")) {
+ !CurrentToken->TokenText.starts_with("//")) {
CurrentToken->setType(TT_ImplicitStringLiteral);
}
next();
@@ -2077,8 +2081,8 @@ private:
}
Current.setType(TT_BinaryOperator);
} else if (Current.is(tok::comment)) {
- if (Current.TokenText.startswith("/*")) {
- if (Current.TokenText.endswith("*/")) {
+ if (Current.TokenText.starts_with("/*")) {
+ if (Current.TokenText.ends_with("*/")) {
Current.setType(TT_BlockComment);
} else {
// The lexer has for some reason determined a comment here. But we
@@ -3724,8 +3728,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
return 100;
if (Left.is(TT_JsTypeColon))
return 35;
- if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
- (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) {
+ if ((Left.is(TT_TemplateString) && Left.TokenText.ends_with("${")) ||
+ (Right.is(TT_TemplateString) && Right.TokenText.starts_with("}"))) {
return 100;
}
// Prefer breaking call chains (".foo") over empty "{}", "[]" or "()".
@@ -4224,7 +4228,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
}
if (Left.is(TT_BlockComment)) {
// No whitespace in x(/*foo=*/1), except for JavaScript.
- return Style.isJavaScript() || !Left.TokenText.endswith("=*/");
+ return Style.isJavaScript() || !Left.TokenText.ends_with("=*/");
}
// Space between template and attribute.
@@ -4572,8 +4576,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Next && Next->is(TT_FatArrow))
return true;
}
- if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
- (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) {
+ if ((Left.is(TT_TemplateString) && Left.TokenText.ends_with("${")) ||
+ (Right.is(TT_TemplateString) && Right.TokenText.starts_with("}"))) {
return false;
}
// In tagged template literals ("html`bar baz`"), there is no space between
@@ -5212,7 +5216,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
Left.is(TT_InheritanceComma)) {
return true;
}
- if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\"")) {
+ if (Right.is(tok::string_literal) && Right.TokenText.starts_with("R\"")) {
// Multiline raw string literals are special wrt. line breaks. The author
// has made a deliberate choice and might have aligned the contents of the
// string literal accordingly. Thus, we try keep existing line breaks.
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 57126b8dfeac..c38b4c884070 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -1333,7 +1333,7 @@ bool UnwrappedLineParser::parseModuleImport() {
// Mark tokens up to the trailing line comments as implicit string
// literals.
if (FormatTok->isNot(tok::comment) &&
- !FormatTok->TokenText.startswith("//")) {
+ !FormatTok->TokenText.starts_with("//")) {
FormatTok->setFinalizedType(TT_ImplicitStringLiteral);
}
nextToken();
@@ -1371,7 +1371,7 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous);
bool PreviousStartsTemplateExpr =
- Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${");
+ Previous->is(TT_TemplateString) && Previous->TokenText.ends_with("${");
if (PreviousMustBeValue || Previous->is(tok::r_paren)) {
// If the line contains an '@' sign, the previous token might be an
// annotation, which can precede another identifier/value.
@@ -1385,7 +1385,7 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
return addUnwrappedLine();
bool NextMustBeValue = mustBeJSIdentOrValue(Keywords, Next);
bool NextEndsTemplateExpr =
- Next->is(TT_TemplateString) && Next->TokenText.startswith("}");
+ Next->is(TT_TemplateString) && Next->TokenText.starts_with("}");
if (NextMustBeValue && !NextEndsTemplateExpr && !PreviousStartsTemplateExpr &&
(PreviousMustBeValue ||
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
@@ -4459,8 +4459,8 @@ continuesLineCommentSection(const FormatToken &FormatTok,
return false;
StringRef IndentContent = FormatTok.TokenText;
- if (FormatTok.TokenText.startswith("//") ||
- FormatTok.TokenText.startswith("/*")) {
+ if (FormatTok.TokenText.starts_with("//") ||
+ FormatTok.TokenText.starts_with("/*")) {
IndentContent = FormatTok.TokenText.substr(2);
}
if (CommentPragmasRegex.match(IndentContent))
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index b33bdad2ad81..11f3f2c2d642 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2829,7 +2829,7 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
"-interface-stub-version=ifs-v1"
<< ErrorMessage;
ProgramAction = frontend::ParseSyntaxOnly;
- } else if (!ArgStr.startswith("ifs-")) {
+ } else if (!ArgStr.starts_with("ifs-")) {
std::string ErrorMessage =
"Invalid interface stub format: " + ArgStr.str() + ".";
Diags.Report(diag::err_drv_invalid_value)
@@ -4106,13 +4106,13 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
// Check the version number is valid: either 3.x (0 <= x <= 9) or
// y or y.0 (4 <= y <= current version).
- if (!VerParts.first.startswith("0") &&
- !VerParts.first.getAsInteger(10, Major) &&
- 3 <= Major && Major <= CLANG_VERSION_MAJOR &&
- (Major == 3 ? VerParts.second.size() == 1 &&
- !VerParts.second.getAsInteger(10, Minor)
- : VerParts.first.size() == Ver.size() ||
- VerParts.second == "0")) {
+ if (!VerParts.first.starts_with("0") &&
+ !VerParts.first.getAsInteger(10, Major) && 3 <= Major &&
+ Major <= CLANG_VERSION_MAJOR &&
+ (Major == 3
+ ? VerParts.second.size() == 1 &&
+ !VerParts.second.getAsInteger(10, Minor)
+ : VerParts.first.size() == Ver.size() || VerParts.second == "0")) {
// Got a valid version number.
if (Major == 3 && Minor <= 8)
Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8);
diff --git a/clang/lib/Frontend/DependencyGraph.cpp b/clang/lib/Frontend/DependencyGraph.cpp
index 6aad04370f6e..e96669f856bb 100644
--- a/clang/lib/Frontend/DependencyGraph.cpp
+++ b/clang/lib/Frontend/DependencyGraph.cpp
@@ -110,7 +110,7 @@ void DependencyGraphCallback::OutputGraphFile() {
writeNodeReference(OS, AllFiles[I]);
OS << " [ shape=\"box\", label=\"";
StringRef FileName = AllFiles[I].getName();
- if (FileName.startswith(SysRoot))
+ if (FileName.starts_with(SysRoot))
FileName = FileName.substr(SysRoot.size());
OS << DOT::EscapeString(std::string(FileName)) << "\"];\n";
diff --git a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
index 2c3a253a67d5..b6b37461089e 100644
--- a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -307,7 +307,7 @@ void InclusionRewriter::OutputContentUpTo(const MemoryBufferRef &FromFile,
Rest = Rest.substr(Idx);
}
}
- if (EnsureNewline && !TextToWrite.endswith(LocalEOL))
+ if (EnsureNewline && !TextToWrite.ends_with(LocalEOL))
OS << MainEOL;
WriteFrom = WriteTo;
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index ab8174f4f4db..09c1460d54e1 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -226,10 +226,10 @@ public:
P = C;
while (P < End) {
StringRef S(P, End - P);
- if (S.startswith(OpenBrace)) {
+ if (S.starts_with(OpenBrace)) {
++Depth;
P += OpenBrace.size();
- } else if (S.startswith(CloseBrace)) {
+ } else if (S.starts_with(CloseBrace)) {
--Depth;
if (Depth == 0) {
PEnd = P + CloseBrace.size();
@@ -445,7 +445,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// others.
// Regex in initial directive token: -re
- if (DToken.endswith("-re")) {
+ if (DToken.ends_with("-re")) {
D.RegexKind = true;
KindStr = "regex";
DToken = DToken.substr(0, DToken.size()-3);
@@ -454,20 +454,19 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// Type in initial directive token: -{error|warning|note|no-diagnostics}
bool NoDiag = false;
StringRef DType;
- if (DToken.endswith(DType="-error"))
+ if (DToken.ends_with(DType = "-error"))
D.DL = ED ? &ED->Errors : nullptr;
- else if (DToken.endswith(DType="-warning"))
+ else if (DToken.ends_with(DType = "-warning"))
D.DL = ED ? &ED->Warnings : nullptr;
- else if (DToken.endswith(DType="-remark"))
+ else if (DToken.ends_with(DType = "-remark"))
D.DL = ED ? &ED->Remarks : nullptr;
- else if (DToken.endswith(DType="-note"))
+ else if (DToken.ends_with(DType = "-note"))
D.DL = ED ? &ED->Notes : nullptr;
- else if (DToken.endswith(DType="-no-diagnostics")) {
+ else if (DToken.ends_with(DType = "-no-diagnostics")) {
NoDiag = true;
if (D.RegexKind)
continue;
- }
- else
+ } else
continue;
DToken = DToken.substr(0, DToken.size()-DType.size());
@@ -1145,7 +1144,7 @@ std::unique_ptr<Directive> Directive::create(bool RegexKind,
std::string RegexStr;
StringRef S = Text;
while (!S.empty()) {
- if (S.startswith("{{")) {
+ if (S.starts_with("{{")) {
S = S.drop_front(2);
size_t RegexMatchLength = S.find("}}");
assert(RegexMatchLength != StringRef::npos);
diff --git a/clang/lib/Headers/avx512bwintrin.h b/clang/lib/Headers/avx512bwintrin.h
index 51dba5427b0f..c854720de6a6 100644
--- a/clang/lib/Headers/avx512bwintrin.h
+++ b/clang/lib/Headers/avx512bwintrin.h
@@ -18,8 +18,9 @@ typedef unsigned int __mmask32;
typedef unsigned long long __mmask64;
/* Define the default attributes for the functions in this file. */
-#define __DEFAULT_FN_ATTRS512 __attribute__((__always_inline__, __nodebug__, __target__("avx512bw,evex512"), __min_vector_width__(512)))
-#define __DEFAULT_FN_ATTRS64 __attribute__((__always_inline__, __nodebug__, __target__("avx512bw,evex512")))
+#define __DEFAULT_FN_ATTRS512 \
+ __attribute__((__always_inline__, __nodebug__, \
+ __target__("avx512bw,evex512"), __min_vector_width__(512)))
#define __DEFAULT_FN_ATTRS \
__attribute__((__always_inline__, __nodebug__, \
__target__("avx512bw,no-evex512")))
@@ -30,9 +31,7 @@ _knot_mask32(__mmask32 __M)
return __builtin_ia32_knotsi(__M);
}
-static __inline __mmask64 __DEFAULT_FN_ATTRS64
-_knot_mask64(__mmask64 __M)
-{
+static __inline __mmask64 __DEFAULT_FN_ATTRS _knot_mask64(__mmask64 __M) {
return __builtin_ia32_knotdi(__M);
}
@@ -42,9 +41,8 @@ _kand_mask32(__mmask32 __A, __mmask32 __B)
return (__mmask32)__builtin_ia32_kandsi((__mmask32)__A, (__mmask32)__B);
}
-static __inline__ __mmask64 __DEFAULT_FN_ATTRS64
-_kand_mask64(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ __mmask64 __DEFAULT_FN_ATTRS _kand_mask64(__mmask64 __A,
+ __mmask64 __B) {
return (__mmask64)__builtin_ia32_kanddi((__mmask64)__A, (__mmask64)__B);
}
@@ -54,9 +52,8 @@ _kandn_mask32(__mmask32 __A, __mmask32 __B)
return (__mmask32)__builtin_ia32_kandnsi((__mmask32)__A, (__mmask32)__B);
}
-static __inline__ __mmask64 __DEFAULT_FN_ATTRS64
-_kandn_mask64(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ __mmask64 __DEFAULT_FN_ATTRS _kandn_mask64(__mmask64 __A,
+ __mmask64 __B) {
return (__mmask64)__builtin_ia32_kandndi((__mmask64)__A, (__mmask64)__B);
}
@@ -66,9 +63,8 @@ _kor_mask32(__mmask32 __A, __mmask32 __B)
return (__mmask32)__builtin_ia32_korsi((__mmask32)__A, (__mmask32)__B);
}
-static __inline__ __mmask64 __DEFAULT_FN_ATTRS64
-_kor_mask64(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ __mmask64 __DEFAULT_FN_ATTRS _kor_mask64(__mmask64 __A,
+ __mmask64 __B) {
return (__mmask64)__builtin_ia32_kordi((__mmask64)__A, (__mmask64)__B);
}
@@ -78,9 +74,8 @@ _kxnor_mask32(__mmask32 __A, __mmask32 __B)
return (__mmask32)__builtin_ia32_kxnorsi((__mmask32)__A, (__mmask32)__B);
}
-static __inline__ __mmask64 __DEFAULT_FN_ATTRS64
-_kxnor_mask64(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ __mmask64 __DEFAULT_FN_ATTRS _kxnor_mask64(__mmask64 __A,
+ __mmask64 __B) {
return (__mmask64)__builtin_ia32_kxnordi((__mmask64)__A, (__mmask64)__B);
}
@@ -90,9 +85,8 @@ _kxor_mask32(__mmask32 __A, __mmask32 __B)
return (__mmask32)__builtin_ia32_kxorsi((__mmask32)__A, (__mmask32)__B);
}
-static __inline__ __mmask64 __DEFAULT_FN_ATTRS64
-_kxor_mask64(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ __mmask64 __DEFAULT_FN_ATTRS _kxor_mask64(__mmask64 __A,
+ __mmask64 __B) {
return (__mmask64)__builtin_ia32_kxordi((__mmask64)__A, (__mmask64)__B);
}
@@ -114,19 +108,17 @@ _kortest_mask32_u8(__mmask32 __A, __mmask32 __B, unsigned char *__C) {
return (unsigned char)__builtin_ia32_kortestzsi(__A, __B);
}
-static __inline__ unsigned char __DEFAULT_FN_ATTRS64
-_kortestc_mask64_u8(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ unsigned char __DEFAULT_FN_ATTRS
+_kortestc_mask64_u8(__mmask64 __A, __mmask64 __B) {
return (unsigned char)__builtin_ia32_kortestcdi(__A, __B);
}
-static __inline__ unsigned char __DEFAULT_FN_ATTRS64
-_kortestz_mask64_u8(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ unsigned char __DEFAULT_FN_ATTRS
+_kortestz_mask64_u8(__mmask64 __A, __mmask64 __B) {
return (unsigned char)__builtin_ia32_kortestzdi(__A, __B);
}
-static __inline__ unsigned char __DEFAULT_FN_ATTRS64
+static __inline__ unsigned char __DEFAULT_FN_ATTRS
_kortest_mask64_u8(__mmask64 __A, __mmask64 __B, unsigned char *__C) {
*__C = (unsigned char)__builtin_ia32_kortestcdi(__A, __B);
return (unsigned char)__builtin_ia32_kortestzdi(__A, __B);
@@ -150,19 +142,17 @@ _ktest_mask32_u8(__mmask32 __A, __mmask32 __B, unsigned char *__C) {
return (unsigned char)__builtin_ia32_ktestzsi(__A, __B);
}
-static __inline__ unsigned char __DEFAULT_FN_ATTRS64
-_ktestc_mask64_u8(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ unsigned char __DEFAULT_FN_ATTRS
+_ktestc_mask64_u8(__mmask64 __A, __mmask64 __B) {
return (unsigned char)__builtin_ia32_ktestcdi(__A, __B);
}
-static __inline__ unsigned char __DEFAULT_FN_ATTRS64
-_ktestz_mask64_u8(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ unsigned char __DEFAULT_FN_ATTRS
+_ktestz_mask64_u8(__mmask64 __A, __mmask64 __B) {
return (unsigned char)__builtin_ia32_ktestzdi(__A, __B);
}
-static __inline__ unsigned char __DEFAULT_FN_ATTRS64
+static __inline__ unsigned char __DEFAULT_FN_ATTRS
_ktest_mask64_u8(__mmask64 __A, __mmask64 __B, unsigned char *__C) {
*__C = (unsigned char)__builtin_ia32_ktestcdi(__A, __B);
return (unsigned char)__builtin_ia32_ktestzdi(__A, __B);
@@ -174,9 +164,8 @@ _kadd_mask32(__mmask32 __A, __mmask32 __B)
return (__mmask32)__builtin_ia32_kaddsi((__mmask32)__A, (__mmask32)__B);
}
-static __inline__ __mmask64 __DEFAULT_FN_ATTRS64
-_kadd_mask64(__mmask64 __A, __mmask64 __B)
-{
+static __inline__ __mmask64 __DEFAULT_FN_ATTRS _kadd_mask64(__mmask64 __A,
+ __mmask64 __B) {
return (__mmask64)__builtin_ia32_kadddi((__mmask64)__A, (__mmask64)__B);
}
@@ -197,7 +186,7 @@ _cvtmask32_u32(__mmask32 __A) {
return (unsigned int)__builtin_ia32_kmovd((__mmask32)__A);
}
-static __inline__ unsigned long long __DEFAULT_FN_ATTRS64
+static __inline__ unsigned long long __DEFAULT_FN_ATTRS
_cvtmask64_u64(__mmask64 __A) {
return (unsigned long long)__builtin_ia32_kmovq((__mmask64)__A);
}
@@ -207,7 +196,7 @@ _cvtu32_mask32(unsigned int __A) {
return (__mmask32)__builtin_ia32_kmovd((__mmask32)__A);
}
-static __inline__ __mmask64 __DEFAULT_FN_ATTRS64
+static __inline__ __mmask64 __DEFAULT_FN_ATTRS
_cvtu64_mask64(unsigned long long __A) {
return (__mmask64)__builtin_ia32_kmovq((__mmask64)__A);
}
@@ -217,8 +206,7 @@ _load_mask32(__mmask32 *__A) {
return (__mmask32)__builtin_ia32_kmovd(*(__mmask32 *)__A);
}
-static __inline__ __mmask64 __DEFAULT_FN_ATTRS64
-_load_mask64(__mmask64 *__A) {
+static __inline__ __mmask64 __DEFAULT_FN_ATTRS _load_mask64(__mmask64 *__A) {
return (__mmask64)__builtin_ia32_kmovq(*(__mmask64 *)__A);
}
@@ -227,8 +215,8 @@ _store_mask32(__mmask32 *__A, __mmask32 __B) {
*(__mmask32 *)__A = __builtin_ia32_kmovd((__mmask32)__B);
}
-static __inline__ void __DEFAULT_FN_ATTRS64
-_store_mask64(__mmask64 *__A, __mmask64 __B) {
+static __inline__ void __DEFAULT_FN_ATTRS _store_mask64(__mmask64 *__A,
+ __mmask64 __B) {
*(__mmask64 *)__A = __builtin_ia32_kmovq((__mmask64)__B);
}
@@ -1717,9 +1705,8 @@ _mm512_maskz_set1_epi8 (__mmask64 __M, char __A)
(__v64qi) _mm512_setzero_si512());
}
-static __inline__ __mmask64 __DEFAULT_FN_ATTRS64
-_mm512_kunpackd (__mmask64 __A, __mmask64 __B)
-{
+static __inline__ __mmask64 __DEFAULT_FN_ATTRS _mm512_kunpackd(__mmask64 __A,
+ __mmask64 __B) {
return (__mmask64) __builtin_ia32_kunpckdi ((__mmask64) __A,
(__mmask64) __B);
}
diff --git a/clang/lib/Headers/vecintrin.h b/clang/lib/Headers/vecintrin.h
index ecfd6cd1a2f8..1f51e32c0d13 100644
--- a/clang/lib/Headers/vecintrin.h
+++ b/clang/lib/Headers/vecintrin.h
@@ -8359,7 +8359,7 @@ vec_min(__vector double __a, __vector double __b) {
static inline __ATTRS_ai __vector unsigned char
vec_add_u128(__vector unsigned char __a, __vector unsigned char __b) {
- return __builtin_s390_vaq(__a, __b);
+ return (__vector unsigned char)((__int128)__a + (__int128)__b);
}
/*-- vec_addc ---------------------------------------------------------------*/
@@ -8388,7 +8388,8 @@ vec_addc(__vector unsigned long long __a, __vector unsigned long long __b) {
static inline __ATTRS_ai __vector unsigned char
vec_addc_u128(__vector unsigned char __a, __vector unsigned char __b) {
- return __builtin_s390_vaccq(__a, __b);
+ return (__vector unsigned char)
+ __builtin_s390_vaccq((unsigned __int128)__a, (unsigned __int128)__b);
}
/*-- vec_adde_u128 ----------------------------------------------------------*/
@@ -8396,7 +8397,9 @@ vec_addc_u128(__vector unsigned char __a, __vector unsigned char __b) {
static inline __ATTRS_ai __vector unsigned char
vec_adde_u128(__vector unsigned char __a, __vector unsigned char __b,
__vector unsigned char __c) {
- return __builtin_s390_vacq(__a, __b, __c);
+ return (__vector unsigned char)
+ __builtin_s390_vacq((unsigned __int128)__a, (unsigned __int128)__b,
+ (unsigned __int128)__c);
}
/*-- vec_addec_u128 ---------------------------------------------------------*/
@@ -8404,7 +8407,9 @@ vec_adde_u128(__vector unsigned char __a, __vector unsigned char __b,
static inline __ATTRS_ai __vector unsigned char
vec_addec_u128(__vector unsigned char __a, __vector unsigned char __b,
__vector unsigned char __c) {
- return __builtin_s390_vacccq(__a, __b, __c);
+ return (__vector unsigned char)
+ __builtin_s390_vacccq((unsigned __int128)__a, (unsigned __int128)__b,
+ (unsigned __int128)__c);
}
/*-- vec_avg ----------------------------------------------------------------*/
@@ -8478,7 +8483,7 @@ vec_gfmsum(__vector unsigned int __a, __vector unsigned int __b) {
static inline __ATTRS_o_ai __vector unsigned char
vec_gfmsum_128(__vector unsigned long long __a,
__vector unsigned long long __b) {
- return __builtin_s390_vgfmg(__a, __b);
+ return (__vector unsigned char)__builtin_s390_vgfmg(__a, __b);
}
/*-- vec_gfmsum_accum -------------------------------------------------------*/
@@ -8507,7 +8512,8 @@ static inline __ATTRS_o_ai __vector unsigned char
vec_gfmsum_accum_128(__vector unsigned long long __a,
__vector unsigned long long __b,
__vector unsigned char __c) {
- return __builtin_s390_vgfmag(__a, __b, __c);
+ return (__vector unsigned char)
+ __builtin_s390_vgfmag(__a, __b, (unsigned __int128)__c);
}
/*-- vec_mladd --------------------------------------------------------------*/
@@ -8797,15 +8803,21 @@ vec_mulo(__vector unsigned int __a, __vector unsigned int __b) {
/*-- vec_msum_u128 ----------------------------------------------------------*/
#if __ARCH__ >= 12
+extern __ATTRS_o __vector unsigned char
+vec_msum_u128(__vector unsigned long long __a, __vector unsigned long long __b,
+ __vector unsigned char __c, int __d)
+ __constant_range(__d, 0, 15);
+
#define vec_msum_u128(X, Y, Z, W) \
- ((__vector unsigned char)__builtin_s390_vmslg((X), (Y), (Z), (W)));
+ ((__typeof__((vec_msum_u128)((X), (Y), (Z), (W)))) \
+ __builtin_s390_vmslg((X), (Y), (unsigned __int128)(Z), (W)))
#endif
/*-- vec_sub_u128 -----------------------------------------------------------*/
static inline __ATTRS_ai __vector unsigned char
vec_sub_u128(__vector unsigned char __a, __vector unsigned char __b) {
- return __builtin_s390_vsq(__a, __b);
+ return (__vector unsigned char)((__int128)__a - (__int128)__b);
}
/*-- vec_subc ---------------------------------------------------------------*/
@@ -8834,7 +8846,8 @@ vec_subc(__vector unsigned long long __a, __vector unsigned long long __b) {
static inline __ATTRS_ai __vector unsigned char
vec_subc_u128(__vector unsigned char __a, __vector unsigned char __b) {
- return __builtin_s390_vscbiq(__a, __b);
+ return (__vector unsigned char)
+ __builtin_s390_vscbiq((unsigned __int128)__a, (unsigned __int128)__b);
}
/*-- vec_sube_u128 ----------------------------------------------------------*/
@@ -8842,7 +8855,9 @@ vec_subc_u128(__vector unsigned char __a, __vector unsigned char __b) {
static inline __ATTRS_ai __vector unsigned char
vec_sube_u128(__vector unsigned char __a, __vector unsigned char __b,
__vector unsigned char __c) {
- return __builtin_s390_vsbiq(__a, __b, __c);
+ return (__vector unsigned char)
+ __builtin_s390_vsbiq((unsigned __int128)__a, (unsigned __int128)__b,
+ (unsigned __int128)__c);
}
/*-- vec_subec_u128 ---------------------------------------------------------*/
@@ -8850,7 +8865,9 @@ vec_sube_u128(__vector unsigned char __a, __vector unsigned char __b,
static inline __ATTRS_ai __vector unsigned char
vec_subec_u128(__vector unsigned char __a, __vector unsigned char __b,
__vector unsigned char __c) {
- return __builtin_s390_vsbcbiq(__a, __b, __c);
+ return (__vector unsigned char)
+ __builtin_s390_vsbcbiq((unsigned __int128)__a, (unsigned __int128)__b,
+ (unsigned __int128)__c);
}
/*-- vec_sum2 ---------------------------------------------------------------*/
@@ -8869,12 +8886,12 @@ vec_sum2(__vector unsigned int __a, __vector unsigned int __b) {
static inline __ATTRS_o_ai __vector unsigned char
vec_sum_u128(__vector unsigned int __a, __vector unsigned int __b) {
- return __builtin_s390_vsumqf(__a, __b);
+ return (__vector unsigned char)__builtin_s390_vsumqf(__a, __b);
}
static inline __ATTRS_o_ai __vector unsigned char
vec_sum_u128(__vector unsigned long long __a, __vector unsigned long long __b) {
- return __builtin_s390_vsumqg(__a, __b);
+ return (__vector unsigned char)__builtin_s390_vsumqg(__a, __b);
}
/*-- vec_sum4 ---------------------------------------------------------------*/
diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp
index c67810ad126b..0f79694d1faa 100644
--- a/clang/lib/Index/IndexSymbol.cpp
+++ b/clang/lib/Index/IndexSymbol.cpp
@@ -36,7 +36,7 @@ static bool isUnitTest(const ObjCMethodDecl *D) {
return false;
if (!D->getReturnType()->isVoidType())
return false;
- if (!D->getSelector().getNameForSlot(0).startswith("test"))
+ if (!D->getSelector().getNameForSlot(0).starts_with("test"))
return false;
return isUnitTestCase(D->getClassInterface());
}
diff --git a/clang/lib/IndexSerialization/SerializablePathCollection.cpp b/clang/lib/IndexSerialization/SerializablePathCollection.cpp
index bd5f861bf482..74ed18a4f612 100644
--- a/clang/lib/IndexSerialization/SerializablePathCollection.cpp
+++ b/clang/lib/IndexSerialization/SerializablePathCollection.cpp
@@ -70,11 +70,11 @@ PathPool::DirPath SerializablePathCollection::tryStoreDirPath(StringRef Dir) {
const std::string OrigDir = Dir.str();
PathPool::RootDirKind Root = PathPool::RootDirKind::Regular;
- if (!SysRoot.empty() && Dir.startswith(SysRoot) &&
+ if (!SysRoot.empty() && Dir.starts_with(SysRoot) &&
llvm::sys::path::is_separator(Dir[SysRoot.size()])) {
Root = PathPool::RootDirKind::SysRoot;
Dir = Dir.drop_front(SysRoot.size());
- } else if (!WorkDir.empty() && Dir.startswith(WorkDir) &&
+ } else if (!WorkDir.empty() && Dir.starts_with(WorkDir) &&
llvm::sys::path::is_separator(Dir[WorkDir.size()])) {
Root = PathPool::RootDirKind::CurrentWorkDir;
Dir = Dir.drop_front(WorkDir.size());
diff --git a/clang/lib/Lex/HeaderMap.cpp b/clang/lib/Lex/HeaderMap.cpp
index 22a1532c2d93..00bf880726ee 100644
--- a/clang/lib/Lex/HeaderMap.cpp
+++ b/clang/lib/Lex/HeaderMap.cpp
@@ -11,16 +11,17 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/HeaderMap.h"
-#include "clang/Lex/HeaderMapTypes.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Lex/HeaderMapTypes.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SwapByteOrder.h"
-#include "llvm/Support/Debug.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include <cstring>
#include <memory>
#include <optional>
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index c03cf19688d9..0f1090187734 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -796,7 +796,7 @@ static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader,
} else if (*I == "PrivateHeaders") {
++FoundComp;
IsPrivateHeader = true;
- } else if (I->endswith(".framework")) {
+ } else if (I->ends_with(".framework")) {
StringRef Name = I->drop_back(10); // Drop .framework
// Need to reset the strings and counter to support nested frameworks.
FrameworkName.clear();
@@ -1085,7 +1085,7 @@ OptionalFileEntryRef HeaderSearch::LookupFile(
// If the filename matches a known system header prefix, override
// whether the file is a system header.
for (unsigned j = SystemHeaderPrefixes.size(); j; --j) {
- if (Filename.startswith(SystemHeaderPrefixes[j-1].first)) {
+ if (Filename.starts_with(SystemHeaderPrefixes[j - 1].first)) {
HFI.DirInfo = SystemHeaderPrefixes[j-1].second ? SrcMgr::C_System
: SrcMgr::C_User;
break;
@@ -1656,7 +1656,8 @@ bool HeaderSearch::findUsableModuleForFrameworkHeader(
}
static OptionalFileEntryRef getPrivateModuleMap(FileEntryRef File,
- FileManager &FileMgr) {
+ FileManager &FileMgr,
+ DiagnosticsEngine &Diags) {
StringRef Filename = llvm::sys::path::filename(File.getName());
SmallString<128> PrivateFilename(File.getDir().getName());
if (Filename == "module.map")
@@ -1665,7 +1666,14 @@ static OptionalFileEntryRef getPrivateModuleMap(FileEntryRef File,
llvm::sys::path::append(PrivateFilename, "module.private.modulemap");
else
return std::nullopt;
- return FileMgr.getOptionalFileRef(PrivateFilename);
+ auto PMMFile = FileMgr.getOptionalFileRef(PrivateFilename);
+ if (PMMFile) {
+ if (Filename == "module.map")
+ Diags.Report(diag::warn_deprecated_module_dot_map)
+ << PrivateFilename << 1
+ << File.getDir().getName().ends_with(".framework");
+ }
+ return PMMFile;
}
bool HeaderSearch::loadModuleMapFile(FileEntryRef File, bool IsSystem,
@@ -1694,7 +1702,7 @@ bool HeaderSearch::loadModuleMapFile(FileEntryRef File, bool IsSystem,
StringRef DirName(Dir->getName());
if (llvm::sys::path::filename(DirName) == "Modules") {
DirName = llvm::sys::path::parent_path(DirName);
- if (DirName.endswith(".framework"))
+ if (DirName.ends_with(".framework"))
if (auto MaybeDir = FileMgr.getOptionalDirectoryRef(DirName))
Dir = *MaybeDir;
// FIXME: This assert can fail if there's a race between the above check
@@ -1731,7 +1739,8 @@ HeaderSearch::loadModuleMapFileImpl(FileEntryRef File, bool IsSystem,
}
// Try to load a corresponding private module map.
- if (OptionalFileEntryRef PMMFile = getPrivateModuleMap(File, FileMgr)) {
+ if (OptionalFileEntryRef PMMFile =
+ getPrivateModuleMap(File, FileMgr, Diags)) {
if (ModMap.parseModuleMapFile(*PMMFile, IsSystem, Dir)) {
LoadedModuleMaps[File] = false;
return LMM_InvalidModuleMap;
@@ -1755,11 +1764,14 @@ HeaderSearch::lookupModuleMapFile(DirectoryEntryRef Dir, bool IsFramework) {
if (auto F = FileMgr.getOptionalFileRef(ModuleMapFileName))
return *F;
- // Continue to allow module.map
+ // Continue to allow module.map, but warn it's deprecated.
ModuleMapFileName = Dir.getName();
llvm::sys::path::append(ModuleMapFileName, "module.map");
- if (auto F = FileMgr.getOptionalFileRef(ModuleMapFileName))
+ if (auto F = FileMgr.getOptionalFileRef(ModuleMapFileName)) {
+ Diags.Report(diag::warn_deprecated_module_dot_map)
+ << ModuleMapFileName << 0 << IsFramework;
return *F;
+ }
// For frameworks, allow to have a private module map with a preferred
// spelling when a public module map is absent.
@@ -1965,10 +1977,10 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
// Special case Apple .sdk folders since the search path is typically a
// symlink like `iPhoneSimulator14.5.sdk` while the file is instead
// located in `iPhoneSimulator.sdk` (the real folder).
- if (NI->endswith(".sdk") && DI->endswith(".sdk")) {
+ if (NI->ends_with(".sdk") && DI->ends_with(".sdk")) {
StringRef NBasename = path::stem(*NI);
StringRef DBasename = path::stem(*DI);
- if (DBasename.startswith(NBasename))
+ if (DBasename.starts_with(NBasename))
continue;
}
diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp
index 5b1b7c859c85..2218db15013d 100644
--- a/clang/lib/Lex/InitHeaderSearch.cpp
+++ b/clang/lib/Lex/InitHeaderSearch.cpp
@@ -141,8 +141,8 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
// If use system headers while cross-compiling, emit the warning.
- if (HasSysroot && (MappedPathStr.startswith("/usr/include") ||
- MappedPathStr.startswith("/usr/local/include"))) {
+ if (HasSysroot && (MappedPathStr.starts_with("/usr/include") ||
+ MappedPathStr.starts_with("/usr/local/include"))) {
Headers.getDiags().Report(diag::warn_poison_system_directories)
<< MappedPathStr;
}
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index f4f1daab857f..50b56265f6e1 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -3212,8 +3212,8 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) {
return false;
// Check to see if we have <<<<<<< or >>>>.
- if (!StringRef(CurPtr, BufferEnd - CurPtr).startswith("<<<<<<<") &&
- !StringRef(CurPtr, BufferEnd - CurPtr).startswith(">>>> "))
+ if (!StringRef(CurPtr, BufferEnd - CurPtr).starts_with("<<<<<<<") &&
+ !StringRef(CurPtr, BufferEnd - CurPtr).starts_with(">>>> "))
return false;
// If we have a situation where we don't care about conflict markers, ignore
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 268b72c966ab..ea5d13deb114 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -235,7 +235,7 @@ OptionalFileEntryRef ModuleMap::findHeader(
llvm::sys::path::append(FullPathName, RelativePathName);
auto NormalHdrFile = GetFile(FullPathName);
- if (!NormalHdrFile && Directory->getName().endswith(".framework")) {
+ if (!NormalHdrFile && Directory->getName().ends_with(".framework")) {
// The lack of 'framework' keyword in a module declaration it's a simple
// mistake we can diagnose when the header exists within the proper
// framework style path.
@@ -1034,7 +1034,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
if (inferred == InferredDirectories.end()) {
// We haven't looked here before. Load a module map, if there is
// one.
- bool IsFrameworkDir = Parent.endswith(".framework");
+ bool IsFrameworkDir = Parent.ends_with(".framework");
if (OptionalFileEntryRef ModMapFile =
HeaderInfo.lookupModuleMapFile(*ParentDir, IsFrameworkDir)) {
parseModuleMapFile(*ModMapFile, Attrs.IsSystem, *ParentDir);
@@ -1125,7 +1125,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
Dir = FS.dir_begin(SubframeworksDirName, EC),
DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- if (!StringRef(Dir->path()).endswith(".framework"))
+ if (!StringRef(Dir->path()).ends_with(".framework"))
continue;
if (auto SubframeworkDir = FileMgr.getOptionalDirectoryRef(Dir->path())) {
@@ -1337,7 +1337,7 @@ ModuleMap::canonicalizeModuleMapPath(SmallVectorImpl<char> &Path) {
// Modules/ not Versions/A/Modules.
if (llvm::sys::path::filename(Dir) == "Modules") {
StringRef Parent = llvm::sys::path::parent_path(Dir);
- if (Parent.endswith(".framework"))
+ if (Parent.ends_with(".framework"))
Dir = Parent;
}
@@ -1864,7 +1864,7 @@ void ModuleMapParser::diagnosePrivateModules(SourceLocation ExplicitLoc,
continue;
SmallString<128> FullName(ActiveModule->getFullModuleName());
- if (!FullName.startswith(M->Name) && !FullName.endswith("Private"))
+ if (!FullName.starts_with(M->Name) && !FullName.ends_with("Private"))
continue;
SmallString<128> FixedPrivModDecl;
SmallString<128> Canonical(M->Name);
@@ -2119,8 +2119,8 @@ void ModuleMapParser::parseModuleDecl() {
ActiveModule->Directory = Directory;
StringRef MapFileName(ModuleMapFile.getName());
- if (MapFileName.endswith("module.private.modulemap") ||
- MapFileName.endswith("module_private.map")) {
+ if (MapFileName.ends_with("module.private.modulemap") ||
+ MapFileName.ends_with("module_private.map")) {
ActiveModule->ModuleMapIsPrivate = true;
}
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 14003480d7fa..112bc8dc572c 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -164,13 +164,13 @@ static bool isLanguageDefinedBuiltin(const SourceManager &SourceMgr,
return false;
// C defines macros starting with __STDC, and C++ defines macros starting with
// __STDCPP
- if (MacroName.startswith("__STDC"))
+ if (MacroName.starts_with("__STDC"))
return true;
// C++ defines the __cplusplus macro
if (MacroName == "__cplusplus")
return true;
// C++ defines various feature-test macros starting with __cpp
- if (MacroName.startswith("__cpp"))
+ if (MacroName.starts_with("__cpp"))
return true;
// Anything else isn't language-defined
return false;
@@ -646,7 +646,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
Directive = StringRef(DirectiveBuf, IdLen);
}
- if (Directive.startswith("if")) {
+ if (Directive.starts_with("if")) {
StringRef Sub = Directive.substr(2);
if (Sub.empty() || // "if"
Sub == "def" || // "ifdef"
@@ -2788,14 +2788,14 @@ static bool isConfigurationPattern(Token &MacroName, MacroInfo *MI,
return false;
StringRef ValueText = II->getName();
StringRef TrimmedValue = ValueText;
- if (!ValueText.startswith("__")) {
- if (ValueText.startswith("_"))
+ if (!ValueText.starts_with("__")) {
+ if (ValueText.starts_with("_"))
TrimmedValue = TrimmedValue.drop_front(1);
else
return false;
} else {
TrimmedValue = TrimmedValue.drop_front(2);
- if (TrimmedValue.endswith("__"))
+ if (TrimmedValue.ends_with("__"))
TrimmedValue = TrimmedValue.drop_back(2);
}
return TrimmedValue.equals(MacroText);
diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp
index 269984aae07b..1feb0eb18d71 100644
--- a/clang/lib/Lex/PPExpressions.cpp
+++ b/clang/lib/Lex/PPExpressions.cpp
@@ -267,7 +267,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
const StringRef IdentifierName = II->getName();
if (llvm::any_of(UndefPrefixes,
[&IdentifierName](const std::string &Prefix) {
- return IdentifierName.startswith(Prefix);
+ return IdentifierName.starts_with(Prefix);
}))
PP.Diag(PeekTok, diag::warn_pp_undef_prefix)
<< AddFlagValue{llvm::join(UndefPrefixes, ",")} << II;
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 30c4abdbad8a..ad02f31209b0 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1136,7 +1136,8 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) {
const LangOptions &LangOpts = PP.getLangOpts();
// Normalize the feature name, __foo__ becomes foo.
- if (Feature.startswith("__") && Feature.endswith("__") && Feature.size() >= 4)
+ if (Feature.starts_with("__") && Feature.ends_with("__") &&
+ Feature.size() >= 4)
Feature = Feature.substr(2, Feature.size() - 4);
#define FEATURE(Name, Predicate) .Case(#Name, Predicate)
@@ -1162,7 +1163,7 @@ static bool HasExtension(const Preprocessor &PP, StringRef Extension) {
const LangOptions &LangOpts = PP.getLangOpts();
// Normalize the extension name, __foo__ becomes foo.
- if (Extension.startswith("__") && Extension.endswith("__") &&
+ if (Extension.starts_with("__") && Extension.ends_with("__") &&
Extension.size() >= 4)
Extension = Extension.substr(2, Extension.size() - 4);
@@ -1691,9 +1692,9 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// as being "builtin functions", even if the syntax isn't a valid
// function call (for example, because the builtin takes a type
// argument).
- if (II->getName().startswith("__builtin_") ||
- II->getName().startswith("__is_") ||
- II->getName().startswith("__has_"))
+ if (II->getName().starts_with("__builtin_") ||
+ II->getName().starts_with("__is_") ||
+ II->getName().starts_with("__has_"))
return true;
return llvm::StringSwitch<bool>(II->getName())
.Case("__array_rank", true)
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index ece3698967e2..ed006f9d67de 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -84,7 +84,7 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, DeclaratorContext Context,
/// Normalizes an attribute name by dropping prefixed and suffixed __.
static StringRef normalizeAttrName(StringRef Name) {
- if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
+ if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__"))
return Name.drop_front(2).drop_back(2);
return Name;
}
@@ -7854,7 +7854,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
bool IsUnqual = Tok.is(tok::kw_typeof_unqual);
const IdentifierInfo *II = Tok.getIdentifierInfo();
- if (getLangOpts().C23 && !II->getName().startswith("__"))
+ if (getLangOpts().C23 && !II->getName().starts_with("__"))
Diag(Tok.getLocation(), diag::warn_c23_compat_keyword) << Tok.getName();
Token OpTok = Tok;
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 8b86db1bb8fc..ef9ea6575205 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1311,18 +1311,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
D.takeAttributes(Attributes);
}
- // Helper to emit a warning if we see a CUDA host/device/global attribute
- // after '(...)'. nvcc doesn't accept this.
- auto WarnIfHasCUDATargetAttr = [&] {
- if (getLangOpts().CUDA)
- for (const ParsedAttr &A : Attributes)
- if (A.getKind() == ParsedAttr::AT_CUDADevice ||
- A.getKind() == ParsedAttr::AT_CUDAHost ||
- A.getKind() == ParsedAttr::AT_CUDAGlobal)
- Diag(A.getLoc(), diag::warn_cuda_attr_lambda_position)
- << A.getAttrName()->getName();
- };
-
MultiParseScope TemplateParamScope(*this);
if (Tok.is(tok::less)) {
Diag(Tok, getLangOpts().CPlusPlus20
@@ -1377,91 +1365,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
bool HasSpecifiers = false;
SourceLocation MutableLoc;
- auto ParseConstexprAndMutableSpecifiers = [&] {
- // GNU-style attributes must be parsed before the mutable specifier to
- // be compatible with GCC. MSVC-style attributes must be parsed before
- // the mutable specifier to be compatible with MSVC.
- MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attributes);
- // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
- // the DeclEndLoc.
- SourceLocation ConstexprLoc;
- SourceLocation ConstevalLoc;
- SourceLocation StaticLoc;
-
- tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc, ConstexprLoc,
- ConstevalLoc, DeclEndLoc);
-
- DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc, Intro);
-
- addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS);
- addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
- addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
- };
-
- auto ParseLambdaSpecifiers =
- [&](MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo,
- SourceLocation EllipsisLoc) {
- // Parse exception-specification[opt].
- ExceptionSpecificationType ESpecType = EST_None;
- SourceRange ESpecRange;
- SmallVector<ParsedType, 2> DynamicExceptions;
- SmallVector<SourceRange, 2> DynamicExceptionRanges;
- ExprResult NoexceptExpr;
- CachedTokens *ExceptionSpecTokens;
-
- ESpecType = tryParseExceptionSpecification(
- /*Delayed=*/false, ESpecRange, DynamicExceptions,
- DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens);
-
- if (ESpecType != EST_None)
- DeclEndLoc = ESpecRange.getEnd();
-
- // Parse attribute-specifier[opt].
- if (MaybeParseCXX11Attributes(Attributes))
- DeclEndLoc = Attributes.Range.getEnd();
-
- // Parse OpenCL addr space attribute.
- if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local,
- tok::kw___constant, tok::kw___generic)) {
- ParseOpenCLQualifiers(DS.getAttributes());
- ConsumeToken();
- }
-
- SourceLocation FunLocalRangeEnd = DeclEndLoc;
-
- // Parse trailing-return-type[opt].
- if (Tok.is(tok::arrow)) {
- FunLocalRangeEnd = Tok.getLocation();
- SourceRange Range;
- TrailingReturnType = ParseTrailingReturnType(
- Range, /*MayBeFollowedByDirectInit*/ false);
- TrailingReturnTypeLoc = Range.getBegin();
- if (Range.getEnd().isValid())
- DeclEndLoc = Range.getEnd();
- }
-
- SourceLocation NoLoc;
- D.AddTypeInfo(
- DeclaratorChunk::getFunction(
- /*HasProto=*/true,
- /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(),
- ParamInfo.size(), EllipsisLoc, RParenLoc,
- /*RefQualifierIsLvalueRef=*/true,
- /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange,
- DynamicExceptions.data(), DynamicExceptionRanges.data(),
- DynamicExceptions.size(),
- NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
- /*ExceptionSpecTokens*/ nullptr,
- /*DeclsInPrototype=*/std::nullopt, LParenLoc, FunLocalRangeEnd,
- D, TrailingReturnType, TrailingReturnTypeLoc, &DS),
- std::move(Attributes), DeclEndLoc);
-
- Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc);
-
- if (HasParentheses && Tok.is(tok::kw_requires))
- ParseTrailingRequiresClause(D);
- };
-
ParseScope Prototype(this, Scope::FunctionPrototypeScope |
Scope::FunctionDeclarationScope |
Scope::DeclScope);
@@ -1511,18 +1414,104 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
<< FixItHint::CreateInsertion(Tok.getLocation(), "() ");
}
- if (HasParentheses || HasSpecifiers)
- ParseConstexprAndMutableSpecifiers();
+ if (HasParentheses || HasSpecifiers) {
+ // GNU-style attributes must be parsed before the mutable specifier to
+ // be compatible with GCC. MSVC-style attributes must be parsed before
+ // the mutable specifier to be compatible with MSVC.
+ MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attributes);
+ // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
+ // the DeclEndLoc.
+ SourceLocation ConstexprLoc;
+ SourceLocation ConstevalLoc;
+ SourceLocation StaticLoc;
+
+ tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc, ConstexprLoc,
+ ConstevalLoc, DeclEndLoc);
+
+ DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc, Intro);
+
+ addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS);
+ addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
+ addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
+ }
Actions.ActOnLambdaClosureParameters(getCurScope(), ParamInfo);
if (!HasParentheses)
Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc);
- if (HasSpecifiers || HasParentheses)
- ParseLambdaSpecifiers(ParamInfo, EllipsisLoc);
+ if (HasSpecifiers || HasParentheses) {
+ // Parse exception-specification[opt].
+ ExceptionSpecificationType ESpecType = EST_None;
+ SourceRange ESpecRange;
+ SmallVector<ParsedType, 2> DynamicExceptions;
+ SmallVector<SourceRange, 2> DynamicExceptionRanges;
+ ExprResult NoexceptExpr;
+ CachedTokens *ExceptionSpecTokens;
+
+ ESpecType = tryParseExceptionSpecification(
+ /*Delayed=*/false, ESpecRange, DynamicExceptions,
+ DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens);
+
+ if (ESpecType != EST_None)
+ DeclEndLoc = ESpecRange.getEnd();
+
+ // Parse attribute-specifier[opt].
+ if (MaybeParseCXX11Attributes(Attributes))
+ DeclEndLoc = Attributes.Range.getEnd();
+
+ // Parse OpenCL addr space attribute.
+ if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local,
+ tok::kw___constant, tok::kw___generic)) {
+ ParseOpenCLQualifiers(DS.getAttributes());
+ ConsumeToken();
+ }
+
+ SourceLocation FunLocalRangeEnd = DeclEndLoc;
+
+ // Parse trailing-return-type[opt].
+ if (Tok.is(tok::arrow)) {
+ FunLocalRangeEnd = Tok.getLocation();
+ SourceRange Range;
+ TrailingReturnType =
+ ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit=*/false);
+ TrailingReturnTypeLoc = Range.getBegin();
+ if (Range.getEnd().isValid())
+ DeclEndLoc = Range.getEnd();
+ }
+
+ SourceLocation NoLoc;
+ D.AddTypeInfo(DeclaratorChunk::getFunction(
+ /*HasProto=*/true,
+ /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(),
+ ParamInfo.size(), EllipsisLoc, RParenLoc,
+ /*RefQualifierIsLvalueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType,
+ ESpecRange, DynamicExceptions.data(),
+ DynamicExceptionRanges.data(), DynamicExceptions.size(),
+ NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
+ /*ExceptionSpecTokens*/ nullptr,
+ /*DeclsInPrototype=*/std::nullopt, LParenLoc,
+ FunLocalRangeEnd, D, TrailingReturnType,
+ TrailingReturnTypeLoc, &DS),
+ std::move(Attributes), DeclEndLoc);
- WarnIfHasCUDATargetAttr();
+ Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc);
+
+ if (HasParentheses && Tok.is(tok::kw_requires))
+ ParseTrailingRequiresClause(D);
+ }
+
+ // Emit a warning if we see a CUDA host/device/global attribute
+ // after '(...)'. nvcc doesn't accept this.
+ if (getLangOpts().CUDA) {
+ for (const ParsedAttr &A : Attributes)
+ if (A.getKind() == ParsedAttr::AT_CUDADevice ||
+ A.getKind() == ParsedAttr::AT_CUDAHost ||
+ A.getKind() == ParsedAttr::AT_CUDAGlobal)
+ Diag(A.getLoc(), diag::warn_cuda_attr_lambda_position)
+ << A.getAttrName()->getName();
+ }
Prototype.Exit();
@@ -1548,7 +1537,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid() &&
!D.isInvalidType())
- return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
+ return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get());
Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
return ExprError();
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index efdf7c90f977..730ac1a0fee5 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -137,7 +137,20 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler {
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &Tok) override {
tok::OnOffSwitch OOS;
- PP.LexOnOffSwitch(OOS);
+ if (PP.LexOnOffSwitch(OOS))
+ return;
+
+ MutableArrayRef<Token> Toks(
+ PP.getPreprocessorAllocator().Allocate<Token>(1), 1);
+
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_cx_limited_range);
+ Toks[0].setLocation(Tok.getLocation());
+ Toks[0].setAnnotationEndLoc(Tok.getLocation());
+ Toks[0].setAnnotationValue(
+ reinterpret_cast<void *>(static_cast<uintptr_t>(OOS)));
+ PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
+ /*IsReinject=*/false);
}
};
@@ -888,6 +901,31 @@ void Parser::HandlePragmaFEnvRound() {
Actions.ActOnPragmaFEnvRound(PragmaLoc, RM);
}
+void Parser::HandlePragmaCXLimitedRange() {
+ assert(Tok.is(tok::annot_pragma_cx_limited_range));
+ tok::OnOffSwitch OOS = static_cast<tok::OnOffSwitch>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+
+ LangOptions::ComplexRangeKind Range;
+ switch (OOS) {
+ case tok::OOS_ON:
+ Range = LangOptions::CX_Limited;
+ break;
+ case tok::OOS_OFF:
+ Range = LangOptions::CX_Full;
+ break;
+ case tok::OOS_DEFAULT:
+ // According to ISO C99 standard chapter 7.3.4, the default value
+ // for the pragma is ``off'. -fcx-limited-range and -fcx-fortran-rules
+ // control the default value of these pragmas.
+ Range = getLangOpts().getComplexRange();
+ break;
+ }
+
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
+ Actions.ActOnPragmaCXLimitedRange(PragmaLoc, Range);
+}
+
StmtResult Parser::HandlePragmaCaptured()
{
assert(Tok.is(tok::annot_pragma_captured));
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 918afdc2baea..d0ff33bd1379 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -444,6 +444,14 @@ Retry:
ConsumeAnnotationToken();
return StmtError();
+ case tok::annot_pragma_cx_limited_range:
+ ProhibitAttributes(CXX11Attrs);
+ ProhibitAttributes(GNUAttrs);
+ Diag(Tok, diag::err_pragma_file_or_compound_scope)
+ << "STDC CX_LIMITED_RANGE";
+ ConsumeAnnotationToken();
+ return StmtError();
+
case tok::annot_pragma_float_control:
ProhibitAttributes(CXX11Attrs);
ProhibitAttributes(GNUAttrs);
@@ -1066,6 +1074,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
case tok::annot_pragma_fenv_round:
HandlePragmaFEnvRound();
break;
+ case tok::annot_pragma_cx_limited_range:
+ HandlePragmaCXLimitedRange();
+ break;
case tok::annot_pragma_float_control:
HandlePragmaFloatControl();
break;
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 1baeb2aeb021..b703c2d9b8e0 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -844,6 +844,9 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
case tok::annot_pragma_fenv_round:
HandlePragmaFEnvRound();
return nullptr;
+ case tok::annot_pragma_cx_limited_range:
+ HandlePragmaCXLimitedRange();
+ return nullptr;
case tok::annot_pragma_float_control:
HandlePragmaFloatControl();
return nullptr;
@@ -2642,7 +2645,7 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
auto &SrcMgr = PP.getSourceManager();
auto FE = SrcMgr.getFileEntryRefForID(SrcMgr.getFileID(AtLoc));
if (FE && llvm::sys::path::parent_path(FE->getDir().getName())
- .endswith(".framework"))
+ .ends_with(".framework"))
Diags.Report(AtLoc, diag::warn_atimport_in_framework_header);
}
diff --git a/clang/lib/Rewrite/Rewriter.cpp b/clang/lib/Rewrite/Rewriter.cpp
index 0896221dd0bd..0e6ae3650644 100644
--- a/clang/lib/Rewrite/Rewriter.cpp
+++ b/clang/lib/Rewrite/Rewriter.cpp
@@ -386,7 +386,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
}
if (parentSpace.size() >= startSpace.size())
return true;
- if (!startSpace.startswith(parentSpace))
+ if (!startSpace.starts_with(parentSpace))
return true;
StringRef indent = startSpace.substr(parentSpace.size());
@@ -399,7 +399,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
while (isWhitespaceExceptNL(MB[i]))
++i;
StringRef origIndent = MB.substr(offs, i-offs);
- if (origIndent.startswith(startSpace))
+ if (origIndent.starts_with(startSpace))
RB.InsertText(offs, indent, /*InsertAfter=*/false);
}
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp
index 9caa1a8431e9..350bd78b5710 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -630,15 +630,16 @@ bool PrintingCodeCompleteConsumer::isResultFilteredOut(
StringRef Filter, CodeCompletionResult Result) {
switch (Result.Kind) {
case CodeCompletionResult::RK_Declaration:
- return !(Result.Declaration->getIdentifier() &&
- Result.Declaration->getIdentifier()->getName().startswith(Filter));
+ return !(
+ Result.Declaration->getIdentifier() &&
+ Result.Declaration->getIdentifier()->getName().starts_with(Filter));
case CodeCompletionResult::RK_Keyword:
- return !StringRef(Result.Keyword).startswith(Filter);
+ return !StringRef(Result.Keyword).starts_with(Filter);
case CodeCompletionResult::RK_Macro:
- return !Result.Macro->getName().startswith(Filter);
+ return !Result.Macro->getName().starts_with(Filter);
case CodeCompletionResult::RK_Pattern:
return !(Result.Pattern->getTypedText() &&
- StringRef(Result.Pattern->getTypedText()).startswith(Filter));
+ StringRef(Result.Pattern->getTypedText()).starts_with(Filter));
}
llvm_unreachable("Unknown code completion result Kind.");
}
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 8ed6480a9f5c..1a1febf7a352 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -116,11 +116,11 @@ struct BuiltinTypeDeclBuilder {
}
BuiltinTypeDeclBuilder &annotateResourceClass(ResourceClass RC,
- ResourceKind RK) {
+ ResourceKind RK, bool IsROV) {
if (Record->isCompleteDefinition())
return *this;
- Record->addAttr(
- HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RC, RK));
+ Record->addAttr(HLSLResourceAttr::CreateImplicit(Record->getASTContext(),
+ RC, RK, IsROV));
return *this;
}
@@ -478,12 +478,12 @@ void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
/// Set up common members and attributes for buffer types
static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
- ResourceClass RC,
- ResourceKind RK) {
+ ResourceClass RC, ResourceKind RK,
+ bool IsROV) {
return BuiltinTypeDeclBuilder(Decl)
.addHandleMember()
.addDefaultHandleConstructor(S, RC)
- .annotateResourceClass(RC, RK);
+ .annotateResourceClass(RC, RK, IsROV);
}
void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
@@ -493,7 +493,18 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
.Record;
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
- ResourceKind::TypedBuffer)
+ ResourceKind::TypedBuffer, /*IsROV=*/false)
+ .addArraySubscriptOperators()
+ .completeDefinition();
+ });
+
+ Decl =
+ BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
+ .addSimpleTemplateParams({"element_type"})
+ .Record;
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
+ ResourceKind::TypedBuffer, /*IsROV=*/true)
.addArraySubscriptOperators()
.completeDefinition();
});
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 22929aa6316d..cafbecebc8a1 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -870,6 +870,7 @@ static void checkUndefinedButUsed(Sema &S) {
// Collect all the still-undefined entities with internal linkage.
SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
S.getUndefinedButUsed(Undefined);
+ S.UndefinedButUsed.clear();
if (Undefined.empty()) return;
for (const auto &Undef : Undefined) {
@@ -923,8 +924,6 @@ static void checkUndefinedButUsed(Sema &S) {
if (UseLoc.isValid())
S.Diag(UseLoc, diag::note_used_here);
}
-
- S.UndefinedButUsed.clear();
}
void Sema::LoadExternalWeakUndeclaredIdentifiers() {
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 79271c872627..0dcf42e48997 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -1352,6 +1352,14 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
}
+void Sema::ActOnPragmaCXLimitedRange(SourceLocation Loc,
+ LangOptions::ComplexRangeKind Range) {
+ FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
+ NewFPFeatures.setComplexRangeOverride(Range);
+ FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
+ CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
+}
+
void Sema::ActOnPragmaFPExceptions(SourceLocation Loc,
LangOptions::FPExceptionModeKind FPE) {
setExceptionMode(Loc, FPE);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 5c9734618447..d4a40b850cea 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1219,7 +1219,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
if (IsChkVariant) {
FunctionName = FunctionName.drop_front(std::strlen("__builtin___"));
FunctionName = FunctionName.drop_back(std::strlen("_chk"));
- } else if (FunctionName.startswith("__builtin_")) {
+ } else if (FunctionName.starts_with("__builtin_")) {
FunctionName = FunctionName.drop_front(std::strlen("__builtin_"));
}
return FunctionName;
@@ -5030,14 +5030,14 @@ bool Sema::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
if (!llvm::isValidAtomicOrderingCABI(Ord))
return Diag(ArgExpr->getBeginLoc(),
diag::warn_atomic_op_has_invalid_memory_order)
- << ArgExpr->getSourceRange();
+ << 0 << ArgExpr->getSourceRange();
switch (static_cast<llvm::AtomicOrderingCABI>(Ord)) {
case llvm::AtomicOrderingCABI::relaxed:
case llvm::AtomicOrderingCABI::consume:
if (BuiltinID == AMDGPU::BI__builtin_amdgcn_fence)
return Diag(ArgExpr->getBeginLoc(),
diag::warn_atomic_op_has_invalid_memory_order)
- << ArgExpr->getSourceRange();
+ << 0 << ArgExpr->getSourceRange();
break;
case llvm::AtomicOrderingCABI::acquire:
case llvm::AtomicOrderingCABI::release:
@@ -5082,12 +5082,10 @@ static bool CheckInvalidVLENandLMUL(const TargetInfo &TI, CallExpr *TheCall,
assert((EGW == 128 || EGW == 256) && "EGW can only be 128 or 256 bits");
// LMUL * VLEN >= EGW
- unsigned ElemSize = Type->isRVVType(32, false) ? 32 : 64;
- unsigned MinElemCount = Type->isRVVType(1) ? 1
- : Type->isRVVType(2) ? 2
- : Type->isRVVType(4) ? 4
- : Type->isRVVType(8) ? 8
- : 16;
+ ASTContext::BuiltinVectorTypeInfo Info =
+ S.Context.getBuiltinVectorTypeInfo(Type->castAs<BuiltinType>());
+ unsigned ElemSize = S.Context.getTypeSize(Info.ElementType);
+ unsigned MinElemCount = Info.EC.getKnownMinValue();
unsigned EGS = EGW / ElemSize;
// If EGS is less than or equal to the minimum number of elements, then the
@@ -5215,15 +5213,13 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vsmul_vx_tum:
case RISCVVector::BI__builtin_rvv_vsmul_vv_tumu:
case RISCVVector::BI__builtin_rvv_vsmul_vx_tumu: {
- bool RequireV = false;
- for (unsigned ArgNum = 0; ArgNum < TheCall->getNumArgs(); ++ArgNum)
- RequireV |= TheCall->getArg(ArgNum)->getType()->isRVVType(
- /* Bitwidth */ 64, /* IsFloat */ false);
+ ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo(
+ TheCall->getType()->castAs<BuiltinType>());
- if (RequireV && !TI.hasFeature("v"))
+ if (Context.getTypeSize(Info.ElementType) == 64 && !TI.hasFeature("v"))
return Diag(TheCall->getBeginLoc(),
diag::err_riscv_builtin_requires_extension)
- << /* IsExtension */ false << TheCall->getSourceRange() << "v";
+ << /* IsExtension */ true << TheCall->getSourceRange() << "v";
break;
}
@@ -5327,9 +5323,9 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
QualType Op3Type = TheCall->getArg(2)->getType();
uint64_t ElemSize = Op1Type->isRVVType(32, false) ? 32 : 64;
if (ElemSize == 64 && !TI.hasFeature("experimental-zvknhb"))
- return
- Diag(TheCall->getBeginLoc(), diag::err_riscv_type_requires_extension)
- << Op1Type << "experimental-zvknhb";
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_riscv_type_requires_extension)
+ << Op1Type << "zvknhb";
return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, ElemSize << 2) ||
CheckInvalidVLENandLMUL(TI, TheCall, *this, Op2Type, ElemSize << 2) ||
@@ -8181,13 +8177,31 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
break;
}
+ // If the memory orders are constants, check they are valid.
if (SubExprs.size() >= 2 && Form != Init) {
- if (std::optional<llvm::APSInt> Result =
- SubExprs[1]->getIntegerConstantExpr(Context))
- if (!isValidOrderingForOp(Result->getSExtValue(), Op))
- Diag(SubExprs[1]->getBeginLoc(),
- diag::warn_atomic_op_has_invalid_memory_order)
- << SubExprs[1]->getSourceRange();
+ std::optional<llvm::APSInt> Success =
+ SubExprs[1]->getIntegerConstantExpr(Context);
+ if (Success && !isValidOrderingForOp(Success->getSExtValue(), Op)) {
+ Diag(SubExprs[1]->getBeginLoc(),
+ diag::warn_atomic_op_has_invalid_memory_order)
+ << /*success=*/(Form == C11CmpXchg || Form == GNUCmpXchg)
+ << SubExprs[1]->getSourceRange();
+ }
+ if (SubExprs.size() >= 5) {
+ if (std::optional<llvm::APSInt> Failure =
+ SubExprs[3]->getIntegerConstantExpr(Context)) {
+ if (!llvm::is_contained(
+ {llvm::AtomicOrderingCABI::relaxed,
+ llvm::AtomicOrderingCABI::consume,
+ llvm::AtomicOrderingCABI::acquire,
+ llvm::AtomicOrderingCABI::seq_cst},
+ (llvm::AtomicOrderingCABI)Failure->getSExtValue())) {
+ Diag(SubExprs[3]->getBeginLoc(),
+ diag::warn_atomic_op_has_invalid_memory_order)
+ << /*failure=*/2 << SubExprs[3]->getSourceRange();
+ }
+ }
+ }
}
if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
@@ -18274,15 +18288,14 @@ static bool isSetterLikeSelector(Selector sel) {
StringRef str = sel.getNameForSlot(0);
while (!str.empty() && str.front() == '_') str = str.substr(1);
- if (str.startswith("set"))
+ if (str.starts_with("set"))
str = str.substr(3);
- else if (str.startswith("add")) {
+ else if (str.starts_with("add")) {
// Specially allow 'addOperationWithBlock:'.
- if (sel.getNumArgs() == 1 && str.startswith("addOperationWithBlock"))
+ if (sel.getNumArgs() == 1 && str.starts_with("addOperationWithBlock"))
return false;
str = str.substr(3);
- }
- else
+ } else
return false;
if (str.empty()) return true;
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 6169144ef1c2..c44be0df9b0a 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -9798,7 +9798,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(
Results.ExitScope();
if (!AtParameterName && !SelIdents.empty() &&
- SelIdents.front()->getName().startswith("init")) {
+ SelIdents.front()->getName().starts_with("init")) {
for (const auto &M : PP.macros()) {
if (M.first->getName() != "NS_DESIGNATED_INITIALIZER")
continue;
@@ -10110,9 +10110,9 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
}
const StringRef &Dirname = llvm::sys::path::filename(Dir);
- const bool isQt = Dirname.startswith("Qt") || Dirname == "ActiveQt";
+ const bool isQt = Dirname.starts_with("Qt") || Dirname == "ActiveQt";
const bool ExtensionlessHeaders =
- IsSystem || isQt || Dir.endswith(".framework/Headers");
+ IsSystem || isQt || Dir.ends_with(".framework/Headers");
std::error_code EC;
unsigned Count = 0;
for (auto It = FS.dir_begin(Dir, EC);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 19d972ed8ab2..be6a136ef37b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15800,7 +15800,7 @@ Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
}
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
- return ActOnFinishFunctionBody(D, BodyArg, false);
+ return ActOnFinishFunctionBody(D, BodyArg, /*IsInstantiation=*/false);
}
/// RAII object that pops an ExpressionEvaluationContext when exiting a function
@@ -16005,7 +16005,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
return StartTok.consume_front("const") &&
(StartTok.empty() || isWhitespace(StartTok[0]) ||
- StartTok.startswith("/*") || StartTok.startswith("//"));
+ StartTok.starts_with("/*") || StartTok.starts_with("//"));
};
auto findBeginLoc = [&]() {
@@ -16359,7 +16359,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
// Extension in C99 (defaults to error). Legal in C89, but warn about it.
unsigned diag_id;
- if (II.getName().startswith("__builtin_"))
+ if (II.getName().starts_with("__builtin_"))
diag_id = diag::warn_builtin_unknown;
// OpenCL v2.0 s6.9.u - Implicit function declaration is not supported.
else if (getLangOpts().C99)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 59e456fd9f72..5b29b05dee54 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1809,8 +1809,8 @@ static void handleAssumumptionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
/// Normalize the attribute, __foo__ becomes foo.
/// Returns true if normalization was applied.
static bool normalizeName(StringRef &AttrName) {
- if (AttrName.size() > 4 && AttrName.startswith("__") &&
- AttrName.endswith("__")) {
+ if (AttrName.size() > 4 && AttrName.starts_with("__") &&
+ AttrName.ends_with("__")) {
AttrName = AttrName.drop_front(2).drop_back(2);
return true;
}
@@ -3605,7 +3605,7 @@ bool Sema::checkTargetClonesAttrString(
}
} else {
// Other targets ( currently X86 )
- if (Cur.startswith("arch=")) {
+ if (Cur.starts_with("arch=")) {
if (!Context.getTargetInfo().isValidCPUName(
Cur.drop_front(sizeof("arch=") - 1)))
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
@@ -3623,7 +3623,7 @@ bool Sema::checkTargetClonesAttrString(
StringsBuffer.push_back(Cur);
}
}
- if (Str.rtrim().endswith(","))
+ if (Str.rtrim().ends_with(","))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << "" << TargetClones;
return false;
@@ -5225,8 +5225,16 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.checkAtLeastNumArgs(S, 1))
+ if (AL.getAttributeSpellingListIndex() == SuppressAttr::CXX11_gsl_suppress) {
+ // Suppression attribute with GSL spelling requires at least 1 argument.
+ if (!AL.checkAtLeastNumArgs(S, 1))
+ return;
+ } else if (!isa<VarDecl>(D)) {
+ // Analyzer suppression applies only to variables and statements.
+ S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type_str)
+ << AL << 0 << "variables and statements";
return;
+ }
std::vector<StringRef> DiagnosticIdentifiers;
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
@@ -5235,8 +5243,6 @@ static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.checkStringLiteralArgumentAttr(AL, I, RuleName, nullptr))
return;
- // FIXME: Warn if the rule name is unknown. This is tricky because only
- // clang-tidy knows about available rules.
DiagnosticIdentifiers.push_back(RuleName);
}
D->addAttr(::new (S.Context)
@@ -5819,7 +5825,7 @@ struct IntrinToName {
static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
ArrayRef<IntrinToName> Map,
const char *IntrinNames) {
- if (AliasName.startswith("__arm_"))
+ if (AliasName.starts_with("__arm_"))
AliasName = AliasName.substr(6);
const IntrinToName *It =
llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {
@@ -6663,10 +6669,10 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc,
// Check whether this will be mapped to a getter or setter of a property.
bool IsGetter = false, IsSetter = false;
- if (Name.startswith("getter:")) {
+ if (Name.starts_with("getter:")) {
IsGetter = true;
Name = Name.substr(7);
- } else if (Name.startswith("setter:")) {
+ } else if (Name.starts_with("setter:")) {
IsSetter = true;
Name = Name.substr(7);
}
@@ -7292,7 +7298,7 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
}
}
- if (!Space.startswith("space")) {
+ if (!Space.starts_with("space")) {
S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
return;
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index c6218a491aec..36e53c684ac4 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17879,6 +17879,8 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
ForExternalRedeclaration);
+ bool isTemplateId = D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId;
+
// There are five cases here.
// - There's no scope specifier and we're in a local class. Only look
// for functions declared in the immediately-enclosing block scope.
@@ -17916,14 +17918,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
}
adjustContextForLocalExternDecl(DC);
- // C++ [class.friend]p6:
- // A function can be defined in a friend declaration of a class if and
- // only if the class is a non-local class (9.8), the function name is
- // unqualified, and the function has namespace scope.
- if (D.isFunctionDefinition()) {
- Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
- }
-
// - There's no scope specifier, in which case we just go to the
// appropriate scope and look for a function or function template
// there as appropriate.
@@ -17934,8 +17928,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// elaborated-type-specifier, the lookup to determine whether
// the entity has been previously declared shall not consider
// any scopes outside the innermost enclosing namespace.
- bool isTemplateId =
- D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId;
// Find the appropriate context according to the above.
DC = CurContext;
@@ -17988,39 +17980,12 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
diag::warn_cxx98_compat_friend_is_member :
diag::err_friend_is_member);
- if (D.isFunctionDefinition()) {
- // C++ [class.friend]p6:
- // A function can be defined in a friend declaration of a class if and
- // only if the class is a non-local class (9.8), the function name is
- // unqualified, and the function has namespace scope.
- //
- // FIXME: We should only do this if the scope specifier names the
- // innermost enclosing namespace; otherwise the fixit changes the
- // meaning of the code.
- SemaDiagnosticBuilder DB
- = Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
-
- DB << SS.getScopeRep();
- if (DC->isFileContext())
- DB << FixItHint::CreateRemoval(SS.getRange());
- SS.clear();
- }
-
// - There's a scope specifier that does not match any template
// parameter lists, in which case we use some arbitrary context,
// create a method or method template, and wait for instantiation.
// - There's a scope specifier that does match some template
// parameter lists, which we don't handle right now.
} else {
- if (D.isFunctionDefinition()) {
- // C++ [class.friend]p6:
- // A function can be defined in a friend declaration of a class if and
- // only if the class is a non-local class (9.8), the function name is
- // unqualified, and the function has namespace scope.
- Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def)
- << SS.getScopeRep();
- }
-
DC = CurContext;
assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
}
@@ -18105,6 +18070,38 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
else
FD = cast<FunctionDecl>(ND);
+ // C++ [class.friend]p6:
+ // A function may be defined in a friend declaration of a class if and
+ // only if the class is a non-local class, and the function name is
+ // unqualified.
+ if (D.isFunctionDefinition()) {
+ // Qualified friend function definition.
+ if (SS.isNotEmpty()) {
+ // FIXME: We should only do this if the scope specifier names the
+ // innermost enclosing namespace; otherwise the fixit changes the
+ // meaning of the code.
+ SemaDiagnosticBuilder DB =
+ Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
+
+ DB << SS.getScopeRep();
+ if (DC->isFileContext())
+ DB << FixItHint::CreateRemoval(SS.getRange());
+
+ // Friend function defined in a local class.
+ } else if (FunctionContainingLocalClass) {
+ Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
+
+ // Per [basic.pre]p4, a template-id is not a name. Therefore, if we have
+ // a template-id, the function name is not unqualified because these is
+ // no name. While the wording requires some reading in-between the
+ // lines, GCC, MSVC, and EDG all consider a friend function
+ // specialization definitions // to be de facto explicit specialization
+ // and diagnose them as such.
+ } else if (isTemplateId) {
+ Diag(NameInfo.getBeginLoc(), diag::err_friend_specialization_def);
+ }
+ }
+
// C++11 [dcl.fct.default]p4: If a friend declaration specifies a
// default argument expression, that declaration shall be a definition
// and shall be the only declaration of the function or function
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index cdfa6ad3f281..c3b95e168a60 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -296,7 +296,7 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S, const NamedDecl *ND,
RealizedPlatform = S.Context.getTargetInfo().getPlatformName();
// Warn about implementing unavailable methods, unless the unavailable
// is for an app extension.
- if (RealizedPlatform.endswith("_app_extension"))
+ if (RealizedPlatform.ends_with("_app_extension"))
return;
S.Diag(ImplLoc, diag::warn_unavailable_def);
S.Diag(ND->getLocation(), diag::note_method_declared_at)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d629be083d8c..c7185d56cc99 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13808,12 +13808,12 @@ static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS,
StringRef RHSStrRef = RHSStr;
// Do not diagnose literals with digit separators, binary, hexadecimal, octal
// literals.
- if (LHSStrRef.startswith("0b") || LHSStrRef.startswith("0B") ||
- RHSStrRef.startswith("0b") || RHSStrRef.startswith("0B") ||
- LHSStrRef.startswith("0x") || LHSStrRef.startswith("0X") ||
- RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") ||
- (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) ||
- (RHSStrRef.size() > 1 && RHSStrRef.startswith("0")) ||
+ if (LHSStrRef.starts_with("0b") || LHSStrRef.starts_with("0B") ||
+ RHSStrRef.starts_with("0b") || RHSStrRef.starts_with("0B") ||
+ LHSStrRef.starts_with("0x") || LHSStrRef.starts_with("0X") ||
+ RHSStrRef.starts_with("0x") || RHSStrRef.starts_with("0X") ||
+ (LHSStrRef.size() > 1 && LHSStrRef.starts_with("0")) ||
+ (RHSStrRef.size() > 1 && RHSStrRef.starts_with("0")) ||
LHSStrRef.contains('\'') || RHSStrRef.contains('\''))
return;
@@ -15508,7 +15508,7 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R,
if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) {
Selector S = ME->getSelector();
StringRef SelArg0 = S.getNameForSlot(0);
- if (SelArg0.startswith("performSelector"))
+ if (SelArg0.starts_with("performSelector"))
Diag = diag::warn_objc_pointer_masking_performSelector;
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 5ca6b232df66..035eaae58965 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -465,7 +465,8 @@ class InitListChecker {
void FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE, bool &RequiresSecondPass,
- bool FillWithNoInit = false);
+ bool FillWithNoInit = false,
+ bool WarnIfMissing = false);
void FillInEmptyInitializations(const InitializedEntity &Entity,
InitListExpr *ILE, bool &RequiresSecondPass,
InitListExpr *OuterILE, unsigned OuterIndex,
@@ -654,11 +655,16 @@ void InitListChecker::FillInEmptyInitForBase(
}
}
-void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
- const InitializedEntity &ParentEntity,
- InitListExpr *ILE,
- bool &RequiresSecondPass,
- bool FillWithNoInit) {
+static bool hasAnyDesignatedInits(const InitListExpr *IL) {
+ return llvm::any_of(*IL, [=](const Stmt *Init) {
+ return isa_and_nonnull<DesignatedInitExpr>(Init);
+ });
+}
+
+void InitListChecker::FillInEmptyInitForField(
+ unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity,
+ InitListExpr *ILE, bool &RequiresSecondPass, bool FillWithNoInit,
+ bool WarnIfMissing) {
SourceLocation Loc = ILE->getEndLoc();
unsigned NumInits = ILE->getNumInits();
InitializedEntity MemberEntity
@@ -726,15 +732,52 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
if (hadError || VerifyOnly) {
// Do nothing
- } else if (Init < NumInits) {
- ILE->setInit(Init, MemberInit.getAs<Expr>());
- } else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) {
- // Empty initialization requires a constructor call, so
- // extend the initializer list to include the constructor
- // call and make a note that we'll need to take another pass
- // through the initializer list.
- ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs<Expr>());
- RequiresSecondPass = true;
+ } else {
+ if (WarnIfMissing) {
+ auto CheckAnonMember = [&](const FieldDecl *FD,
+ auto &&CheckAnonMember) -> FieldDecl * {
+ FieldDecl *Uninitialized = nullptr;
+ RecordDecl *RD = FD->getType()->getAsRecordDecl();
+ assert(RD && "Not anonymous member checked?");
+ for (auto *F : RD->fields()) {
+ FieldDecl *UninitializedFieldInF = nullptr;
+ if (F->isAnonymousStructOrUnion())
+ UninitializedFieldInF = CheckAnonMember(F, CheckAnonMember);
+ else if (!F->isUnnamedBitfield() &&
+ !F->getType()->isIncompleteArrayType() &&
+ !F->hasInClassInitializer())
+ UninitializedFieldInF = F;
+
+ if (RD->isUnion() && !UninitializedFieldInF)
+ return nullptr;
+ if (!Uninitialized)
+ Uninitialized = UninitializedFieldInF;
+ }
+ return Uninitialized;
+ };
+
+ FieldDecl *FieldToDiagnose = nullptr;
+ if (Field->isAnonymousStructOrUnion())
+ FieldToDiagnose = CheckAnonMember(Field, CheckAnonMember);
+ else if (!Field->isUnnamedBitfield() &&
+ !Field->getType()->isIncompleteArrayType())
+ FieldToDiagnose = Field;
+
+ if (FieldToDiagnose)
+ SemaRef.Diag(Loc, diag::warn_missing_field_initializers)
+ << FieldToDiagnose;
+ }
+
+ if (Init < NumInits) {
+ ILE->setInit(Init, MemberInit.getAs<Expr>());
+ } else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) {
+ // Empty initialization requires a constructor call, so
+ // extend the initializer list to include the constructor
+ // call and make a note that we'll need to take another pass
+ // through the initializer list.
+ ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs<Expr>());
+ RequiresSecondPass = true;
+ }
}
} else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init))) {
@@ -802,9 +845,36 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
}
}
} else {
+ InitListExpr *SForm =
+ ILE->isSyntacticForm() ? ILE : ILE->getSyntacticForm();
// The fields beyond ILE->getNumInits() are default initialized, so in
// order to leave them uninitialized, the ILE is expanded and the extra
// fields are then filled with NoInitExpr.
+
+ // Some checks that are required for missing fields warning are bound to
+ // how many elements the initializer list originally was provided; perform
+ // them before the list is expanded.
+ bool WarnIfMissingField =
+ !SForm->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
+ ILE->getNumInits();
+
+ // Disable check for missing fields when designators are used in C to
+ // match gcc behaviour.
+ // FIXME: Should we emulate possible gcc warning bug?
+ WarnIfMissingField &=
+ SemaRef.getLangOpts().CPlusPlus || !hasAnyDesignatedInits(SForm);
+
+ if (OuterILE) {
+ // When nested designators are present, there might be two nested init
+ // lists created and only outer will contain designated initializer
+ // expression, so check outer list as well.
+ InitListExpr *OuterSForm = OuterILE->isSyntacticForm()
+ ? OuterILE
+ : OuterILE->getSyntacticForm();
+ WarnIfMissingField &= SemaRef.getLangOpts().CPlusPlus ||
+ !hasAnyDesignatedInits(OuterSForm);
+ }
+
unsigned NumElems = numStructUnionElements(ILE->getType());
if (!RDecl->isUnion() && RDecl->hasFlexibleArrayMember())
++NumElems;
@@ -832,7 +902,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
return;
FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass,
- FillWithNoInit);
+ FillWithNoInit, WarnIfMissingField);
if (hadError)
return;
@@ -947,13 +1017,6 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
}
}
-static bool hasAnyDesignatedInits(const InitListExpr *IL) {
- for (const Stmt *Init : *IL)
- if (isa_and_nonnull<DesignatedInitExpr>(Init))
- return true;
- return false;
-}
-
InitListChecker::InitListChecker(
Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T,
bool VerifyOnly, bool TreatUnavailableAsInvalid, bool InOverloadResolution,
@@ -2225,12 +2288,8 @@ void InitListChecker::CheckStructUnionTypes(
size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) {
return isa<FieldDecl>(D) || isa<RecordDecl>(D);
});
- bool CheckForMissingFields =
- !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
bool HasDesignatedInit = false;
- llvm::SmallPtrSet<FieldDecl *, 4> InitializedFields;
-
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
SourceLocation InitLoc = Init->getBeginLoc();
@@ -2254,24 +2313,17 @@ void InitListChecker::CheckStructUnionTypes(
// Find the field named by the designated initializer.
DesignatedInitExpr::Designator *D = DIE->getDesignator(0);
- if (!VerifyOnly && D->isFieldDesignator()) {
+ if (!VerifyOnly && D->isFieldDesignator() && !DesignatedInitFailed) {
FieldDecl *F = D->getFieldDecl();
- InitializedFields.insert(F);
- if (!DesignatedInitFailed) {
- QualType ET = SemaRef.Context.getBaseElementType(F->getType());
- if (checkDestructorReference(ET, InitLoc, SemaRef)) {
- hadError = true;
- return;
- }
+ QualType ET = SemaRef.Context.getBaseElementType(F->getType());
+ if (checkDestructorReference(ET, InitLoc, SemaRef)) {
+ hadError = true;
+ return;
}
}
InitializedSomething = true;
- // Disable check for missing fields when designators are used.
- // This matches gcc behaviour.
- if (!SemaRef.getLangOpts().CPlusPlus)
- CheckForMissingFields = false;
continue;
}
@@ -2350,7 +2402,6 @@ void InitListChecker::CheckStructUnionTypes(
CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, StructuredIndex);
InitializedSomething = true;
- InitializedFields.insert(*Field);
if (RD->isUnion() && StructuredList) {
// Initialize the first field within the union.
@@ -2360,28 +2411,6 @@ void InitListChecker::CheckStructUnionTypes(
++Field;
}
- // Emit warnings for missing struct field initializers.
- if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
- !RD->isUnion()) {
- // It is possible we have one or more unnamed bitfields remaining.
- // Find first (if any) named field and emit warning.
- for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
- : Field,
- end = RD->field_end();
- it != end; ++it) {
- if (HasDesignatedInit && InitializedFields.count(*it))
- continue;
-
- if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
- !it->getType()->isIncompleteArrayType()) {
- SemaRef.Diag(IList->getSourceRange().getEnd(),
- diag::warn_missing_field_initializers)
- << *it;
- break;
- }
- }
- }
-
// Check that any remaining fields can be value-initialized if we're not
// building a structured list. (If we are, we'll check this later.)
if (!StructuredList && Field != FieldEnd && !RD->isUnion() &&
@@ -4414,7 +4443,8 @@ static void TryReferenceInitializationCore(Sema &S,
Qualifiers T1Quals,
QualType cv2T2, QualType T2,
Qualifiers T2Quals,
- InitializationSequence &Sequence);
+ InitializationSequence &Sequence,
+ bool TopLevelOfInitList);
static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
@@ -4468,7 +4498,8 @@ static void TryReferenceListInitialization(Sema &S,
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
- T1Quals, cv2T2, T2, T2Quals, Sequence);
+ T1Quals, cv2T2, T2, T2Quals, Sequence,
+ /*TopLevelOfInitList=*/true);
if (Sequence)
Sequence.RewrapReferenceInitList(cv1T1, InitList);
return;
@@ -4927,11 +4958,11 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
Expr *CurInitExpr);
/// Attempt reference initialization (C++0x [dcl.init.ref])
-static void TryReferenceInitialization(Sema &S,
- const InitializedEntity &Entity,
+static void TryReferenceInitialization(Sema &S, const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr *Initializer,
- InitializationSequence &Sequence) {
+ InitializationSequence &Sequence,
+ bool TopLevelOfInitList) {
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
@@ -4949,7 +4980,8 @@ static void TryReferenceInitialization(Sema &S,
// Delegate everything else to a subfunction.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
- T1Quals, cv2T2, T2, T2Quals, Sequence);
+ T1Quals, cv2T2, T2, T2Quals, Sequence,
+ TopLevelOfInitList);
}
/// Determine whether an expression is a non-referenceable glvalue (one to
@@ -4972,7 +5004,8 @@ static void TryReferenceInitializationCore(Sema &S,
Qualifiers T1Quals,
QualType cv2T2, QualType T2,
Qualifiers T2Quals,
- InitializationSequence &Sequence) {
+ InitializationSequence &Sequence,
+ bool TopLevelOfInitList) {
QualType DestType = Entity.getType();
SourceLocation DeclLoc = Initializer->getBeginLoc();
@@ -5246,7 +5279,8 @@ static void TryReferenceInitializationCore(Sema &S,
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
return;
} else {
- Sequence.AddConversionSequenceStep(ICS, TempEntity.getType());
+ Sequence.AddConversionSequenceStep(ICS, TempEntity.getType(),
+ TopLevelOfInitList);
}
// [...] If T1 is reference-related to T2, cv1 must be the
@@ -6210,7 +6244,8 @@ void InitializationSequence::InitializeFrom(Sema &S,
else if (isa<InitListExpr>(Args[0]))
SetFailed(FK_ParenthesizedListInitForReference);
else
- TryReferenceInitialization(S, Entity, Kind, Args[0], *this);
+ TryReferenceInitialization(S, Entity, Kind, Args[0], *this,
+ TopLevelOfInitList);
return;
}
@@ -10413,7 +10448,7 @@ static void DiagnoseNarrowingInInitList(Sema &S,
: diag::warn_init_list_type_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
- << EntityType.getLocalUnqualifiedType();
+ << EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;
case NK_Constant_Narrowing:
@@ -10424,7 +10459,7 @@ static void DiagnoseNarrowingInInitList(Sema &S,
: diag::warn_init_list_constant_narrowing)
<< PostInit->getSourceRange()
<< ConstantValue.getAsString(S.getASTContext(), ConstantType)
- << EntityType.getLocalUnqualifiedType();
+ << EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;
case NK_Variable_Narrowing:
@@ -10435,7 +10470,7 @@ static void DiagnoseNarrowingInInitList(Sema &S,
: diag::warn_init_list_variable_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
- << EntityType.getLocalUnqualifiedType();
+ << EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;
}
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 4cc87c9fa765..e7b6443c984c 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1885,8 +1885,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
return InitSeq.Perform(*this, Entity, InitKind, InitExpr);
}
-ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
- Scope *CurScope) {
+ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body) {
LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back());
ActOnFinishFunctionBody(LSI.CallOperator, Body);
return BuildLambdaExpr(StartLoc, Body->getEndLoc(), &LSI);
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 9282ceb8dee0..db0cbd5ec6d6 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -268,7 +268,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
StringRef FirstComponentName = Path[0].first->getName();
if (!getSourceManager().isInSystemHeader(Path[0].second) &&
(FirstComponentName == "std" ||
- (FirstComponentName.startswith("std") &&
+ (FirstComponentName.starts_with("std") &&
llvm::all_of(FirstComponentName.drop_front(3), &llvm::isDigit))))
Diag(Path[0].second, diag::warn_reserved_module_name) << Path[0].first;
diff --git a/clang/lib/Sema/SemaRISCVVectorLookup.cpp b/clang/lib/Sema/SemaRISCVVectorLookup.cpp
index 9a5aecf669a0..e4642e4da016 100644
--- a/clang/lib/Sema/SemaRISCVVectorLookup.cpp
+++ b/clang/lib/Sema/SemaRISCVVectorLookup.cpp
@@ -34,12 +34,6 @@ namespace {
// Function definition of a RVV intrinsic.
struct RVVIntrinsicDef {
- /// Full function name with suffix, e.g. vadd_vv_i32m1.
- std::string Name;
-
- /// Overloaded function name, e.g. vadd.
- std::string OverloadName;
-
/// Mapping to which clang built-in function, e.g. __builtin_rvv_vadd.
std::string BuiltinName;
@@ -49,7 +43,7 @@ struct RVVIntrinsicDef {
struct RVVOverloadIntrinsicDef {
// Indexes of RISCVIntrinsicManagerImpl::IntrinsicList.
- SmallVector<size_t, 8> Indexes;
+ SmallVector<uint32_t, 8> Indexes;
};
} // namespace
@@ -168,7 +162,7 @@ private:
// List of all RVV intrinsic.
std::vector<RVVIntrinsicDef> IntrinsicList;
// Mapping function name to index of IntrinsicList.
- StringMap<size_t> Intrinsics;
+ StringMap<uint32_t> Intrinsics;
// Mapping function name to RVVOverloadIntrinsicDef.
StringMap<RVVOverloadIntrinsicDef> OverloadIntrinsics;
@@ -180,7 +174,7 @@ private:
// Create FunctionDecl for a vector intrinsic.
void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II,
- Preprocessor &PP, unsigned Index,
+ Preprocessor &PP, uint32_t Index,
bool IsOverload);
void ConstructRVVIntrinsics(ArrayRef<RVVIntrinsicRecord> Recs,
@@ -392,8 +386,8 @@ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
Record.HasFRMRoundModeOp);
// Put into IntrinsicList.
- size_t Index = IntrinsicList.size();
- IntrinsicList.push_back({Name, OverloadedName, BuiltinName, Signature});
+ uint32_t Index = IntrinsicList.size();
+ IntrinsicList.push_back({BuiltinName, Signature});
// Creating mapping to Intrinsics.
Intrinsics.insert({Name, Index});
@@ -409,7 +403,7 @@ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
void RISCVIntrinsicManagerImpl::CreateRVVIntrinsicDecl(LookupResult &LR,
IdentifierInfo *II,
Preprocessor &PP,
- unsigned Index,
+ uint32_t Index,
bool IsOverload) {
ASTContext &Context = S.Context;
RVVIntrinsicDef &IDef = IntrinsicList[Index];
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 725d8efe3828..e6a4d3e63e4a 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -53,6 +53,13 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A,
static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SourceRange Range) {
+ if (A.getAttributeSpellingListIndex() == SuppressAttr::CXX11_gsl_suppress &&
+ A.getNumArgs() < 1) {
+ // Suppression attribute with GSL spelling requires at least 1 argument.
+ S.Diag(A.getLoc(), diag::err_attribute_too_few_arguments) << A << 1;
+ return nullptr;
+ }
+
std::vector<StringRef> DiagnosticIdentifiers;
for (unsigned I = 0, E = A.getNumArgs(); I != E; ++I) {
StringRef RuleName;
@@ -60,8 +67,6 @@ static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
if (!S.checkStringLiteralArgumentAttr(A, I, RuleName, nullptr))
return nullptr;
- // FIXME: Warn if the rule name is unknown. This is tricky because only
- // clang-tidy knows about available rules.
DiagnosticIdentifiers.push_back(RuleName);
}
@@ -356,11 +361,10 @@ static Attr *handleCodeAlignAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
}
// Diagnose non-identical duplicates as a 'conflicting' loop attributes
-// and suppress duplicate errors in cases where the two match for
-// [[clang::code_align()]] attribute.
-static void CheckForDuplicateCodeAlignAttrs(Sema &S,
- ArrayRef<const Attr *> Attrs) {
- auto FindFunc = [](const Attr *A) { return isa<const CodeAlignAttr>(A); };
+// and suppress duplicate errors in cases where the two match.
+template <typename LoopAttrT>
+static void CheckForDuplicateLoopAttrs(Sema &S, ArrayRef<const Attr *> Attrs) {
+ auto FindFunc = [](const Attr *A) { return isa<const LoopAttrT>(A); };
const auto *FirstItr = std::find_if(Attrs.begin(), Attrs.end(), FindFunc);
if (FirstItr == Attrs.end()) // no attributes found
@@ -370,7 +374,7 @@ static void CheckForDuplicateCodeAlignAttrs(Sema &S,
std::optional<llvm::APSInt> FirstValue;
const auto *CAFA =
- dyn_cast<ConstantExpr>(cast<CodeAlignAttr>(*FirstItr)->getAlignment());
+ dyn_cast<ConstantExpr>(cast<LoopAttrT>(*FirstItr)->getAlignment());
// Return early if first alignment expression is dependent (since we don't
// know what the effective size will be), and skip the loop entirely.
if (!CAFA)
@@ -378,8 +382,8 @@ static void CheckForDuplicateCodeAlignAttrs(Sema &S,
while (Attrs.end() != (LastFoundItr = std::find_if(LastFoundItr + 1,
Attrs.end(), FindFunc))) {
- const auto *CASA = dyn_cast<ConstantExpr>(
- cast<CodeAlignAttr>(*LastFoundItr)->getAlignment());
+ const auto *CASA =
+ dyn_cast<ConstantExpr>(cast<LoopAttrT>(*LastFoundItr)->getAlignment());
// If the value is dependent, we can not test anything.
if (!CASA)
return;
@@ -630,10 +634,10 @@ void Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributes &InAttrs,
}
CheckForIncompatibleAttributes(*this, OutAttrs);
- CheckForDuplicateCodeAlignAttrs(*this, OutAttrs);
+ CheckForDuplicateLoopAttrs<CodeAlignAttr>(*this, OutAttrs);
}
-bool Sema::CheckRebuiltCodeAlignStmtAttributes(ArrayRef<const Attr *> Attrs) {
- CheckForDuplicateCodeAlignAttrs(*this, Attrs);
+bool Sema::CheckRebuiltStmtAttributes(ArrayRef<const Attr *> Attrs) {
+ CheckForDuplicateLoopAttrs<CodeAlignAttr>(*this, Attrs);
return false;
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 83610503ed9b..a376f20fa4f4 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -5371,7 +5371,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
!(D.getIdentifier() &&
((D.getIdentifier()->getName() == "printf" &&
LangOpts.getOpenCLCompatibleVersion() >= 120) ||
- D.getIdentifier()->getName().startswith("__")))) {
+ D.getIdentifier()->getName().starts_with("__")))) {
S.Diag(D.getIdentifierLoc(), diag::err_opencl_variadic_function);
D.setInvalidType(true);
}
@@ -8360,12 +8360,25 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
// not to need a separate attribute)
if (!(S.Context.getTargetInfo().hasFeature("neon") ||
S.Context.getTargetInfo().hasFeature("mve") ||
- IsTargetCUDAAndHostARM)) {
+ S.Context.getTargetInfo().hasFeature("sve") ||
+ S.Context.getTargetInfo().hasFeature("sme") ||
+ IsTargetCUDAAndHostARM) &&
+ VecKind == VectorKind::Neon) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_unsupported)
+ << Attr << "'neon', 'mve', 'sve' or 'sme'";
+ Attr.setInvalid();
+ return;
+ }
+ if (!(S.Context.getTargetInfo().hasFeature("neon") ||
+ S.Context.getTargetInfo().hasFeature("mve") ||
+ IsTargetCUDAAndHostARM) &&
+ VecKind == VectorKind::NeonPoly) {
S.Diag(Attr.getLoc(), diag::err_attribute_unsupported)
<< Attr << "'neon' or 'mve'";
Attr.setInvalid();
return;
}
+
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1ad843d0bf4e..7df5bf0cb713 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1378,7 +1378,7 @@ public:
StmtResult RebuildAttributedStmt(SourceLocation AttrLoc,
ArrayRef<const Attr *> Attrs,
Stmt *SubStmt) {
- if (SemaRef.CheckRebuiltCodeAlignStmtAttributes(Attrs))
+ if (SemaRef.CheckRebuiltStmtAttributes(Attrs))
return StmtError();
return SemaRef.BuildAttributedStmt(AttrLoc, Attrs, SubStmt);
}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 5b51ac40000d..9effd333dacc 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1781,26 +1781,26 @@ llvm::Error ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor,
}
}
-Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
+Token ASTReader::ReadToken(ModuleFile &M, const RecordDataImpl &Record,
unsigned &Idx) {
Token Tok;
Tok.startToken();
- Tok.setLocation(ReadSourceLocation(F, Record, Idx));
+ Tok.setLocation(ReadSourceLocation(M, Record, Idx));
Tok.setKind((tok::TokenKind)Record[Idx++]);
Tok.setFlag((Token::TokenFlags)Record[Idx++]);
if (Tok.isAnnotation()) {
- Tok.setAnnotationEndLoc(ReadSourceLocation(F, Record, Idx));
+ Tok.setAnnotationEndLoc(ReadSourceLocation(M, Record, Idx));
switch (Tok.getKind()) {
case tok::annot_pragma_loop_hint: {
auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
- Info->PragmaName = ReadToken(F, Record, Idx);
- Info->Option = ReadToken(F, Record, Idx);
+ Info->PragmaName = ReadToken(M, Record, Idx);
+ Info->Option = ReadToken(M, Record, Idx);
unsigned NumTokens = Record[Idx++];
SmallVector<Token, 4> Toks;
Toks.reserve(NumTokens);
for (unsigned I = 0; I < NumTokens; ++I)
- Toks.push_back(ReadToken(F, Record, Idx));
+ Toks.push_back(ReadToken(M, Record, Idx));
Info->Toks = llvm::ArrayRef(Toks).copy(PP.getPreprocessorAllocator());
Tok.setAnnotationValue(static_cast<void *>(Info));
break;
@@ -1811,7 +1811,7 @@ Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
auto SlotLabel = ReadString(Record, Idx);
Info->SlotLabel =
llvm::StringRef(SlotLabel).copy(PP.getPreprocessorAllocator());
- Info->Alignment = ReadToken(F, Record, Idx);
+ Info->Alignment = ReadToken(M, Record, Idx);
Tok.setAnnotationValue(static_cast<void *>(Info));
break;
}
@@ -1827,7 +1827,7 @@ Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
}
} else {
Tok.setLength(Record[Idx++]);
- if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
+ if (IdentifierInfo *II = getLocalIdentifier(M, Record[Idx++]))
Tok.setIdentifierInfo(II);
}
return Tok;
@@ -1997,10 +1997,10 @@ unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
}
HeaderFileInfoTrait::internal_key_type
-HeaderFileInfoTrait::GetInternalKey(external_key_type FE) {
- internal_key_type ikey = {FE.getSize(),
- M.HasTimestamps ? FE.getModificationTime() : 0,
- FE.getName(), /*Imported*/ false};
+HeaderFileInfoTrait::GetInternalKey(external_key_type ekey) {
+ internal_key_type ikey = {ekey.getSize(),
+ M.HasTimestamps ? ekey.getModificationTime() : 0,
+ ekey.getName(), /*Imported*/ false};
return ikey;
}
@@ -8946,10 +8946,10 @@ Module *ASTReader::getModule(unsigned ID) {
return getSubmodule(ID);
}
-ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &F, unsigned ID) {
+ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &M, unsigned ID) {
if (ID & 1) {
// It's a module, look it up by submodule ID.
- auto I = GlobalSubmoduleMap.find(getGlobalSubmoduleID(F, ID >> 1));
+ auto I = GlobalSubmoduleMap.find(getGlobalSubmoduleID(M, ID >> 1));
return I == GlobalSubmoduleMap.end() ? nullptr : I->second;
} else {
// It's a prefix (preamble, PCH, ...). Look it up by index.
@@ -8959,19 +8959,19 @@ ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &F, unsigned ID) {
}
}
-unsigned ASTReader::getModuleFileID(ModuleFile *F) {
- if (!F)
+unsigned ASTReader::getModuleFileID(ModuleFile *M) {
+ if (!M)
return 1;
// For a file representing a module, use the submodule ID of the top-level
// module as the file ID. For any other kind of file, the number of such
// files loaded beforehand will be the same on reload.
// FIXME: Is this true even if we have an explicit module file and a PCH?
- if (F->isModule())
- return ((F->BaseSubmoduleID + NUM_PREDEF_SUBMODULE_IDS) << 1) | 1;
+ if (M->isModule())
+ return ((M->BaseSubmoduleID + NUM_PREDEF_SUBMODULE_IDS) << 1) | 1;
auto PCHModules = getModuleManager().pch_modules();
- auto I = llvm::find(PCHModules, F);
+ auto I = llvm::find(PCHModules, M);
assert(I != PCHModules.end() && "emitting reference to unknown file");
return (I - PCHModules.end()) << 1;
}
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index bc16cfc67a24..7140a14aefbf 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -583,6 +583,9 @@ void ASTDeclReader::Visit(Decl *D) {
}
void ASTDeclReader::VisitDecl(Decl *D) {
+ BitsUnpacker DeclBits(Record.readInt());
+ bool HasStandaloneLexicalDC = DeclBits.getNextBit();
+
if (D->isTemplateParameter() || D->isTemplateParameterPack() ||
isa<ParmVarDecl, ObjCTypeParamDecl>(D)) {
// We don't want to deserialize the DeclContext of a template
@@ -592,7 +595,8 @@ void ASTDeclReader::VisitDecl(Decl *D) {
// return type of the function). Use the translation unit DeclContext as a
// placeholder.
GlobalDeclID SemaDCIDForTemplateParmDecl = readDeclID();
- GlobalDeclID LexicalDCIDForTemplateParmDecl = readDeclID();
+ GlobalDeclID LexicalDCIDForTemplateParmDecl =
+ HasStandaloneLexicalDC ? readDeclID() : 0;
if (!LexicalDCIDForTemplateParmDecl)
LexicalDCIDForTemplateParmDecl = SemaDCIDForTemplateParmDecl;
Reader.addPendingDeclContextInfo(D,
@@ -601,7 +605,8 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->setDeclContext(Reader.getContext().getTranslationUnitDecl());
} else {
auto *SemaDC = readDeclAs<DeclContext>();
- auto *LexicalDC = readDeclAs<DeclContext>();
+ auto *LexicalDC =
+ HasStandaloneLexicalDC ? readDeclAs<DeclContext>() : nullptr;
if (!LexicalDC)
LexicalDC = SemaDC;
// If the context is a class, we might not have actually merged it yet, in
@@ -618,7 +623,6 @@ void ASTDeclReader::VisitDecl(Decl *D) {
}
D->setLocation(ThisDeclLoc);
- BitsUnpacker DeclBits(Record.readInt());
D->InvalidDecl = DeclBits.getNextBit();
bool HasAttrs = DeclBits.getNextBit();
D->setImplicit(DeclBits.getNextBit());
@@ -765,7 +769,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
TD->setCompleteDefinitionRequired(TagDeclBits.getNextBit());
TD->setBraceRange(readSourceRange());
- switch (Record.readInt()) {
+ switch (TagDeclBits.getNextBits(/*Width=*/2)) {
case 0:
break;
case 1: { // ExtInfo
@@ -1089,7 +1093,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setCachedLinkage((Linkage)FunctionDeclBits.getNextBits(/*Width=*/3));
FD->EndRangeLoc = readSourceLocation();
- FD->setDefaultLoc(readSourceLocation());
+ if (FD->isExplicitlyDefaulted())
+ FD->setDefaultLoc(readSourceLocation());
FD->ODRHash = Record.readInt();
FD->setHasODRHash(true);
@@ -1703,7 +1708,7 @@ void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
unsigned isObjCMethodParam = ParmVarDeclBits.getNextBit();
unsigned scopeDepth = ParmVarDeclBits.getNextBits(/*Width=*/7);
unsigned scopeIndex = ParmVarDeclBits.getNextBits(/*Width=*/8);
- unsigned declQualifier = Record.readInt();
+ unsigned declQualifier = ParmVarDeclBits.getNextBits(/*Width=*/7);
if (isObjCMethodParam) {
assert(scopeDepth == 0);
PD->setObjCMethodScopeInfo(scopeIndex);
@@ -1716,7 +1721,9 @@ void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
PD->ParmVarDeclBits.HasInheritedDefaultArg = ParmVarDeclBits.getNextBit();
if (ParmVarDeclBits.getNextBit()) // hasUninstantiatedDefaultArg.
PD->setUninstantiatedDefaultArg(Record.readExpr());
- PD->ExplicitObjectParameterIntroducerLoc = Record.readSourceLocation();
+
+ if (ParmVarDeclBits.getNextBit()) // Valid explicit object parameter
+ PD->ExplicitObjectParameterIntroducerLoc = Record.readSourceLocation();
// FIXME: If this is a redeclaration of a function from another module, handle
// inheritance of default arguments.
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index d7d0c0e5bb21..b3a6f619372b 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -108,7 +108,7 @@ namespace clang {
/// The number of record fields required for the Expr class
/// itself.
- static const unsigned NumExprFields = NumStmtFields + 4;
+ static const unsigned NumExprFields = NumStmtFields + 2;
/// Read and initialize a ExplicitTemplateArgumentList structure.
void ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
@@ -524,9 +524,13 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
void ASTStmtReader::VisitExpr(Expr *E) {
VisitStmt(E);
E->setType(Record.readType());
- E->setDependence(static_cast<ExprDependence>(Record.readInt()));
- E->setValueKind(static_cast<ExprValueKind>(Record.readInt()));
- E->setObjectKind(static_cast<ExprObjectKind>(Record.readInt()));
+ BitsUnpacker ExprBits(Record.readInt());
+ E->setDependence(
+ static_cast<ExprDependence>(ExprBits.getNextBits(/*Width=*/5)));
+ E->setValueKind(
+ static_cast<ExprValueKind>(ExprBits.getNextBits(/*Width=*/2)));
+ E->setObjectKind(
+ static_cast<ExprObjectKind>(ExprBits.getNextBits(/*Width=*/3)));
assert(Record.getIdx() == NumExprFields &&
"Incorrect expression field count");
}
@@ -995,14 +999,19 @@ void ASTStmtReader::VisitOMPIteratorExpr(OMPIteratorExpr *E) {
void ASTStmtReader::VisitCallExpr(CallExpr *E) {
VisitExpr(E);
- unsigned NumArgs = Record.readInt();
- bool HasFPFeatures = Record.readInt();
+
+ BitsUnpacker CallExprBits = Record.readInt();
+
+ unsigned NumArgs = CallExprBits.getNextBits(/*Width=*/16);
+ bool HasFPFeatures = CallExprBits.getNextBit();
+ E->setADLCallKind(
+ static_cast<CallExpr::ADLCallKind>(CallExprBits.getNextBit()));
assert((NumArgs == E->getNumArgs()) && "Wrong NumArgs!");
E->setRParenLoc(readSourceLocation());
E->setCallee(Record.readSubExpr());
for (unsigned I = 0; I != NumArgs; ++I)
E->setArg(I, Record.readSubExpr());
- E->setADLCallKind(static_cast<CallExpr::ADLCallKind>(Record.readInt()));
+
if (HasFPFeatures)
E->setStoredFPFeatures(
FPOptionsOverride::getFromOpaqueInt(Record.readInt()));
@@ -2013,14 +2022,15 @@ ASTStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
VisitExpr(E);
- unsigned NumResults = Record.readInt();
- bool HasTemplateKWAndArgsInfo = Record.readInt();
+ BitsUnpacker OverloadExprBits = Record.readInt();
+ unsigned NumResults = OverloadExprBits.getNextBits(/*Width=*/14);
+ bool HasTemplateKWAndArgsInfo = OverloadExprBits.getNextBit();
assert((E->getNumDecls() == NumResults) && "Wrong NumResults!");
assert((E->hasTemplateKWAndArgsInfo() == HasTemplateKWAndArgsInfo) &&
"Wrong HasTemplateKWAndArgsInfo!");
if (HasTemplateKWAndArgsInfo) {
- unsigned NumTemplateArgs = Record.readInt();
+ unsigned NumTemplateArgs = OverloadExprBits.getNextBits(/*Width=*/14);
ReadTemplateKWAndArgsInfo(*E->getTrailingASTTemplateKWAndArgsInfo(),
E->getTrailingTemplateArgumentLoc(),
NumTemplateArgs);
@@ -3022,11 +3032,13 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Record[ASTStmtReader::NumExprFields]);
break;
- case EXPR_CALL:
- S = CallExpr::CreateEmpty(
- Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields],
- /*HasFPFeatures=*/Record[ASTStmtReader::NumExprFields + 1], Empty);
+ case EXPR_CALL: {
+ BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
+ auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
+ auto HasFPFeatures = CallExprBits.getNextBit();
+ S = CallExpr::CreateEmpty(Context, NumArgs, HasFPFeatures, Empty);
break;
+ }
case EXPR_RECOVERY:
S = RecoveryExpr::CreateEmpty(
@@ -3764,17 +3776,23 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
- case EXPR_CXX_OPERATOR_CALL:
- S = CXXOperatorCallExpr::CreateEmpty(
- Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields],
- /*HasFPFeatures=*/Record[ASTStmtReader::NumExprFields + 1], Empty);
+ case EXPR_CXX_OPERATOR_CALL: {
+ BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
+ auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
+ auto HasFPFeatures = CallExprBits.getNextBit();
+ S = CXXOperatorCallExpr::CreateEmpty(Context, NumArgs, HasFPFeatures,
+ Empty);
break;
+ }
- case EXPR_CXX_MEMBER_CALL:
- S = CXXMemberCallExpr::CreateEmpty(
- Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields],
- /*HasFPFeatures=*/Record[ASTStmtReader::NumExprFields + 1], Empty);
+ case EXPR_CXX_MEMBER_CALL: {
+ BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
+ auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
+ auto HasFPFeatures = CallExprBits.getNextBit();
+ S = CXXMemberCallExpr::CreateEmpty(Context, NumArgs, HasFPFeatures,
+ Empty);
break;
+ }
case EXPR_CXX_REWRITTEN_BINARY_OPERATOR:
S = new (Context) CXXRewrittenBinaryOperator(Empty);
@@ -3833,11 +3851,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) BuiltinBitCastExpr(Empty);
break;
- case EXPR_USER_DEFINED_LITERAL:
- S = UserDefinedLiteral::CreateEmpty(
- Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields],
- /*HasFPFeatures=*/Record[ASTStmtReader::NumExprFields + 1], Empty);
+ case EXPR_USER_DEFINED_LITERAL: {
+ BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
+ auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
+ auto HasFPFeatures = CallExprBits.getNextBit();
+ S = UserDefinedLiteral::CreateEmpty(Context, NumArgs, HasFPFeatures,
+ Empty);
break;
+ }
case EXPR_CXX_STD_INITIALIZER_LIST:
S = new (Context) CXXStdInitializerListExpr(Empty);
@@ -3948,23 +3969,21 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case EXPR_CXX_UNRESOLVED_MEMBER:
S = UnresolvedMemberExpr::CreateEmpty(
Context,
- /*NumResults=*/Record[ASTStmtReader::NumExprFields],
- /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields + 1],
- /*NumTemplateArgs=*/
- Record[ASTStmtReader::NumExprFields + 1]
- ? Record[ASTStmtReader::NumExprFields + 2]
- : 0);
+ /*NumResults=*/Record[ASTStmtReader::NumExprFields] & ((1 << 14) - 1),
+ /*HasTemplateKWAndArgsInfo=*/
+ (Record[ASTStmtReader::NumExprFields] >> 14) & (0x1),
+ /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] >> 14 &
+ ((1 << 14) - 1));
break;
case EXPR_CXX_UNRESOLVED_LOOKUP:
S = UnresolvedLookupExpr::CreateEmpty(
Context,
- /*NumResults=*/Record[ASTStmtReader::NumExprFields],
- /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields + 1],
- /*NumTemplateArgs=*/
- Record[ASTStmtReader::NumExprFields + 1]
- ? Record[ASTStmtReader::NumExprFields + 2]
- : 0);
+ /*NumResults=*/Record[ASTStmtReader::NumExprFields] & ((1 << 14) - 1),
+ /*HasTemplateKWAndArgsInfo=*/
+ (Record[ASTStmtReader::NumExprFields] >> 14) & (0x1),
+ /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] >> 14 &
+ ((1 << 14) - 1));
break;
case EXPR_TYPE_TRAIT:
@@ -4024,11 +4043,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) OpaqueValueExpr(Empty);
break;
- case EXPR_CUDA_KERNEL_CALL:
- S = CUDAKernelCallExpr::CreateEmpty(
- Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields],
- /*HasFPFeatures=*/Record[ASTStmtReader::NumExprFields + 1], Empty);
+ case EXPR_CUDA_KERNEL_CALL: {
+ BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
+ auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
+ auto HasFPFeatures = CallExprBits.getNextBit();
+ S = CUDAKernelCallExpr::CreateEmpty(Context, NumArgs, HasFPFeatures,
+ Empty);
break;
+ }
case EXPR_ASTYPE:
S = new (Context) AsTypeExpr(Empty);
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index bf082e5b8eac..43169b2befc6 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -320,13 +320,8 @@ void ASTDeclWriter::Visit(Decl *D) {
}
void ASTDeclWriter::VisitDecl(Decl *D) {
- Record.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()));
- if (D->getDeclContext() != D->getLexicalDeclContext())
- Record.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()));
- else
- Record.push_back(0);
-
BitsPacker DeclBits;
+ DeclBits.addBit(D->getDeclContext() != D->getLexicalDeclContext());
DeclBits.addBit(D->isInvalidDecl());
DeclBits.addBit(D->hasAttrs());
DeclBits.addBit(D->isImplicit());
@@ -337,6 +332,10 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
DeclBits.addBits((uint64_t)D->getModuleOwnershipKind(), /*BitWidth=*/3);
Record.push_back(DeclBits);
+ Record.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()));
+ if (D->getDeclContext() != D->getLexicalDeclContext())
+ Record.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()));
+
if (D->hasAttrs())
Record.AddAttributes(D->getAttrs());
@@ -450,19 +449,18 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
TagDeclBits.addBit(D->isEmbeddedInDeclarator());
TagDeclBits.addBit(D->isFreeStanding());
TagDeclBits.addBit(D->isCompleteDefinitionRequired());
+ TagDeclBits.addBits(
+ D->hasExtInfo() ? 1 : (D->getTypedefNameForAnonDecl() ? 2 : 0),
+ /*BitWidth=*/2);
Record.push_back(TagDeclBits);
Record.AddSourceRange(D->getBraceRange());
if (D->hasExtInfo()) {
- Record.push_back(1);
Record.AddQualifierInfo(*D->getExtInfo());
} else if (auto *TD = D->getTypedefNameForAnonDecl()) {
- Record.push_back(2);
Record.AddDeclRef(TD);
Record.AddIdentifierRef(TD->getDeclName().getAsIdentifierInfo());
- } else {
- Record.push_back(0);
}
}
@@ -702,7 +700,8 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(FunctionDeclBits);
Record.AddSourceLocation(D->getEndLoc());
- Record.AddSourceLocation(D->getDefaultLoc());
+ if (D->isExplicitlyDefaulted())
+ Record.AddSourceLocation(D->getDefaultLoc());
Record.push_back(D->getODRHash());
@@ -1176,15 +1175,18 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
ParmVarDeclBits.addBit(D->isObjCMethodParameter());
ParmVarDeclBits.addBits(D->getFunctionScopeDepth(), /*BitsWidth=*/7);
ParmVarDeclBits.addBits(D->getFunctionScopeIndex(), /*BitsWidth=*/8);
+ // FIXME: stable encoding
+ ParmVarDeclBits.addBits(D->getObjCDeclQualifier(), /*BitsWidth=*/7);
ParmVarDeclBits.addBit(D->isKNRPromoted());
ParmVarDeclBits.addBit(D->hasInheritedDefaultArg());
ParmVarDeclBits.addBit(D->hasUninstantiatedDefaultArg());
+ ParmVarDeclBits.addBit(D->getExplicitObjectParamThisLoc().isValid());
Record.push_back(ParmVarDeclBits);
- Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding
if (D->hasUninstantiatedDefaultArg())
Record.AddStmt(D->getUninstantiatedDefaultArg());
- Record.AddSourceLocation(D->getExplicitObjectParamThisLoc());
+ if (D->getExplicitObjectParamThisLoc().isValid())
+ Record.AddSourceLocation(D->getExplicitObjectParamThisLoc());
Code = serialization::DECL_PARM_VAR;
// If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
@@ -2038,13 +2040,12 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD));
// Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 12)); // Packed DeclBits: HasStandaloneLexicalDC,
+ // isInvalidDecl, HasAttrs, isImplicit, isUsed,
+ // isReferenced, TopLevelDeclInObjCContainer,
+ // AccessSpecifier, ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(
- BitCodeAbbrevOp::Fixed,
- 11)); // Packed DeclBits: isInvalidDecl, HasAttrs, isImplicit, isUsed,
- // isReferenced, TopLevelDeclInObjCContainer, AccessSpecifier,
- // ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
@@ -2068,13 +2069,12 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR));
// Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 12)); // Packed DeclBits: HasStandaloneLexicalDC,
+ // isInvalidDecl, HasAttrs, isImplicit, isUsed,
+ // isReferenced, TopLevelDeclInObjCContainer,
+ // AccessSpecifier, ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(
- BitCodeAbbrevOp::Fixed,
- 11)); // Packed DeclBits: isInvalidDecl, HasAttrs, isImplicit, isUsed,
- // isReferenced, TopLevelDeclInObjCContainer, AccessSpecifier,
- // ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
@@ -2103,13 +2103,12 @@ void ASTWriter::WriteDeclAbbrevs() {
// Redeclarable
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 12)); // Packed DeclBits: HasStandaloneLexicalDC,
+ // isInvalidDecl, HasAttrs, isImplicit, isUsed,
+ // isReferenced, TopLevelDeclInObjCContainer,
+ // AccessSpecifier, ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(
- BitCodeAbbrevOp::Fixed,
- 11)); // Packed DeclBits: isInvalidDecl, HasAttrs, isImplicit, isUsed,
- // isReferenced, TopLevelDeclInObjCContainer, AccessSpecifier,
- // ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
@@ -2122,11 +2121,11 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
Abv->Add(BitCodeAbbrevOp(
BitCodeAbbrevOp::Fixed,
- 7)); // Packed Tag Decl Bits: getTagKind, isCompleteDefinition,
- // EmbeddedInDeclarator, IsFreeStanding, isCompleteDefinitionRequired
+ 9)); // Packed Tag Decl Bits: getTagKind, isCompleteDefinition,
+ // EmbeddedInDeclarator, IsFreeStanding,
+ // isCompleteDefinitionRequired, ExtInfoKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
- Abv->Add(BitCodeAbbrevOp(0)); // ExtInfoKind
// EnumDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddTypeRef
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IntegerType
@@ -2145,13 +2144,12 @@ void ASTWriter::WriteDeclAbbrevs() {
// Redeclarable
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 12)); // Packed DeclBits: HasStandaloneLexicalDC,
+ // isInvalidDecl, HasAttrs, isImplicit, isUsed,
+ // isReferenced, TopLevelDeclInObjCContainer,
+ // AccessSpecifier, ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(
- BitCodeAbbrevOp::Fixed,
- 11)); // Packed DeclBits: isInvalidDecl, HasAttrs, isImplicit, isUsed,
- // isReferenced, TopLevelDeclInObjCContainer, AccessSpecifier,
- // ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
@@ -2164,11 +2162,11 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
Abv->Add(BitCodeAbbrevOp(
BitCodeAbbrevOp::Fixed,
- 7)); // Packed Tag Decl Bits: getTagKind, isCompleteDefinition,
- // EmbeddedInDeclarator, IsFreeStanding, isCompleteDefinitionRequired
+ 9)); // Packed Tag Decl Bits: getTagKind, isCompleteDefinition,
+ // EmbeddedInDeclarator, IsFreeStanding,
+ // isCompleteDefinitionRequired, ExtInfoKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
- Abv->Add(BitCodeAbbrevOp(0)); // ExtInfoKind
// RecordDecl
Abv->Add(BitCodeAbbrevOp(
BitCodeAbbrevOp::Fixed,
@@ -2194,13 +2192,12 @@ void ASTWriter::WriteDeclAbbrevs() {
// Redeclarable
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 12)); // Packed DeclBits: HasStandaloneLexicalDC,
+ // isInvalidDecl, HasAttrs, isImplicit, isUsed,
+ // isReferenced, TopLevelDeclInObjCContainer,
+ // AccessSpecifier, ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(
- BitCodeAbbrevOp::Fixed,
- 11)); // Packed DeclBits: isInvalidDecl, HasAttrs, isImplicit, isUsed,
- // isReferenced, TopLevelDeclInObjCContainer, AccessSpecifier,
- // ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
@@ -2221,10 +2218,9 @@ void ASTWriter::WriteDeclAbbrevs() {
// ParmVarDecl
Abv->Add(BitCodeAbbrevOp(
BitCodeAbbrevOp::Fixed,
- 19)); // Packed Parm Var Decl bits: IsObjCMethodParameter, ScopeDepth,
- // ScopeIndex, KNRPromoted, HasInheritedDefaultArg
- Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier
- Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg
+ 27)); // Packed Parm Var Decl bits: IsObjCMethodParameter, ScopeDepth,
+ // ScopeIndex, ObjCDeclQualifier, KNRPromoted,
+ // HasInheritedDefaultArg, HasUninstantiatedDefaultArg
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
@@ -2236,13 +2232,12 @@ void ASTWriter::WriteDeclAbbrevs() {
// Redeclarable
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 12)); // Packed DeclBits: HasStandaloneLexicalDC,
+ // isInvalidDecl, HasAttrs, isImplicit, isUsed,
+ // isReferenced, TopLevelDeclInObjCContainer,
+ // AccessSpecifier, ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(
- BitCodeAbbrevOp::Fixed,
- 11)); // Packed DeclBits: isInvalidDecl, HasAttrs, isImplicit, isUsed,
- // isReferenced, TopLevelDeclInObjCContainer, AccessSpecifier,
- // ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
@@ -2262,13 +2257,12 @@ void ASTWriter::WriteDeclAbbrevs() {
// Redeclarable
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 12)); // Packed DeclBits: HasStandaloneLexicalDC,
+ // isInvalidDecl, HasAttrs, isImplicit, isUsed,
+ // isReferenced, TopLevelDeclInObjCContainer,
+ // AccessSpecifier, ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(
- BitCodeAbbrevOp::Fixed,
- 11)); // Packed DeclBits: isInvalidDecl, HasAttrs, isImplicit, isUsed,
- // isReferenced, TopLevelDeclInObjCContainer, AccessSpecifier,
- // ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
@@ -2303,13 +2297,12 @@ void ASTWriter::WriteDeclAbbrevs() {
// FIXME: Implement abbreviation for other template kinds.
Abv->Add(BitCodeAbbrevOp(FunctionDecl::TK_NonTemplate)); // TemplateKind
// Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 12)); // Packed DeclBits: HasStandaloneLexicalDC,
+ // isInvalidDecl, HasAttrs, isImplicit, isUsed,
+ // isReferenced, TopLevelDeclInObjCContainer,
+ // AccessSpecifier, ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(
- BitCodeAbbrevOp::Fixed,
- 11)); // Packed DeclBits: isInvalidDecl, HasAttrs, isImplicit, isUsed,
- // isReferenced, TopLevelDeclInObjCContainer, AccessSpecifier,
- // ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind
@@ -2346,16 +2339,14 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
DeclCXXMethodAbbrev = Stream.EmitAbbrev(std::move(Abv));
- unsigned ExprDependenceBits = llvm::BitWidth<ExprDependence>;
// Abbreviation for EXPR_DECL_REF
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_DECL_REF));
//Stmt
// Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, ExprDependenceBits));
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ // DependenceKind, ValueKind, ObjectKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
//DeclRefExpr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HasQualifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound
@@ -2374,9 +2365,8 @@ void ASTWriter::WriteDeclAbbrevs() {
//Stmt
// Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, ExprDependenceBits));
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ // DependenceKind, ValueKind, ObjectKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
//Integer Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
Abv->Add(BitCodeAbbrevOp(32)); // Bit Width
@@ -2389,9 +2379,8 @@ void ASTWriter::WriteDeclAbbrevs() {
//Stmt
// Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, ExprDependenceBits));
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ // DependenceKind, ValueKind, ObjectKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
//Character Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
@@ -2404,9 +2393,8 @@ void ASTWriter::WriteDeclAbbrevs() {
// Stmt
// Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, ExprDependenceBits));
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ // DependenceKind, ValueKind, ObjectKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
// CastExpr
Abv->Add(BitCodeAbbrevOp(0)); // PathSize
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasFPFeatures
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 59be6828fafa..8524484ea8a0 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -549,9 +549,14 @@ void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
void ASTStmtWriter::VisitExpr(Expr *E) {
VisitStmt(E);
Record.AddTypeRef(E->getType());
- Record.push_back(E->getDependence());
- Record.push_back(E->getValueKind());
- Record.push_back(E->getObjectKind());
+
+ BitsPacker ExprBits;
+
+ ExprBits.addBits(E->getDependence(), /*BitsWidth=*/5);
+ ExprBits.addBits(E->getValueKind(), /*BitsWidth=*/2);
+ ExprBits.addBits(E->getObjectKind(), /*BitsWidth=*/3);
+
+ Record.push_back(ExprBits);
}
void ASTStmtWriter::VisitConstantExpr(ConstantExpr *E) {
@@ -866,14 +871,20 @@ void ASTStmtWriter::VisitOMPIteratorExpr(OMPIteratorExpr *E) {
void ASTStmtWriter::VisitCallExpr(CallExpr *E) {
VisitExpr(E);
- Record.push_back(E->getNumArgs());
- Record.push_back(E->hasStoredFPFeatures());
+
+ BitsPacker CallExprBits;
+ // 16 bits should be sufficient to store the number args;
+ CallExprBits.addBits(E->getNumArgs(), /*BitsWidth=*/16);
+ CallExprBits.addBit(E->hasStoredFPFeatures());
+ CallExprBits.addBit(static_cast<bool>(E->getADLCallKind()));
+ Record.push_back(CallExprBits);
+
Record.AddSourceLocation(E->getRParenLoc());
Record.AddStmt(E->getCallee());
for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
Arg != ArgEnd; ++Arg)
Record.AddStmt(*Arg);
- Record.push_back(static_cast<unsigned>(E->getADLCallKind()));
+
if (E->hasStoredFPFeatures())
Record.push_back(E->getFPFeatures().getAsOpaqueInt());
Code = serialization::EXPR_CALL;
@@ -1938,14 +1949,19 @@ ASTStmtWriter::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) {
VisitExpr(E);
- Record.push_back(E->getNumDecls());
- Record.push_back(E->hasTemplateKWAndArgsInfo());
+ BitsPacker OverloadExprBits;
+ // 14 Bits should enough to store the number of decls.
+ OverloadExprBits.addBits(E->getNumDecls(), /*BitWidth=*/14);
+ OverloadExprBits.addBit(E->hasTemplateKWAndArgsInfo());
if (E->hasTemplateKWAndArgsInfo()) {
const ASTTemplateKWAndArgsInfo &ArgInfo =
*E->getTrailingASTTemplateKWAndArgsInfo();
- Record.push_back(ArgInfo.NumTemplateArgs);
+ // 14 Bits should enough to store the number of template args.
+ OverloadExprBits.addBits(ArgInfo.NumTemplateArgs, /*BitWidth=*/14);
+ Record.push_back(OverloadExprBits);
AddTemplateKWAndArgsInfo(ArgInfo, E->getTrailingTemplateArgumentLoc());
- }
+ } else
+ Record.push_back(OverloadExprBits);
for (OverloadExpr::decls_iterator OvI = E->decls_begin(),
OvE = E->decls_end();
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index bd6655cc1e3f..fedc6db3723a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -1045,8 +1045,8 @@ bool ObjCDeallocChecker::isReleasedByCIFilterDealloc(
StringRef IvarName = PropImpl->getPropertyIvarDecl()->getName();
const char *ReleasePrefix = "input";
- if (!(PropName.startswith(ReleasePrefix) ||
- IvarName.startswith(ReleasePrefix))) {
+ if (!(PropName.starts_with(ReleasePrefix) ||
+ IvarName.starts_with(ReleasePrefix))) {
return false;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index dbba12bb4355..afc5e6b48008 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -140,7 +140,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
if (!II) // if no identifier, not a simple C function
return;
StringRef Name = II->getName();
- if (Name.startswith("__builtin_"))
+ if (Name.starts_with("__builtin_"))
Name = Name.substr(10);
// Set the evaluation function by switching on the callee name.
@@ -763,7 +763,7 @@ void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
StringRef Name = FD->getIdentifier()->getName();
- if (Name.startswith("__builtin_"))
+ if (Name.starts_with("__builtin_"))
Name = Name.substr(10);
int ArgIndex =
diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 5f44c9476928..86f446fc411c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -183,7 +183,7 @@ public:
// Files autogenerated by DriverKit IIG contain some dead stores that
// we don't want to report.
- if (Data.startswith("/* iig"))
+ if (Data.starts_with("/* iig"))
return true;
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
index 14433d06c2d0..7c51673422a0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -159,6 +159,9 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
// Every initialization an enum with a fixed underlying type but without any
// enumerators would produce a warning if we were to continue at this point.
// The most notable example is std::byte in the C++17 standard library.
+ // TODO: Create heuristics to bail out when the enum type is intended to be
+ // used to store combinations of flag values (to mitigate the limitation
+ // described in the docs).
if (DeclValues.size() == 0)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp
index 8e02ef74c668..5637941a58f0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp
@@ -73,7 +73,7 @@ decltype(auto) bindAssignmentToDecl(const char *DeclName) {
static bool isTest(const Decl *D) {
if (const auto* ND = dyn_cast<NamedDecl>(D)) {
std::string DeclName = ND->getNameAsString();
- if (StringRef(DeclName).startswith("test"))
+ if (StringRef(DeclName).starts_with("test"))
return true;
}
if (const auto *OD = dyn_cast<ObjCMethodDecl>(D)) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index b77e9bf09a33..70f911fc66ab 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -817,9 +817,9 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// Handle the case where the receiver is an NSString
// These special NSString methods draw to the screen
- if (!(SelectorName.startswith("drawAtPoint") ||
- SelectorName.startswith("drawInRect") ||
- SelectorName.startswith("drawWithRect")))
+ if (!(SelectorName.starts_with("drawAtPoint") ||
+ SelectorName.starts_with("drawInRect") ||
+ SelectorName.starts_with("drawWithRect")))
return;
SVal svTitle = msg.getReceiverSVal();
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index c5e4add50188..79ab05f2c786 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -3150,16 +3150,16 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
// transferred. Again, though, we can't be sure that the object will use
// free() to deallocate the memory, so we can't model it explicitly.
StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
- if (FirstSlot.endswith("NoCopy"))
+ if (FirstSlot.ends_with("NoCopy"))
return true;
// If the first selector starts with addPointer, insertPointer,
// or replacePointer, assume we are dealing with NSPointerArray or similar.
// This is similar to C++ containers (vector); we still might want to check
// that the pointers get freed by following the container itself.
- if (FirstSlot.startswith("addPointer") ||
- FirstSlot.startswith("insertPointer") ||
- FirstSlot.startswith("replacePointer") ||
+ if (FirstSlot.starts_with("addPointer") ||
+ FirstSlot.starts_with("insertPointer") ||
+ FirstSlot.starts_with("replacePointer") ||
FirstSlot.equals("valueWithPointer")) {
return true;
}
@@ -3199,7 +3199,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
// White list the 'XXXNoCopy' CoreFoundation functions.
// We specifically check these before
- if (FName.endswith("NoCopy")) {
+ if (FName.ends_with("NoCopy")) {
// Look for the deallocator argument. We know that the memory ownership
// is not transferred only if the deallocator argument is
// 'kCFAllocatorNull'.
diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 627b51af6bd4..06f1ad00eaf2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -890,7 +890,7 @@ void NullabilityChecker::checkPostCall(const CallEvent &Call,
// of CG calls.
const SourceManager &SM = C.getSourceManager();
StringRef FilePath = SM.getFilename(SM.getSpellingLoc(Decl->getBeginLoc()));
- if (llvm::sys::path::filename(FilePath).startswith("CG")) {
+ if (llvm::sys::path::filename(FilePath).starts_with("CG")) {
State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
C.addTransition(State);
return;
@@ -992,7 +992,7 @@ void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
// In order to reduce the noise in the diagnostics generated by this checker,
// some framework and programming style based heuristics are used. These
// heuristics are for Cocoa APIs which have NS prefix.
- if (Name.startswith("NS")) {
+ if (Name.starts_with("NS")) {
// Developers rely on dynamic invariants such as an item should be available
// in a collection, or a collection is not empty often. Those invariants can
// not be inferred by any static analysis tool. To not to bother the users
diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
index 4636fd160511..08ad6877cbe6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
@@ -50,7 +50,7 @@ void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D,
const std::string &PropTypeName(T->getPointeeType().getCanonicalType()
.getUnqualifiedType()
.getAsString());
- if (!StringRef(PropTypeName).startswith("NSMutable"))
+ if (!StringRef(PropTypeName).starts_with("NSMutable"))
return;
const ObjCImplDecl *ImplD = nullptr;
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index 9532254e3c45..f3e0a5f9f314 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -12,12 +12,15 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/ParentMapContext.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -2139,15 +2142,14 @@ PathSensitiveBugReport::PathSensitiveBugReport(
"checkers to emit warnings, because checkers should depend on "
"*modeling*, not *diagnostics*.");
- assert(
- (bt.getCheckerName().startswith("debug") ||
- !isHidden(ErrorNode->getState()
- ->getAnalysisManager()
- .getCheckerManager()
- ->getCheckerRegistryData(),
- bt.getCheckerName())) &&
- "Hidden checkers musn't emit diagnostics as they are by definition "
- "non-user facing!");
+ assert((bt.getCheckerName().starts_with("debug") ||
+ !isHidden(ErrorNode->getState()
+ ->getAnalysisManager()
+ .getCheckerManager()
+ ->getCheckerRegistryData(),
+ bt.getCheckerName())) &&
+ "Hidden checkers musn't emit diagnostics as they are by definition "
+ "non-user facing!");
}
void PathSensitiveBugReport::addVisitor(
@@ -2425,6 +2427,12 @@ PathSensitiveBugReport::getLocation() const {
}
if (S) {
+ // Attributed statements usually have corrupted begin locations,
+ // it's OK to ignore attributes for our purposes and deal with
+ // the actual annotated statement.
+ if (const auto *AS = dyn_cast<AttributedStmt>(S))
+ S = AS->getSubStmt();
+
// For member expressions, return the location of the '.' or '->'.
if (const auto *ME = dyn_cast<MemberExpr>(S))
return PathDiagnosticLocation::createMemberLoc(ME, SM);
@@ -2897,6 +2905,10 @@ void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
if (!ValidSourceLoc)
return;
+ // If the user asked to suppress this report, we should skip it.
+ if (UserSuppressions.isSuppressed(*R))
+ return;
+
// Compute the bug report's hash to determine its equivalence class.
llvm::FoldingSetNodeID ID;
R->Profile(ID);
@@ -3064,8 +3076,7 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
// See whether we need to silence the checker/package.
for (const std::string &CheckerOrPackage :
getAnalyzerOptions().SilencedCheckersAndPackages) {
- if (report->getBugType().getCheckerName().startswith(
- CheckerOrPackage))
+ if (report->getBugType().getCheckerName().starts_with(CheckerOrPackage))
return;
}
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 4a9d130c240a..2f9965036b9e 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -3372,7 +3372,7 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
FullSourceLoc Loc = BR.getLocation().asLocation();
while (Loc.isMacroID()) {
Loc = Loc.getSpellingLoc();
- if (SM.getFilename(Loc).endswith("sys/queue.h")) {
+ if (SM.getFilename(Loc).ends_with("sys/queue.h")) {
BR.markInvalid(getTag(), nullptr);
return;
}
diff --git a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
new file mode 100644
index 000000000000..b5991e47a538
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
@@ -0,0 +1,169 @@
+//===- BugSuppression.cpp - Suppression interface -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+using Ranges = llvm::SmallVectorImpl<SourceRange>;
+
+inline bool hasSuppression(const Decl *D) {
+ // FIXME: Implement diagnostic identifier arguments
+ // (checker names, "hashtags").
+ if (const auto *Suppression = D->getAttr<SuppressAttr>())
+ return !Suppression->isGSL() &&
+ (Suppression->diagnosticIdentifiers().empty());
+ return false;
+}
+inline bool hasSuppression(const AttributedStmt *S) {
+ // FIXME: Implement diagnostic identifier arguments
+ // (checker names, "hashtags").
+ return llvm::any_of(S->getAttrs(), [](const Attr *A) {
+ const auto *Suppression = dyn_cast<SuppressAttr>(A);
+ return Suppression && !Suppression->isGSL() &&
+ (Suppression->diagnosticIdentifiers().empty());
+ });
+}
+
+template <class NodeType> inline SourceRange getRange(const NodeType *Node) {
+ return Node->getSourceRange();
+}
+template <> inline SourceRange getRange(const AttributedStmt *S) {
+ // Begin location for attributed statement node seems to be ALWAYS invalid.
+ //
+ // It is unlikely that we ever report any warnings on suppression
+ // attribute itself, but even if we do, we wouldn't want that warning
+ // to be suppressed by that same attribute.
+ //
+ // Long story short, we can use inner statement and it's not going to break
+ // anything.
+ return getRange(S->getSubStmt());
+}
+
+inline bool isLessOrEqual(SourceLocation LHS, SourceLocation RHS,
+ const SourceManager &SM) {
+ // SourceManager::isBeforeInTranslationUnit tests for strict
+ // inequality, when we need a non-strict comparison (bug
+ // can be reported directly on the annotated note).
+ // For this reason, we use the following equivalence:
+ //
+ // A <= B <==> !(B < A)
+ //
+ return !SM.isBeforeInTranslationUnit(RHS, LHS);
+}
+
+inline bool fullyContains(SourceRange Larger, SourceRange Smaller,
+ const SourceManager &SM) {
+ // Essentially this means:
+ //
+ // Larger.fullyContains(Smaller)
+ //
+ // However, that method has a very trivial implementation and couldn't
+ // compare regular locations and locations from macro expansions.
+ // We could've converted everything into regular locations as a solution,
+ // but the following solution seems to be the most bulletproof.
+ return isLessOrEqual(Larger.getBegin(), Smaller.getBegin(), SM) &&
+ isLessOrEqual(Smaller.getEnd(), Larger.getEnd(), SM);
+}
+
+class CacheInitializer : public RecursiveASTVisitor<CacheInitializer> {
+public:
+ static void initialize(const Decl *D, Ranges &ToInit) {
+ CacheInitializer(ToInit).TraverseDecl(const_cast<Decl *>(D));
+ }
+
+ bool VisitVarDecl(VarDecl *VD) {
+ // Bug location could be somewhere in the init value of
+ // a freshly declared variable. Even though it looks like the
+ // user applied attribute to a statement, it will apply to a
+ // variable declaration, and this is where we check for it.
+ return VisitAttributedNode(VD);
+ }
+
+ bool VisitAttributedStmt(AttributedStmt *AS) {
+ // When we apply attributes to statements, it actually creates
+ // a wrapper statement that only contains attributes and the wrapped
+ // statement.
+ return VisitAttributedNode(AS);
+ }
+
+private:
+ template <class NodeType> bool VisitAttributedNode(NodeType *Node) {
+ if (hasSuppression(Node)) {
+ // TODO: In the future, when we come up with good stable IDs for checkers
+ // we can return a list of kinds to ignore, or all if no arguments
+ // were provided.
+ addRange(getRange(Node));
+ }
+ // We should keep traversing AST.
+ return true;
+ }
+
+ void addRange(SourceRange R) {
+ if (R.isValid()) {
+ Result.push_back(R);
+ }
+ }
+
+ CacheInitializer(Ranges &R) : Result(R) {}
+ Ranges &Result;
+};
+
+} // end anonymous namespace
+
+// TODO: Introduce stable IDs for checkers and check for those here
+// to be more specific. Attribute without arguments should still
+// be considered as "suppress all".
+// It is already much finer granularity than what we have now
+// (i.e. removing the whole function from the analysis).
+bool BugSuppression::isSuppressed(const BugReport &R) {
+ PathDiagnosticLocation Location = R.getLocation();
+ PathDiagnosticLocation UniqueingLocation = R.getUniqueingLocation();
+ const Decl *DeclWithIssue = R.getDeclWithIssue();
+
+ return isSuppressed(Location, DeclWithIssue, {}) ||
+ isSuppressed(UniqueingLocation, DeclWithIssue, {});
+}
+
+bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location,
+ const Decl *DeclWithIssue,
+ DiagnosticIdentifierList Hashtags) {
+ if (!Location.isValid() || DeclWithIssue == nullptr)
+ return false;
+
+ // While some warnings are attached to AST nodes (mostly path-sensitive
+ // checks), others are simply associated with a plain source location
+ // or range. Figuring out the node based on locations can be tricky,
+ // so instead, we traverse the whole body of the declaration and gather
+ // information on ALL suppressions. After that we can simply check if
+ // any of those suppressions affect the warning in question.
+ //
+ // Traversing AST of a function is not a heavy operation, but for
+ // large functions with a lot of bugs it can make a dent in performance.
+ // In order to avoid this scenario, we cache traversal results.
+ auto InsertionResult = CachedSuppressionLocations.insert(
+ std::make_pair(DeclWithIssue, CachedRanges{}));
+ Ranges &SuppressionRanges = InsertionResult.first->second;
+ if (InsertionResult.second) {
+ // We haven't checked this declaration for suppressions yet!
+ CacheInitializer::initialize(DeclWithIssue, SuppressionRanges);
+ }
+
+ SourceRange BugRange = Location.asRange();
+ const SourceManager &SM = Location.getManager();
+
+ return llvm::any_of(SuppressionRanges,
+ [BugRange, &SM](SourceRange Suppression) {
+ return fullyContains(Suppression, BugRange, SM);
+ });
+}
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index d004c12bf2c1..0ac1d91b79be 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -659,17 +659,17 @@ bool AnyFunctionCall::argumentsMayEscape() const {
// - CoreFoundation functions that end with "NoCopy" can free a passed-in
// buffer even if it is const.
- if (FName.endswith("NoCopy"))
+ if (FName.ends_with("NoCopy"))
return true;
// - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
// be deallocated by NSMapRemove.
- if (FName.startswith("NS") && FName.contains("Insert"))
+ if (FName.starts_with("NS") && FName.contains("Insert"))
return true;
// - Many CF containers allow objects to escape through custom
// allocators/deallocators upon container construction. (PR12101)
- if (FName.startswith("CF") || FName.startswith("CG")) {
+ if (FName.starts_with("CF") || FName.starts_with("CG")) {
return StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
diff --git a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
index c25165cce128..d6d4cec9dd3d 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -105,10 +105,11 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
if (FName.equals(Name))
return true;
- if (FName.startswith("__inline") && FName.contains(Name))
+ if (FName.starts_with("__inline") && FName.contains(Name))
return true;
- if (FName.startswith("__") && FName.endswith("_chk") && FName.contains(Name))
+ if (FName.starts_with("__") && FName.ends_with("_chk") &&
+ FName.contains(Name))
return true;
return false;
diff --git a/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
index 1b3e8b11549d..b9c6278991f4 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
@@ -82,7 +82,7 @@ static constexpr char PackageSeparator = '.';
static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) {
// Does the checker's full name have the package as a prefix?
- if (!Checker.FullName.startswith(PackageName))
+ if (!Checker.FullName.starts_with(PackageName))
return false;
// Is the package actually just the name of a specific checker?
@@ -158,7 +158,7 @@ void CheckerRegistryData::printCheckerWithDescList(
continue;
}
- if (Checker.FullName.startswith("alpha")) {
+ if (Checker.FullName.starts_with("alpha")) {
if (AnOpts.ShowCheckerHelpAlpha)
Print(Out, Checker,
("(Enable only for development!) " + Checker.Desc).str());
@@ -228,7 +228,7 @@ void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts,
}
if (Option.DevelopmentStatus == "alpha" ||
- Entry.first.startswith("alpha")) {
+ Entry.first.starts_with("alpha")) {
if (AnOpts.ShowCheckerOptionAlphaList)
Print(Out, FullOption,
llvm::Twine("(Enable only for development!) " + Desc).str());
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 142acab7cd08..b6ef40595e3c 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -308,7 +308,7 @@ public:
bool VisitFunctionDecl(FunctionDecl *FD) {
IdentifierInfo *II = FD->getIdentifier();
- if (II && II->getName().startswith("__inline"))
+ if (II && II->getName().starts_with("__inline"))
return true;
// We skip function template definitions, as their semantics is
diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
index f0d3f43c414c..317df90a7781 100644
--- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -310,8 +310,8 @@ template <bool IsWeak> void CheckerRegistry::resolveDependencies() {
"Failed to find the dependency of a checker!");
// We do allow diagnostics from unit test/example dependency checkers.
- assert((DependencyIt->FullName.startswith("test") ||
- DependencyIt->FullName.startswith("example") || IsWeak ||
+ assert((DependencyIt->FullName.starts_with("test") ||
+ DependencyIt->FullName.starts_with("example") || IsWeak ||
DependencyIt->IsHidden) &&
"Strong dependencies are modeling checkers, and as such "
"non-user facing! Mark them hidden in Checkers.td!");
diff --git a/clang/lib/Support/RISCVVIntrinsicUtils.cpp b/clang/lib/Support/RISCVVIntrinsicUtils.cpp
index a04694e628de..bb9f7dc7e7e3 100644
--- a/clang/lib/Support/RISCVVIntrinsicUtils.cpp
+++ b/clang/lib/Support/RISCVVIntrinsicUtils.cpp
@@ -464,7 +464,7 @@ PrototypeDescriptor::parsePrototypeDescriptor(
PrototypeDescriptorStr = PrototypeDescriptorStr.drop_back();
// Compute the vector type transformers, it can only appear one time.
- if (PrototypeDescriptorStr.startswith("(")) {
+ if (PrototypeDescriptorStr.starts_with("(")) {
assert(VTM == VectorTypeModifier::NoModifier &&
"VectorTypeModifier should only have one modifier");
size_t Idx = PrototypeDescriptorStr.find(')');
diff --git a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
index 52e57976ac09..356b4bd5a1b8 100644
--- a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
+++ b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -371,7 +371,7 @@ SyntaxTree::Impl::getRelativeName(const NamedDecl *ND,
// Strip the qualifier, if Val refers to something in the current scope.
// But leave one leading ':' in place, so that we know that this is a
// relative path.
- if (!ContextPrefix.empty() && StringRef(Val).startswith(ContextPrefix))
+ if (!ContextPrefix.empty() && StringRef(Val).starts_with(ContextPrefix))
Val = Val.substr(ContextPrefix.size() + 1);
return Val;
}
diff --git a/clang/lib/Tooling/ArgumentsAdjusters.cpp b/clang/lib/Tooling/ArgumentsAdjusters.cpp
index e40df6257378..df4c74205b08 100644
--- a/clang/lib/Tooling/ArgumentsAdjusters.cpp
+++ b/clang/lib/Tooling/ArgumentsAdjusters.cpp
@@ -45,12 +45,12 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster() {
StringRef Arg = Args[i];
// Skip output commands.
if (llvm::any_of(OutputCommands, [&Arg](llvm::StringRef OutputCommand) {
- return Arg.startswith(OutputCommand);
+ return Arg.starts_with(OutputCommand);
}))
continue;
- if (!Arg.startswith("-fcolor-diagnostics") &&
- !Arg.startswith("-fdiagnostics-color"))
+ if (!Arg.starts_with("-fcolor-diagnostics") &&
+ !Arg.starts_with("-fdiagnostics-color"))
AdjustedArgs.push_back(Args[i]);
// If we strip a color option, make sure we strip any preceeding `-Xclang`
// option as well.
@@ -73,7 +73,7 @@ ArgumentsAdjuster getClangStripOutputAdjuster() {
CommandLineArguments AdjustedArgs;
for (size_t i = 0, e = Args.size(); i < e; ++i) {
StringRef Arg = Args[i];
- if (!Arg.startswith("-o"))
+ if (!Arg.starts_with("-o"))
AdjustedArgs.push_back(Args[i]);
if (Arg == "-o") {
@@ -102,11 +102,11 @@ ArgumentsAdjuster getClangStripDependencyFileAdjuster() {
// When not using the cl driver mode, dependency file generation options
// begin with -M. These include -MM, -MF, -MG, -MP, -MT, -MQ, -MD, and
// -MMD.
- if (!UsingClDriver && Arg.startswith("-M"))
+ if (!UsingClDriver && Arg.starts_with("-M"))
continue;
// Under MSVC's cl driver mode, dependency file generation is controlled
// using /showIncludes
- if (Arg.startswith("/showIncludes") || Arg.startswith("-showIncludes"))
+ if (Arg.starts_with("/showIncludes") || Arg.starts_with("-showIncludes"))
continue;
AdjustedArgs.push_back(Args[i]);
@@ -159,7 +159,7 @@ ArgumentsAdjuster getStripPluginsAdjuster() {
// -Xclang <arbitrary-argument>
if (I + 4 < E && Args[I] == "-Xclang" &&
(Args[I + 1] == "-load" || Args[I + 1] == "-plugin" ||
- llvm::StringRef(Args[I + 1]).startswith("-plugin-arg-") ||
+ llvm::StringRef(Args[I + 1]).starts_with("-plugin-arg-") ||
Args[I + 1] == "-add-plugin") &&
Args[I + 2] == "-Xclang") {
I += 3;
diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp
index fdf6015508d9..87ad8f25a1ab 100644
--- a/clang/lib/Tooling/CompilationDatabase.cpp
+++ b/clang/lib/Tooling/CompilationDatabase.cpp
@@ -204,7 +204,7 @@ public:
// which don't support these options.
struct FilterUnusedFlags {
bool operator() (StringRef S) {
- return (S == "-no-integrated-as") || S.startswith("-Wa,");
+ return (S == "-no-integrated-as") || S.starts_with("-Wa,");
}
};
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
index 3e53c8fc5740..6f71650a3982 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
@@ -290,7 +290,7 @@ DependencyScanningWorkerFilesystem::status(const Twine &Path) {
SmallString<256> OwnedFilename;
StringRef Filename = Path.toStringRef(OwnedFilename);
- if (Filename.endswith(".pcm"))
+ if (Filename.ends_with(".pcm"))
return getUnderlyingFS().status(Path);
llvm::ErrorOr<EntryRef> Result = getOrCreateFileSystemEntry(Filename);
@@ -350,7 +350,7 @@ DependencyScanningWorkerFilesystem::openFileForRead(const Twine &Path) {
SmallString<256> OwnedFilename;
StringRef Filename = Path.toStringRef(OwnedFilename);
- if (Filename.endswith(".pcm"))
+ if (Filename.ends_with(".pcm"))
return getUnderlyingFS().openFileForRead(Path);
llvm::ErrorOr<EntryRef> Result = getOrCreateFileSystemEntry(Filename);
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index f65da413bb87..bfaa89785104 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -119,6 +119,8 @@ makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
// units.
CI.getFrontendOpts().Inputs.clear();
CI.getFrontendOpts().OutputFile.clear();
+ // LLVM options are not going to affect the AST
+ CI.getFrontendOpts().LLVMArgs.clear();
// TODO: Figure out better way to set options to their default value.
CI.getCodeGenOpts().MainFileName.clear();
@@ -530,7 +532,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
// this file in the proper directory and relies on the rest of Clang to
// handle it like normal. With explicitly built modules we don't need
// to play VFS tricks, so replace it with the correct module map.
- if (StringRef(IFI.Filename).endswith("__inferred_module.map")) {
+ if (StringRef(IFI.Filename).ends_with("__inferred_module.map")) {
MDC.addFileDep(MD, ModuleMap->getName());
return;
}
@@ -548,7 +550,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
if (!(IFI.TopLevel && IFI.ModuleMap))
return;
if (StringRef(IFI.FilenameAsRequested)
- .endswith("__inferred_module.map"))
+ .ends_with("__inferred_module.map"))
return;
MD.ModuleMapFileDeps.emplace_back(IFI.FilenameAsRequested);
});
diff --git a/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp b/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
index 0b3c4de08ab8..52b634e2e1af 100644
--- a/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
+++ b/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
@@ -21,7 +21,7 @@ bool isIf(llvm::StringRef Line) {
if (!Line.consume_front("#"))
return false;
Line = Line.ltrim();
- return Line.startswith("if");
+ return Line.starts_with("if");
}
// Is Line an #error directive mentioning includes?
@@ -30,7 +30,7 @@ bool isErrorAboutInclude(llvm::StringRef Line) {
if (!Line.consume_front("#"))
return false;
Line = Line.ltrim();
- if (!Line.startswith("error"))
+ if (!Line.starts_with("error"))
return false;
return Line.contains_insensitive(
"includ"); // Matches "include" or "including".
@@ -54,7 +54,7 @@ bool isImportLine(llvm::StringRef Line) {
if (!Line.consume_front("#"))
return false;
Line = Line.ltrim();
- return Line.startswith("import");
+ return Line.starts_with("import");
}
llvm::StringRef getFileContents(FileEntryRef FE, const SourceManager &SM) {
diff --git a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
index 15a2024c4788..d275222ac6b5 100644
--- a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
+++ b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
@@ -196,10 +196,10 @@ IncludeCategoryManager::IncludeCategoryManager(const IncludeStyle &Style,
? llvm::Regex::NoFlags
: llvm::Regex::IgnoreCase);
}
- IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
- FileName.endswith(".cpp") || FileName.endswith(".c++") ||
- FileName.endswith(".cxx") || FileName.endswith(".m") ||
- FileName.endswith(".mm");
+ IsMainFile = FileName.ends_with(".c") || FileName.ends_with(".cc") ||
+ FileName.ends_with(".cpp") || FileName.ends_with(".c++") ||
+ FileName.ends_with(".cxx") || FileName.ends_with(".m") ||
+ FileName.ends_with(".mm");
if (!Style.IncludeIsMainSourceRegex.empty()) {
llvm::Regex MainFileRegex(Style.IncludeIsMainSourceRegex);
IsMainFile |= MainFileRegex.match(FileName);
@@ -234,7 +234,7 @@ int IncludeCategoryManager::getSortIncludePriority(StringRef IncludeName,
return Ret;
}
bool IncludeCategoryManager::isMainHeader(StringRef IncludeName) const {
- if (!IncludeName.startswith("\""))
+ if (!IncludeName.starts_with("\""))
return false;
IncludeName =
@@ -357,8 +357,8 @@ HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled,
if (It != ExistingIncludes.end()) {
for (const auto &Inc : It->second)
if (Inc.Directive == Directive &&
- ((IsAngled && StringRef(Inc.Name).startswith("<")) ||
- (!IsAngled && StringRef(Inc.Name).startswith("\""))))
+ ((IsAngled && StringRef(Inc.Name).starts_with("<")) ||
+ (!IsAngled && StringRef(Inc.Name).starts_with("\""))))
return std::nullopt;
}
std::string Quoted =
@@ -400,8 +400,8 @@ tooling::Replacements HeaderIncludes::remove(llvm::StringRef IncludeName,
if (Iter == ExistingIncludes.end())
return Result;
for (const auto &Inc : Iter->second) {
- if ((IsAngled && StringRef(Inc.Name).startswith("\"")) ||
- (!IsAngled && StringRef(Inc.Name).startswith("<")))
+ if ((IsAngled && StringRef(Inc.Name).starts_with("\"")) ||
+ (!IsAngled && StringRef(Inc.Name).starts_with("<")))
continue;
llvm::Error Err = Result.add(tooling::Replacement(
FileName, Inc.R.getOffset(), Inc.R.getLength(), ""));
diff --git a/clang/lib/Tooling/Refactoring/AtomicChange.cpp b/clang/lib/Tooling/Refactoring/AtomicChange.cpp
index 7237393f00e5..3d5ae2fed014 100644
--- a/clang/lib/Tooling/Refactoring/AtomicChange.cpp
+++ b/clang/lib/Tooling/Refactoring/AtomicChange.cpp
@@ -150,7 +150,7 @@ createReplacementsForHeaders(llvm::StringRef FilePath, llvm::StringRef Code,
for (const auto &Change : Changes) {
for (llvm::StringRef Header : Change.getInsertedHeaders()) {
std::string EscapedHeader =
- Header.startswith("<") || Header.startswith("\"")
+ Header.starts_with("<") || Header.starts_with("\"")
? Header.str()
: ("\"" + Header + "\"").str();
std::string ReplacementText = "#include " + EscapedHeader;
diff --git a/clang/lib/Tooling/Refactoring/Lookup.cpp b/clang/lib/Tooling/Refactoring/Lookup.cpp
index 9468d4d032a7..52799f16fab2 100644
--- a/clang/lib/Tooling/Refactoring/Lookup.cpp
+++ b/clang/lib/Tooling/Refactoring/Lookup.cpp
@@ -98,7 +98,7 @@ static StringRef getBestNamespaceSubstr(const DeclContext *DeclA,
// from NewName if it has an identical prefix.
std::string NS =
"::" + cast<NamespaceDecl>(DeclA)->getQualifiedNameAsString() + "::";
- if (NewName.startswith(NS))
+ if (NewName.starts_with(NS))
return NewName.substr(NS.size());
// No match yet. Strip of a namespace from the end of the chain and try
@@ -128,9 +128,9 @@ static std::string disambiguateSpellingInScope(StringRef Spelling,
StringRef QName,
const DeclContext &UseContext,
SourceLocation UseLoc) {
- assert(QName.startswith("::"));
- assert(QName.endswith(Spelling));
- if (Spelling.startswith("::"))
+ assert(QName.starts_with("::"));
+ assert(QName.ends_with(Spelling));
+ if (Spelling.starts_with("::"))
return std::string(Spelling);
auto UnspelledSpecifier = QName.drop_back(Spelling.size());
@@ -146,7 +146,7 @@ static std::string disambiguateSpellingInScope(StringRef Spelling,
UseLoc = SM.getSpellingLoc(UseLoc);
auto IsAmbiguousSpelling = [&](const llvm::StringRef CurSpelling) {
- if (CurSpelling.startswith("::"))
+ if (CurSpelling.starts_with("::"))
return false;
// Lookup the first component of Spelling in all enclosing namespaces
// and check if there is any existing symbols with the same name but in
@@ -160,7 +160,7 @@ static std::string disambiguateSpellingInScope(StringRef Spelling,
// ambiguous. For example, a reference in a header file should not be
// affected by a potentially ambiguous name in some file that includes
// the header.
- if (!TrimmedQName.startswith(Res->getQualifiedNameAsString()) &&
+ if (!TrimmedQName.starts_with(Res->getQualifiedNameAsString()) &&
SM.isBeforeInTranslationUnit(
SM.getSpellingLoc(Res->getLocation()), UseLoc))
return true;
@@ -187,7 +187,7 @@ std::string tooling::replaceNestedName(const NestedNameSpecifier *Use,
const DeclContext *UseContext,
const NamedDecl *FromDecl,
StringRef ReplacementString) {
- assert(ReplacementString.startswith("::") &&
+ assert(ReplacementString.starts_with("::") &&
"Expected fully-qualified name!");
// We can do a raw name replacement when we are not inside the namespace for
diff --git a/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
index 9cdeeec0574b..c18f9290471f 100644
--- a/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
+++ b/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
@@ -562,8 +562,8 @@ createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
ReplacedName = tooling::replaceNestedName(
RenameInfo.Specifier, RenameInfo.Begin,
RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl,
- NewName.startswith("::") ? NewName.str()
- : ("::" + NewName).str());
+ NewName.starts_with("::") ? NewName.str()
+ : ("::" + NewName).str());
} else {
// This fixes the case where type `T` is a parameter inside a function
// type (e.g. `std::function<void(T)>`) and the DeclContext of `T`
@@ -578,13 +578,13 @@ createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
SM, TranslationUnitDecl->getASTContext().getLangOpts());
// Add the leading "::" back if the name written in the code contains
// it.
- if (ActualName.startswith("::") && !NewName.startswith("::")) {
+ if (ActualName.starts_with("::") && !NewName.starts_with("::")) {
ReplacedName = "::" + NewName.str();
}
}
}
// If the NewName contains leading "::", add it back.
- if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
+ if (NewName.starts_with("::") && NewName.substr(2) == ReplacedName)
ReplacedName = NewName.str();
}
Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index e292fa724d2b..33bfa8d3d81f 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -255,7 +255,7 @@ llvm::Expected<std::string> getAbsolutePath(llvm::vfs::FileSystem &FS,
StringRef File) {
StringRef RelativePath(File);
// FIXME: Should '.\\' be accepted on Win32?
- if (RelativePath.startswith("./")) {
+ if (RelativePath.starts_with("./")) {
RelativePath = RelativePath.substr(strlen("./"));
}
@@ -294,9 +294,9 @@ void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
for (auto Token = ++CommandLine.begin(); Token != CommandLine.end();
++Token) {
StringRef TokenRef(*Token);
- ShouldAddTarget = ShouldAddTarget && !TokenRef.startswith(TargetOPT) &&
+ ShouldAddTarget = ShouldAddTarget && !TokenRef.starts_with(TargetOPT) &&
!TokenRef.equals(TargetOPTLegacy);
- ShouldAddMode = ShouldAddMode && !TokenRef.startswith(DriverModeOPT);
+ ShouldAddMode = ShouldAddMode && !TokenRef.starts_with(DriverModeOPT);
}
if (ShouldAddMode) {
CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode);
@@ -507,7 +507,7 @@ static void injectResourceDir(CommandLineArguments &Args, const char *Argv0,
void *MainAddr) {
// Allow users to override the resource dir.
for (StringRef Arg : Args)
- if (Arg.startswith("-resource-dir"))
+ if (Arg.starts_with("-resource-dir"))
return;
// If there's no override in place add our resource dir.
diff --git a/clang/lib/Tooling/Transformer/SourceCode.cpp b/clang/lib/Tooling/Transformer/SourceCode.cpp
index 30009537b592..6aae834b0db5 100644
--- a/clang/lib/Tooling/Transformer/SourceCode.cpp
+++ b/clang/lib/Tooling/Transformer/SourceCode.cpp
@@ -425,7 +425,7 @@ CharSourceRange tooling::getAssociatedRange(const Decl &Decl,
for (llvm::StringRef Prefix : {"[[", "__attribute__(("}) {
// Handle whitespace between attribute prefix and attribute value.
- if (BeforeAttrStripped.endswith(Prefix)) {
+ if (BeforeAttrStripped.ends_with(Prefix)) {
// Move start to start position of prefix, which is
// length(BeforeAttr) - length(BeforeAttrStripped) + length(Prefix)
// positions to the left.
diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp
index 5663c2c5a6c9..b9b287127015 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -234,7 +234,7 @@ int main(int argc, const char **argv) {
while (std::optional<std::string> Line = LE.readLine()) {
llvm::StringRef L = *Line;
L = L.trim();
- if (L.endswith("\\")) {
+ if (L.ends_with("\\")) {
// FIXME: Support #ifdef X \ ...
Input += L.drop_back(1);
LE.setPrompt("clang-repl... ");
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 531b5b4a61c1..4adc7f7ad0da 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -122,7 +122,7 @@ static void ApplyOneQAOverride(raw_ostream &OS,
GetStableCStr(SavedStrings, Edit.substr(1));
OS << "### Adding argument " << Str << " at end\n";
Args.push_back(Str);
- } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
+ } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.ends_with("/") &&
Edit.slice(2, Edit.size() - 1).contains('/')) {
StringRef MatchPattern = Edit.substr(2).split('/').first;
StringRef ReplPattern = Edit.substr(2).split('/').second;
@@ -403,7 +403,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
}
// Handle -cc1 integrated tools.
- if (Args.size() >= 2 && StringRef(Args[1]).startswith("-cc1"))
+ if (Args.size() >= 2 && StringRef(Args[1]).starts_with("-cc1"))
return ExecuteCC1Tool(Args, ToolContext);
// Handle options that need handling before the real command line parsing in
diff --git a/clang/utils/TableGen/ASTTableGen.cpp b/clang/utils/TableGen/ASTTableGen.cpp
index 60f563d9a1ff..54288ff6a03b 100644
--- a/clang/utils/TableGen/ASTTableGen.cpp
+++ b/clang/utils/TableGen/ASTTableGen.cpp
@@ -33,7 +33,7 @@ llvm::StringRef clang::tblgen::HasProperties::getName() const {
static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
StringRef nodeName = node->getName();
- if (!nodeName.endswith(suffix)) {
+ if (!nodeName.ends_with(suffix)) {
PrintFatalError(node->getLoc(),
Twine("name of node doesn't end in ") + suffix);
}
diff --git a/clang/utils/TableGen/MveEmitter.cpp b/clang/utils/TableGen/MveEmitter.cpp
index fae889d68346..f0bd0865c1c8 100644
--- a/clang/utils/TableGen/MveEmitter.cpp
+++ b/clang/utils/TableGen/MveEmitter.cpp
@@ -882,7 +882,7 @@ public:
} else if (V->varnameUsed()) {
std::string Type = V->typeName();
OS << V->typeName();
- if (!StringRef(Type).endswith("*"))
+ if (!StringRef(Type).ends_with("*"))
OS << " ";
OS << V->varname() << " = ";
}
@@ -1680,7 +1680,7 @@ void EmitterBase::EmitBuiltinCG(raw_ostream &OS) {
for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) {
StringRef Type = MG.ParamTypes[i];
OS << " " << Type;
- if (!Type.endswith("*"))
+ if (!Type.ends_with("*"))
OS << " ";
OS << " Param" << utostr(i) << ";\n";
}
@@ -1833,7 +1833,7 @@ void MveEmitter::EmitHeader(raw_ostream &OS) {
// prototype.
std::string RetTypeName = Int.returnType()->cName();
- if (!StringRef(RetTypeName).endswith("*"))
+ if (!StringRef(RetTypeName).ends_with("*"))
RetTypeName += " ";
std::vector<std::string> ArgTypeNames;
@@ -2078,7 +2078,7 @@ void CdeEmitter::EmitHeader(raw_ostream &OS) {
// Make strings for the types involved in the function's
// prototype.
std::string RetTypeName = Int.returnType()->cName();
- if (!StringRef(RetTypeName).endswith("*"))
+ if (!StringRef(RetTypeName).ends_with("*"))
RetTypeName += " ";
std::vector<std::string> ArgTypeNames;
diff --git a/clang/utils/TableGen/NeonEmitter.cpp b/clang/utils/TableGen/NeonEmitter.cpp
index 4b112972a1ec..e5f79ba99c5c 100644
--- a/clang/utils/TableGen/NeonEmitter.cpp
+++ b/clang/utils/TableGen/NeonEmitter.cpp
@@ -593,6 +593,8 @@ public:
// Emit arm_bf16.h.inc
void runBF16(raw_ostream &o);
+ void runVectorTypes(raw_ostream &o);
+
// Emit all the __builtin prototypes used in arm_neon.h, arm_fp16.h and
// arm_bf16.h
void runHeader(raw_ostream &o);
@@ -2355,13 +2357,7 @@ void NeonEmitter::run(raw_ostream &OS) {
OS << "#include <arm_bf16.h>\n";
- // Emit NEON-specific scalar typedefs.
- OS << "typedef float float32_t;\n";
- OS << "typedef __fp16 float16_t;\n";
-
- OS << "#ifdef __aarch64__\n";
- OS << "typedef double float64_t;\n";
- OS << "#endif\n\n";
+ OS << "#include <arm_vector_types.h>\n";
// For now, signedness of polynomial types depends on target
OS << "#ifdef __aarch64__\n";
@@ -2374,10 +2370,7 @@ void NeonEmitter::run(raw_ostream &OS) {
OS << "typedef int16_t poly16_t;\n";
OS << "typedef int64_t poly64_t;\n";
OS << "#endif\n";
-
- emitNeonTypeDefs("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl", OS);
-
- emitNeonTypeDefs("bQb", OS);
+ emitNeonTypeDefs("PcQPcPsQPsPlQPl", OS);
OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
"__nodebug__))\n\n";
@@ -2546,6 +2539,38 @@ void NeonEmitter::runFP16(raw_ostream &OS) {
OS << "#endif /* __ARM_FP16_H */\n";
}
+void NeonEmitter::runVectorTypes(raw_ostream &OS) {
+ OS << "/*===---- arm_vector_types - ARM vector type "
+ "------===\n"
+ " *\n"
+ " *\n"
+ " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+ "Exceptions.\n"
+ " * See https://llvm.org/LICENSE.txt for license information.\n"
+ " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ " *\n"
+ " *===-----------------------------------------------------------------"
+ "------===\n"
+ " */\n\n";
+ OS << "#if !defined(__ARM_NEON_H) && !defined(__ARM_SVE_H)\n";
+ OS << "#error \"This file should not be used standalone. Please include"
+ " arm_neon.h or arm_sve.h instead\"\n\n";
+ OS << "#endif\n";
+ OS << "#ifndef __ARM_NEON_TYPES_H\n";
+ OS << "#define __ARM_NEON_TYPES_H\n";
+ OS << "typedef float float32_t;\n";
+ OS << "typedef __fp16 float16_t;\n";
+
+ OS << "#ifdef __aarch64__\n";
+ OS << "typedef double float64_t;\n";
+ OS << "#endif\n\n";
+
+ emitNeonTypeDefs("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQd", OS);
+
+ emitNeonTypeDefs("bQb", OS);
+ OS << "#endif // __ARM_NEON_TYPES_H\n";
+}
+
void NeonEmitter::runBF16(raw_ostream &OS) {
OS << "/*===---- arm_bf16.h - ARM BF16 intrinsics "
"-----------------------------------===\n"
@@ -2640,6 +2665,10 @@ void clang::EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
NeonEmitter(Records).runHeader(OS);
}
+void clang::EmitVectorTypes(RecordKeeper &Records, raw_ostream &OS) {
+ NeonEmitter(Records).runVectorTypes(OS);
+}
+
void clang::EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
llvm_unreachable("Neon test generation no longer implemented!");
}
diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp
index b8a1fb4bab0f..9361b9950637 100644
--- a/clang/utils/TableGen/SveEmitter.cpp
+++ b/clang/utils/TableGen/SveEmitter.cpp
@@ -97,6 +97,7 @@ public:
bool isScalar() const { return NumVectors == 0; }
bool isVector() const { return NumVectors > 0; }
bool isScalableVector() const { return isVector() && IsScalable; }
+ bool isFixedLengthVector() const { return isVector() && !IsScalable; }
bool isChar() const { return ElementBitwidth == 8; }
bool isVoid() const { return Void & !Pointer; }
bool isDefault() const { return DefaultType; }
@@ -466,7 +467,8 @@ std::string SVEType::builtin_str() const {
return S;
}
- assert(isScalableVector() && "Unsupported type");
+ if (isFixedLengthVector())
+ return "V" + utostr(getNumElements() * NumVectors) + S;
return "q" + utostr(getNumElements() * NumVectors) + S;
}
@@ -499,7 +501,7 @@ std::string SVEType::str() const {
if (!isScalarPredicate() && !isPredicateVector() && !isSvcount())
S += utostr(ElementBitwidth);
- if (!isScalableVector() && isVector())
+ if (isFixedLengthVector())
S += "x" + utostr(getNumElements());
if (NumVectors > 1)
S += "x" + utostr(NumVectors);
@@ -610,6 +612,11 @@ void SVEType::applyModifier(char Mod) {
Bitwidth = 16;
ElementBitwidth = 1;
break;
+ case '{':
+ IsScalable = false;
+ Bitwidth = 128;
+ NumVectors = 1;
+ break;
case 's':
case 'a':
Bitwidth = ElementBitwidth;
@@ -1286,6 +1293,7 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "typedef __SVBfloat16_t svbfloat16_t;\n";
OS << "#include <arm_bf16.h>\n";
+ OS << "#include <arm_vector_types.h>\n";
OS << "typedef __SVFloat32_t svfloat32_t;\n";
OS << "typedef __SVFloat64_t svfloat64_t;\n";
@@ -1730,4 +1738,5 @@ void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createSMERangeChecks(OS);
}
+
} // End namespace clang
diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index 7efb6c731d3e..3ad46b95984e 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -73,6 +73,7 @@ enum ActionType {
GenArmNeon,
GenArmFP16,
GenArmBF16,
+ GenArmVectorType,
GenArmNeonSema,
GenArmNeonTest,
GenArmMveHeader,
@@ -229,6 +230,8 @@ cl::opt<ActionType> Action(
clEnumValN(GenArmNeon, "gen-arm-neon", "Generate arm_neon.h for clang"),
clEnumValN(GenArmFP16, "gen-arm-fp16", "Generate arm_fp16.h for clang"),
clEnumValN(GenArmBF16, "gen-arm-bf16", "Generate arm_bf16.h for clang"),
+ clEnumValN(GenArmVectorType, "gen-arm-vector-type",
+ "Generate arm_vector_types.h for clang"),
clEnumValN(GenArmNeonSema, "gen-arm-neon-sema",
"Generate ARM NEON sema support for clang"),
clEnumValN(GenArmNeonTest, "gen-arm-neon-test",
@@ -449,6 +452,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenArmFP16:
EmitFP16(Records, OS);
break;
+ case GenArmVectorType:
+ EmitVectorTypes(Records, OS);
+ break;
case GenArmBF16:
EmitBF16(Records, OS);
break;
diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h
index d8f447069376..ef255612f4b8 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -97,6 +97,7 @@ void EmitNeon(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitFP16(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitBF16(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitNeonSema(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitVectorTypes(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitNeonTest(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSveHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc
index 44a449800923..f5de23ff4b94 100644
--- a/compiler-rt/include/profile/InstrProfData.inc
+++ b/compiler-rt/include/profile/InstrProfData.inc
@@ -295,6 +295,12 @@ INSTR_PROF_SECT_ENTRY(IPSK_covfun, \
INSTR_PROF_SECT_ENTRY(IPSK_orderfile, \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON), \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COFF), "__DATA,")
+INSTR_PROF_SECT_ENTRY(IPSK_covdata, \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVDATA_COMMON), \
+ INSTR_PROF_COVDATA_COFF, "__LLVM_COV,")
+INSTR_PROF_SECT_ENTRY(IPSK_covname, \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON), \
+ INSTR_PROF_COVNAME_COFF, "__LLVM_COV,")
#undef INSTR_PROF_SECT_ENTRY
#endif
@@ -701,6 +707,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds
#define INSTR_PROF_COVMAP_COMMON __llvm_covmap
#define INSTR_PROF_COVFUN_COMMON __llvm_covfun
+#define INSTR_PROF_COVDATA_COMMON __llvm_covdata
+#define INSTR_PROF_COVNAME_COMMON __llvm_covnames
#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile
/* Windows section names. Because these section names contain dollar characters,
* they must be quoted.
@@ -713,6 +721,11 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_COFF ".lprfnd$M"
#define INSTR_PROF_COVMAP_COFF ".lcovmap$M"
#define INSTR_PROF_COVFUN_COFF ".lcovfun$M"
+/* Since cov data and cov names sections are not allocated, we don't need to
+ * access them at runtime.
+ */
+#define INSTR_PROF_COVDATA_COFF ".lcovd"
+#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"
#ifdef _WIN32
@@ -729,6 +742,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COFF
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF
#define INSTR_PROF_COVFUN_SECT_NAME INSTR_PROF_COVFUN_COFF
+#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_COVDATA_COFF
+#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_COVNAME_COFF
#define INSTR_PROF_ORDERFILE_SECT_NAME INSTR_PROF_ORDERFILE_COFF
#else
/* Runtime section names and name strings. */
@@ -744,6 +759,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON)
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON)
#define INSTR_PROF_COVFUN_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVFUN_COMMON)
+#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVDATA_COMMON)
+#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON)
/* Order file instrumentation. */
#define INSTR_PROF_ORDERFILE_SECT_NAME \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON)
diff --git a/compiler-rt/include/sanitizer/hwasan_interface.h b/compiler-rt/include/sanitizer/hwasan_interface.h
index abe310c06669..407f488a24a6 100644
--- a/compiler-rt/include/sanitizer/hwasan_interface.h
+++ b/compiler-rt/include/sanitizer/hwasan_interface.h
@@ -44,6 +44,10 @@ void SANITIZER_CDECL __hwasan_tag_memory(const volatile void *p,
void *SANITIZER_CDECL __hwasan_tag_pointer(const volatile void *p,
unsigned char tag);
+/// Get tag from the pointer.
+unsigned char SANITIZER_CDECL
+__hwasan_get_tag_from_pointer(const volatile void *p);
+
// Set memory tag from the current SP address to the given address to zero.
// This is meant to annotate longjmp and other non-local jumps.
// This function needs to know the (almost) exact destination frame address;
diff --git a/compiler-rt/lib/asan/asan_fuchsia.cpp b/compiler-rt/lib/asan/asan_fuchsia.cpp
index 2b15504123be..12625e9d7583 100644
--- a/compiler-rt/lib/asan/asan_fuchsia.cpp
+++ b/compiler-rt/lib/asan/asan_fuchsia.cpp
@@ -240,6 +240,8 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) {
// So this doesn't install any atexit hook like on other platforms.
void InstallAtExitCheckLeaks() {}
+void InstallAtForkHandler() {}
+
} // namespace __asan
namespace __lsan {
diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h
index 5b97e77882cd..2944ebe213b5 100644
--- a/compiler-rt/lib/asan/asan_internal.h
+++ b/compiler-rt/lib/asan/asan_internal.h
@@ -126,6 +126,7 @@ void *AsanDlSymNext(const char *sym);
bool HandleDlopenInit();
void InstallAtExitCheckLeaks();
+void InstallAtForkHandler();
#define ASAN_ON_ERROR() \
if (&__asan_on_error) \
diff --git a/compiler-rt/lib/asan/asan_posix.cpp b/compiler-rt/lib/asan/asan_posix.cpp
index e1f66641617c..206551b6ef91 100644
--- a/compiler-rt/lib/asan/asan_posix.cpp
+++ b/compiler-rt/lib/asan/asan_posix.cpp
@@ -148,6 +148,30 @@ void PlatformTSDDtor(void *tsd) {
}
#endif
+void InstallAtForkHandler() {
+ auto before = []() {
+ if (CAN_SANITIZE_LEAKS) {
+ __lsan::LockGlobal();
+ }
+ // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the
+ // stuff we need.
+ __lsan::LockThreads();
+ __lsan::LockAllocator();
+ StackDepotLockAll();
+ };
+ auto after = []() {
+ StackDepotUnlockAll();
+ // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock
+ // the stuff we need.
+ __lsan::UnlockAllocator();
+ __lsan::UnlockThreads();
+ if (CAN_SANITIZE_LEAKS) {
+ __lsan::UnlockGlobal();
+ }
+ };
+ pthread_atfork(before, after, after);
+}
+
void InstallAtExitCheckLeaks() {
if (CAN_SANITIZE_LEAKS) {
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp
index 04ecd20821fa..a61deed7382b 100644
--- a/compiler-rt/lib/asan/asan_rtl.cpp
+++ b/compiler-rt/lib/asan/asan_rtl.cpp
@@ -71,16 +71,16 @@ static void CheckUnwind() {
}
// -------------------------- Globals --------------------- {{{1
-static int asan_inited = 0;
-static int asan_init_is_running = 0;
+static StaticSpinMutex asan_inited_mutex;
+static atomic_uint8_t asan_inited = {0};
-static void SetAsanInited() { asan_inited = 1; }
-
-static void SetAsanInitIsRunning(u32 val) { asan_init_is_running = val; }
-
-bool AsanInited() { return asan_inited == 1; }
+static void SetAsanInited() {
+ atomic_store(&asan_inited, 1, memory_order_release);
+}
-static bool AsanInitIsRunning() { return asan_init_is_running == 1; }
+bool AsanInited() {
+ return atomic_load(&asan_inited, memory_order_acquire) == 1;
+}
bool replace_intrin_cached;
@@ -390,12 +390,10 @@ void PrintAddressSpaceLayout() {
kHighShadowBeg > kMidMemEnd);
}
-static void AsanInitInternal() {
+static bool AsanInitInternal() {
if (LIKELY(AsanInited()))
- return;
+ return true;
SanitizerToolName = "AddressSanitizer";
- CHECK(!AsanInitIsRunning() && "ASan init calls itself!");
- SetAsanInitIsRunning(1);
CacheBinaryName();
@@ -408,9 +406,8 @@ static void AsanInitInternal() {
// Stop performing init at this point if we are being loaded via
// dlopen() and the platform supports it.
if (SANITIZER_SUPPORTS_INIT_FOR_DLOPEN && UNLIKELY(HandleDlopenInit())) {
- SetAsanInitIsRunning(0);
VReport(1, "AddressSanitizer init is being performed for dlopen().\n");
- return;
+ return false;
}
AsanCheckIncompatibleRT();
@@ -471,7 +468,6 @@ static void AsanInitInternal() {
// should be set to 1 prior to initializing the threads.
replace_intrin_cached = flags()->replace_intrin;
SetAsanInited();
- SetAsanInitIsRunning(0);
if (flags()->atexit)
Atexit(asan_atexit);
@@ -497,6 +493,8 @@ static void AsanInitInternal() {
InstallAtExitCheckLeaks();
}
+ InstallAtForkHandler();
+
#if CAN_SANITIZE_UB
__ubsan::InitAsPlugin();
#endif
@@ -515,22 +513,27 @@ static void AsanInitInternal() {
VReport(1, "AddressSanitizer Init done\n");
WaitForDebugger(flags()->sleep_after_init, "after init");
+
+ return true;
}
// Initialize as requested from some part of ASan runtime library (interceptors,
// allocator, etc).
void AsanInitFromRtl() {
- CHECK(!AsanInitIsRunning());
- if (UNLIKELY(!AsanInited()))
- AsanInitInternal();
+ if (LIKELY(AsanInited()))
+ return;
+ SpinMutexLock lock(&asan_inited_mutex);
+ AsanInitInternal();
}
bool TryAsanInitFromRtl() {
- if (UNLIKELY(AsanInitIsRunning()))
+ if (LIKELY(AsanInited()))
+ return true;
+ if (!asan_inited_mutex.TryLock())
return false;
- if (UNLIKELY(!AsanInited()))
- AsanInitInternal();
- return true;
+ bool result = AsanInitInternal();
+ asan_inited_mutex.Unlock();
+ return result;
}
#if ASAN_DYNAMIC
@@ -603,7 +606,7 @@ static void UnpoisonFakeStack() {
using namespace __asan;
void NOINLINE __asan_handle_no_return() {
- if (AsanInitIsRunning())
+ if (UNLIKELY(!AsanInited()))
return;
if (!PlatformUnpoisonStacks())
@@ -633,7 +636,7 @@ void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
// We use this call as a trigger to wake up ASan from deactivated state.
void __asan_init() {
AsanActivate();
- AsanInitInternal();
+ AsanInitFromRtl();
}
void __asan_version_mismatch_check() {
diff --git a/compiler-rt/lib/asan/asan_win.cpp b/compiler-rt/lib/asan/asan_win.cpp
index d5a30f471e2b..f16ce677618e 100644
--- a/compiler-rt/lib/asan/asan_win.cpp
+++ b/compiler-rt/lib/asan/asan_win.cpp
@@ -203,6 +203,8 @@ void InitializePlatformInterceptors() {
void InstallAtExitCheckLeaks() {}
+void InstallAtForkHandler() {}
+
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
UNIMPLEMENTED();
}
diff --git a/compiler-rt/lib/hwasan/hwasan.cpp b/compiler-rt/lib/hwasan/hwasan.cpp
index 2f6cb10caf1b..52780becbdb2 100644
--- a/compiler-rt/lib/hwasan/hwasan.cpp
+++ b/compiler-rt/lib/hwasan/hwasan.cpp
@@ -678,6 +678,8 @@ uptr __hwasan_tag_pointer(uptr p, u8 tag) {
return AddTagToPointer(p, tag);
}
+u8 __hwasan_get_tag_from_pointer(uptr p) { return GetTagFromPointer(p); }
+
void __hwasan_handle_longjmp(const void *sp_dst) {
uptr dst = (uptr)sp_dst;
// HWASan does not support tagged SP.
diff --git a/compiler-rt/lib/hwasan/hwasan.h b/compiler-rt/lib/hwasan/hwasan.h
index 37ef48222851..df21375e8167 100644
--- a/compiler-rt/lib/hwasan/hwasan.h
+++ b/compiler-rt/lib/hwasan/hwasan.h
@@ -104,9 +104,9 @@ static inline void *UntagPtr(const void *tagged_ptr) {
}
static inline uptr AddTagToPointer(uptr p, tag_t tag) {
- return InTaggableRegion(p)
- ? ((p & ~kAddressTagMask) | ((uptr)tag << kAddressTagShift))
- : p;
+ return InTaggableRegion(p) ? ((p & ~kAddressTagMask) |
+ ((uptr)(tag & kTagMask) << kAddressTagShift))
+ : p;
}
namespace __hwasan {
diff --git a/compiler-rt/lib/hwasan/hwasan_interface_internal.h b/compiler-rt/lib/hwasan/hwasan_interface_internal.h
index e7804cc49033..8f2f77dad917 100644
--- a/compiler-rt/lib/hwasan/hwasan_interface_internal.h
+++ b/compiler-rt/lib/hwasan/hwasan_interface_internal.h
@@ -161,6 +161,9 @@ SANITIZER_INTERFACE_ATTRIBUTE
uptr __hwasan_tag_pointer(uptr p, u8 tag);
SANITIZER_INTERFACE_ATTRIBUTE
+u8 __hwasan_get_tag_from_pointer(uptr p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
void __hwasan_tag_mismatch(uptr addr, u8 ts);
SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp
index f01fa4276413..3271a955e7ed 100644
--- a/compiler-rt/lib/hwasan/hwasan_linux.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp
@@ -523,12 +523,24 @@ uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {
void HwasanInstallAtForkHandler() {
auto before = []() {
- HwasanAllocatorLock();
+ if (CAN_SANITIZE_LEAKS) {
+ __lsan::LockGlobal();
+ }
+ // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the
+ // stuff we need.
+ __lsan::LockThreads();
+ __lsan::LockAllocator();
StackDepotLockAll();
};
auto after = []() {
StackDepotUnlockAll();
- HwasanAllocatorUnlock();
+ // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock
+ // the stuff we need.
+ __lsan::UnlockAllocator();
+ __lsan::UnlockThreads();
+ if (CAN_SANITIZE_LEAKS) {
+ __lsan::UnlockGlobal();
+ }
};
pthread_atfork(before, after, after);
}
diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp
index ce36547580e6..3e14a718513d 100644
--- a/compiler-rt/lib/hwasan/hwasan_thread.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp
@@ -68,6 +68,7 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size,
}
Print("Creating : ");
}
+ ClearShadowForThreadStackAndTLS();
}
void Thread::InitStackRingBuffer(uptr stack_buffer_start,
diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp
index 6b223603c6a7..7a27b600f203 100644
--- a/compiler-rt/lib/lsan/lsan.cpp
+++ b/compiler-rt/lib/lsan/lsan.cpp
@@ -101,6 +101,7 @@ extern "C" void __lsan_init() {
InstallDeadlySignalHandlers(LsanOnDeadlySignal);
InitializeMainThread();
InstallAtExitCheckLeaks();
+ InstallAtForkHandler();
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
diff --git a/compiler-rt/lib/lsan/lsan.h b/compiler-rt/lib/lsan/lsan.h
index 757edec8e104..0074ad530878 100644
--- a/compiler-rt/lib/lsan/lsan.h
+++ b/compiler-rt/lib/lsan/lsan.h
@@ -40,6 +40,7 @@ void InitializeInterceptors();
void ReplaceSystemMalloc();
void LsanOnDeadlySignal(int signo, void *siginfo, void *context);
void InstallAtExitCheckLeaks();
+void InstallAtForkHandler();
#define ENSURE_LSAN_INITED \
do { \
diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp
index 8b1af5b629fb..e24839c984b3 100644
--- a/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/compiler-rt/lib/lsan/lsan_common.cpp
@@ -42,6 +42,9 @@ namespace __lsan {
// also to protect the global list of root regions.
static Mutex global_mutex;
+void LockGlobal() SANITIZER_ACQUIRE(global_mutex) { global_mutex.Lock(); }
+void UnlockGlobal() SANITIZER_RELEASE(global_mutex) { global_mutex.Unlock(); }
+
Flags lsan_flags;
void DisableCounterUnderflow() {
diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h
index d3e768363e93..c598b6210587 100644
--- a/compiler-rt/lib/lsan/lsan_common.h
+++ b/compiler-rt/lib/lsan/lsan_common.h
@@ -120,6 +120,10 @@ void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads);
void LockAllocator();
void UnlockAllocator();
+// Lock/unlock global mutext.
+void LockGlobal();
+void UnlockGlobal();
+
// Returns the address range occupied by the global allocator object.
void GetAllocatorGlobalRange(uptr *begin, uptr *end);
// If p points into a chunk that has been allocated to the user, returns its
diff --git a/compiler-rt/lib/lsan/lsan_fuchsia.cpp b/compiler-rt/lib/lsan/lsan_fuchsia.cpp
index 4edac9757a9c..ba59bc9b71e3 100644
--- a/compiler-rt/lib/lsan/lsan_fuchsia.cpp
+++ b/compiler-rt/lib/lsan/lsan_fuchsia.cpp
@@ -80,6 +80,7 @@ void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
// On Fuchsia, leak detection is done by a special hook after atexit hooks.
// So this doesn't install any atexit hook like on other platforms.
void InstallAtExitCheckLeaks() {}
+void InstallAtForkHandler() {}
// ASan defines this to check its `halt_on_error` flag.
bool UseExitcodeOnLeak() { return true; }
diff --git a/compiler-rt/lib/lsan/lsan_posix.cpp b/compiler-rt/lib/lsan/lsan_posix.cpp
index d99e1cc0105e..3677f0141a2f 100644
--- a/compiler-rt/lib/lsan/lsan_posix.cpp
+++ b/compiler-rt/lib/lsan/lsan_posix.cpp
@@ -14,11 +14,13 @@
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_POSIX
-#include "lsan.h"
-#include "lsan_allocator.h"
-#include "lsan_thread.h"
-#include "sanitizer_common/sanitizer_stacktrace.h"
-#include "sanitizer_common/sanitizer_tls_get_addr.h"
+# include <pthread.h>
+
+# include "lsan.h"
+# include "lsan_allocator.h"
+# include "lsan_thread.h"
+# include "sanitizer_common/sanitizer_stacktrace.h"
+# include "sanitizer_common/sanitizer_tls_get_addr.h"
namespace __lsan {
@@ -98,6 +100,22 @@ void InstallAtExitCheckLeaks() {
Atexit(DoLeakCheck);
}
+void InstallAtForkHandler() {
+ auto before = []() {
+ LockGlobal();
+ LockThreads();
+ LockAllocator();
+ StackDepotLockAll();
+ };
+ auto after = []() {
+ StackDepotUnlockAll();
+ UnlockAllocator();
+ UnlockThreads();
+ UnlockGlobal();
+ };
+ pthread_atfork(before, after, after);
+}
+
} // namespace __lsan
#endif // SANITIZER_POSIX
diff --git a/compiler-rt/lib/msan/msan.cpp b/compiler-rt/lib/msan/msan.cpp
index c4f47dea1104..3cdf10c14990 100644
--- a/compiler-rt/lib/msan/msan.cpp
+++ b/compiler-rt/lib/msan/msan.cpp
@@ -449,6 +449,7 @@ void __msan_init() {
__sanitizer_set_report_path(common_flags()->log_path);
InitializeInterceptors();
+ InstallAtForkHandler();
CheckASLR();
InitTlsSize();
InstallDeadlySignalHandlers(MsanOnDeadlySignal);
diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h
index b3a9c641b4fb..25fa2212bdad 100644
--- a/compiler-rt/lib/msan/msan.h
+++ b/compiler-rt/lib/msan/msan.h
@@ -336,6 +336,8 @@ void *MsanTSDGet();
void MsanTSDSet(void *tsd);
void MsanTSDDtor(void *tsd);
+void InstallAtForkHandler();
+
} // namespace __msan
#endif // MSAN_H
diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp
index c3b0f8512e82..72a7f980d39f 100644
--- a/compiler-rt/lib/msan/msan_allocator.cpp
+++ b/compiler-rt/lib/msan/msan_allocator.cpp
@@ -159,6 +159,10 @@ void MsanAllocatorInit() {
max_malloc_size = kMaxAllowedMallocSize;
}
+void LockAllocator() { allocator.ForceLock(); }
+
+void UnlockAllocator() { allocator.ForceUnlock(); }
+
AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) {
CHECK(ms);
CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
diff --git a/compiler-rt/lib/msan/msan_allocator.h b/compiler-rt/lib/msan/msan_allocator.h
index 364331d96406..c2a38a401f3b 100644
--- a/compiler-rt/lib/msan/msan_allocator.h
+++ b/compiler-rt/lib/msan/msan_allocator.h
@@ -28,5 +28,8 @@ struct MsanThreadLocalMallocStorage {
MsanThreadLocalMallocStorage() {}
};
+void LockAllocator();
+void UnlockAllocator();
+
} // namespace __msan
#endif // MSAN_ALLOCATOR_H
diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp
index c2d740e7762b..2c9f2c01e14b 100644
--- a/compiler-rt/lib/msan/msan_interceptors.cpp
+++ b/compiler-rt/lib/msan/msan_interceptors.cpp
@@ -1326,24 +1326,6 @@ static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso) {
return res;
}
-static void BeforeFork() {
- StackDepotLockAll();
- ChainedOriginDepotLockAll();
-}
-
-static void AfterFork() {
- ChainedOriginDepotUnlockAll();
- StackDepotUnlockAll();
-}
-
-INTERCEPTOR(int, fork, void) {
- ENSURE_MSAN_INITED();
- BeforeFork();
- int pid = REAL(fork)();
- AfterFork();
- return pid;
-}
-
// NetBSD ships with openpty(3) in -lutil, that needs to be prebuilt explicitly
// with MSan.
#if SANITIZER_LINUX
@@ -1933,7 +1915,6 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(atexit);
INTERCEPT_FUNCTION(__cxa_atexit);
INTERCEPT_FUNCTION(shmat);
- INTERCEPT_FUNCTION(fork);
MSAN_MAYBE_INTERCEPT_OPENPTY;
MSAN_MAYBE_INTERCEPT_FORKPTY;
diff --git a/compiler-rt/lib/msan/msan_linux.cpp b/compiler-rt/lib/msan/msan_linux.cpp
index bced00ba2428..04af6f4b27ac 100644
--- a/compiler-rt/lib/msan/msan_linux.cpp
+++ b/compiler-rt/lib/msan/msan_linux.cpp
@@ -14,23 +14,25 @@
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
-#include "msan.h"
-#include "msan_report.h"
-#include "msan_thread.h"
-
-#include <elf.h>
-#include <link.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-#include <unwind.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_procmaps.h"
+# include <elf.h>
+# include <link.h>
+# include <pthread.h>
+# include <signal.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <sys/resource.h>
+# include <sys/time.h>
+# include <unistd.h>
+# include <unwind.h>
+
+# include "msan.h"
+# include "msan_allocator.h"
+# include "msan_chained_origin_depot.h"
+# include "msan_report.h"
+# include "msan_thread.h"
+# include "sanitizer_common/sanitizer_common.h"
+# include "sanitizer_common/sanitizer_procmaps.h"
+# include "sanitizer_common/sanitizer_stackdepot.h"
namespace __msan {
@@ -256,6 +258,22 @@ void MsanTSDDtor(void *tsd) {
}
#endif
+void InstallAtForkHandler() {
+ auto before = []() {
+ // Usually we lock ThreadRegistry, but msan does not have one.
+ LockAllocator();
+ StackDepotLockAll();
+ ChainedOriginDepotLockAll();
+ };
+ auto after = []() {
+ ChainedOriginDepotUnlockAll();
+ StackDepotUnlockAll();
+ UnlockAllocator();
+ // Usually we unlock ThreadRegistry, but msan does not have one.
+ };
+ pthread_atfork(before, after, after);
+}
+
} // namespace __msan
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h
index c5b0b34f2d8a..137115996748 100644
--- a/compiler-rt/lib/profile/InstrProfiling.h
+++ b/compiler-rt/lib/profile/InstrProfiling.h
@@ -55,6 +55,12 @@ int __llvm_profile_is_continuous_mode_enabled(void);
void __llvm_profile_enable_continuous_mode(void);
/*!
+ * \brief Disable continuous mode.
+ *
+ */
+void __llvm_profile_disable_continuous_mode(void);
+
+/*!
* \brief Set the page size.
*
* This is a pre-requisite for enabling continuous mode. The buffer size
diff --git a/compiler-rt/lib/profile/InstrProfilingBuffer.c b/compiler-rt/lib/profile/InstrProfilingBuffer.c
index cd1f067bd188..af52804b2b53 100644
--- a/compiler-rt/lib/profile/InstrProfilingBuffer.c
+++ b/compiler-rt/lib/profile/InstrProfilingBuffer.c
@@ -33,6 +33,10 @@ COMPILER_RT_VISIBILITY void __llvm_profile_enable_continuous_mode(void) {
ContinuouslySyncProfile = 1;
}
+COMPILER_RT_VISIBILITY void __llvm_profile_disable_continuous_mode(void) {
+ ContinuouslySyncProfile = 0;
+}
+
COMPILER_RT_VISIBILITY void __llvm_profile_set_page_size(unsigned PS) {
PageSize = PS;
}
diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c
index 1685b30b9492..745c567f2167 100644
--- a/compiler-rt/lib/profile/InstrProfilingFile.c
+++ b/compiler-rt/lib/profile/InstrProfilingFile.c
@@ -806,6 +806,7 @@ static int parseFilenamePattern(const char *FilenamePat,
if (__llvm_profile_is_continuous_mode_enabled()) {
PROF_WARN("%%c specifier can only be specified once in %s.\n",
FilenamePat);
+ __llvm_profile_disable_continuous_mode();
return -1;
}
#if defined(__APPLE__) || defined(__ELF__) || defined(_WIN32)
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c b/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c
index 9dbd702865fd..9070b8a606eb 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c
@@ -13,13 +13,14 @@
#if defined(_MSC_VER)
/* Merge read-write sections into .data. */
-#pragma comment(linker, "/MERGE:.lprfc=.data")
#pragma comment(linker, "/MERGE:.lprfb=.data")
#pragma comment(linker, "/MERGE:.lprfd=.data")
#pragma comment(linker, "/MERGE:.lprfv=.data")
#pragma comment(linker, "/MERGE:.lprfnd=.data")
/* Do *NOT* merge .lprfn and .lcovmap into .rdata. llvm-cov must be able to find
* after the fact.
+ * Do *NOT* merge .lprfc .rdata. When binary profile correlation is enabled,
+ * llvm-cov must be able to find after the fact.
*/
/* Allocate read-only section bounds. */
diff --git a/compiler-rt/lib/scudo/standalone/common.h b/compiler-rt/lib/scudo/standalone/common.h
index 3581c946d160..ae45683f1ee3 100644
--- a/compiler-rt/lib/scudo/standalone/common.h
+++ b/compiler-rt/lib/scudo/standalone/common.h
@@ -112,6 +112,21 @@ template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) {
*RandState = State;
}
+inline void computePercentage(uptr Numerator, uptr Denominator, uptr *Integral,
+ uptr *Fractional) {
+ constexpr uptr Digits = 100;
+ if (Denominator == 0) {
+ *Integral = 100;
+ *Fractional = 0;
+ return;
+ }
+
+ *Integral = Numerator * Digits / Denominator;
+ *Fractional =
+ (((Numerator * Digits) % Denominator) * Digits + Denominator / 2) /
+ Denominator;
+}
+
// Platform specific functions.
extern uptr PageSizeCached;
diff --git a/compiler-rt/lib/scudo/standalone/flags_parser.cpp b/compiler-rt/lib/scudo/standalone/flags_parser.cpp
index 6f9b23ea90e2..3d8c6f3789b4 100644
--- a/compiler-rt/lib/scudo/standalone/flags_parser.cpp
+++ b/compiler-rt/lib/scudo/standalone/flags_parser.cpp
@@ -10,6 +10,7 @@
#include "common.h"
#include "report.h"
+#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -143,19 +144,18 @@ bool FlagParser::runHandler(const char *Name, const char *Value,
break;
case FlagType::FT_int:
char *ValueEnd;
+ errno = 0;
long V = strtol(Value, &ValueEnd, 10);
- // strtol returns LONG_MAX on overflow and LONG_MIN on underflow.
- // This is why we compare-equal here (and lose INT_MIN and INT_MAX as a
- // value, but that's okay)
- if (V >= INT_MAX || V <= INT_MIN) {
+ if (errno != 0 || // strtol failed (over or underflow)
+ V > INT_MAX || V < INT_MIN || // overflows integer
+ // contains unexpected characters
+ (*ValueEnd != '"' && *ValueEnd != '\'' &&
+ !isSeparatorOrNull(*ValueEnd))) {
reportInvalidFlag("int", Value);
- return false;
+ break;
}
*reinterpret_cast<int *>(Flags[I].Var) = static_cast<int>(V);
- Ok =
- *ValueEnd == '"' || *ValueEnd == '\'' || isSeparatorOrNull(*ValueEnd);
- if (!Ok)
- reportInvalidFlag("int", Value);
+ Ok = true;
break;
}
return Ok;
diff --git a/compiler-rt/lib/scudo/standalone/primary32.h b/compiler-rt/lib/scudo/standalone/primary32.h
index 8281e02ba164..4d03b282d000 100644
--- a/compiler-rt/lib/scudo/standalone/primary32.h
+++ b/compiler-rt/lib/scudo/standalone/primary32.h
@@ -931,10 +931,14 @@ private:
AllocatedPagesCount - Recorder.getReleasedPagesCount();
const uptr InUseBytes = InUsePages * PageSize;
+ uptr Integral;
+ uptr Fractional;
+ computePercentage(BlockSize * InUseBlocks, InUsePages * PageSize, &Integral,
+ &Fractional);
Str->append(" %02zu (%6zu): inuse/total blocks: %6zu/%6zu inuse/total "
- "pages: %6zu/%6zu inuse bytes: %6zuK\n",
+ "pages: %6zu/%6zu inuse bytes: %6zuK util: %3zu.%02zu%%\n",
ClassId, BlockSize, InUseBlocks, TotalBlocks, InUsePages,
- AllocatedPagesCount, InUseBytes >> 10);
+ AllocatedPagesCount, InUseBytes >> 10, Integral, Fractional);
}
NOINLINE uptr releaseToOSMaybe(SizeClassInfo *Sci, uptr ClassId,
diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h
index d1929ff7212f..9a642d23620e 100644
--- a/compiler-rt/lib/scudo/standalone/primary64.h
+++ b/compiler-rt/lib/scudo/standalone/primary64.h
@@ -1130,10 +1130,14 @@ private:
AllocatedPagesCount - Recorder.getReleasedPagesCount();
const uptr InUseBytes = InUsePages * PageSize;
+ uptr Integral;
+ uptr Fractional;
+ computePercentage(BlockSize * InUseBlocks, InUsePages * PageSize, &Integral,
+ &Fractional);
Str->append(" %02zu (%6zu): inuse/total blocks: %6zu/%6zu inuse/total "
- "pages: %6zu/%6zu inuse bytes: %6zuK\n",
+ "pages: %6zu/%6zu inuse bytes: %6zuK util: %3zu.%02zu%%\n",
ClassId, BlockSize, InUseBlocks, TotalBlocks, InUsePages,
- AllocatedPagesCount, InUseBytes >> 10);
+ AllocatedPagesCount, InUseBytes >> 10, Integral, Fractional);
}
NOINLINE uptr releaseToOSMaybe(RegionInfo *Region, uptr ClassId,
diff --git a/compiler-rt/lib/scudo/standalone/secondary.h b/compiler-rt/lib/scudo/standalone/secondary.h
index 8dc4c87fa7c6..f52a4188bcf3 100644
--- a/compiler-rt/lib/scudo/standalone/secondary.h
+++ b/compiler-rt/lib/scudo/standalone/secondary.h
@@ -155,20 +155,16 @@ public:
void getStats(ScopedString *Str) {
ScopedLock L(Mutex);
- u32 Integral = 0;
- u32 Fractional = 0;
- if (CallsToRetrieve != 0) {
- Integral = SuccessfulRetrieves * 100 / CallsToRetrieve;
- Fractional = (((SuccessfulRetrieves * 100) % CallsToRetrieve) * 100 +
- CallsToRetrieve / 2) /
- CallsToRetrieve;
- }
+ uptr Integral;
+ uptr Fractional;
+ computePercentage(SuccessfulRetrieves, CallsToRetrieve, &Integral,
+ &Fractional);
Str->append("Stats: MapAllocatorCache: EntriesCount: %d, "
"MaxEntriesCount: %u, MaxEntrySize: %zu\n",
EntriesCount, atomic_load_relaxed(&MaxEntriesCount),
atomic_load_relaxed(&MaxEntrySize));
Str->append("Stats: CacheRetrievalStats: SuccessRate: %u/%u "
- "(%u.%02u%%)\n",
+ "(%zu.%02zu%%)\n",
SuccessfulRetrieves, CallsToRetrieve, Integral, Fractional);
for (CachedBlock Entry : Entries) {
if (!Entry.isValid())
diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h
index 0118489d9469..754e597130c5 100644
--- a/libcxx/include/__algorithm/find.h
+++ b/libcxx/include/__algorithm/find.h
@@ -10,6 +10,7 @@
#ifndef _LIBCPP___ALGORITHM_FIND_H
#define _LIBCPP___ALGORITHM_FIND_H
+#include <__algorithm/find_segment_if.h>
#include <__algorithm/min.h>
#include <__algorithm/unwrap_iter.h>
#include <__bit/countr.h>
@@ -18,8 +19,10 @@
#include <__functional/identity.h>
#include <__functional/invoke.h>
#include <__fwd/bit_reference.h>
+#include <__iterator/segmented_iterator.h>
#include <__string/constexpr_c_functions.h>
#include <__type_traits/is_same.h>
+#include <__utility/move.h>
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# include <cwchar>
@@ -118,6 +121,34 @@ __find_impl(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst>
return std::__find_bool<false>(__first, static_cast<typename _Cp::size_type>(__last - __first));
}
+// segmented iterator implementation
+
+template <class>
+struct __find_segment;
+
+template <class _SegmentedIterator,
+ class _Tp,
+ class _Proj,
+ __enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator
+__find_impl(_SegmentedIterator __first, _SegmentedIterator __last, const _Tp& __value, _Proj& __proj) {
+ return std::__find_segment_if(std::move(__first), std::move(__last), __find_segment<_Tp>(__value), __proj);
+}
+
+template <class _Tp>
+struct __find_segment {
+ const _Tp& __value_;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __find_segment(const _Tp& __value) : __value_(__value) {}
+
+ template <class _InputIterator, class _Proj>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _InputIterator
+ operator()(_InputIterator __first, _InputIterator __last, _Proj& __proj) const {
+ return std::__find_impl(__first, __last, __value_, __proj);
+ }
+};
+
+// public API
template <class _InputIterator, class _Tp>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator
find(_InputIterator __first, _InputIterator __last, const _Tp& __value) {
diff --git a/libcxx/include/__algorithm/find_segment_if.h b/libcxx/include/__algorithm/find_segment_if.h
new file mode 100644
index 000000000000..9d6064f3e283
--- /dev/null
+++ b/libcxx/include/__algorithm/find_segment_if.h
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_FIND_SEGMENT_IF_H
+#define _LIBCPP___ALGORITHM_FIND_SEGMENT_IF_H
+
+#include <__config>
+#include <__iterator/segmented_iterator.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// __find_segment_if is a utility function for optimizing iteration over segmented iterators linearly.
+// [__first, __last) has to be a segmented range. __pred is expected to take a range of local iterators and the __proj.
+// It returns an iterator to the first element that satisfies the predicate, or a one-past-the-end iterator if there was
+// no match. __proj may be anything that should be passed to __pred, but is expected to be a projection to support
+// ranges algorithms, or __identity for classic algorithms.
+
+template <class _SegmentedIterator, class _Pred, class _Proj>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator
+__find_segment_if(_SegmentedIterator __first, _SegmentedIterator __last, _Pred __pred, _Proj& __proj) {
+ using _Traits = __segmented_iterator_traits<_SegmentedIterator>;
+
+ auto __sfirst = _Traits::__segment(__first);
+ auto __slast = _Traits::__segment(__last);
+
+ // We are in a single segment, so we might not be at the beginning or end
+ if (__sfirst == __slast)
+ return _Traits::__compose(__sfirst, __pred(_Traits::__local(__first), _Traits::__local(__last), __proj));
+
+ { // We have more than one segment. Iterate over the first segment, since we might not start at the beginning
+ auto __llast = _Traits::__end(__sfirst);
+ auto __liter = __pred(_Traits::__local(__first), __llast, __proj);
+ if (__liter != __llast)
+ return _Traits::__compose(__sfirst, __liter);
+ }
+ ++__sfirst;
+
+ // Iterate over the segments which are guaranteed to be completely in the range
+ while (__sfirst != __slast) {
+ auto __llast = _Traits::__end(__sfirst);
+ auto __liter = __pred(_Traits::__begin(__sfirst), _Traits::__end(__sfirst), __proj);
+ if (__liter != __llast)
+ return _Traits::__compose(__sfirst, __liter);
+ ++__sfirst;
+ }
+
+ // Iterate over the last segment
+ return _Traits::__compose(__sfirst, __pred(_Traits::__begin(__sfirst), _Traits::__local(__last), __proj));
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___ALGORITHM_FIND_SEGMENT_IF_H
diff --git a/libcxx/include/__chrono/day.h b/libcxx/include/__chrono/day.h
index c907c036c146..d908453d5b08 100644
--- a/libcxx/include/__chrono/day.h
+++ b/libcxx/include/__chrono/day.h
@@ -46,7 +46,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr
bool operator==(const day& __lhs, const day& __rhs) noexcept
{ return static_cast<unsigned>(__lhs) == static_cast<unsigned>(__rhs); }
-_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const day& __lhs, const day& __rhs) noexcept {
+_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const day& __lhs, const day& __rhs) noexcept {
return static_cast<unsigned>(__lhs) <=> static_cast<unsigned>(__rhs);
}
diff --git a/libcxx/include/__chrono/hh_mm_ss.h b/libcxx/include/__chrono/hh_mm_ss.h
index 5bd452e57fa3..0adee2d60db8 100644
--- a/libcxx/include/__chrono/hh_mm_ss.h
+++ b/libcxx/include/__chrono/hh_mm_ss.h
@@ -87,17 +87,17 @@ private:
};
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(hh_mm_ss);
-_LIBCPP_HIDE_FROM_ABI constexpr bool is_am(const hours& __h) noexcept { return __h >= hours( 0) && __h < hours(12); }
-_LIBCPP_HIDE_FROM_ABI constexpr bool is_pm(const hours& __h) noexcept { return __h >= hours(12) && __h < hours(24); }
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_am(const hours& __h) noexcept { return __h >= hours( 0) && __h < hours(12); }
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_pm(const hours& __h) noexcept { return __h >= hours(12) && __h < hours(24); }
-_LIBCPP_HIDE_FROM_ABI constexpr hours make12(const hours& __h) noexcept
+_LIBCPP_HIDE_FROM_ABI inline constexpr hours make12(const hours& __h) noexcept
{
if (__h == hours( 0)) return hours(12);
else if (__h <= hours(12)) return __h;
else return __h - hours(12);
}
-_LIBCPP_HIDE_FROM_ABI constexpr hours make24(const hours& __h, bool __is_pm) noexcept
+_LIBCPP_HIDE_FROM_ABI inline constexpr hours make24(const hours& __h, bool __is_pm) noexcept
{
if (__is_pm)
return __h == hours(12) ? __h : __h + hours(12);
diff --git a/libcxx/include/__chrono/month.h b/libcxx/include/__chrono/month.h
index 7566e4ed2998..2dee5d8c6c70 100644
--- a/libcxx/include/__chrono/month.h
+++ b/libcxx/include/__chrono/month.h
@@ -46,7 +46,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr
bool operator==(const month& __lhs, const month& __rhs) noexcept
{ return static_cast<unsigned>(__lhs) == static_cast<unsigned>(__rhs); }
-_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const month& __lhs, const month& __rhs) noexcept {
+_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const month& __lhs, const month& __rhs) noexcept {
return static_cast<unsigned>(__lhs) <=> static_cast<unsigned>(__rhs);
}
diff --git a/libcxx/include/__chrono/monthday.h b/libcxx/include/__chrono/monthday.h
index 03fd7503a6b4..8403d9ec4eeb 100644
--- a/libcxx/include/__chrono/monthday.h
+++ b/libcxx/include/__chrono/monthday.h
@@ -59,7 +59,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr
bool operator==(const month_day& __lhs, const month_day& __rhs) noexcept
{ return __lhs.month() == __rhs.month() && __lhs.day() == __rhs.day(); }
-_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const month_day& __lhs, const month_day& __rhs) noexcept {
+_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const month_day& __lhs, const month_day& __rhs) noexcept {
if (auto __c = __lhs.month() <=> __rhs.month(); __c != 0)
return __c;
return __lhs.day() <=> __rhs.day();
@@ -69,7 +69,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr
month_day operator/(const month& __lhs, const day& __rhs) noexcept
{ return month_day{__lhs, __rhs}; }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
month_day operator/(const day& __lhs, const month& __rhs) noexcept
{ return __rhs / __lhs; }
@@ -77,11 +77,11 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr
month_day operator/(const month& __lhs, int __rhs) noexcept
{ return __lhs / day(__rhs); }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
month_day operator/(int __lhs, const day& __rhs) noexcept
{ return month(__lhs) / __rhs; }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
month_day operator/(const day& __lhs, int __rhs) noexcept
{ return month(__rhs) / __lhs; }
@@ -99,7 +99,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr
bool operator==(const month_day_last& __lhs, const month_day_last& __rhs) noexcept
{ return __lhs.month() == __rhs.month(); }
-_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering
+_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering
operator<=>(const month_day_last& __lhs, const month_day_last& __rhs) noexcept {
return __lhs.month() <=> __rhs.month();
}
diff --git a/libcxx/include/__chrono/weekday.h b/libcxx/include/__chrono/weekday.h
index 776d8ed3124c..292fcb40dc30 100644
--- a/libcxx/include/__chrono/weekday.h
+++ b/libcxx/include/__chrono/weekday.h
@@ -85,7 +85,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr
bool operator>=(const weekday& __lhs, const weekday& __rhs) noexcept
{ return !(__lhs < __rhs); }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
weekday operator+(const weekday& __lhs, const days& __rhs) noexcept
{
auto const __mu = static_cast<long long>(__lhs.c_encoding()) + __rhs.count();
@@ -93,15 +93,15 @@ weekday operator+(const weekday& __lhs, const days& __rhs) noexcept
return weekday{static_cast<unsigned>(__mu - __yr * 7)};
}
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
weekday operator+(const days& __lhs, const weekday& __rhs) noexcept
{ return __rhs + __lhs; }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
weekday operator-(const weekday& __lhs, const days& __rhs) noexcept
{ return __lhs + -__rhs; }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
days operator-(const weekday& __lhs, const weekday& __rhs) noexcept
{
const int __wdu = __lhs.c_encoding() - __rhs.c_encoding();
diff --git a/libcxx/include/__chrono/year_month.h b/libcxx/include/__chrono/year_month.h
index f4eea8427fc5..320cf588ccd3 100644
--- a/libcxx/include/__chrono/year_month.h
+++ b/libcxx/include/__chrono/year_month.h
@@ -36,10 +36,10 @@ public:
: __y_{__yval}, __m_{__mval} {}
_LIBCPP_HIDE_FROM_ABI inline constexpr chrono::year year() const noexcept { return __y_; }
_LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __m_; }
- _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator+=(const months& __dm) noexcept { this->__m_ += __dm; return *this; }
- _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator-=(const months& __dm) noexcept { this->__m_ -= __dm; return *this; }
- _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator+=(const years& __dy) noexcept { this->__y_ += __dy; return *this; }
- _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator-=(const years& __dy) noexcept { this->__y_ -= __dy; return *this; }
+ _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator+=(const months& __dm) noexcept;
+ _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator-=(const months& __dm) noexcept;
+ _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator+=(const years& __dy) noexcept;
+ _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator-=(const years& __dy) noexcept;
_LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __y_.ok() && __m_.ok(); }
};
@@ -53,13 +53,13 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr
bool operator==(const year_month& __lhs, const year_month& __rhs) noexcept
{ return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month(); }
-_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const year_month& __lhs, const year_month& __rhs) noexcept {
+_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const year_month& __lhs, const year_month& __rhs) noexcept {
if (auto __c = __lhs.year() <=> __rhs.year(); __c != 0)
return __c;
return __lhs.month() <=> __rhs.month();
}
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
year_month operator+(const year_month& __lhs, const months& __rhs) noexcept
{
int __dmi = static_cast<int>(static_cast<unsigned>(__lhs.month())) - 1 + __rhs.count();
@@ -68,30 +68,50 @@ year_month operator+(const year_month& __lhs, const months& __rhs) noexcept
return (__lhs.year() + years(__dy)) / month(static_cast<unsigned>(__dmi));
}
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
year_month operator+(const months& __lhs, const year_month& __rhs) noexcept
{ return __rhs + __lhs; }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
year_month operator+(const year_month& __lhs, const years& __rhs) noexcept
{ return (__lhs.year() + __rhs) / __lhs.month(); }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
year_month operator+(const years& __lhs, const year_month& __rhs) noexcept
{ return __rhs + __lhs; }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
months operator-(const year_month& __lhs, const year_month& __rhs) noexcept
{ return (__lhs.year() - __rhs.year()) + months(static_cast<unsigned>(__lhs.month()) - static_cast<unsigned>(__rhs.month())); }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
year_month operator-(const year_month& __lhs, const months& __rhs) noexcept
{ return __lhs + -__rhs; }
-_LIBCPP_HIDE_FROM_ABI constexpr
+_LIBCPP_HIDE_FROM_ABI inline constexpr
year_month operator-(const year_month& __lhs, const years& __rhs) noexcept
{ return __lhs + -__rhs; }
+_LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator+=(const months& __dm) noexcept {
+ *this = *this + __dm;
+ return *this;
+}
+
+_LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator-=(const months& __dm) noexcept {
+ *this = *this - __dm;
+ return *this;
+}
+
+_LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator+=(const years& __dy) noexcept {
+ *this = *this + __dy;
+ return *this;
+}
+
+_LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator-=(const years& __dy) noexcept {
+ *this = *this - __dy;
+ return *this;
+}
+
} // namespace chrono
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__chrono/year_month_day.h b/libcxx/include/__chrono/year_month_day.h
index ed5903f7d3f6..e84d2f8a838b 100644
--- a/libcxx/include/__chrono/year_month_day.h
+++ b/libcxx/include/__chrono/year_month_day.h
@@ -110,7 +110,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr
bool operator==(const year_month_day& __lhs, const year_month_day& __rhs) noexcept
{ return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month() && __lhs.day() == __rhs.day(); }
-_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering
+_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering
operator<=>(const year_month_day& __lhs, const year_month_day& __rhs) noexcept {
if (auto __c = __lhs.year() <=> __rhs.year(); __c != 0)
return __c;
diff --git a/libcxx/include/__mdspan/mdspan.h b/libcxx/include/__mdspan/mdspan.h
index 58f3b9cf1b18..684828eb90ec 100644
--- a/libcxx/include/__mdspan/mdspan.h
+++ b/libcxx/include/__mdspan/mdspan.h
@@ -244,9 +244,14 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr const mapping_type& mapping() const noexcept { return __map_; };
_LIBCPP_HIDE_FROM_ABI constexpr const accessor_type& accessor() const noexcept { return __acc_; };
- _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() { return mapping_type::is_always_unique(); };
- _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() { return mapping_type::is_always_exhaustive(); };
- _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() { return mapping_type::is_always_strided(); };
+ // per LWG-4021 "mdspan::is_always_meow() should be noexcept"
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return mapping_type::is_always_unique(); };
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept {
+ return mapping_type::is_always_exhaustive();
+ };
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept {
+ return mapping_type::is_always_strided();
+ };
_LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const { return __map_.is_unique(); };
_LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const { return __map_.is_exhaustive(); };
diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h
index e6240dfd2580..f80beda33b11 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -32,6 +32,8 @@
#include <__ranges/view_interface.h>
#include <__type_traits/common_type.h>
#include <__type_traits/maybe_const.h>
+#include <__utility/as_lvalue.h>
+#include <__utility/empty.h>
#include <__utility/forward.h>
#include <optional>
@@ -41,10 +43,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-// Note: `join_view` is still marked experimental because there is an ABI-breaking change that affects `join_view` in
-// the pipeline (https://isocpp.org/files/papers/D2770R0.html).
-// TODO: make `join_view` non-experimental once D2770 is implemented.
-#if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
+#if _LIBCPP_STD_VER >= 20
namespace ranges {
template<class>
@@ -84,11 +83,16 @@ namespace ranges {
template <class>
friend struct std::__segmented_iterator_traits;
- static constexpr bool _UseCache = !is_reference_v<_InnerRange>;
- using _Cache = _If<_UseCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>;
- _LIBCPP_NO_UNIQUE_ADDRESS _Cache __cache_;
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
+ static constexpr bool _UseOuterCache = !forward_range<_View>;
+ using _OuterCache = _If<_UseOuterCache, __non_propagating_cache<iterator_t<_View>>, __empty_cache>;
+ _LIBCPP_NO_UNIQUE_ADDRESS _OuterCache __outer_;
+
+ static constexpr bool _UseInnerCache = !is_reference_v<_InnerRange>;
+ using _InnerCache = _If<_UseInnerCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>;
+ _LIBCPP_NO_UNIQUE_ADDRESS _InnerCache __inner_;
+
public:
_LIBCPP_HIDE_FROM_ABI
join_view() requires default_initializable<_View> = default;
@@ -105,16 +109,22 @@ namespace ranges {
_LIBCPP_HIDE_FROM_ABI
constexpr auto begin() {
- constexpr bool __use_const = __simple_view<_View> &&
- is_reference_v<range_reference_t<_View>>;
- return __iterator<__use_const>{*this, ranges::begin(__base_)};
+ if constexpr (forward_range<_View>) {
+ constexpr bool __use_const = __simple_view<_View> &&
+ is_reference_v<range_reference_t<_View>>;
+ return __iterator<__use_const>{*this, ranges::begin(__base_)};
+ } else {
+ __outer_.__emplace(ranges::begin(__base_));
+ return __iterator<false>{*this};
+ }
}
template<class _V2 = _View>
_LIBCPP_HIDE_FROM_ABI
constexpr auto begin() const
- requires input_range<const _V2> &&
- is_reference_v<range_reference_t<const _V2>>
+ requires forward_range<const _V2> &&
+ is_reference_v<range_reference_t<const _V2>> &&
+ input_range<range_reference_t<const _V2>>
{
return __iterator<true>{*this, ranges::begin(__base_)};
}
@@ -134,13 +144,12 @@ namespace ranges {
template<class _V2 = _View>
_LIBCPP_HIDE_FROM_ABI
constexpr auto end() const
- requires input_range<const _V2> &&
- is_reference_v<range_reference_t<const _V2>>
+ requires forward_range<const _V2> &&
+ is_reference_v<range_reference_t<const _V2>> &&
+ input_range<range_reference_t<const _V2>>
{
using _ConstInnerRange = range_reference_t<const _View>;
- if constexpr (forward_range<const _View> &&
- is_reference_v<_ConstInnerRange> &&
- forward_range<_ConstInnerRange> &&
+ if constexpr (forward_range<_ConstInnerRange> &&
common_range<const _View> &&
common_range<_ConstInnerRange>) {
return __iterator<true>{*this, ranges::end(__base_)};
@@ -154,12 +163,12 @@ namespace ranges {
requires view<_View> && input_range<range_reference_t<_View>>
template<bool _Const>
struct join_view<_View>::__sentinel {
- template<bool>
+ private:
+ template <bool>
friend struct __sentinel;
- private:
- using _Parent = __maybe_const<_Const, join_view<_View>>;
- using _Base = __maybe_const<_Const, _View>;
+ using _Parent = __maybe_const<_Const, join_view>;
+ using _Base = __maybe_const<_Const, _View>;
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
public:
@@ -179,7 +188,7 @@ namespace ranges {
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
_LIBCPP_HIDE_FROM_ABI
friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
- return __x.__outer_ == __y.__end_;
+ return __x.__get_outer() == __y.__end_;
}
};
@@ -191,9 +200,7 @@ namespace ranges {
template<bool _Const>
struct join_view<_View>::__iterator final
: public __join_view_iterator_category<__maybe_const<_Const, _View>> {
-
- template<bool>
- friend struct __iterator;
+ friend join_view;
template <class>
friend struct std::__segmented_iterator_traits;
@@ -207,23 +214,25 @@ namespace ranges {
using _Inner = iterator_t<range_reference_t<_Base>>;
using _InnerRange = range_reference_t<_View>;
+ static_assert(!_Const || forward_range<_Base>, "Const can only be true when Base models forward_range.");
+
static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>;
- public:
- _Outer __outer_ = _Outer();
+ static constexpr bool _OuterPresent = forward_range<_Base>;
+ using _OuterType = _If<_OuterPresent, _Outer, std::__empty>;
+ _LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType();
- private:
optional<_Inner> __inner_;
- _Parent *__parent_ = nullptr;
+ _Parent* __parent_ = nullptr;
_LIBCPP_HIDE_FROM_ABI
constexpr void __satisfy() {
- for (; __outer_ != ranges::end(__parent_->__base_); ++__outer_) {
- auto&& __inner = [&]() -> auto&& {
+ for (; __get_outer() != ranges::end(__parent_->__base_); ++__get_outer()) {
+ auto&& __inner = [this]() -> auto&& {
if constexpr (__ref_is_glvalue)
- return *__outer_;
+ return *__get_outer();
else
- return __parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__outer_; });
+ return __parent_->__inner_.__emplace_from([&]() -> decltype(auto) { return *__get_outer(); });
}();
__inner_ = ranges::begin(__inner);
if (*__inner_ != ranges::end(__inner))
@@ -234,8 +243,37 @@ namespace ranges {
__inner_.reset();
}
+ _LIBCPP_HIDE_FROM_ABI constexpr _Outer& __get_outer() {
+ if constexpr (forward_range<_Base>) {
+ return __outer_;
+ } else {
+ return *__parent_->__outer_;
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Outer& __get_outer() const {
+ if constexpr (forward_range<_Base>) {
+ return __outer_;
+ } else {
+ return *__parent_->__outer_;
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, _Outer __outer)
+ requires forward_range<_Base>
+ : __outer_(std::move(__outer)), __parent_(std::addressof(__parent)) {
+ __satisfy();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(_Parent& __parent)
+ requires(!forward_range<_Base>)
+ : __parent_(std::addressof(__parent)) {
+ __satisfy();
+ }
+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner)
- : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
+ requires forward_range<_Base>
+ : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
public:
using iterator_concept = _If<
@@ -254,15 +292,7 @@ namespace ranges {
using difference_type = common_type_t<
range_difference_t<_Base>, range_difference_t<range_reference_t<_Base>>>;
- _LIBCPP_HIDE_FROM_ABI
- __iterator() requires default_initializable<_Outer> = default;
-
- _LIBCPP_HIDE_FROM_ABI
- constexpr __iterator(_Parent& __parent, _Outer __outer)
- : __outer_(std::move(__outer))
- , __parent_(std::addressof(__parent)) {
- __satisfy();
- }
+ _LIBCPP_HIDE_FROM_ABI __iterator() = default;
_LIBCPP_HIDE_FROM_ABI
constexpr __iterator(__iterator<!_Const> __i)
@@ -287,14 +317,14 @@ namespace ranges {
_LIBCPP_HIDE_FROM_ABI
constexpr __iterator& operator++() {
- auto&& __inner = [&]() -> auto&& {
+ auto __get_inner_range = [&]() -> decltype(auto) {
if constexpr (__ref_is_glvalue)
- return *__outer_;
+ return *__get_outer();
else
- return *__parent_->__cache_;
- }();
- if (++*__inner_ == ranges::end(__inner)) {
- ++__outer_;
+ return *__parent_->__inner_;
+ };
+ if (++*__inner_ == ranges::end(std::__as_lvalue(__get_inner_range()))) {
+ ++__get_outer();
__satisfy();
}
return *this;
@@ -324,11 +354,11 @@ namespace ranges {
common_range<range_reference_t<_Base>>
{
if (__outer_ == ranges::end(__parent_->__base_))
- __inner_ = ranges::end(*--__outer_);
+ __inner_ = ranges::end(std::__as_lvalue(*--__outer_));
// Skip empty inner ranges when going backwards.
- while (*__inner_ == ranges::begin(*__outer_)) {
- __inner_ = ranges::end(*--__outer_);
+ while (*__inner_ == ranges::begin(std::__as_lvalue(*__outer_))) {
+ __inner_ = ranges::end(std::__as_lvalue(*--__outer_));
}
--*__inner_;
@@ -350,7 +380,7 @@ namespace ranges {
_LIBCPP_HIDE_FROM_ABI
friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
requires __ref_is_glvalue &&
- equality_comparable<iterator_t<_Base>> &&
+ forward_range<_Base> &&
equality_comparable<iterator_t<range_reference_t<_Base>>>
{
return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_;
@@ -436,7 +466,7 @@ struct __segmented_iterator_traits<_JoinViewIterator> {
}
};
-#endif // #if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
+#endif // #if _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__ranges/lazy_split_view.h b/libcxx/include/__ranges/lazy_split_view.h
index 2c654bfd325a..8ed4bcfdeb56 100644
--- a/libcxx/include/__ranges/lazy_split_view.h
+++ b/libcxx/include/__ranges/lazy_split_view.h
@@ -437,7 +437,7 @@ lazy_split_view(_Range&&, range_value_t<_Range>)
namespace views {
namespace __lazy_split_view {
-struct __fn : __range_adaptor_closure<__fn> {
+struct __fn {
template <class _Range, class _Pattern>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
constexpr auto operator()(_Range&& __range, _Pattern&& __pattern) const
diff --git a/libcxx/include/__ranges/split_view.h b/libcxx/include/__ranges/split_view.h
index a27ac4ef7a19..7f03be3c346a 100644
--- a/libcxx/include/__ranges/split_view.h
+++ b/libcxx/include/__ranges/split_view.h
@@ -194,7 +194,7 @@ public:
namespace views {
namespace __split_view {
-struct __fn : __range_adaptor_closure<__fn> {
+struct __fn {
// clang-format off
template <class _Range, class _Pattern>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI
diff --git a/libcxx/include/__ranges/take_view.h b/libcxx/include/__ranges/take_view.h
index 4204017d9249..518375d684ab 100644
--- a/libcxx/include/__ranges/take_view.h
+++ b/libcxx/include/__ranges/take_view.h
@@ -180,10 +180,9 @@ public:
return __lhs.count() == 0 || __lhs.base() == __rhs.__end_;
}
- template<bool _OtherConst = !_Const>
+ template <bool _OtherConst = !_Const>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- _LIBCPP_HIDE_FROM_ABI
- friend constexpr bool operator==(const _Iter<_Const>& __lhs, const __sentinel& __rhs) {
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const _Iter<_OtherConst>& __lhs, const __sentinel& __rhs) {
return __lhs.count() == 0 || __lhs.base() == __rhs.__end_;
}
};
diff --git a/libcxx/include/__utility/as_lvalue.h b/libcxx/include/__utility/as_lvalue.h
new file mode 100644
index 000000000000..159f45dad4d4
--- /dev/null
+++ b/libcxx/include/__utility/as_lvalue.h
@@ -0,0 +1,37 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_AS_LVALUE_H
+#define _LIBCPP___UTILITY_AS_LVALUE_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#ifndef _LIBCPP_CXX03_LANG
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp& __as_lvalue(_LIBCPP_LIFETIMEBOUND _Tp&& __t) {
+ return static_cast<_Tp&>(__t);
+}
+
+#endif // !_LIBCPP_CXX03_LANG
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___UTILITY_AS_LVALUE_H
diff --git a/libcxx/include/__variant/monostate.h b/libcxx/include/__variant/monostate.h
index 8fec34008f2d..2944e41ac704 100644
--- a/libcxx/include/__variant/monostate.h
+++ b/libcxx/include/__variant/monostate.h
@@ -25,25 +25,25 @@ _LIBCPP_BEGIN_NAMESPACE_STD
struct _LIBCPP_TEMPLATE_VIS monostate {};
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(monostate, monostate) noexcept { return true; }
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(monostate, monostate) noexcept { return true; }
# if _LIBCPP_STD_VER >= 20
-_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(monostate, monostate) noexcept {
+_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(monostate, monostate) noexcept {
return strong_ordering::equal;
}
# else // _LIBCPP_STD_VER >= 20
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(monostate, monostate) noexcept { return false; }
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator!=(monostate, monostate) noexcept { return false; }
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(monostate, monostate) noexcept { return false; }
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<(monostate, monostate) noexcept { return false; }
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(monostate, monostate) noexcept { return false; }
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>(monostate, monostate) noexcept { return false; }
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(monostate, monostate) noexcept { return true; }
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<=(monostate, monostate) noexcept { return true; }
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(monostate, monostate) noexcept { return true; }
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>=(monostate, monostate) noexcept { return true; }
# endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/any b/libcxx/include/any
index 516fd6ddb23c..7dcffc46a60d 100644
--- a/libcxx/include/any
+++ b/libcxx/include/any
@@ -194,9 +194,7 @@ namespace __any_imp
if (__id && *__id == typeid(_Tp))
return true;
#endif
- if (!__id && __fallback_id == __any_imp::__get_fallback_typeid<_Tp>())
- return true;
- return false;
+ return !__id && __fallback_id == __any_imp::__get_fallback_typeid<_Tp>();
}
template <class _Tp>
diff --git a/libcxx/include/array b/libcxx/include/array
index 127092f6bca9..d00bf278e635 100644
--- a/libcxx/include/array
+++ b/libcxx/include/array
@@ -131,6 +131,7 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexce
#include <__type_traits/is_same.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/remove_cv.h>
+#include <__utility/empty.h>
#include <__utility/integer_sequence.h>
#include <__utility/move.h>
#include <__utility/unreachable.h>
@@ -280,10 +281,10 @@ struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0>
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
- typedef __conditional_t<is_const<_Tp>::value, const char, char> _CharType;
+ typedef __conditional_t<is_const<_Tp>::value, const __empty, __empty> _EmptyType;
struct _ArrayInStructT { _Tp __data_[1]; };
- _ALIGNAS_TYPE(_ArrayInStructT) _CharType __elems_[sizeof(_ArrayInStructT)];
+ _ALIGNAS_TYPE(_ArrayInStructT) _EmptyType __elems_[sizeof(_ArrayInStructT)];
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17
value_type* data() _NOEXCEPT {return nullptr;}
diff --git a/libcxx/include/cmath b/libcxx/include/cmath
index 37f3c63fcef8..e8a2acf078cd 100644
--- a/libcxx/include/cmath
+++ b/libcxx/include/cmath
@@ -798,13 +798,13 @@ _Fp __lerp(_Fp __a, _Fp __b, _Fp __t) noexcept {
return __x < __b ? __x : __b;
}
-_LIBCPP_HIDE_FROM_ABI constexpr float
+_LIBCPP_HIDE_FROM_ABI inline constexpr float
lerp(float __a, float __b, float __t) _NOEXCEPT { return __lerp(__a, __b, __t); }
-_LIBCPP_HIDE_FROM_ABI constexpr double
+_LIBCPP_HIDE_FROM_ABI inline constexpr double
lerp(double __a, double __b, double __t) _NOEXCEPT { return __lerp(__a, __b, __t); }
-_LIBCPP_HIDE_FROM_ABI constexpr long double
+_LIBCPP_HIDE_FROM_ABI inline constexpr long double
lerp(long double __a, long double __b, long double __t) _NOEXCEPT { return __lerp(__a, __b, __t); }
template <class _A1, class _A2, class _A3>
diff --git a/libcxx/include/complex b/libcxx/include/complex
index 7017f25e6c5e..44579b1ad528 100644
--- a/libcxx/include/complex
+++ b/libcxx/include/complex
@@ -1503,34 +1503,34 @@ inline namespace literals
{
inline namespace complex_literals
{
- _LIBCPP_HIDE_FROM_ABI constexpr complex<long double> operator""il(long double __im)
+ _LIBCPP_HIDE_FROM_ABI inline constexpr complex<long double> operator""il(long double __im)
{
return { 0.0l, __im };
}
- _LIBCPP_HIDE_FROM_ABI constexpr complex<long double> operator""il(unsigned long long __im)
+ _LIBCPP_HIDE_FROM_ABI inline constexpr complex<long double> operator""il(unsigned long long __im)
{
return { 0.0l, static_cast<long double>(__im) };
}
- _LIBCPP_HIDE_FROM_ABI constexpr complex<double> operator""i(long double __im)
+ _LIBCPP_HIDE_FROM_ABI inline constexpr complex<double> operator""i(long double __im)
{
return { 0.0, static_cast<double>(__im) };
}
- _LIBCPP_HIDE_FROM_ABI constexpr complex<double> operator""i(unsigned long long __im)
+ _LIBCPP_HIDE_FROM_ABI inline constexpr complex<double> operator""i(unsigned long long __im)
{
return { 0.0, static_cast<double>(__im) };
}
- _LIBCPP_HIDE_FROM_ABI constexpr complex<float> operator""if(long double __im)
+ _LIBCPP_HIDE_FROM_ABI inline constexpr complex<float> operator""if(long double __im)
{
return { 0.0f, static_cast<float>(__im) };
}
- _LIBCPP_HIDE_FROM_ABI constexpr complex<float> operator""if(unsigned long long __im)
+ _LIBCPP_HIDE_FROM_ABI inline constexpr complex<float> operator""if(unsigned long long __im)
{
return { 0.0f, static_cast<float>(__im) };
}
diff --git a/libcxx/include/cstddef b/libcxx/include/cstddef
index 3844d4a37332..24be0fe78058 100644
--- a/libcxx/include/cstddef
+++ b/libcxx/include/cstddef
@@ -71,7 +71,7 @@ namespace std // purposefully not versioned
{
enum class byte : unsigned char {};
-_LIBCPP_HIDE_FROM_ABI constexpr byte operator| (byte __lhs, byte __rhs) noexcept
+_LIBCPP_HIDE_FROM_ABI inline constexpr byte operator| (byte __lhs, byte __rhs) noexcept
{
return static_cast<byte>(
static_cast<unsigned char>(
@@ -79,10 +79,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr byte operator| (byte __lhs, byte __rhs) noexce
));
}
-_LIBCPP_HIDE_FROM_ABI constexpr byte& operator|=(byte& __lhs, byte __rhs) noexcept
+_LIBCPP_HIDE_FROM_ABI inline constexpr byte& operator|=(byte& __lhs, byte __rhs) noexcept
{ return __lhs = __lhs | __rhs; }
-_LIBCPP_HIDE_FROM_ABI constexpr byte operator& (byte __lhs, byte __rhs) noexcept
+_LIBCPP_HIDE_FROM_ABI inline constexpr byte operator& (byte __lhs, byte __rhs) noexcept
{
return static_cast<byte>(
static_cast<unsigned char>(
@@ -90,10 +90,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr byte operator& (byte __lhs, byte __rhs) noexce
));
}
-_LIBCPP_HIDE_FROM_ABI constexpr byte& operator&=(byte& __lhs, byte __rhs) noexcept
+_LIBCPP_HIDE_FROM_ABI inline constexpr byte& operator&=(byte& __lhs, byte __rhs) noexcept
{ return __lhs = __lhs & __rhs; }
-_LIBCPP_HIDE_FROM_ABI constexpr byte operator^ (byte __lhs, byte __rhs) noexcept
+_LIBCPP_HIDE_FROM_ABI inline constexpr byte operator^ (byte __lhs, byte __rhs) noexcept
{
return static_cast<byte>(
static_cast<unsigned char>(
@@ -101,10 +101,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr byte operator^ (byte __lhs, byte __rhs) noexce
));
}
-_LIBCPP_HIDE_FROM_ABI constexpr byte& operator^=(byte& __lhs, byte __rhs) noexcept
+_LIBCPP_HIDE_FROM_ABI inline constexpr byte& operator^=(byte& __lhs, byte __rhs) noexcept
{ return __lhs = __lhs ^ __rhs; }
-_LIBCPP_HIDE_FROM_ABI constexpr byte operator~ (byte __b) noexcept
+_LIBCPP_HIDE_FROM_ABI inline constexpr byte operator~ (byte __b) noexcept
{
return static_cast<byte>(
static_cast<unsigned char>(
diff --git a/libcxx/include/deque b/libcxx/include/deque
index b5d094dc415d..eabcc7bd0e3c 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -440,7 +440,7 @@ public:
}
static _LIBCPP_HIDE_FROM_ABI _Iterator __compose(__segment_iterator __segment, __local_iterator __local) {
- if (__local == __end(__segment)) {
+ if (__segment && __local == __end(__segment)) {
++__segment;
return _Iterator(__segment, *__segment);
}
@@ -967,12 +967,18 @@ public:
// For more details, see the "Using libc++" documentation page or
// the documentation for __sanitizer_annotate_contiguous_container.
_LIBCPP_HIDE_FROM_ABI void __annotate_double_ended_contiguous_container(
- [[__maybe_unused__]] const void* __beg,
- [[__maybe_unused__]] const void* __end,
- [[__maybe_unused__]] const void* __old_con_beg,
- [[__maybe_unused__]] const void* __old_con_end,
- [[__maybe_unused__]] const void* __new_con_beg,
- [[__maybe_unused__]] const void* __new_con_end) const {
+ const void* __beg,
+ const void* __end,
+ const void* __old_con_beg,
+ const void* __old_con_end,
+ const void* __new_con_beg,
+ const void* __new_con_end) const {
+ (void)__beg;
+ (void)__end;
+ (void)__old_con_beg;
+ (void)__old_con_end;
+ (void)__new_con_beg;
+ (void)__new_con_end;
#ifndef _LIBCPP_HAS_NO_ASAN
if (__beg != nullptr && __asan_annotate_container_with_allocator<_Allocator>::value)
__sanitizer_annotate_double_ended_contiguous_container(
@@ -982,10 +988,14 @@ public:
_LIBCPP_HIDE_FROM_ABI
void __annotate_from_to(
- [[__maybe_unused__]] size_type __beg,
- [[__maybe_unused__]] size_type __end,
- [[__maybe_unused__]] __asan_annotation_type __annotation_type,
- [[__maybe_unused__]] __asan_annotation_place __place) const _NOEXCEPT {
+ size_type __beg,
+ size_type __end,
+ __asan_annotation_type __annotation_type,
+ __asan_annotation_place __place) const _NOEXCEPT {
+ (void)__beg;
+ (void)__end;
+ (void)__annotation_type;
+ (void)__place;
#ifndef _LIBCPP_HAS_NO_ASAN
// __beg - index of the first item to annotate
// __end - index behind the last item to annotate (so last item + 1)
diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan
index d55cdc4a4df5..c13d9eef001a 100644
--- a/libcxx/include/mdspan
+++ b/libcxx/include/mdspan
@@ -334,11 +334,12 @@ namespace std {
constexpr const mapping_type& mapping() const noexcept { return map_; }
constexpr const accessor_type& accessor() const noexcept { return acc_; }
- static constexpr bool is_always_unique()
+ // per LWG-4021 "mdspan::is_always_meow() should be noexcept"
+ static constexpr bool is_always_unique() noexcept
{ return mapping_type::is_always_unique(); }
- static constexpr bool is_always_exhaustive()
+ static constexpr bool is_always_exhaustive() noexcept
{ return mapping_type::is_always_exhaustive(); }
- static constexpr bool is_always_strided()
+ static constexpr bool is_always_strided() noexcept
{ return mapping_type::is_always_strided(); }
constexpr bool is_unique() const
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 90ee7fbb2157..5f57a8a2b1bf 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -665,6 +665,7 @@ module std_private_algorithm_find_end [system
module std_private_algorithm_find_first_of [system] { header "__algorithm/find_first_of.h" }
module std_private_algorithm_find_if [system] { header "__algorithm/find_if.h" }
module std_private_algorithm_find_if_not [system] { header "__algorithm/find_if_not.h" }
+module std_private_algorithm_find_segment_if [system] { header "__algorithm/find_segment_if.h" }
module std_private_algorithm_for_each [system] { header "__algorithm/for_each.h" }
module std_private_algorithm_for_each_n [system] { header "__algorithm/for_each_n.h" }
module std_private_algorithm_for_each_segment [system] { header "__algorithm/for_each_segment.h" }
@@ -2019,6 +2020,7 @@ module std_private_type_traits_unwrap_ref [system
module std_private_type_traits_void_t [system] { header "__type_traits/void_t.h" }
module std_private_utility_as_const [system] { header "__utility/as_const.h" }
+module std_private_utility_as_lvalue [system] { header "__utility/as_lvalue.h" }
module std_private_utility_auto_cast [system] {
header "__utility/auto_cast.h"
export std_private_type_traits_decay
diff --git a/libcxx/include/regex b/libcxx/include/regex
index fcdd85f8c499..008fe70a0ca6 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -697,6 +697,7 @@ public:
typedef const value_type* pointer;
typedef const value_type& reference;
typedef forward_iterator_tag iterator_category;
+ typedef input_iterator_tag iterator_concept; // since C++20
regex_iterator();
regex_iterator(BidirectionalIterator a, BidirectionalIterator b,
@@ -737,6 +738,7 @@ public:
typedef const value_type* pointer;
typedef const value_type& reference;
typedef forward_iterator_tag iterator_category;
+ typedef input_iterator_tag iterator_concept; // since C++20
regex_token_iterator();
regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
@@ -6407,6 +6409,9 @@ public:
typedef const value_type* pointer;
typedef const value_type& reference;
typedef forward_iterator_tag iterator_category;
+#if _LIBCPP_STD_VER >= 20
+ typedef input_iterator_tag iterator_concept;
+#endif
private:
_BidirectionalIterator __begin_;
@@ -6542,6 +6547,9 @@ public:
typedef const value_type* pointer;
typedef const value_type& reference;
typedef forward_iterator_tag iterator_category;
+#if _LIBCPP_STD_VER >= 20
+ typedef input_iterator_tag iterator_concept;
+#endif
private:
typedef regex_iterator<_BidirectionalIterator, _CharT, _Traits> _Position;
diff --git a/libcxx/include/string b/libcxx/include/string
index 9c97abefcb8d..5bb4e941af36 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -649,6 +649,17 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
+#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
+# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address")))
+// This macro disables AddressSanitizer (ASan) instrumentation for a specific function,
+// allowing memory accesses that would normally trigger ASan errors to proceed without crashing.
+// This is useful for accessing parts of objects memory, which should not be accessed,
+// such as unused bytes in short strings, that should never be accessed
+// by other parts of the program.
+#else
+# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
+#endif
+#define _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED false
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -706,6 +717,9 @@ struct __init_with_sentinel_tag {};
template<class _CharT, class _Traits, class _Allocator>
class basic_string
{
+private:
+ using __default_allocator_type = allocator<_CharT>;
+
public:
typedef basic_string __self;
typedef basic_string_view<_CharT, _Traits> __self_view;
@@ -860,6 +874,7 @@ private:
__set_long_pointer(__allocation);
__set_long_size(__size);
}
+ __annotate_new(__size);
}
template <class _Iter, class _Sent>
@@ -882,7 +897,9 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __r_(__value_init_tag(), __default_init_tag()) {}
+ : __r_(__value_init_tag(), __default_init_tag()) {
+ __annotate_new(0);
+ }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const allocator_type& __a)
#if _LIBCPP_STD_VER <= 14
@@ -890,44 +907,65 @@ public:
#else
_NOEXCEPT
#endif
- : __r_(__value_init_tag(), __a) {}
+ : __r_(__value_init_tag(), __a) {
+ __annotate_new(0);
+ }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const basic_string& __str)
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str)
: __r_(__default_init_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc())) {
if (!__str.__is_long())
+ {
__r_.first() = __str.__r_.first();
+ __annotate_new(__get_short_size());
+ }
else
__init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const basic_string& __str, const allocator_type& __a)
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str, const allocator_type& __a)
: __r_(__default_init_tag(), __a) {
if (!__str.__is_long())
+ {
__r_.first() = __str.__r_.first();
+ __annotate_new(__get_short_size());
+ }
else
__init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
}
#ifndef _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(basic_string&& __str)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ basic_string(basic_string&& __str)
# if _LIBCPP_STD_VER <= 14
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
# else
_NOEXCEPT
# endif
- : __r_(std::move(__str.__r_)) {
+ // Turning off ASan instrumentation for variable initialization with _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
+ // does not work consistently during initialization of __r_, so we instead unpoison __str's memory manually first.
+ // __str's memory needs to be unpoisoned only in the case where it's a short string.
+ : __r_( ( (__str.__is_long() ? 0 : (__str.__annotate_delete(), 0)), std::move(__str.__r_)) ) {
__str.__r_.first() = __rep();
+ __str.__annotate_new(0);
+ if(!__is_long())
+ __annotate_new(size());
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(basic_string&& __str, const allocator_type& __a)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ basic_string(basic_string&& __str, const allocator_type& __a)
: __r_(__default_init_tag(), __a) {
if (__str.__is_long() && __a != __str.__alloc()) // copy, not move
__init(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
else {
if (__libcpp_is_constant_evaluated())
__r_.first() = __rep();
+ if (!__str.__is_long())
+ __str.__annotate_delete();
__r_.first() = __str.__r_.first();
__str.__r_.first() = __rep();
+ __str.__annotate_new(0);
+ if(!__is_long() && this != &__str)
+ __annotate_new(size());
}
}
#endif // _LIBCPP_CXX03_LANG
@@ -1085,6 +1123,7 @@ public:
#endif // _LIBCPP_CXX03_LANG
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 ~basic_string() {
+ __annotate_delete();
if (__is_long())
__alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());
}
@@ -1092,7 +1131,7 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
operator __self_view() const _NOEXCEPT { return __self_view(data(), size()); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(const basic_string& __str);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& operator=(const basic_string& __str);
template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value &&
!__is_same_uncvref<_Tp, basic_string>::value, int> = 0>
@@ -1102,8 +1141,8 @@ public:
}
#ifndef _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(basic_string&& __str)
- _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
+ operator=(basic_string&& __str) _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) {
__move_assign(__str, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
return *this;
}
@@ -1116,7 +1155,7 @@ public:
#if _LIBCPP_STD_VER >= 23
basic_string& operator=(nullptr_t) = delete;
#endif
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(value_type __c);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& operator=(value_type __c);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
iterator begin() _NOEXCEPT
@@ -1339,12 +1378,22 @@ public:
void __move_assign(basic_string&& __str, size_type __pos, size_type __len) {
// Pilfer the allocation from __str.
_LIBCPP_ASSERT_INTERNAL(__alloc() == __str.__alloc(), "__move_assign called with wrong allocator");
+ size_type __old_sz = __str.size();
+ if (!__str.__is_long())
+ __str.__annotate_delete();
__r_.first() = __str.__r_.first();
__str.__r_.first() = __rep();
+ __str.__annotate_new(0);
_Traits::move(data(), data() + __pos, __len);
__set_size(__len);
_Traits::assign(data()[__len], value_type());
+
+ if (!__is_long()) {
+ __annotate_new(__len);
+ } else if(__old_sz > __len) {
+ __annotate_shrink(__old_sz);
+ }
}
#endif
@@ -1742,7 +1791,7 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend(size_type __target_capacity);
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
bool __is_long() const _NOEXCEPT {
if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__r_.first().__l.__is_long_)) {
return __r_.first().__l.__is_long_;
@@ -1782,6 +1831,7 @@ private:
value_type* __p;
if (__cap - __sz >= __n)
{
+ __annotate_increase(__n);
__p = std::__to_address(__get_pointer());
size_type __n_move = __sz - __ip;
if (__n_move != 0)
@@ -1808,7 +1858,7 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 allocator_type& __alloc() _NOEXCEPT { return __r_.second(); }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __r_.second(); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
void __set_short_size(size_type __s) _NOEXCEPT {
_LIBCPP_ASSERT_INTERNAL(
__s < __min_cap, "__s should never be greater than or equal to the short string capacity");
@@ -1816,7 +1866,7 @@ private:
__r_.first().__s.__is_long_ = false;
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
size_type __get_short_size() const _NOEXCEPT {
_LIBCPP_ASSERT_INTERNAL(
!__r_.first().__s.__is_long_, "String has to be short when trying to get the short size");
@@ -1866,6 +1916,43 @@ private:
const_pointer __get_pointer() const _NOEXCEPT
{return __is_long() ? __get_long_pointer() : __get_short_pointer();}
+ // The following functions are no-ops outside of AddressSanitizer mode.
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_contiguous_container(const void* __old_mid, const void* __new_mid) const {
+ (void)__old_mid;
+ (void)__new_mid;
+#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
+ const void* __begin = data();
+ const void* __end = data() + capacity() + 1;
+ if (!__libcpp_is_constant_evaluated() && __begin != nullptr && is_same<allocator_type, __default_allocator_type>::value)
+ __sanitizer_annotate_contiguous_container(__begin, __end, __old_mid, __new_mid);
+#endif
+ }
+
+ // ASan: short string is poisoned if and only if this function returns true.
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __asan_short_string_is_annotated() const _NOEXCEPT {
+ return _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED && !__libcpp_is_constant_evaluated();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_new(size_type __current_size) const _NOEXCEPT {
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
+ __annotate_contiguous_container(data() + capacity() + 1, data() + __current_size + 1);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_delete() const _NOEXCEPT {
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
+ __annotate_contiguous_container(data() + size() + 1, data() + capacity() + 1);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_increase(size_type __n) const _NOEXCEPT {
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
+ __annotate_contiguous_container(data() + size() + 1, data() + size() + 1 + __n);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_shrink(size_type __old_size) const _NOEXCEPT {
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
+ __annotate_contiguous_container(data() + __old_size + 1, data() + size() + 1);
+ }
+
template <size_type __a> static
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
size_type __align_it(size_type __s) _NOEXCEPT
@@ -1968,6 +2055,7 @@ private:
}
else
{
+ __annotate_delete();
allocator_type __a = __str.__alloc();
auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap());
__begin_lifetime(__allocation.ptr, __allocation.count);
@@ -1977,6 +2065,7 @@ private:
__set_long_pointer(__allocation.ptr);
__set_long_cap(__allocation.count);
__set_long_size(__str.size());
+ __annotate_new(__get_long_size());
}
}
}
@@ -1989,7 +2078,7 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void __move_assign(basic_string& __str, false_type)
_NOEXCEPT_(__alloc_traits::is_always_equal::value);
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
void __move_assign(basic_string& __str, true_type)
#if _LIBCPP_STD_VER >= 17
_NOEXCEPT;
@@ -2024,18 +2113,28 @@ private:
// Assigns the value in __s, guaranteed to be __n < __min_cap in length.
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& __assign_short(const value_type* __s, size_type __n) {
+ size_type __old_size = size();
+ if (__n > __old_size)
+ __annotate_increase(__n - __old_size);
pointer __p = __is_long()
? (__set_long_size(__n), __get_long_pointer())
: (__set_short_size(__n), __get_short_pointer());
traits_type::move(std::__to_address(__p), __s, __n);
traits_type::assign(__p[__n], value_type());
+ if (__old_size > __n)
+ __annotate_shrink(__old_size);
return *this;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string& __null_terminate_at(value_type* __p, size_type __newsz) {
+ size_type __old_size = size();
+ if (__newsz > __old_size)
+ __annotate_increase(__newsz - __old_size);
__set_size(__newsz);
traits_type::assign(__p[__newsz], value_type());
+ if (__old_size > __newsz)
+ __annotate_shrink(__old_size);
return *this;
}
@@ -2142,6 +2241,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s,
}
traits_type::copy(std::__to_address(__p), __s, __sz);
traits_type::assign(__p[__sz], value_type());
+ __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2170,6 +2270,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_ty
}
traits_type::copy(std::__to_address(__p), __s, __sz);
traits_type::assign(__p[__sz], value_type());
+ __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2194,6 +2295,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(
__set_long_size(__sz);
}
traits_type::copy(std::__to_address(__p), __s, __sz + 1);
+ __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2223,6 +2325,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c)
}
traits_type::assign(std::__to_address(__p), __n, __c);
traits_type::assign(__p[__n], value_type());
+ __annotate_new(__n);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2238,6 +2341,7 @@ template <class _InputIterator, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputIterator __first, _Sentinel __last) {
__r_.first() = __rep();
+ __annotate_new(0);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
@@ -2249,6 +2353,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputItera
}
catch (...)
{
+ __annotate_delete();
if (__is_long())
__alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());
throw;
@@ -2309,6 +2414,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_with_size(
throw;
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
+ __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2325,6 +2431,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
size_type __cap = __old_cap < __ms / 2 - __alignment ?
__recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) :
__ms - 1;
+ __annotate_delete();
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
pointer __p = __allocation.ptr;
__begin_lifetime(__p, __allocation.count);
@@ -2344,6 +2451,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
__old_sz = __n_copy + __n_add + __sec_cp_sz;
__set_long_size(__old_sz);
traits_type::assign(__p[__old_sz], value_type());
+ __annotate_new(__old_cap + __delta_cap);
}
// __grow_by is deprecated because it does not set the size. It may not update the size when the size is changed, and it
@@ -2366,6 +2474,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t
size_type __cap = __old_cap < __ms / 2 - __alignment ?
__recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) :
__ms - 1;
+ __annotate_delete();
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
pointer __p = __allocation.ptr;
__begin_lifetime(__p, __allocation.count);
@@ -2396,6 +2505,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace(
__grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add);
_LIBCPP_SUPPRESS_DEPRECATED_POP
__set_long_size(__old_sz - __n_del + __n_add);
+ __annotate_new(__old_sz - __n_del + __n_add);
}
// assign
@@ -2408,10 +2518,15 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias(
const value_type* __s, size_type __n) {
size_type __cap = __is_short ? static_cast<size_type>(__min_cap) : __get_long_cap();
if (__n < __cap) {
+ size_type __old_size = __is_short ? __get_short_size() : __get_long_size();
+ if (__n > __old_size)
+ __annotate_increase(__n - __old_size);
pointer __p = __is_short ? __get_short_pointer() : __get_long_pointer();
__is_short ? __set_short_size(__n) : __set_long_size(__n);
traits_type::copy(std::__to_address(__p), __s, __n);
traits_type::assign(__p[__n], value_type());
+ if (__old_size > __n)
+ __annotate_shrink(__old_size);
} else {
size_type __sz = __is_short ? __get_short_size() : __get_long_size();
__grow_by_and_replace(__cap - 1, __n - __cap + 1, __sz, 0, __sz, __n, __s);
@@ -2426,6 +2541,9 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_external(
const value_type* __s, size_type __n) {
size_type __cap = capacity();
if (__cap >= __n) {
+ size_type __old_size = size();
+ if (__n > __old_size)
+ __annotate_increase(__n - __old_size);
value_type* __p = std::__to_address(__get_pointer());
traits_type::move(__p, __s, __n);
return __null_terminate_at(__p, __n);
@@ -2453,11 +2571,15 @@ basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c)
{
size_type __cap = capacity();
+ size_type __old_size = size();
if (__cap < __n)
{
size_type __sz = size();
__grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz);
+ __annotate_increase(__n);
}
+ else if(__n > __old_size)
+ __annotate_increase(__n - __old_size);
value_type* __p = std::__to_address(__get_pointer());
traits_type::assign(__p, __n, __c);
return __null_terminate_at(__p, __n);
@@ -2468,24 +2590,26 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::operator=(value_type __c)
{
- pointer __p;
- if (__is_long())
- {
- __p = __get_long_pointer();
- __set_long_size(1);
- }
- else
- {
- __p = __get_short_pointer();
- __set_short_size(1);
- }
- traits_type::assign(*__p, __c);
- traits_type::assign(*++__p, value_type());
- return *this;
+ pointer __p;
+ size_type __old_size = size();
+ if (__old_size == 0)
+ __annotate_increase(1);
+ if (__is_long()) {
+ __p = __get_long_pointer();
+ __set_long_size(1);
+ } else {
+ __p = __get_short_pointer();
+ __set_short_size(1);
+ }
+ traits_type::assign(*__p, __c);
+ traits_type::assign(*++__p, value_type());
+ if (__old_size > 1)
+ __annotate_shrink(__old_size);
+ return *this;
}
template <class _CharT, class _Traits, class _Allocator>
-_LIBCPP_CONSTEXPR_SINCE_CXX20
+_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str)
{
@@ -2493,7 +2617,12 @@ basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str)
__copy_assign_alloc(__str);
if (!__is_long()) {
if (!__str.__is_long()) {
+ size_type __old_size = __get_short_size();
+ if (__get_short_size() < __str.__get_short_size())
+ __annotate_increase(__str.__get_short_size() - __get_short_size());
__r_.first() = __str.__r_.first();
+ if (__old_size > __get_short_size())
+ __annotate_shrink(__old_size);
} else {
return __assign_no_alias<true>(__str.data(), __str.size());
}
@@ -2519,7 +2648,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, fa
}
template <class _CharT, class _Traits, class _Allocator>
-inline _LIBCPP_CONSTEXPR_SINCE_CXX20
+inline _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
void
basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, true_type)
#if _LIBCPP_STD_VER >= 17
@@ -2528,6 +2657,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
#endif
{
+ __annotate_delete();
if (__is_long()) {
__alloc_traits::deallocate(__alloc(), __get_long_pointer(),
__get_long_cap());
@@ -2535,13 +2665,35 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr
if (!is_nothrow_move_assignable<allocator_type>::value) {
__set_short_size(0);
traits_type::assign(__get_short_pointer()[0], value_type());
+ __annotate_new(0);
}
#endif
}
+ size_type __str_old_size = __str.size();
+ bool __str_was_short = !__str.__is_long();
+
__move_assign_alloc(__str);
__r_.first() = __str.__r_.first();
__str.__set_short_size(0);
traits_type::assign(__str.__get_short_pointer()[0], value_type());
+
+ if (__str_was_short && this != &__str)
+ __str.__annotate_shrink(__str_old_size);
+ else
+ // ASan annotations: was long, so object memory is unpoisoned as new.
+ // Or is same as *this, and __annotate_delete() was called.
+ __str.__annotate_new(0);
+
+ // ASan annotations: Guard against `std::string s; s = std::move(s);`
+ // You can find more here: https://en.cppreference.com/w/cpp/utility/move
+ // Quote: "Unless otherwise specified, all standard library objects that have been moved
+ // from are placed in a "valid but unspecified state", meaning the object's class
+ // invariants hold (so functions without preconditions, such as the assignment operator,
+ // can be safely used on the object after it was moved from):"
+ // Quote: "v = std::move(v); // the value of v is unspecified"
+ if (!__is_long() && &__str != this)
+ // If it is long string, delete was never called on original __str's buffer.
+ __annotate_new(__get_short_size());
}
#endif
@@ -2587,6 +2739,7 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _
_LIBCPP_ASSERT_INTERNAL(
__string_is_trivial_iterator<_Iterator>::value, "The iterator type given to `__assign_trivial` must be trivial");
+ size_type __old_size = size();
size_type __cap = capacity();
if (__cap < __n) {
// Unlike `append` functions, if the input range points into the string itself, there is no case that the input
@@ -2597,12 +2750,17 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _
// object itself stays valid even if reallocation happens.
size_type __sz = size();
__grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz);
+ __annotate_increase(__n);
}
+ else if (__n > __old_size)
+ __annotate_increase(__n - __old_size);
pointer __p = __get_pointer();
for (; __first != __last; ++__p, (void) ++__first)
traits_type::assign(*__p, *__first);
traits_type::assign(*__p, value_type());
__set_size(__n);
+ if (__n < __old_size)
+ __annotate_shrink(__old_size);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2663,6 +2821,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_ty
{
if (__n)
{
+ __annotate_increase(__n);
value_type* __p = std::__to_address(__get_pointer());
traits_type::copy(__p + __sz, __s, __n);
__sz += __n;
@@ -2686,6 +2845,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c)
size_type __sz = size();
if (__cap - __sz < __n)
__grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
+ __annotate_increase(__n);
pointer __p = __get_pointer();
traits_type::assign(std::__to_address(__p) + __sz, __n, __c);
__sz += __n;
@@ -2705,6 +2865,7 @@ basic_string<_CharT, _Traits, _Allocator>::__append_default_init(size_type __n)
size_type __sz = size();
if (__cap - __sz < __n)
__grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
+ __annotate_increase(__n);
pointer __p = __get_pointer();
__sz += __n;
__set_size(__sz);
@@ -2733,8 +2894,10 @@ basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c)
if (__sz == __cap)
{
__grow_by_without_replace(__cap, 1, __sz, __sz, 0);
+ __annotate_increase(1);
__is_short = false; // the string is always long after __grow_by
- }
+ } else
+ __annotate_increase(1);
pointer __p = __get_pointer();
if (__is_short)
{
@@ -2766,6 +2929,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(
{
if (__cap - __sz < __n)
__grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
+ __annotate_increase(__n);
pointer __p = __get_pointer() + __sz;
for (; __first != __last; ++__p, (void) ++__first)
traits_type::assign(*__p, *__first);
@@ -2831,6 +2995,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_t
{
if (__n)
{
+ __annotate_increase(__n);
value_type* __p = std::__to_address(__get_pointer());
size_type __n_move = __sz - __pos;
if (__n_move != 0)
@@ -2864,6 +3029,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, size_type __n
value_type* __p;
if (__cap - __sz >= __n)
{
+ __annotate_increase(__n);
__p = std::__to_address(__get_pointer());
size_type __n_move = __sz - __pos;
if (__n_move != 0)
@@ -2972,6 +3138,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, value_ty
}
else
{
+ __annotate_increase(1);
__p = std::__to_address(__get_pointer());
size_type __n_move = __sz - __ip;
if (__n_move != 0)
@@ -3002,6 +3169,8 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __
value_type* __p = std::__to_address(__get_pointer());
if (__n1 != __n2)
{
+ if (__n2 > __n1)
+ __annotate_increase(__n2 - __n1);
size_type __n_move = __sz - __pos - __n1;
if (__n_move != 0)
{
@@ -3046,20 +3215,18 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __
__n1 = std::min(__n1, __sz - __pos);
size_type __cap = capacity();
value_type* __p;
- if (__cap - __sz + __n1 >= __n2)
- {
- __p = std::__to_address(__get_pointer());
- if (__n1 != __n2)
- {
- size_type __n_move = __sz - __pos - __n1;
- if (__n_move != 0)
- traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move);
- }
- }
- else
- {
- __grow_by_without_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2);
- __p = std::__to_address(__get_long_pointer());
+ if (__cap - __sz + __n1 >= __n2) {
+ __p = std::__to_address(__get_pointer());
+ if (__n1 != __n2) {
+ if (__n2 > __n1)
+ __annotate_increase(__n2 - __n1);
+ size_type __n_move = __sz - __pos - __n1;
+ if (__n_move != 0)
+ traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move);
+ }
+ } else {
+ __grow_by_without_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2);
+ __p = std::__to_address(__get_long_pointer());
}
traits_type::assign(__p + __pos, __n2, __c);
return __null_terminate_at(__p, __sz - (__n1 - __n2));
@@ -3187,6 +3354,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20
void
basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT
{
+ size_type __old_size = size();
if (__is_long())
{
traits_type::assign(*__get_long_pointer(), value_type());
@@ -3197,6 +3365,7 @@ basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT
traits_type::assign(*__get_short_pointer(), value_type());
__set_short_size(0);
}
+ __annotate_shrink(__old_size);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -3259,6 +3428,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20
void
basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity)
{
+ __annotate_delete();
size_type __cap = capacity();
size_type __sz = size();
@@ -3315,6 +3485,7 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
}
else
__set_short_size(__sz);
+ __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -3365,8 +3536,16 @@ basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str)
__alloc_traits::propagate_on_container_swap::value ||
__alloc_traits::is_always_equal::value ||
__alloc() == __str.__alloc(), "swapping non-equal allocators");
+ if (!__is_long())
+ __annotate_delete();
+ if (this != &__str && !__str.__is_long())
+ __str.__annotate_delete();
std::swap(__r_.first(), __str.__r_.first());
std::__swap_allocator(__alloc(), __str.__alloc());
+ if (!__is_long())
+ __annotate_new(__get_short_size());
+ if (this != &__str && !__str.__is_long())
+ __str.__annotate_new(__str.__get_short_size());
}
// find
@@ -3854,12 +4033,12 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20
void
basic_string<_CharT, _Traits, _Allocator>::__clear_and_shrink() _NOEXCEPT
{
- clear();
- if(__is_long())
- {
- __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1);
- __r_.first() = __rep();
- }
+ clear();
+ if (__is_long()) {
+ __annotate_delete();
+ __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1);
+ __r_.first() = __rep();
+ }
}
// operator==
diff --git a/libcxx/include/typeindex b/libcxx/include/typeindex
index a3571e2ea04a..36bf90722c21 100644
--- a/libcxx/include/typeindex
+++ b/libcxx/include/typeindex
@@ -70,8 +70,8 @@ public:
_LIBCPP_HIDE_FROM_ABI
bool operator==(const type_index& __y) const _NOEXCEPT
{return *__t_ == *__y.__t_;}
- _LIBCPP_HIDE_FROM_ABI
#if _LIBCPP_STD_VER <= 17
+ _LIBCPP_HIDE_FROM_ABI
bool operator!=(const type_index& __y) const _NOEXCEPT
{return *__t_ != *__y.__t_;}
#endif
diff --git a/libcxx/include/utility b/libcxx/include/utility
index c5581d55e79b..1deef3db2041 100644
--- a/libcxx/include/utility
+++ b/libcxx/include/utility
@@ -249,6 +249,7 @@ template <class T>
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <__utility/as_const.h>
+#include <__utility/as_lvalue.h>
#include <__utility/auto_cast.h>
#include <__utility/cmp.h>
#include <__utility/declval.h>
diff --git a/libcxx/include/vector b/libcxx/include/vector
index fd2d5e11f0ea..d010a1f6ec9f 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -852,11 +852,15 @@ private:
// the documentation for __sanitizer_annotate_contiguous_container.
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
- void __annotate_contiguous_container([[__maybe_unused__]] const void *__beg,
- [[__maybe_unused__]] const void *__end,
- [[__maybe_unused__]] const void *__old_mid,
- [[__maybe_unused__]] const void *__new_mid) const
- {
+ void __annotate_contiguous_container(const void *__beg,
+ const void *__end,
+ const void *__old_mid,
+ const void *__new_mid) const
+ {
+ (void)__beg;
+ (void)__end;
+ (void)__old_mid;
+ (void)__new_mid;
#ifndef _LIBCPP_HAS_NO_ASAN
if (!__libcpp_is_constant_evaluated() && __beg != nullptr && __asan_annotate_container_with_allocator<_Allocator>::value)
__sanitizer_annotate_contiguous_container(__beg, __end, __old_mid, __new_mid);
diff --git a/libcxx/modules/std.compat.cppm.in b/libcxx/modules/std.compat.cppm.in
new file mode 100644
index 000000000000..f199e194e60b
--- /dev/null
+++ b/libcxx/modules/std.compat.cppm.in
@@ -0,0 +1,208 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING, this entire header is generated by
+// utils/generate_libcxx_cppm_in.py
+// DO NOT MODIFY!
+
+module;
+
+#include <__config>
+
+// The headers of Table 24: C++ library headers [tab:headers.cpp]
+// and the headers of Table 25: C++ headers for C library facilities [tab:headers.cpp.c]
+#include <algorithm>
+#include <any>
+#include <array>
+#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
+# include <atomic>
+#endif
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <barrier>
+#endif
+#include <bit>
+#include <bitset>
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+#include <cfenv>
+#include <cfloat>
+#include <charconv>
+#include <chrono>
+#include <cinttypes>
+#include <climits>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <clocale>
+#endif
+#include <cmath>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <codecvt>
+#endif
+#include <compare>
+#include <complex>
+#include <concepts>
+#include <condition_variable>
+#include <coroutine>
+#include <csetjmp>
+#include <csignal>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <cuchar>
+#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
+# include <cwchar>
+#endif
+#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
+# include <cwctype>
+#endif
+#include <deque>
+#include <exception>
+#include <execution>
+#include <expected>
+#include <filesystem>
+#include <format>
+#include <forward_list>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <fstream>
+#endif
+#include <functional>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <future>
+#endif
+#include <initializer_list>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <iomanip>
+#endif
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <ios>
+#endif
+#include <iosfwd>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <iostream>
+#endif
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <istream>
+#endif
+#include <iterator>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <latch>
+#endif
+#include <limits>
+#include <list>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <locale>
+#endif
+#include <map>
+#include <mdspan>
+#include <memory>
+#include <memory_resource>
+#include <mutex>
+#include <new>
+#include <numbers>
+#include <numeric>
+#include <optional>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <ostream>
+#endif
+#include <print>
+#include <queue>
+#include <random>
+#include <ranges>
+#include <ratio>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <regex>
+#endif
+#include <scoped_allocator>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <semaphore>
+#endif
+#include <set>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <shared_mutex>
+#endif
+#include <source_location>
+#include <span>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <sstream>
+#endif
+#include <stack>
+#include <stdexcept>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <stop_token>
+#endif
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <streambuf>
+#endif
+#include <string>
+#include <string_view>
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <strstream>
+#endif
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <syncstream>
+#endif
+#include <system_error>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+# include <thread>
+#endif
+#include <tuple>
+#include <type_traits>
+#include <typeindex>
+#include <typeinfo>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <valarray>
+#include <variant>
+#include <vector>
+#include <version>
+
+// *** Headers not yet available ***
+#if __has_include(<debugging>)
+# error "please update the header information for <debugging> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<debugging>)
+#if __has_include(<flat_map>)
+# error "please update the header information for <flat_map> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<flat_map>)
+#if __has_include(<flat_set>)
+# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<flat_set>)
+#if __has_include(<generator>)
+# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<generator>)
+#if __has_include(<hazard_pointer>)
+# error "please update the header information for <hazard_pointer> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<hazard_pointer>)
+#if __has_include(<linalg>)
+# error "please update the header information for <linalg> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<linalg>)
+#if __has_include(<rcu>)
+# error "please update the header information for <rcu> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<rcu>)
+#if __has_include(<spanstream>)
+# error "please update the header information for <spanstream> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<spanstream>)
+#if __has_include(<stacktrace>)
+# error "please update the header information for <stacktrace> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<stacktrace>)
+#if __has_include(<stdfloat>)
+# error "please update the header information for <stdfloat> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<stdfloat>)
+#if __has_include(<text_encoding>)
+# error "please update the header information for <text_encoding> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<text_encoding>)
+
+export module std.compat;
+
+@LIBCXX_MODULE_STD_INCLUDE_SOURCES@
+@LIBCXX_MODULE_STD_COMPAT_INCLUDE_SOURCES@ \ No newline at end of file
diff --git a/libcxx/modules/std.compat/cassert.inc b/libcxx/modules/std.compat/cassert.inc
new file mode 100644
index 000000000000..ac0533d14e9a
--- /dev/null
+++ b/libcxx/modules/std.compat/cassert.inc
@@ -0,0 +1,12 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // This module exports nothing.
+} // export
diff --git a/libcxx/modules/std.compat/cctype.inc b/libcxx/modules/std.compat/cctype.inc
new file mode 100644
index 000000000000..56fb45a374a5
--- /dev/null
+++ b/libcxx/modules/std.compat/cctype.inc
@@ -0,0 +1,25 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::isalnum;
+ using ::isalpha;
+ using ::isblank;
+ using ::iscntrl;
+ using ::isdigit;
+ using ::isgraph;
+ using ::islower;
+ using ::isprint;
+ using ::ispunct;
+ using ::isspace;
+ using ::isupper;
+ using ::isxdigit;
+ using ::tolower;
+ using ::toupper;
+} // export
diff --git a/libcxx/modules/std.compat/cerrno.inc b/libcxx/modules/std.compat/cerrno.inc
new file mode 100644
index 000000000000..ac0533d14e9a
--- /dev/null
+++ b/libcxx/modules/std.compat/cerrno.inc
@@ -0,0 +1,12 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // This module exports nothing.
+} // export
diff --git a/libcxx/modules/std.compat/cfenv.inc b/libcxx/modules/std.compat/cfenv.inc
new file mode 100644
index 000000000000..50128463d6a9
--- /dev/null
+++ b/libcxx/modules/std.compat/cfenv.inc
@@ -0,0 +1,29 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // types
+ using ::fenv_t;
+ using ::fexcept_t;
+
+ // functions
+ using ::feclearexcept;
+ using ::fegetexceptflag;
+ using ::feraiseexcept;
+ using ::fesetexceptflag;
+ using ::fetestexcept;
+
+ using ::fegetround;
+ using ::fesetround;
+
+ using ::fegetenv;
+ using ::feholdexcept;
+ using ::fesetenv;
+ using ::feupdateenv;
+} // export
diff --git a/libcxx/modules/std.compat/cfloat.inc b/libcxx/modules/std.compat/cfloat.inc
new file mode 100644
index 000000000000..ac0533d14e9a
--- /dev/null
+++ b/libcxx/modules/std.compat/cfloat.inc
@@ -0,0 +1,12 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // This module exports nothing.
+} // export
diff --git a/libcxx/modules/std.compat/cinttypes.inc b/libcxx/modules/std.compat/cinttypes.inc
new file mode 100644
index 000000000000..a64c088d0d6f
--- /dev/null
+++ b/libcxx/modules/std.compat/cinttypes.inc
@@ -0,0 +1,25 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::imaxdiv_t;
+
+ using ::imaxabs;
+ using ::imaxdiv;
+ using ::strtoimax;
+ using ::strtoumax;
+ using ::wcstoimax;
+ using ::wcstoumax;
+
+ // abs is conditionally here, but always present in cmath.cppm. To avoid
+ // conflicing declarations omit the using here.
+
+ // div is conditionally here, but always present in cstdlib.cppm. To avoid
+ // conflicing declarations omit the using here.
+} // export
diff --git a/libcxx/modules/std.compat/climits.inc b/libcxx/modules/std.compat/climits.inc
new file mode 100644
index 000000000000..ac0533d14e9a
--- /dev/null
+++ b/libcxx/modules/std.compat/climits.inc
@@ -0,0 +1,12 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // This module exports nothing.
+} // export
diff --git a/libcxx/modules/std.compat/clocale.inc b/libcxx/modules/std.compat/clocale.inc
new file mode 100644
index 000000000000..d9785a737943
--- /dev/null
+++ b/libcxx/modules/std.compat/clocale.inc
@@ -0,0 +1,17 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ using ::lconv;
+
+ using ::localeconv;
+ using ::setlocale;
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+} // export
diff --git a/libcxx/modules/std.compat/cmath.inc b/libcxx/modules/std.compat/cmath.inc
new file mode 100644
index 000000000000..de5379275c5f
--- /dev/null
+++ b/libcxx/modules/std.compat/cmath.inc
@@ -0,0 +1,268 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::double_t;
+ using ::float_t;
+
+ using ::acos;
+ using ::acosf;
+ using ::acosl;
+
+ using ::asin;
+ using ::asinf;
+ using ::asinl;
+
+ using ::atan;
+ using ::atanf;
+ using ::atanl;
+
+ using ::atan2;
+ using ::atan2f;
+ using ::atan2l;
+
+ using ::cos;
+ using ::cosf;
+ using ::cosl;
+
+ using ::sin;
+ using ::sinf;
+ using ::sinl;
+
+ using ::tan;
+ using ::tanf;
+ using ::tanl;
+
+ using ::acosh;
+ using ::acoshf;
+ using ::acoshl;
+
+ using ::asinh;
+ using ::asinhf;
+ using ::asinhl;
+
+ using ::atanh;
+ using ::atanhf;
+ using ::atanhl;
+
+ using ::cosh;
+ using ::coshf;
+ using ::coshl;
+
+ using ::sinh;
+ using ::sinhf;
+ using ::sinhl;
+
+ using ::tanh;
+ using ::tanhf;
+ using ::tanhl;
+
+ using ::exp;
+ using ::expf;
+ using ::expl;
+
+ using ::exp2;
+ using ::exp2f;
+ using ::exp2l;
+
+ using ::expm1;
+ using ::expm1f;
+ using ::expm1l;
+
+ using ::frexp;
+ using ::frexpf;
+ using ::frexpl;
+
+ using ::ilogb;
+ using ::ilogbf;
+ using ::ilogbl;
+
+ using ::ldexp;
+ using ::ldexpf;
+ using ::ldexpl;
+
+ using ::log;
+ using ::logf;
+ using ::logl;
+
+ using ::log10;
+ using ::log10f;
+ using ::log10l;
+
+ using ::log1p;
+ using ::log1pf;
+ using ::log1pl;
+
+ using ::log2;
+ using ::log2f;
+ using ::log2l;
+
+ using ::logb;
+ using ::logbf;
+ using ::logbl;
+
+ using ::modf;
+ using ::modff;
+ using ::modfl;
+
+ using ::scalbn;
+ using ::scalbnf;
+ using ::scalbnl;
+
+ using ::scalbln;
+ using ::scalblnf;
+ using ::scalblnl;
+
+ using ::cbrt;
+ using ::cbrtf;
+ using ::cbrtl;
+
+ // [c.math.abs], absolute values
+ using ::abs;
+
+ using ::fabs;
+ using ::fabsf;
+ using ::fabsl;
+
+ using ::hypot;
+ using ::hypotf;
+ using ::hypotl;
+
+ // [c.math.hypot3], three-dimensional hypotenuse
+
+ using ::pow;
+ using ::powf;
+ using ::powl;
+
+ using ::sqrt;
+ using ::sqrtf;
+ using ::sqrtl;
+
+ using ::erf;
+ using ::erff;
+ using ::erfl;
+
+ using ::erfc;
+ using ::erfcf;
+ using ::erfcl;
+
+ using ::lgamma;
+ using ::lgammaf;
+ using ::lgammal;
+
+ using ::tgamma;
+ using ::tgammaf;
+ using ::tgammal;
+
+ using ::ceil;
+ using ::ceilf;
+ using ::ceill;
+
+ using ::floor;
+ using ::floorf;
+ using ::floorl;
+
+ using ::nearbyint;
+ using ::nearbyintf;
+ using ::nearbyintl;
+
+ using ::rint;
+ using ::rintf;
+ using ::rintl;
+
+ using ::lrint;
+ using ::lrintf;
+ using ::lrintl;
+
+ using ::llrint;
+ using ::llrintf;
+ using ::llrintl;
+
+ using ::round;
+ using ::roundf;
+ using ::roundl;
+
+ using ::lround;
+ using ::lroundf;
+ using ::lroundl;
+
+ using ::llround;
+ using ::llroundf;
+ using ::llroundl;
+
+ using ::trunc;
+ using ::truncf;
+ using ::truncl;
+
+ using ::fmod;
+ using ::fmodf;
+ using ::fmodl;
+
+ using ::remainder;
+ using ::remainderf;
+ using ::remainderl;
+
+ using ::remquo;
+ using ::remquof;
+ using ::remquol;
+
+ using ::copysign;
+ using ::copysignf;
+ using ::copysignl;
+
+ using ::nan;
+ using ::nanf;
+ using ::nanl;
+
+ using ::nextafter;
+ using ::nextafterf;
+ using ::nextafterl;
+
+ using ::nexttoward;
+ using ::nexttowardf;
+ using ::nexttowardl;
+
+ using ::fdim;
+ using ::fdimf;
+ using ::fdiml;
+
+ using ::fmax;
+ using ::fmaxf;
+ using ::fmaxl;
+
+ using ::fmin;
+ using ::fminf;
+ using ::fminl;
+
+ using ::fma;
+ using ::fmaf;
+ using ::fmal;
+
+ // [c.math.lerp], linear interpolation
+ // [support.c.headers.other]/1
+ // ... placed within the global namespace scope, except for the functions
+ // described in [sf.cmath], the std::lerp function overloads ([c.math.lerp])
+ // ...
+
+ // [c.math.fpclass], classification / comparison functions
+ using ::fpclassify;
+ using ::isfinite;
+ using ::isgreater;
+ using ::isgreaterequal;
+ using ::isinf;
+ using ::isless;
+ using ::islessequal;
+ using ::islessgreater;
+ using ::isnan;
+ using ::isnormal;
+ using ::isunordered;
+ using ::signbit;
+
+ // [sf.cmath], mathematical special functions
+} // export
diff --git a/libcxx/modules/std.compat/csetjmp.inc b/libcxx/modules/std.compat/csetjmp.inc
new file mode 100644
index 000000000000..1fc42ea3ee03
--- /dev/null
+++ b/libcxx/modules/std.compat/csetjmp.inc
@@ -0,0 +1,13 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::jmp_buf;
+ using ::longjmp;
+} // export
diff --git a/libcxx/modules/std.compat/csignal.inc b/libcxx/modules/std.compat/csignal.inc
new file mode 100644
index 000000000000..33af6a9f2b73
--- /dev/null
+++ b/libcxx/modules/std.compat/csignal.inc
@@ -0,0 +1,17 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::sig_atomic_t;
+
+ // [support.signal], signal handlers
+ using ::signal;
+
+ using ::raise;
+} // export
diff --git a/libcxx/modules/std.compat/cstdarg.inc b/libcxx/modules/std.compat/cstdarg.inc
new file mode 100644
index 000000000000..3efb34617a8b
--- /dev/null
+++ b/libcxx/modules/std.compat/cstdarg.inc
@@ -0,0 +1,10 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export { using ::va_list; } // export
diff --git a/libcxx/modules/std.compat/cstddef.inc b/libcxx/modules/std.compat/cstddef.inc
new file mode 100644
index 000000000000..94ad036fd8f4
--- /dev/null
+++ b/libcxx/modules/std.compat/cstddef.inc
@@ -0,0 +1,22 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::max_align_t;
+ using ::nullptr_t;
+ using ::ptrdiff_t;
+ using ::size_t;
+
+ // [support.c.headers]/1
+ // ... placed within the global namespace scope, except for ... the
+ // declaration of std::byte ([cstddef.syn]), and the functions and
+ // function templates described in [support.types.byteops]. ...
+
+ // [support.types.byteops], byte type operations
+} // export
diff --git a/libcxx/modules/std.compat/cstdint.inc b/libcxx/modules/std.compat/cstdint.inc
new file mode 100644
index 000000000000..1a74efc70cea
--- /dev/null
+++ b/libcxx/modules/std.compat/cstdint.inc
@@ -0,0 +1,50 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // signed
+ using ::int8_t _LIBCPP_USING_IF_EXISTS;
+ using ::int16_t _LIBCPP_USING_IF_EXISTS;
+ using ::int32_t _LIBCPP_USING_IF_EXISTS;
+ using ::int64_t _LIBCPP_USING_IF_EXISTS;
+
+ using ::int_fast16_t;
+ using ::int_fast32_t;
+ using ::int_fast64_t;
+ using ::int_fast8_t;
+
+ using ::int_least16_t;
+ using ::int_least32_t;
+ using ::int_least64_t;
+ using ::int_least8_t;
+
+ using ::intmax_t;
+
+ using ::intptr_t _LIBCPP_USING_IF_EXISTS;
+
+ // unsigned
+ using ::uint8_t _LIBCPP_USING_IF_EXISTS;
+ using ::uint16_t _LIBCPP_USING_IF_EXISTS;
+ using ::uint32_t _LIBCPP_USING_IF_EXISTS;
+ using ::uint64_t _LIBCPP_USING_IF_EXISTS;
+
+ using ::uint_fast16_t;
+ using ::uint_fast32_t;
+ using ::uint_fast64_t;
+ using ::uint_fast8_t;
+
+ using ::uint_least16_t;
+ using ::uint_least32_t;
+ using ::uint_least64_t;
+ using ::uint_least8_t;
+
+ using ::uintmax_t;
+
+ using ::uintptr_t _LIBCPP_USING_IF_EXISTS;
+} // export
diff --git a/libcxx/modules/std.compat/cstdio.inc b/libcxx/modules/std.compat/cstdio.inc
new file mode 100644
index 000000000000..1ec3015c9e2a
--- /dev/null
+++ b/libcxx/modules/std.compat/cstdio.inc
@@ -0,0 +1,61 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::FILE;
+ using ::fpos_t;
+ using ::size_t;
+
+ using ::clearerr;
+ using ::fclose;
+ using ::feof;
+ using ::ferror;
+ using ::fflush;
+ using ::fgetc;
+ using ::fgetpos;
+ using ::fgets;
+ using ::fopen;
+ using ::fprintf;
+ using ::fputc;
+ using ::fputs;
+ using ::fread;
+ using ::freopen;
+ using ::fscanf;
+ using ::fseek;
+ using ::fsetpos;
+ using ::ftell;
+ using ::fwrite;
+ using ::getc;
+ using ::getchar;
+ using ::perror;
+ using ::printf;
+ using ::putc;
+ using ::putchar;
+ using ::puts;
+ using ::remove;
+ using ::rename;
+ using ::rewind;
+ using ::scanf;
+ using ::setbuf;
+ using ::setvbuf;
+ using ::snprintf;
+ using ::sprintf;
+ using ::sscanf;
+ using ::tmpfile;
+ using ::tmpnam;
+ using ::ungetc;
+ using ::vfprintf;
+ using ::vfscanf;
+ using ::vprintf;
+ using ::vscanf;
+ using ::vsnprintf;
+ using ::vsprintf;
+ using ::vsscanf;
+
+} // export
diff --git a/libcxx/modules/std.compat/cstdlib.inc b/libcxx/modules/std.compat/cstdlib.inc
new file mode 100644
index 000000000000..9333d8487071
--- /dev/null
+++ b/libcxx/modules/std.compat/cstdlib.inc
@@ -0,0 +1,72 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::div_t;
+ using ::ldiv_t;
+ using ::lldiv_t;
+ using ::size_t;
+
+ // [support.start.term], start and termination
+ using ::_Exit;
+ using ::abort;
+ using ::at_quick_exit;
+ using ::atexit;
+ using ::exit;
+ using ::quick_exit;
+
+ using ::getenv;
+ using ::system;
+
+ // [c.malloc], C library memory allocation
+ using ::aligned_alloc;
+ using ::calloc;
+ using ::free;
+ using ::malloc;
+ using ::realloc;
+
+ using ::atof;
+ using ::atoi;
+ using ::atol;
+ using ::atoll;
+ using ::strtod;
+ using ::strtof;
+ using ::strtol;
+ using ::strtold;
+ using ::strtoll;
+ using ::strtoul;
+ using ::strtoull;
+
+ // [c.mb.wcs], multibyte / wide string and character conversion functions
+ using ::mblen;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using ::mbstowcs;
+ using ::mbtowc;
+ using ::wcstombs;
+ using ::wctomb;
+#endif
+ // [alg.c.library], C standard library algorithms
+ using ::bsearch;
+ using ::qsort;
+
+ // [c.math.rand], low-quality random number generation
+ using ::rand;
+ using ::srand;
+
+ // [c.math.abs], absolute values
+ using ::abs;
+
+ using ::labs;
+ using ::llabs;
+
+ using ::div;
+ using ::ldiv;
+ using ::lldiv;
+
+} // export
diff --git a/libcxx/modules/std.compat/cstring.inc b/libcxx/modules/std.compat/cstring.inc
new file mode 100644
index 000000000000..090350ae8147
--- /dev/null
+++ b/libcxx/modules/std.compat/cstring.inc
@@ -0,0 +1,36 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::size_t;
+
+ using ::memchr;
+ using ::memcmp;
+ using ::memcpy;
+ using ::memmove;
+ using ::memset;
+ using ::strcat;
+ using ::strchr;
+ using ::strcmp;
+ using ::strcoll;
+ using ::strcpy;
+ using ::strcspn;
+ using ::strerror;
+ using ::strlen;
+ using ::strncat;
+ using ::strncmp;
+ using ::strncpy;
+ using ::strpbrk;
+ using ::strrchr;
+ using ::strspn;
+ using ::strstr;
+ using ::strtok;
+ using ::strxfrm;
+
+} // export
diff --git a/libcxx/modules/std.compat/ctime.inc b/libcxx/modules/std.compat/ctime.inc
new file mode 100644
index 000000000000..92e3403a5e58
--- /dev/null
+++ b/libcxx/modules/std.compat/ctime.inc
@@ -0,0 +1,28 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ using ::clock_t;
+ using ::size_t;
+ using ::time_t;
+
+ using ::timespec;
+ using ::tm;
+
+ using ::asctime;
+ using ::clock;
+ using ::ctime;
+ using ::difftime;
+ using ::gmtime;
+ using ::localtime;
+ using ::mktime;
+ using ::strftime;
+ using ::time;
+ using ::timespec_get;
+} // export
diff --git a/libcxx/modules/std.compat/cuchar.inc b/libcxx/modules/std.compat/cuchar.inc
new file mode 100644
index 000000000000..d1a511cadef1
--- /dev/null
+++ b/libcxx/modules/std.compat/cuchar.inc
@@ -0,0 +1,28 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+ // Note the Standard does not mark these symbols optional, but libc++'s header
+ // does. So this seems strictly not to be conforming.
+
+ // mbstate_t is conditionally here, but always present in cwchar.cppm. To avoid
+ // conflicing declarations omit the using here.
+
+ // size_t is conditionally here, but always present in cstddef.cppm. To avoid
+ // conflicing declarations omit the using here.
+
+#if !defined(_LIBCPP_HAS_NO_C8RTOMB_MBRTOC8)
+ using ::mbrtoc8 _LIBCPP_USING_IF_EXISTS;
+ using ::c8rtomb _LIBCPP_USING_IF_EXISTS;
+#endif
+ using ::mbrtoc16 _LIBCPP_USING_IF_EXISTS;
+ using ::c16rtomb _LIBCPP_USING_IF_EXISTS;
+ using ::mbrtoc32 _LIBCPP_USING_IF_EXISTS;
+ using ::c32rtomb _LIBCPP_USING_IF_EXISTS;
+} // export
diff --git a/libcxx/modules/std.compat/cwchar.inc b/libcxx/modules/std.compat/cwchar.inc
new file mode 100644
index 000000000000..8905aecbdfec
--- /dev/null
+++ b/libcxx/modules/std.compat/cwchar.inc
@@ -0,0 +1,80 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using ::mbstate_t;
+ using ::size_t;
+ using ::wint_t;
+
+ using ::tm;
+
+ using ::btowc;
+ using ::fgetwc;
+ using ::fgetws;
+ using ::fputwc;
+ using ::fputws;
+ using ::fwide;
+ using ::fwprintf;
+ using ::fwscanf;
+ using ::getwc;
+ using ::getwchar;
+ using ::putwc;
+ using ::putwchar;
+ using ::swprintf;
+ using ::swscanf;
+ using ::ungetwc;
+ using ::vfwprintf;
+ using ::vfwscanf;
+ using ::vswprintf;
+ using ::vswscanf;
+ using ::vwprintf;
+ using ::vwscanf;
+ using ::wcscat;
+ using ::wcschr;
+ using ::wcscmp;
+ using ::wcscoll;
+ using ::wcscpy;
+ using ::wcscspn;
+ using ::wcsftime;
+ using ::wcslen;
+ using ::wcsncat;
+ using ::wcsncmp;
+ using ::wcsncpy;
+ using ::wcspbrk;
+ using ::wcsrchr;
+ using ::wcsspn;
+ using ::wcsstr;
+ using ::wcstod;
+ using ::wcstof;
+ using ::wcstok;
+ using ::wcstol;
+ using ::wcstold;
+ using ::wcstoll;
+ using ::wcstoul;
+ using ::wcstoull;
+ using ::wcsxfrm;
+ using ::wctob;
+ using ::wmemchr;
+ using ::wmemcmp;
+ using ::wmemcpy;
+ using ::wmemmove;
+ using ::wmemset;
+ using ::wprintf;
+ using ::wscanf;
+
+ // [c.mb.wcs], multibyte / wide string and character conversion functions
+ using ::mbrlen;
+ using ::mbrtowc;
+ using ::mbsinit;
+ using ::mbsrtowcs;
+ using ::wcrtomb;
+ using ::wcsrtombs;
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+} // export
diff --git a/libcxx/modules/std.compat/cwctype.inc b/libcxx/modules/std.compat/cwctype.inc
new file mode 100644
index 000000000000..13aa2b7f3fb7
--- /dev/null
+++ b/libcxx/modules/std.compat/cwctype.inc
@@ -0,0 +1,35 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+export {
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+ using ::wctrans_t;
+ using ::wctype_t;
+ using ::wint_t;
+
+ using ::iswalnum;
+ using ::iswalpha;
+ using ::iswblank;
+ using ::iswcntrl;
+ using ::iswctype;
+ using ::iswdigit;
+ using ::iswgraph;
+ using ::iswlower;
+ using ::iswprint;
+ using ::iswpunct;
+ using ::iswspace;
+ using ::iswupper;
+ using ::iswxdigit;
+ using ::towctrans;
+ using ::towlower;
+ using ::towupper;
+ using ::wctrans;
+ using ::wctype;
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+} // export
diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in
index ecb060126032..b46c52e781f8 100644
--- a/libcxx/modules/std.cppm.in
+++ b/libcxx/modules/std.cppm.in
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
// WARNING, this entire header is generated by
-// utils/generate_std_cppm_in.py
+// utils/generate_libcxx_cppm_in.py
// DO NOT MODIFY!
module;
@@ -169,38 +169,38 @@ module;
// *** Headers not yet available ***
#if __has_include(<debugging>)
-# error "update the header information for <debugging> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<debugging>)
+# error "please update the header information for <debugging> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<debugging>)
#if __has_include(<flat_map>)
-# error "update the header information for <flat_map> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<flat_map>)
+# error "please update the header information for <flat_map> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<flat_map>)
#if __has_include(<flat_set>)
-# error "update the header information for <flat_set> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<flat_set>)
+# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<flat_set>)
#if __has_include(<generator>)
-# error "update the header information for <generator> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<generator>)
+# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<generator>)
#if __has_include(<hazard_pointer>)
-# error "update the header information for <hazard_pointer> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<hazard_pointer>)
+# error "please update the header information for <hazard_pointer> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<hazard_pointer>)
#if __has_include(<linalg>)
-# error "update the header information for <linalg> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<linalg>)
+# error "please update the header information for <linalg> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<linalg>)
#if __has_include(<rcu>)
-# error "update the header information for <rcu> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<rcu>)
+# error "please update the header information for <rcu> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<rcu>)
#if __has_include(<spanstream>)
-# error "update the header information for <spanstream> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<spanstream>)
+# error "please update the header information for <spanstream> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<spanstream>)
#if __has_include(<stacktrace>)
-# error "update the header information for <stacktrace> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<stacktrace>)
+# error "please update the header information for <stacktrace> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<stacktrace>)
#if __has_include(<stdfloat>)
-# error "update the header information for <stdfloat> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<stdfloat>)
+# error "please update the header information for <stdfloat> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<stdfloat>)
#if __has_include(<text_encoding>)
-# error "update the header information for <text_encoding> in libcxx/utils/generate_std_cppm_in.py"
-#endif // __has_include(<text_encoding>)
+# error "please update the header information for <text_encoding> in headers_not_available in utils/libcxx/header_information.py"
+#endif // __has_include(<text_encoding>)
export module std;
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index a883103d8125..82c7d99f8979 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -204,13 +204,11 @@ export namespace std {
using std::ranges::views::drop_while;
} // namespace views
-#ifdef _LIBCPP_ENABLE_EXPERIMENTAL
using std::ranges::join_view;
namespace views {
using std::ranges::views::join;
} // namespace views
-#endif // _LIBCPP_ENABLE_EXPERIMENTAL
#if 0
using std::ranges::join_with_view;
diff --git a/libcxx/modules/std/string.inc b/libcxx/modules/std/string.inc
index 8366690fd9d3..c83ee7643f87 100644
--- a/libcxx/modules/std/string.inc
+++ b/libcxx/modules/std/string.inc
@@ -67,15 +67,10 @@ export namespace std {
// [basic.string.hash], hash support
using std::hash;
- // TODO MODULES is this a bug?
-#if _LIBCPP_STD_VER >= 23
- using std::operator""s;
-#else
inline namespace literals {
inline namespace string_literals {
// [basic.string.literals], suffix for basic_string literals
using std::literals::string_literals::operator""s;
} // namespace string_literals
- } // namespace literals
-#endif
+ } // namespace literals
} // namespace std
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 24126f635a06..48c48cefe91d 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -130,9 +130,9 @@ struct Configuration {
bool forceMultipleRes = false;
bool forceUnresolved = false;
bool debug = false;
- bool debugDwarf = false;
+ bool includeDwarfChunks = false;
bool debugGHashes = false;
- bool debugSymtab = false;
+ bool writeSymtab = false;
bool driver = false;
bool driverUponly = false;
bool driverWdm = false;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 99c1a60735ad..4f11affb35ed 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -858,46 +858,6 @@ static std::string createResponseFile(const opt::InputArgList &args,
return std::string(data.str());
}
-enum class DebugKind {
- Unknown,
- None,
- Full,
- FastLink,
- GHash,
- NoGHash,
- Dwarf,
- Symtab
-};
-
-static DebugKind parseDebugKind(const opt::InputArgList &args) {
- auto *a = args.getLastArg(OPT_debug, OPT_debug_opt);
- if (!a)
- return DebugKind::None;
- if (a->getNumValues() == 0)
- return DebugKind::Full;
-
- DebugKind debug = StringSwitch<DebugKind>(a->getValue())
- .CaseLower("none", DebugKind::None)
- .CaseLower("full", DebugKind::Full)
- .CaseLower("fastlink", DebugKind::FastLink)
- // LLD extensions
- .CaseLower("ghash", DebugKind::GHash)
- .CaseLower("noghash", DebugKind::NoGHash)
- .CaseLower("dwarf", DebugKind::Dwarf)
- .CaseLower("symtab", DebugKind::Symtab)
- .Default(DebugKind::Unknown);
-
- if (debug == DebugKind::FastLink) {
- warn("/debug:fastlink unsupported; using /debug:full");
- return DebugKind::Full;
- }
- if (debug == DebugKind::Unknown) {
- error("/debug: unknown option: " + Twine(a->getValue()));
- return DebugKind::None;
- }
- return debug;
-}
-
static unsigned parseDebugTypes(const opt::InputArgList &args) {
unsigned debugTypes = static_cast<unsigned>(DebugType::None);
@@ -1647,12 +1607,62 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (args.hasArg(OPT_force, OPT_force_multipleres))
config->forceMultipleRes = true;
+ // Don't warn about long section names, such as .debug_info, for mingw (or
+ // when -debug:dwarf is requested, handled below).
+ if (config->mingw)
+ config->warnLongSectionNames = false;
+
+ bool doGC = true;
+
// Handle /debug
- DebugKind debug = parseDebugKind(args);
- if (debug == DebugKind::Full || debug == DebugKind::Dwarf ||
- debug == DebugKind::GHash || debug == DebugKind::NoGHash) {
- config->debug = true;
- config->incremental = true;
+ bool shouldCreatePDB = false;
+ for (auto *arg : args.filtered(OPT_debug, OPT_debug_opt)) {
+ std::string str;
+ if (arg->getOption().getID() == OPT_debug)
+ str = "full";
+ else
+ str = StringRef(arg->getValue()).lower();
+ SmallVector<StringRef, 1> vec;
+ StringRef(str).split(vec, ',');
+ for (StringRef s : vec) {
+ if (s == "fastlink") {
+ warn("/debug:fastlink unsupported; using /debug:full");
+ s = "full";
+ }
+ if (s == "none") {
+ config->debug = false;
+ config->incremental = false;
+ config->includeDwarfChunks = false;
+ config->debugGHashes = false;
+ config->writeSymtab = false;
+ shouldCreatePDB = false;
+ doGC = true;
+ } else if (s == "full" || s == "ghash" || s == "noghash") {
+ config->debug = true;
+ config->incremental = true;
+ config->includeDwarfChunks = true;
+ if (s == "full" || s == "ghash")
+ config->debugGHashes = true;
+ shouldCreatePDB = true;
+ doGC = false;
+ } else if (s == "dwarf") {
+ config->debug = true;
+ config->incremental = true;
+ config->includeDwarfChunks = true;
+ config->writeSymtab = true;
+ config->warnLongSectionNames = false;
+ doGC = false;
+ } else if (s == "nodwarf") {
+ config->includeDwarfChunks = false;
+ } else if (s == "symtab") {
+ config->writeSymtab = true;
+ doGC = false;
+ } else if (s == "nosymtab") {
+ config->writeSymtab = false;
+ } else {
+ error("/debug: unknown option: " + s);
+ }
+ }
}
// Handle /demangle
@@ -1672,9 +1682,6 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
config->driverUponly || config->driverWdm || args.hasArg(OPT_driver);
// Handle /pdb
- bool shouldCreatePDB =
- (debug == DebugKind::Full || debug == DebugKind::GHash ||
- debug == DebugKind::NoGHash);
if (shouldCreatePDB) {
if (auto *arg = args.getLastArg(OPT_pdb))
config->pdbPath = arg->getValue();
@@ -1837,8 +1844,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
config->noimplib = args.hasArg(OPT_noimplib);
+ if (args.hasArg(OPT_profile))
+ doGC = true;
// Handle /opt.
- bool doGC = debug == DebugKind::None || args.hasArg(OPT_profile);
std::optional<ICFLevel> icfLevel;
if (args.hasArg(OPT_profile))
icfLevel = ICFLevel::None;
@@ -1940,6 +1948,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
parseMerge(".didat=.rdata");
parseMerge(".edata=.rdata");
parseMerge(".xdata=.rdata");
+ parseMerge(".00cfg=.rdata");
parseMerge(".bss=.data");
if (config->mingw) {
@@ -2028,9 +2037,6 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
parseSwaprun(arg->getValue());
config->terminalServerAware =
!config->dll && args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
- config->debugDwarf = debug == DebugKind::Dwarf;
- config->debugGHashes = debug == DebugKind::GHash || debug == DebugKind::Full;
- config->debugSymtab = debug == DebugKind::Symtab;
config->autoImport =
args.hasFlag(OPT_auto_import, OPT_auto_import_no, config->mingw);
config->pseudoRelocs = args.hasFlag(
@@ -2047,11 +2053,6 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (args.hasFlag(OPT_inferasanlibs, OPT_inferasanlibs_no, false))
warn("ignoring '/inferasanlibs', this flag is not supported");
- // Don't warn about long section names, such as .debug_info, for mingw or
- // when -debug:dwarf is requested.
- if (config->mingw || config->debugDwarf)
- config->warnLongSectionNames = false;
-
if (config->incremental && args.hasArg(OPT_profile)) {
warn("ignoring '/incremental' due to '/profile' specification");
config->incremental = false;
@@ -2381,6 +2382,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
ctx.symtab.addAbsolute(mangle("__CTOR_LIST__"), 0);
ctx.symtab.addAbsolute(mangle("__DTOR_LIST__"), 0);
}
+ if (config->debug || config->buildIDHash != BuildIDHash::None)
+ if (ctx.symtab.findUnderscore("__buildid"))
+ ctx.symtab.addUndefined(mangle("__buildid"));
// This code may add new undefined symbols to the link, which may enqueue more
// symbol resolution tasks, so we need to continue executing tasks until we
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index dd2e1419bb10..cd744800cb0d 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -236,8 +236,8 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
// CodeView needs linker support. We need to interpret debug info,
// and then write it to a separate .pdb file.
- // Ignore DWARF debug info unless /debug is given.
- if (!ctx.config.debug && name.starts_with(".debug_"))
+ // Ignore DWARF debug info unless requested to be included.
+ if (!ctx.config.includeDwarfChunks && name.starts_with(".debug_"))
return nullptr;
if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp
index f77ff0d4eab8..8b81a71e8fb6 100644
--- a/lld/COFF/PDB.cpp
+++ b/lld/COFF/PDB.cpp
@@ -268,7 +268,7 @@ void PDBLinker::pdbMakeAbsolute(SmallVectorImpl<char> &fileName) {
// decide that it's a unix path if we're fairly certain. Specifically, if
// it starts with a forward slash.
SmallString<128> absoluteFileName = ctx.config.pdbSourcePath;
- sys::path::Style guessedStyle = absoluteFileName.startswith("/")
+ sys::path::Style guessedStyle = absoluteFileName.starts_with("/")
? sys::path::Style::posix
: sys::path::Style::windows;
sys::path::append(absoluteFileName, guessedStyle, fileName);
diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h
index 750269fd0bbb..ca69fb2d0527 100644
--- a/lld/COFF/Symbols.h
+++ b/lld/COFF/Symbols.h
@@ -269,8 +269,8 @@ private:
// __safe_se_handler_table.
class DefinedSynthetic : public Defined {
public:
- explicit DefinedSynthetic(StringRef name, Chunk *c)
- : Defined(DefinedSyntheticKind, name), c(c) {}
+ explicit DefinedSynthetic(StringRef name, Chunk *c, uint32_t offset = 0)
+ : Defined(DefinedSyntheticKind, name), c(c), offset(offset) {}
static bool classof(const Symbol *s) {
return s->kind() == DefinedSyntheticKind;
@@ -278,11 +278,12 @@ public:
// A null chunk indicates that this is __ImageBase. Otherwise, this is some
// other synthesized chunk, like SEHTableChunk.
- uint32_t getRVA() { return c ? c->getRVA() : 0; }
+ uint32_t getRVA() { return c ? c->getRVA() + offset : 0; }
Chunk *getChunk() { return c; }
private:
Chunk *c;
+ uint32_t offset;
};
// This class represents a symbol defined in an archive file. It is
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 7b1ff8071e2e..2982165530c0 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -560,7 +560,7 @@ void Writer::createECCodeMap() {
codeMap.clear();
std::optional<chpe_range_type> lastType;
- Chunk *first, *last;
+ Chunk *first = nullptr, *last = nullptr;
auto closeRange = [&]() {
if (lastType) {
@@ -1121,6 +1121,9 @@ void Writer::createMiscChunks() {
// if we're ultimately not going to write CodeView data to the PDB.
buildId = make<CVDebugRecordChunk>(ctx);
debugRecords.emplace_back(COFF::IMAGE_DEBUG_TYPE_CODEVIEW, buildId);
+ if (Symbol *buildidSym = ctx.symtab.findUnderscore("__buildid"))
+ replaceSymbol<DefinedSynthetic>(buildidSym, buildidSym->getName(),
+ buildId, 4);
}
if (config->cetCompat) {
@@ -1376,7 +1379,7 @@ void Writer::createSymbolAndStringTable() {
sec->setStringTableOff(addEntryToStringTable(sec->name));
}
- if (ctx.config.debugDwarf || ctx.config.debugSymtab) {
+ if (ctx.config.writeSymtab) {
for (ObjFile *file : ctx.objFileInstances) {
for (Symbol *b : file->getSymbols()) {
auto *d = dyn_cast_or_null<Defined>(b);
@@ -1480,7 +1483,7 @@ void Writer::sortECChunks() {
llvm::stable_sort(sec->chunks, [=](const Chunk *a, const Chunk *b) {
std::optional<chpe_range_type> aType = a->getArm64ECRangeType(),
bType = b->getArm64ECRangeType();
- return !aType || (bType && *aType < *bType);
+ return bType && (!aType || *aType < *bType);
});
}
}
diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp
index c10ffebc1666..d34e74a11c6d 100644
--- a/lld/ELF/Arch/ARM.cpp
+++ b/lld/ELF/Arch/ARM.cpp
@@ -948,15 +948,15 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const {
}
static bool isArmMapSymbol(const Symbol *b) {
- return b->getName() == "$a" || b->getName().startswith("$a.");
+ return b->getName() == "$a" || b->getName().starts_with("$a.");
}
static bool isThumbMapSymbol(const Symbol *s) {
- return s->getName() == "$t" || s->getName().startswith("$t.");
+ return s->getName() == "$t" || s->getName().starts_with("$t.");
}
static bool isDataMapSymbol(const Symbol *b) {
- return b->getName() == "$d" || b->getName().startswith("$d.");
+ return b->getName() == "$d" || b->getName().starts_with("$d.");
}
void elf::sortArmMappingSymbols() {
@@ -1189,7 +1189,7 @@ void elf::processArmCmseSymbols() {
// Only symbols with external linkage end up in symtab, so no need to do
// linkage checks. Only check symbol type.
for (Symbol *acleSeSym : symtab.getSymbols()) {
- if (!acleSeSym->getName().startswith(ACLESESYM_PREFIX))
+ if (!acleSeSym->getName().starts_with(ACLESESYM_PREFIX))
continue;
// If input object build attributes do not support CMSE, error and disable
// further scanning for <sym>, __acle_se_<sym> pairs.
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index fe3d7f419e84..210b4d1eb1a7 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1158,8 +1158,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
}
// When producing an executable, we can perform copy relocations (for
- // STT_OBJECT) and canonical PLT (for STT_FUNC).
- if (!config->shared) {
+ // STT_OBJECT) and canonical PLT (for STT_FUNC) if sym is defined by a DSO.
+ if (!config->shared && sym.isShared()) {
if (!canDefineSymbolInExecutable(sym)) {
errorOrWarn("cannot preempt symbol: " + toString(sym) +
getLocation(*sec, sym, offset));
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 31ed24149e78..7d0cdce9de7d 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -1535,7 +1535,7 @@ std::string ObjFile::sourceFile() const {
StringRef sep = sys::path::get_separator();
// We don't use `path::append` here because we want an empty `dir` to result
// in an absolute path. `append` would give us a relative path for that case.
- if (!dir.endswith(sep))
+ if (!dir.ends_with(sep))
dir += sep;
return (dir + unitName).str();
}
diff --git a/lld/docs/WebAssembly.rst b/lld/docs/WebAssembly.rst
index dad3177e2c7d..3f554de46d38 100644
--- a/lld/docs/WebAssembly.rst
+++ b/lld/docs/WebAssembly.rst
@@ -123,9 +123,13 @@ WebAssembly-specific options:
is not possible for undefined data symbols. Undefined data symbols will
still be reported as normal (in accordance with ``--unresolved-symbols``).
+.. option:: --initial-heap=<value>
+
+ Initial size of the heap. Default: zero.
+
.. option:: --initial-memory=<value>
- Initial size of the linear memory. Default: static data size.
+ Initial size of the linear memory. Default: the sum of stack, static data and heap sizes.
.. option:: --max-memory=<value>
diff --git a/lld/docs/windows_support.rst b/lld/docs/windows_support.rst
index 620040ee8196..e4640b4a5259 100644
--- a/lld/docs/windows_support.rst
+++ b/lld/docs/windows_support.rst
@@ -95,3 +95,14 @@ Using Ninja
1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror),
#. run ``cmake -G ninja <llvm-source-dir>`` from VS command prompt,
#. run ``ninja lld``
+
+Extensions
+==========
+
+LLD flags
+---------
+
+* ``/build-id``: Always generate GUID hash. When PDB is generated, LLD uses PDB
+ content hash for GUID. Otherwise, LLD uses output binary content hash for GUID.
+ LLD also provides ``__buildid`` symbol pointing to the 16 bytes GUID hash if
+ there is a reference to it.
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h
index 03ae69acae4c..3a09892f3f19 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h
@@ -31,8 +31,7 @@ public:
~BreakpointResolverAddress() override = default;
static lldb::BreakpointResolverSP
- CreateFromStructuredData(const lldb::BreakpointSP &bkpt,
- const StructuredData::Dictionary &options_dict,
+ CreateFromStructuredData(const StructuredData::Dictionary &options_dict,
Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h b/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h
index 7635729c50a6..610d81727c6c 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h
@@ -28,8 +28,7 @@ public:
std::optional<llvm::StringRef> removed_prefix_opt = std::nullopt);
static lldb::BreakpointResolverSP
- CreateFromStructuredData(const lldb::BreakpointSP &bkpt,
- const StructuredData::Dictionary &data_dict,
+ CreateFromStructuredData(const StructuredData::Dictionary &data_dict,
Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h b/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
index 43e1217c13d5..1dcdba91a5a8 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
@@ -28,8 +28,7 @@ public:
const std::unordered_set<std::string> &func_name_set, bool exact_match);
static lldb::BreakpointResolverSP
- CreateFromStructuredData(const lldb::BreakpointSP &bkpt,
- const StructuredData::Dictionary &options_dict,
+ CreateFromStructuredData(const StructuredData::Dictionary &options_dict,
Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h
index 94b19db3085d..c83814c174e8 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h
@@ -51,8 +51,7 @@ public:
bool skip_prologue);
static lldb::BreakpointResolverSP
- CreateFromStructuredData(const lldb::BreakpointSP &bkpt,
- const StructuredData::Dictionary &data_dict,
+ CreateFromStructuredData(const StructuredData::Dictionary &data_dict,
Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h b/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h
index c0bbc1c2bafb..133fa8058637 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h
@@ -31,8 +31,7 @@ public:
~BreakpointResolverScripted() override = default;
static lldb::BreakpointResolverSP
- CreateFromStructuredData(const lldb::BreakpointSP &bkpt,
- const StructuredData::Dictionary &options_dict,
+ CreateFromStructuredData(const StructuredData::Dictionary &options_dict,
Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 2973ee0e7ec4..f4973cdda1ef 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -415,70 +415,19 @@ public:
void FindGlobalVariables(const RegularExpression &regex, size_t max_matches,
VariableList &variable_list);
- /// Find types by name.
- ///
- /// Type lookups in modules go through the SymbolFile. The SymbolFile needs to
- /// be able to lookup types by basename and not the fully qualified typename.
- /// This allows the type accelerator tables to stay small, even with heavily
- /// templatized C++. The type search will then narrow down the search
- /// results. If "exact_match" is true, then the type search will only match
- /// exact type name matches. If "exact_match" is false, the type will match
- /// as long as the base typename matches and as long as any immediate
- /// containing namespaces/class scopes that are specified match. So to
- /// search for a type "d" in "b::c", the name "b::c::d" can be specified and
- /// it will match any class/namespace "b" which contains a class/namespace
- /// "c" which contains type "d". We do this to allow users to not always
- /// have to specify complete scoping on all expressions, but it also allows
- /// for exact matching when required.
- ///
- /// \param[in] type_name
- /// The name of the type we are looking for that is a fully
- /// or partially qualified type name.
- ///
- /// \param[in] exact_match
- /// If \b true, \a type_name is fully qualified and must match
- /// exactly. If \b false, \a type_name is a partially qualified
- /// name where the leading namespaces or classes can be
- /// omitted to make finding types that a user may type
- /// easier.
- ///
- /// \param[out] types
- /// A type list gets populated with any matches.
+ /// Find types using a type-matching object that contains all search
+ /// parameters.
///
- void
- FindTypes(ConstString type_name, bool exact_match, size_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeList &types);
-
- /// Find types by name.
- ///
- /// This behaves like the other FindTypes method but allows to
- /// specify a DeclContext and a language for the type being searched
- /// for.
- ///
- /// \param searched_symbol_files
- /// Prevents one file from being visited multiple times.
- void
- FindTypes(llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types);
-
- lldb::TypeSP FindFirstType(const SymbolContext &sc, ConstString type_name,
- bool exact_match);
-
- /// Find types by name that are in a namespace. This function is used by the
- /// expression parser when searches need to happen in an exact namespace
- /// scope.
+ /// \see lldb_private::TypeQuery
///
- /// \param[in] type_name
- /// The name of a type within a namespace that should not include
- /// any qualifying namespaces (just a type basename).
+ /// \param[in] query
+ /// A type matching object that contains all of the details of the type
+ /// search.
///
- /// \param[out] type_list
- /// A type list gets populated with any matches.
- void FindTypesInNamespace(ConstString type_name,
- const CompilerDeclContext &parent_decl_ctx,
- size_t max_matches, TypeList &type_list);
+ /// \param[in] results
+ /// Any matching types will be populated into the \a results object using
+ /// TypeMap::InsertUnique(...).
+ void FindTypes(const TypeQuery &query, TypeResults &results);
/// Get const accessor for the module architecture.
///
@@ -1122,12 +1071,6 @@ protected:
private:
Module(); // Only used internally by CreateJITModule ()
- void FindTypes_Impl(
- ConstString name, const CompilerDeclContext &parent_decl_ctx,
- size_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types);
-
Module(const Module &) = delete;
const Module &operator=(const Module &) = delete;
diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h
index 9826dd09e91d..d78f7c5ef3f7 100644
--- a/lldb/include/lldb/Core/ModuleList.h
+++ b/lldb/include/lldb/Core/ModuleList.h
@@ -340,26 +340,22 @@ public:
lldb::SymbolType symbol_type,
SymbolContextList &sc_list) const;
- /// Find types by name.
+ /// Find types using a type-matching object that contains all search
+ /// parameters.
///
/// \param[in] search_first
/// If non-null, this module will be searched before any other
/// modules.
///
- /// \param[in] name
- /// The name of the type we are looking for.
- ///
- /// \param[in] max_matches
- /// Allow the number of matches to be limited to \a
- /// max_matches. Specify UINT32_MAX to get all possible matches.
- ///
- /// \param[out] types
- /// A type list gets populated with any matches.
+ /// \param[in] query
+ /// A type matching object that contains all of the details of the type
+ /// search.
///
- void FindTypes(Module *search_first, ConstString name,
- bool name_is_fully_qualified, size_t max_matches,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeList &types) const;
+ /// \param[in] results
+ /// Any matching types will be populated into the \a results object using
+ /// TypeMap::InsertUnique(...).
+ void FindTypes(Module *search_first, const TypeQuery &query,
+ lldb_private::TypeResults &results) const;
bool FindSourceFile(const FileSpec &orig_spec, FileSpec &new_spec) const;
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 20b308613845..a158199e7fab 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -468,7 +468,7 @@ public:
virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx,
bool can_create = true);
- // this will always create the children if necessary
+ // The method always creates missing children in the path, if necessary.
lldb::ValueObjectSP GetChildAtIndexPath(llvm::ArrayRef<size_t> idxs,
size_t *index_of_error = nullptr);
@@ -476,7 +476,7 @@ public:
GetChildAtIndexPath(llvm::ArrayRef<std::pair<size_t, bool>> idxs,
size_t *index_of_error = nullptr);
- // this will always create the children if necessary
+ // The method always creates missing children in the path, if necessary.
lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef<llvm::StringRef> names);
virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name,
diff --git a/lldb/include/lldb/Host/Editline.h b/lldb/include/lldb/Host/Editline.h
index c59824415078..9049b106f02a 100644
--- a/lldb/include/lldb/Host/Editline.h
+++ b/lldb/include/lldb/Host/Editline.h
@@ -75,6 +75,8 @@ using EditLineCharType = char;
// to wchar_t. It is not possible to detect differentiate between the two
// versions exactly, but this is a pretty good approximation and allows us to
// build against almost any editline version out there.
+// It does, however, require extra care when invoking el_getc, as the type
+// of the input is a single char buffer, but the callback will write a wchar_t.
#if LLDB_EDITLINE_USE_WCHAR || defined(EL_CLIENTDATA) || LLDB_HAVE_EL_RFUNC_T
using EditLineGetCharType = wchar_t;
#else
diff --git a/lldb/include/lldb/Interpreter/CommandCompletions.h b/lldb/include/lldb/Interpreter/CommandCompletions.h
index a89a5be95b80..c7292b3b1471 100644
--- a/lldb/include/lldb/Interpreter/CommandCompletions.h
+++ b/lldb/include/lldb/Interpreter/CommandCompletions.h
@@ -120,6 +120,9 @@ public:
CompletionRequest &request,
SearchFilter *searcher);
+ static void ThreadIDs(CommandInterpreter &interpreter,
+ CompletionRequest &request, SearchFilter *searcher);
+
/// This completer works for commands whose only arguments are a command path.
/// It isn't tied to an argument type because it completes not on a single
/// argument but on the sequence of arguments, so you have to invoke it by
diff --git a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
index 4bf71393bb07..d0cf54c31ca7 100644
--- a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
+++ b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
@@ -192,6 +192,7 @@ static constexpr OptionEnumValueElement g_completion_type[] = {
{lldb::eTypeCategoryNameCompletion, "type-category-name",
"Completes to a type category name."},
{lldb::eCustomCompletion, "custom", "Custom completion."},
+ {lldb::eThreadIDCompletion, "thread-id", "Completes to a thread ID."},
};
llvm::StringRef RegisterNameHelpTextCallback();
diff --git a/lldb/include/lldb/Symbol/CompilerDecl.h b/lldb/include/lldb/Symbol/CompilerDecl.h
index 67290b9be066..825a4f15836f 100644
--- a/lldb/include/lldb/Symbol/CompilerDecl.h
+++ b/lldb/include/lldb/Symbol/CompilerDecl.h
@@ -84,6 +84,13 @@ public:
// based argument index
CompilerType GetFunctionArgumentType(size_t arg_idx) const;
+ /// Populate a valid compiler context from the current declaration.
+ ///
+ /// \returns A valid vector of CompilerContext entries that describes
+ /// this declaration. The first entry in the vector is the parent of
+ /// the subsequent entry, so the topmost entry is the global namespace.
+ std::vector<lldb_private::CompilerContext> GetCompilerContext() const;
+
private:
TypeSystem *m_type_system = nullptr;
void *m_opaque_decl = nullptr;
diff --git a/lldb/include/lldb/Symbol/CompilerDeclContext.h b/lldb/include/lldb/Symbol/CompilerDeclContext.h
index 61a9c9c341bf..89b4a9787688 100644
--- a/lldb/include/lldb/Symbol/CompilerDeclContext.h
+++ b/lldb/include/lldb/Symbol/CompilerDeclContext.h
@@ -11,6 +11,7 @@
#include <vector>
+#include "lldb/Symbol/Type.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
@@ -56,6 +57,13 @@ public:
return m_type_system != nullptr && m_opaque_decl_ctx != nullptr;
}
+ /// Populate a valid compiler context from the current decl context.
+ ///
+ /// \returns A valid vector of CompilerContext entries that describes
+ /// this declaration context. The first entry in the vector is the parent of
+ /// the subsequent entry, so the topmost entry is the global namespace.
+ std::vector<lldb_private::CompilerContext> GetCompilerContext() const;
+
std::vector<CompilerDecl> FindDeclByName(ConstString name,
const bool ignore_using_decls);
diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h
index 0a9533a1ac0e..414c44275aaa 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -194,6 +194,60 @@ public:
bool IsTypedefType() const;
bool IsVoidType() const;
+
+ /// This is used when you don't care about the signedness of the integer.
+ bool IsInteger() const;
+
+ bool IsFloat() const;
+
+ /// This is used when you don't care about the signedness of the enum.
+ bool IsEnumerationType() const;
+
+ bool IsUnscopedEnumerationType() const;
+
+ bool IsIntegerOrUnscopedEnumerationType() const;
+
+ bool IsSigned() const;
+
+ bool IsNullPtrType() const;
+
+ bool IsBoolean() const;
+
+ bool IsEnumerationIntegerTypeSigned() const;
+
+ bool IsScalarOrUnscopedEnumerationType() const;
+
+ bool IsPromotableIntegerType() const;
+
+ bool IsPointerToVoid() const;
+
+ bool IsRecordType() const;
+
+ //// Checks whether `target_base` is a virtual base of `type` (direct or
+ /// indirect). If it is, stores the first virtual base type on the path from
+ /// `type` to `target_type`. Parameter "virtual_base" is where the first
+ /// virtual base type gets stored. Parameter "carry_virtual" is used to
+ /// denote that we're in a recursive check of virtual base classes and we
+ /// have already seen a virtual base class (so should only check direct
+ /// base classes).
+ /// Note: This may only be defined in TypeSystemClang.
+ bool IsVirtualBase(CompilerType target_base, CompilerType *virtual_base,
+ bool carry_virtual = false) const;
+
+ /// This may only be defined in TypeSystemClang.
+ bool IsContextuallyConvertibleToBool() const;
+
+ bool IsBasicType() const;
+
+ std::string TypeDescription();
+
+ bool CompareTypes(CompilerType rhs) const;
+
+ const char *GetTypeTag();
+
+ /// Go through the base classes and count non-empty ones.
+ uint32_t GetNumberOfNonEmptyBaseClasses();
+
/// \}
/// Type Completion.
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index a546b05bfd31..c9a2a647a039 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -301,21 +301,20 @@ public:
bool include_inlines, SymbolContextList &sc_list);
virtual void FindFunctions(const RegularExpression &regex,
bool include_inlines, SymbolContextList &sc_list);
- virtual void
- FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types);
-
- /// Find types specified by a CompilerContextPattern.
- /// \param languages
- /// Only return results in these languages.
- /// \param searched_symbol_files
- /// Prevents one file from being visited multiple times.
- virtual void
- FindTypes(llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types);
+
+ /// Find types using a type-matching object that contains all search
+ /// parameters.
+ ///
+ /// \see lldb_private::TypeQuery
+ ///
+ /// \param[in] query
+ /// A type matching object that contains all of the details of the type
+ /// search.
+ ///
+ /// \param[in] results
+ /// Any matching types will be populated into the \a results object using
+ /// TypeMap::InsertUnique(...).
+ virtual void FindTypes(const TypeQuery &query, TypeResults &results) {}
virtual void
GetMangledNamesForFunction(const std::string &scope_qualified_name,
diff --git a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h
index 9cbcef2a111d..cde9f3c3b8ce 100644
--- a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h
+++ b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h
@@ -152,17 +152,8 @@ public:
const std::string &scope_qualified_name,
std::vector<lldb_private::ConstString> &mangled_names) override;
- void
- FindTypes(lldb_private::ConstString name,
- const lldb_private::CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- lldb_private::TypeMap &types) override;
-
- void FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> pattern,
- lldb_private::LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- lldb_private::TypeMap &types) override;
+ void FindTypes(const lldb_private::TypeQuery &query,
+ lldb_private::TypeResults &results) override;
void GetTypes(lldb_private::SymbolContextScope *sc_scope,
lldb::TypeClass type_mask,
diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h
index 15edbea3cc7a..307be6c55e01 100644
--- a/lldb/include/lldb/Symbol/Type.h
+++ b/lldb/include/lldb/Symbol/Type.h
@@ -12,11 +12,15 @@
#include "lldb/Core/Declaration.h"
#include "lldb/Symbol/CompilerDecl.h"
#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/TypeMap.h"
+#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/DenseSet.h"
#include <optional>
#include <set>
@@ -24,6 +28,23 @@
namespace lldb_private {
class SymbolFileCommon;
+/// A SmallBitVector that represents a set of source languages (\p
+/// lldb::LanguageType). Each lldb::LanguageType is represented by
+/// the bit with the position of its enumerator. The largest
+/// LanguageType is < 64, so this is space-efficient and on 64-bit
+/// architectures a LanguageSet can be completely stack-allocated.
+struct LanguageSet {
+ llvm::SmallBitVector bitvector;
+ LanguageSet();
+
+ /// If the set contains a single language only, return it.
+ std::optional<lldb::LanguageType> GetSingularLanguage();
+ void Insert(lldb::LanguageType language);
+ bool Empty() const;
+ size_t Size() const;
+ bool operator[](unsigned i) const;
+};
+
/// CompilerContext allows an array of these items to be passed to perform
/// detailed lookups in SymbolVendor and SymbolFile functions.
struct CompilerContext {
@@ -45,6 +66,290 @@ struct CompilerContext {
bool contextMatches(llvm::ArrayRef<CompilerContext> context_chain,
llvm::ArrayRef<CompilerContext> pattern);
+FLAGS_ENUM(TypeQueryOptions){
+ e_none = 0u,
+ /// If set, TypeQuery::m_context contains an exact context that must match
+ /// the full context. If not set, TypeQuery::m_context can contain a partial
+ /// type match where the full context isn't fully specified.
+ e_exact_match = (1u << 0),
+ /// If set, TypeQuery::m_context is a clang module compiler context. If not
+ /// set TypeQuery::m_context is normal type lookup context.
+ e_module_search = (1u << 1),
+ /// When true, the find types call should stop the query as soon as a single
+ /// matching type is found. When false, the type query should find all
+ /// matching types.
+ e_find_one = (1u << 2),
+};
+LLDB_MARK_AS_BITMASK_ENUM(TypeQueryOptions)
+
+/// A class that contains all state required for type lookups.
+///
+/// Using a TypeQuery class for matching types simplifies the internal APIs we
+/// need to implement type lookups in LLDB. Type lookups can fully specify the
+/// exact typename by filling out a complete or partial CompilerContext array.
+/// This technique allows for powerful searches and also allows the SymbolFile
+/// classes to use the m_context array to lookup types by basename, then
+/// eliminate potential matches without having to resolve types into each
+/// TypeSystem. This makes type lookups vastly more efficient and allows the
+/// SymbolFile objects to stop looking up types when the type matching is
+/// complete, like if we are looking for only a single type in our search.
+class TypeQuery {
+public:
+ TypeQuery() = delete;
+
+ /// Construct a type match object using a fully- or partially-qualified name.
+ ///
+ /// The specified \a type_name will be chopped up and the m_context will be
+ /// populated by separating the string by looking for "::". We do this because
+ /// symbol files have indexes that contain only the type's basename. This also
+ /// allows symbol files to efficiently not realize types that don't match the
+ /// specified context. Example of \a type_name values that can be specified
+ /// include:
+ /// "foo": Look for any type whose basename matches "foo".
+ /// If \a exact_match is true, then the type can't be contained in any
+ /// declaration context like a namespace, class, or other containing
+ /// scope.
+ /// If \a exact match is false, then we will find all matches including
+ /// ones that are contained in other declaration contexts, including top
+ /// level types.
+ /// "foo::bar": Look for any type whose basename matches "bar" but make sure
+ /// its parent declaration context is any named declaration context
+ /// (namespace, class, struct, etc) whose name matches "foo".
+ /// If \a exact_match is true, then the "foo" declaration context must
+ /// appear at the source file level or inside of a function.
+ /// If \a exact match is false, then the "foo" declaration context can
+ /// be contained in any other declaration contexts.
+ /// "class foo": Only match types that are classes whose basename matches
+ /// "foo".
+ /// "struct foo": Only match types that are structures whose basename
+ /// matches "foo".
+ /// "class foo::bar": Only match types that are classes whose basename
+ /// matches "bar" and that are contained in any named declaration context
+ /// named "foo".
+ ///
+ /// \param[in] type_name
+ /// A fully- or partially-qualified type name. This name will be parsed and
+ /// broken up and the m_context will be populated with the various parts of
+ /// the name. This typename can be prefixed with "struct ", "class ",
+ /// "union", "enum " or "typedef " before the actual type name to limit the
+ /// results of the types that match. The declaration context can be
+ /// specified with the "::" string. For example, "a::b::my_type".
+ ///
+ /// \param[in] options A set of boolean enumeration flags from the
+ /// TypeQueryOptions enumerations. \see TypeQueryOptions.
+ TypeQuery(llvm::StringRef name, TypeQueryOptions options = e_none);
+
+ /// Construct a type-match object that matches a type basename that exists
+ /// in the specified declaration context.
+ ///
+ /// This allows the m_context to be first populated using a declaration
+ /// context to exactly identify the containing declaration context of a type.
+ /// This can be used when you have a forward declaration to a type and you
+ /// need to search for its complete type.
+ ///
+ /// \param[in] decl_ctx
+ /// A declaration context object that comes from a TypeSystem plug-in. This
+ /// object will be asked to populate the array of CompilerContext objects
+ /// by adding the top most declaration context first into the array and then
+ /// adding any containing declaration contexts.
+ ///
+ /// \param[in] type_basename
+ /// The basename of the type to lookup in the specified declaration context.
+ ///
+ /// \param[in] options A set of boolean enumeration flags from the
+ /// TypeQueryOptions enumerations. \see TypeQueryOptions.
+ TypeQuery(const CompilerDeclContext &decl_ctx, ConstString type_basename,
+ TypeQueryOptions options = e_none);
+ /// Construct a type-match object using a compiler declaration that specifies
+ /// a typename and a declaration context to use when doing exact type lookups.
+ ///
+ /// This allows the m_context to be first populated using a type declaration.
+ /// The type declaration might have a declaration context and each TypeSystem
+ /// plug-in can populate the declaration context needed to perform an exact
+ /// lookup for a type.
+ /// This can be used when you have a forward declaration to a type and you
+ /// need to search for its complete type.
+ ///
+ /// \param[in] decl
+ /// A type declaration context object that comes from a TypeSystem plug-in.
+ /// This object will be asked to full the array of CompilerContext objects
+ /// by adding the top most declaration context first into the array and then
+ /// adding any containing declaration contexts, and ending with the exact
+ /// typename and the kind of type it is (class, struct, union, enum, etc).
+ ///
+ /// \param[in] options A set of boolean enumeration flags from the
+ /// TypeQueryOptions enumerations. \see TypeQueryOptions.
+ TypeQuery(const CompilerDecl &decl, TypeQueryOptions options = e_none);
+
+ /// Construct a type-match object using a CompilerContext array.
+ ///
+ /// Clients can manually create compiler contexts and use these to find
+ /// matches when searching for types. There are two types of contexts that
+ /// are supported when doing type searchs: type contexts and clang module
+ /// contexts. Type contexts have contexts that specify the type and its
+ /// containing declaration context like namespaces and classes. Clang module
+ /// contexts specify contexts more completely to find exact matches within
+ /// clang module debug information. They will include the modules that the
+ /// type is included in and any functions that the type might be defined in.
+ /// This allows very fine-grained type resolution.
+ ///
+ /// \param[in] context The compiler context to use when doing the search.
+ ///
+ /// \param[in] options A set of boolean enumeration flags from the
+ /// TypeQueryOptions enumerations. \see TypeQueryOptions.
+ TypeQuery(const llvm::ArrayRef<lldb_private::CompilerContext> &context,
+ TypeQueryOptions options = e_none);
+
+ /// Construct a type-match object that duplicates all matching criterea,
+ /// but not any searched symbol files or the type map for matches. This allows
+ /// the m_context to be modified prior to performing another search.
+ TypeQuery(const TypeQuery &rhs) = default;
+ /// Assign a type-match object that duplicates all matching criterea,
+ /// but not any searched symbol files or the type map for matches. This allows
+ /// the m_context to be modified prior to performing another search.
+ TypeQuery &operator=(const TypeQuery &rhs) = default;
+
+ /// Check of a CompilerContext array from matching type from a symbol file
+ /// matches the \a m_context.
+ ///
+ /// \param[in] context
+ /// A fully qualified CompilerContext array for a potential match that is
+ /// created by the symbol file prior to trying to actually resolve a type.
+ ///
+ /// \returns
+ /// True if the context matches, false if it doesn't. If e_exact_match
+ /// is set in m_options, then \a context must exactly match \a m_context. If
+ /// e_exact_match is not set, then the bottom m_context.size() objects in
+ /// \a context must match. This allows SymbolFile objects the fill in a
+ /// potential type basename match from the index into \a context, and see if
+ /// it matches prior to having to resolve a lldb_private::Type object for
+ /// the type from the index. This allows type parsing to be as efficient as
+ /// possible and only realize the types that match the query.
+ bool
+ ContextMatches(llvm::ArrayRef<lldb_private::CompilerContext> context) const;
+
+ /// Get the type basename to use when searching the type indexes in each
+ /// SymbolFile object.
+ ///
+ /// Debug information indexes often contain indexes that track the basename
+ /// of types only, not a fully qualified path. This allows the indexes to be
+ /// smaller and allows for efficient lookups.
+ ///
+ /// \returns
+ /// The type basename to use when doing lookups as a constant string.
+ ConstString GetTypeBasename() const;
+
+ /// Returns true if any matching languages have been specified in this type
+ /// matching object.
+ bool HasLanguage() const { return m_languages.has_value(); }
+
+ /// Add a language family to the list of languages that should produce a
+ /// match.
+ void AddLanguage(lldb::LanguageType language);
+
+ /// Check if the language matches any languages that have been added to this
+ /// match object.
+ ///
+ /// \returns
+ /// True if no language have been specified, or if some language have been
+ /// added using AddLanguage(...) and they match. False otherwise.
+ bool LanguageMatches(lldb::LanguageType language) const;
+
+ bool GetExactMatch() const { return (m_options & e_exact_match) != 0; }
+ /// The \a m_context can be used in two ways: normal types searching with
+ /// the context containing a stanadard declaration context for a type, or
+ /// with the context being more complete for exact matches in clang modules.
+ /// Set this to true if you wish to search for a type in clang module.
+ bool GetModuleSearch() const { return (m_options & e_module_search) != 0; }
+
+ /// Returns true if the type query is supposed to find only a single matching
+ /// type. Returns false if the type query should find all matches.
+ bool GetFindOne() const { return (m_options & e_find_one) != 0; }
+ void SetFindOne(bool b) {
+ if (b)
+ m_options |= e_find_one;
+ else
+ m_options &= (e_exact_match | e_find_one);
+ }
+
+ /// Access the internal compiler context array.
+ ///
+ /// Clients can use this to populate the context manually.
+ std::vector<lldb_private::CompilerContext> &GetContextRef() {
+ return m_context;
+ }
+
+protected:
+ /// A full or partial compiler context array where the parent declaration
+ /// contexts appear at the top of the array starting at index zero and the
+ /// last entry contains the type and name of the type we are looking for.
+ std::vector<lldb_private::CompilerContext> m_context;
+ /// An options bitmask that contains enabled options for the type query.
+ /// \see TypeQueryOptions.
+ TypeQueryOptions m_options;
+ /// If this variable has a value, then the language family must match at least
+ /// one of the specified languages. If this variable has no value, then the
+ /// language of the type doesn't need to match any types that are searched.
+ std::optional<LanguageSet> m_languages;
+};
+
+/// This class tracks the state and results of a \ref TypeQuery.
+///
+/// Any mutable state required for type lookups and the results are tracked in
+/// this object.
+class TypeResults {
+public:
+ /// Construct a type results object
+ TypeResults() = default;
+
+ /// When types that match a TypeQuery are found, this API is used to insert
+ /// the matching types.
+ ///
+ /// \return
+ /// True if the type was added, false if the \a type_sp was already in the
+ /// results.
+ bool InsertUnique(const lldb::TypeSP &type_sp);
+
+ /// Check if the type matching has found all of the matches that it needs.
+ bool Done(const TypeQuery &query) const;
+
+ /// Check if a SymbolFile object has already been searched by this type match
+ /// object.
+ ///
+ /// This function will add \a sym_file to the set of SymbolFile objects if it
+ /// isn't already in the set and return \a false. Returns true if \a sym_file
+ /// was already in the set and doesn't need to be searched.
+ ///
+ /// Any clients that search for types should first check that the symbol file
+ /// has not already been searched. If this function returns true, the type
+ /// search function should early return to avoid duplicating type searchihng
+ /// efforts.
+ ///
+ /// \param[in] sym_file
+ /// A SymbolFile pointer that will be used to track which symbol files have
+ /// already been searched.
+ ///
+ /// \returns
+ /// True if the symbol file has been search already, false otherwise.
+ bool AlreadySearched(lldb_private::SymbolFile *sym_file);
+
+ /// Access the set of searched symbol files.
+ llvm::DenseSet<lldb_private::SymbolFile *> &GetSearchedSymbolFiles() {
+ return m_searched_symbol_files;
+ }
+
+ lldb::TypeSP GetFirstType() const { return m_type_map.FirstType(); }
+ TypeMap &GetTypeMap() { return m_type_map; }
+ const TypeMap &GetTypeMap() const { return m_type_map; }
+
+private:
+ /// Matching types get added to this map as type search continues.
+ TypeMap m_type_map;
+ /// This set is used to track and make sure we only perform lookups in a
+ /// symbol file one time.
+ llvm::DenseSet<lldb_private::SymbolFile *> m_searched_symbol_files;
+};
+
class SymbolFileType : public std::enable_shared_from_this<SymbolFileType>,
public UserID {
public:
diff --git a/lldb/include/lldb/Symbol/TypeMap.h b/lldb/include/lldb/Symbol/TypeMap.h
index c200ccb9844f..433711875e55 100644
--- a/lldb/include/lldb/Symbol/TypeMap.h
+++ b/lldb/include/lldb/Symbol/TypeMap.h
@@ -27,7 +27,7 @@ public:
void Clear();
void Dump(Stream *s, bool show_context,
- lldb::DescriptionLevel level = lldb::eDescriptionLevelFull);
+ lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) const;
TypeMap FindTypes(ConstString name);
@@ -41,10 +41,12 @@ public:
lldb::TypeSP GetTypeAtIndex(uint32_t idx);
+ lldb::TypeSP FirstType() const;
+
typedef std::multimap<lldb::user_id_t, lldb::TypeSP> collection;
typedef AdaptedIterable<collection, lldb::TypeSP, map_adapter> TypeIterable;
- TypeIterable Types() { return TypeIterable(m_types); }
+ TypeIterable Types() const { return TypeIterable(m_types); }
void ForEach(
std::function<bool(const lldb::TypeSP &type_sp)> const &callback) const;
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index cd5004a3f34d..63829131556e 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -26,6 +26,7 @@
#include "lldb/Expression/Expression.h"
#include "lldb/Symbol/CompilerDecl.h"
#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/Symbol/Type.h"
#include "lldb/lldb-private.h"
class PDBASTParser;
@@ -43,23 +44,6 @@ namespace npdb {
class PdbAstBuilder;
} // namespace npdb
-/// A SmallBitVector that represents a set of source languages (\p
-/// lldb::LanguageType). Each lldb::LanguageType is represented by
-/// the bit with the position of its enumerator. The largest
-/// LanguageType is < 64, so this is space-efficient and on 64-bit
-/// architectures a LanguageSet can be completely stack-allocated.
-struct LanguageSet {
- llvm::SmallBitVector bitvector;
- LanguageSet();
-
- /// If the set contains a single language only, return it.
- std::optional<lldb::LanguageType> GetSingularLanguage();
- void Insert(lldb::LanguageType language);
- bool Empty() const;
- size_t Size() const;
- bool operator[](unsigned i) const;
-};
-
/// Interface for representing a type system.
///
/// Implemented by language plugins to define the type system for a given
@@ -122,6 +106,9 @@ public:
virtual CompilerType DeclGetFunctionArgumentType(void *opaque_decl,
size_t arg_idx);
+ virtual std::vector<lldb_private::CompilerContext>
+ DeclGetCompilerContext(void *opaque_decl);
+
virtual CompilerType GetTypeForDecl(void *opaque_decl) = 0;
// CompilerDeclContext functions
@@ -146,6 +133,9 @@ public:
virtual CompilerDeclContext
GetCompilerDeclContextForType(const CompilerType &type);
+ virtual std::vector<lldb_private::CompilerContext>
+ DeclContextGetCompilerContext(void *opaque_decl_ctx);
+
// Tests
#ifndef NDEBUG
/// Verify the integrity of the type to catch CompilerTypes that mix
diff --git a/lldb/include/lldb/Utility/CompletionRequest.h b/lldb/include/lldb/Utility/CompletionRequest.h
index 1fbc96944e82..1a2b1d639950 100644
--- a/lldb/include/lldb/Utility/CompletionRequest.h
+++ b/lldb/include/lldb/Utility/CompletionRequest.h
@@ -184,7 +184,7 @@ public:
// this can be a static_assert.
static_assert(M != CompletionMode::RewriteLine,
"Shouldn't rewrite line with this function");
- if (completion.startswith(GetCursorArgumentPrefix()))
+ if (completion.starts_with(GetCursorArgumentPrefix()))
AddCompletion(completion, description, M);
}
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 633a3ee696c2..ed1dec85d484 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -1270,36 +1270,38 @@ enum WatchpointValueKind {
};
enum CompletionType {
- eNoCompletion = 0u,
- eSourceFileCompletion = (1u << 0),
- eDiskFileCompletion = (1u << 1),
- eDiskDirectoryCompletion = (1u << 2),
- eSymbolCompletion = (1u << 3),
- eModuleCompletion = (1u << 4),
- eSettingsNameCompletion = (1u << 5),
- ePlatformPluginCompletion = (1u << 6),
- eArchitectureCompletion = (1u << 7),
- eVariablePathCompletion = (1u << 8),
- eRegisterCompletion = (1u << 9),
- eBreakpointCompletion = (1u << 10),
- eProcessPluginCompletion = (1u << 11),
- eDisassemblyFlavorCompletion = (1u << 12),
- eTypeLanguageCompletion = (1u << 13),
- eFrameIndexCompletion = (1u << 14),
- eModuleUUIDCompletion = (1u << 15),
- eStopHookIDCompletion = (1u << 16),
- eThreadIndexCompletion = (1u << 17),
- eWatchpointIDCompletion = (1u << 18),
- eBreakpointNameCompletion = (1u << 19),
- eProcessIDCompletion = (1u << 20),
- eProcessNameCompletion = (1u << 21),
- eRemoteDiskFileCompletion = (1u << 22),
- eRemoteDiskDirectoryCompletion = (1u << 23),
- eTypeCategoryNameCompletion = (1u << 24),
- // This item serves two purposes. It is the last element in the enum, so
- // you can add custom enums starting from here in your Option class. Also
- // if you & in this bit the base code will not process the option.
- eCustomCompletion = (1u << 25)
+ eNoCompletion = 0ul,
+ eSourceFileCompletion = (1ul << 0),
+ eDiskFileCompletion = (1ul << 1),
+ eDiskDirectoryCompletion = (1ul << 2),
+ eSymbolCompletion = (1ul << 3),
+ eModuleCompletion = (1ul << 4),
+ eSettingsNameCompletion = (1ul << 5),
+ ePlatformPluginCompletion = (1ul << 6),
+ eArchitectureCompletion = (1ul << 7),
+ eVariablePathCompletion = (1ul << 8),
+ eRegisterCompletion = (1ul << 9),
+ eBreakpointCompletion = (1ul << 10),
+ eProcessPluginCompletion = (1ul << 11),
+ eDisassemblyFlavorCompletion = (1ul << 12),
+ eTypeLanguageCompletion = (1ul << 13),
+ eFrameIndexCompletion = (1ul << 14),
+ eModuleUUIDCompletion = (1ul << 15),
+ eStopHookIDCompletion = (1ul << 16),
+ eThreadIndexCompletion = (1ul << 17),
+ eWatchpointIDCompletion = (1ul << 18),
+ eBreakpointNameCompletion = (1ul << 19),
+ eProcessIDCompletion = (1ul << 20),
+ eProcessNameCompletion = (1ul << 21),
+ eRemoteDiskFileCompletion = (1ul << 22),
+ eRemoteDiskDirectoryCompletion = (1ul << 23),
+ eTypeCategoryNameCompletion = (1ul << 24),
+ eCustomCompletion = (1ul << 25),
+ eThreadIDCompletion = (1ul << 26),
+ // This last enum element is just for input validation.
+ // Add new completions before this element,
+ // and then increment eTerminatorCompletion's shift value
+ eTerminatorCompletion = (1ul << 27)
};
} // namespace lldb
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 068fce4976ed..4e0c62fa26ca 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -258,9 +258,11 @@ class TypeImpl;
class TypeList;
class TypeListImpl;
class TypeMap;
+class TypeQuery;
class TypeMemberFunctionImpl;
class TypeMemberImpl;
class TypeNameSpecifierImpl;
+class TypeResults;
class TypeSummaryImpl;
class TypeSummaryOptions;
class TypeSystem;
diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h
index 7f98220f9f16..5f1597200a83 100644
--- a/lldb/include/lldb/lldb-private-enumerations.h
+++ b/lldb/include/lldb/lldb-private-enumerations.h
@@ -198,12 +198,15 @@ enum class CompilerContextKind : uint16_t {
Variable = 1 << 7,
Enum = 1 << 8,
Typedef = 1 << 9,
+ Builtin = 1 << 10,
Any = 1 << 15,
/// Match 0..n nested modules.
AnyModule = Any | Module,
/// Match any type.
- AnyType = Any | Class | Struct | Union | Enum | Typedef
+ AnyType = Any | Class | Struct | Union | Enum | Typedef | Builtin,
+ /// Math any declaration context.
+ AnyDeclContext = Any | Namespace | Class | Struct | Union | Enum | Function
};
// Enumerations that can be used to specify the kind of metric we're looking at
diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp
index b865502228e0..262e26c6bf43 100644
--- a/lldb/source/API/SBModule.cpp
+++ b/lldb/source/API/SBModule.cpp
@@ -437,26 +437,25 @@ lldb::SBType SBModule::FindFirstType(const char *name_cstr) {
LLDB_INSTRUMENT_VA(this, name_cstr);
ModuleSP module_sp(GetSP());
- if (!name_cstr || !module_sp)
- return {};
- SymbolContext sc;
- const bool exact_match = false;
- ConstString name(name_cstr);
+ if (name_cstr && module_sp) {
+ ConstString name(name_cstr);
+ TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_find_one);
+ TypeResults results;
+ module_sp->FindTypes(query, results);
+ TypeSP type_sp = results.GetFirstType();
+ if (type_sp)
+ return SBType(type_sp);
- SBType sb_type = SBType(module_sp->FindFirstType(sc, name, exact_match));
-
- if (sb_type.IsValid())
- return sb_type;
+ auto type_system_or_err =
+ module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
+ if (auto err = type_system_or_err.takeError()) {
+ llvm::consumeError(std::move(err));
+ return {};
+ }
- auto type_system_or_err = module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
- if (auto err = type_system_or_err.takeError()) {
- llvm::consumeError(std::move(err));
- return {};
+ if (auto ts = *type_system_or_err)
+ return SBType(ts->GetBuiltinTypeByName(name));
}
-
- if (auto ts = *type_system_or_err)
- return SBType(ts->GetBuiltinTypeByName(name));
-
return {};
}
@@ -471,7 +470,7 @@ lldb::SBType SBModule::GetBasicType(lldb::BasicType type) {
llvm::consumeError(std::move(err));
} else {
if (auto ts = *type_system_or_err)
- return SBType(ts->GetBasicTypeFromAST(type));
+ return SBType(ts->GetBasicTypeFromAST(type));
}
}
return SBType();
@@ -485,13 +484,11 @@ lldb::SBTypeList SBModule::FindTypes(const char *type) {
ModuleSP module_sp(GetSP());
if (type && module_sp) {
TypeList type_list;
- const bool exact_match = false;
- ConstString name(type);
- llvm::DenseSet<SymbolFile *> searched_symbol_files;
- module_sp->FindTypes(name, exact_match, UINT32_MAX, searched_symbol_files,
- type_list);
-
- if (type_list.Empty()) {
+ TypeQuery query(type);
+ TypeResults results;
+ module_sp->FindTypes(query, results);
+ if (results.GetTypeMap().Empty()) {
+ ConstString name(type);
auto type_system_or_err =
module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
if (auto err = type_system_or_err.takeError()) {
@@ -502,11 +499,8 @@ lldb::SBTypeList SBModule::FindTypes(const char *type) {
retval.Append(SBType(compiler_type));
}
} else {
- for (size_t idx = 0; idx < type_list.GetSize(); idx++) {
- TypeSP type_sp(type_list.GetTypeAtIndex(idx));
- if (type_sp)
- retval.Append(SBType(type_sp));
- }
+ for (const TypeSP &type_sp : results.GetTypeMap().Types())
+ retval.Append(SBType(type_sp));
}
}
return retval;
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 2d029554492a..8e616afbcb4e 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1804,21 +1804,13 @@ lldb::SBType SBTarget::FindFirstType(const char *typename_cstr) {
TargetSP target_sp(GetSP());
if (typename_cstr && typename_cstr[0] && target_sp) {
ConstString const_typename(typename_cstr);
- SymbolContext sc;
- const bool exact_match = false;
-
- const ModuleList &module_list = target_sp->GetImages();
- size_t count = module_list.GetSize();
- for (size_t idx = 0; idx < count; idx++) {
- ModuleSP module_sp(module_list.GetModuleAtIndex(idx));
- if (module_sp) {
- TypeSP type_sp(
- module_sp->FindFirstType(sc, const_typename, exact_match));
- if (type_sp)
- return SBType(type_sp);
- }
- }
-
+ TypeQuery query(const_typename.GetStringRef(),
+ TypeQueryOptions::e_find_one);
+ TypeResults results;
+ target_sp->GetImages().FindTypes(/*search_first=*/nullptr, query, results);
+ TypeSP type_sp = results.GetFirstType();
+ if (type_sp)
+ return SBType(type_sp);
// Didn't find the type in the symbols; Try the loaded language runtimes.
if (auto process_sp = target_sp->GetProcessSP()) {
for (auto *runtime : process_sp->GetLanguageRuntimes()) {
@@ -1859,17 +1851,11 @@ lldb::SBTypeList SBTarget::FindTypes(const char *typename_cstr) {
if (typename_cstr && typename_cstr[0] && target_sp) {
ModuleList &images = target_sp->GetImages();
ConstString const_typename(typename_cstr);
- bool exact_match = false;
- TypeList type_list;
- llvm::DenseSet<SymbolFile *> searched_symbol_files;
- images.FindTypes(nullptr, const_typename, exact_match, UINT32_MAX,
- searched_symbol_files, type_list);
-
- for (size_t idx = 0; idx < type_list.GetSize(); idx++) {
- TypeSP type_sp(type_list.GetTypeAtIndex(idx));
- if (type_sp)
- sb_type_list.Append(SBType(type_sp));
- }
+ TypeQuery query(typename_cstr);
+ TypeResults results;
+ images.FindTypes(nullptr, query, results);
+ for (const TypeSP &type_sp : results.GetTypeMap().Types())
+ sb_type_list.Append(SBType(type_sp));
// Try the loaded language runtimes
if (auto process_sp = target_sp->GetProcessSP()) {
diff --git a/lldb/source/Breakpoint/BreakpointResolver.cpp b/lldb/source/Breakpoint/BreakpointResolver.cpp
index 60406bdc4462..89ea308b1eb0 100644
--- a/lldb/source/Breakpoint/BreakpointResolver.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolver.cpp
@@ -113,23 +113,23 @@ BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
switch (resolver_type) {
case FileLineResolver:
result_sp = BreakpointResolverFileLine::CreateFromStructuredData(
- nullptr, *subclass_options, error);
+ *subclass_options, error);
break;
case AddressResolver:
result_sp = BreakpointResolverAddress::CreateFromStructuredData(
- nullptr, *subclass_options, error);
+ *subclass_options, error);
break;
case NameResolver:
result_sp = BreakpointResolverName::CreateFromStructuredData(
- nullptr, *subclass_options, error);
+ *subclass_options, error);
break;
case FileRegexResolver:
result_sp = BreakpointResolverFileRegex::CreateFromStructuredData(
- nullptr, *subclass_options, error);
+ *subclass_options, error);
break;
case PythonResolver:
result_sp = BreakpointResolverScripted::CreateFromStructuredData(
- nullptr, *subclass_options, error);
+ *subclass_options, error);
break;
case ExceptionResolver:
error.SetErrorString("Exception resolvers are hard.");
diff --git a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
index 19fc81a28a7f..a0c628a8e299 100644
--- a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
@@ -31,8 +31,7 @@ BreakpointResolverAddress::BreakpointResolverAddress(const BreakpointSP &bkpt,
m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS) {}
BreakpointResolverSP BreakpointResolverAddress::CreateFromStructuredData(
- const BreakpointSP &bkpt, const StructuredData::Dictionary &options_dict,
- Status &error) {
+ const StructuredData::Dictionary &options_dict, Status &error) {
llvm::StringRef module_name;
lldb::offset_t addr_offset;
FileSpec module_filespec;
@@ -56,7 +55,7 @@ BreakpointResolverSP BreakpointResolverAddress::CreateFromStructuredData(
}
module_filespec.SetFile(module_name, FileSpec::Style::native);
}
- return std::make_shared<BreakpointResolverAddress>(bkpt, address,
+ return std::make_shared<BreakpointResolverAddress>(nullptr, address,
module_filespec);
}
diff --git a/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
index c28b78a0056f..cc4e1d26724f 100644
--- a/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -31,8 +31,7 @@ BreakpointResolverFileLine::BreakpointResolverFileLine(
m_removed_prefix_opt(removed_prefix_opt) {}
BreakpointResolverSP BreakpointResolverFileLine::CreateFromStructuredData(
- const BreakpointSP &bkpt, const StructuredData::Dictionary &options_dict,
- Status &error) {
+ const StructuredData::Dictionary &options_dict, Status &error) {
llvm::StringRef filename;
uint32_t line;
uint16_t column;
@@ -91,7 +90,7 @@ BreakpointResolverSP BreakpointResolverFileLine::CreateFromStructuredData(
return nullptr;
return std::make_shared<BreakpointResolverFileLine>(
- bkpt, offset, skip_prologue, location_spec);
+ nullptr, offset, skip_prologue, location_spec);
}
StructuredData::ObjectSP
@@ -207,7 +206,7 @@ void BreakpointResolverFileLine::DeduceSourceMapping(
[path_separator](llvm::StringRef a, llvm::StringRef b,
bool case_sensitive) -> std::optional<llvm::StringRef> {
if (case_sensitive ? a.consume_back(b) : a.consume_back_insensitive(b)) {
- if (a.empty() || a.endswith(path_separator)) {
+ if (a.empty() || a.ends_with(path_separator)) {
return a;
}
}
diff --git a/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp b/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp
index 13c7f17fd807..06d346afb9f6 100644
--- a/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp
@@ -27,7 +27,6 @@ BreakpointResolverFileRegex::BreakpointResolverFileRegex(
m_function_names(func_names) {}
BreakpointResolverSP BreakpointResolverFileRegex::CreateFromStructuredData(
- const lldb::BreakpointSP &bkpt,
const StructuredData::Dictionary &options_dict, Status &error) {
bool success;
@@ -67,8 +66,8 @@ BreakpointResolverSP BreakpointResolverFileRegex::CreateFromStructuredData(
}
}
- return std::make_shared<BreakpointResolverFileRegex>(bkpt, std::move(regex),
- names_set, exact_match);
+ return std::make_shared<BreakpointResolverFileRegex>(
+ nullptr, std::move(regex), names_set, exact_match);
}
StructuredData::ObjectSP
diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp
index 0097046cf511..82eef43ad6cf 100644
--- a/lldb/source/Breakpoint/BreakpointResolverName.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp
@@ -87,8 +87,7 @@ BreakpointResolverName::BreakpointResolverName(
m_language(rhs.m_language), m_skip_prologue(rhs.m_skip_prologue) {}
BreakpointResolverSP BreakpointResolverName::CreateFromStructuredData(
- const BreakpointSP &bkpt, const StructuredData::Dictionary &options_dict,
- Status &error) {
+ const StructuredData::Dictionary &options_dict, Status &error) {
LanguageType language = eLanguageTypeUnknown;
llvm::StringRef language_name;
bool success = options_dict.GetValueForKeyAsString(
@@ -123,7 +122,8 @@ BreakpointResolverSP BreakpointResolverName::CreateFromStructuredData(
GetKey(OptionNames::RegexString), regex_text);
if (success) {
return std::make_shared<BreakpointResolverName>(
- bkpt, RegularExpression(regex_text), language, offset, skip_prologue);
+ nullptr, RegularExpression(regex_text), language, offset,
+ skip_prologue);
} else {
StructuredData::Array *names_array;
success = options_dict.GetValueForKeyAsArray(
@@ -173,7 +173,7 @@ BreakpointResolverSP BreakpointResolverName::CreateFromStructuredData(
std::shared_ptr<BreakpointResolverName> resolver_sp =
std::make_shared<BreakpointResolverName>(
- bkpt, names[0].c_str(), name_masks[0], language,
+ nullptr, names[0].c_str(), name_masks[0], language,
Breakpoint::MatchType::Exact, offset, skip_prologue);
for (size_t i = 1; i < num_elem; i++) {
resolver_sp->AddNameLookup(ConstString(names[i]), name_masks[i]);
diff --git a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
index 664ce4d573f9..dbfa8b8572f2 100644
--- a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
@@ -59,8 +59,7 @@ void BreakpointResolverScripted::NotifyBreakpointSet() {
}
BreakpointResolverSP BreakpointResolverScripted::CreateFromStructuredData(
- const BreakpointSP &bkpt, const StructuredData::Dictionary &options_dict,
- Status &error) {
+ const StructuredData::Dictionary &options_dict, Status &error) {
llvm::StringRef class_name;
bool success;
@@ -79,8 +78,8 @@ BreakpointResolverSP BreakpointResolverScripted::CreateFromStructuredData(
if (options_dict.GetValueForKeyAsDictionary(GetKey(OptionNames::ScriptArgs),
args_dict))
args_data_impl.SetObjectSP(args_dict->shared_from_this());
- return std::make_shared<BreakpointResolverScripted>(bkpt, class_name, depth,
- args_data_impl);
+ return std::make_shared<BreakpointResolverScripted>(nullptr, class_name,
+ depth, args_data_impl);
}
StructuredData::ObjectSP
diff --git a/lldb/source/Commands/CommandCompletions.cpp b/lldb/source/Commands/CommandCompletions.cpp
index 4d7e3d7f2497..16078a92ab5f 100644
--- a/lldb/source/Commands/CommandCompletions.cpp
+++ b/lldb/source/Commands/CommandCompletions.cpp
@@ -44,7 +44,7 @@ typedef void (*CompletionCallback)(CommandInterpreter &interpreter,
lldb_private::SearchFilter *searcher);
struct CommonCompletionElement {
- uint32_t type;
+ uint64_t type;
CompletionCallback callback;
};
@@ -54,6 +54,7 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks(
bool handled = false;
const CommonCompletionElement common_completions[] = {
+ {lldb::eNoCompletion, nullptr},
{lldb::eSourceFileCompletion, CommandCompletions::SourceFiles},
{lldb::eDiskFileCompletion, CommandCompletions::DiskFiles},
{lldb::eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
@@ -83,12 +84,13 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks(
CommandCompletions::RemoteDiskDirectories},
{lldb::eTypeCategoryNameCompletion,
CommandCompletions::TypeCategoryNames},
- {lldb::CompletionType::eNoCompletion,
+ {lldb::eThreadIDCompletion, CommandCompletions::ThreadIDs},
+ {lldb::eTerminatorCompletion,
nullptr} // This one has to be last in the list.
};
for (int i = 0;; i++) {
- if (common_completions[i].type == lldb::eNoCompletion)
+ if (common_completions[i].type == lldb::eTerminatorCompletion)
break;
else if ((common_completions[i].type & completion_mask) ==
common_completions[i].type &&
@@ -333,7 +335,7 @@ static void DiskFilesOrDirectories(const llvm::Twine &partial_name,
llvm::StringRef SearchDir;
llvm::StringRef PartialItem;
- if (CompletionBuffer.startswith("~")) {
+ if (CompletionBuffer.starts_with("~")) {
llvm::StringRef Buffer = CompletionBuffer;
size_t FirstSep =
Buffer.find_if([](char c) { return path::is_separator(c); });
@@ -422,7 +424,7 @@ static void DiskFilesOrDirectories(const llvm::Twine &partial_name,
auto Name = path::filename(Entry.path());
// Omit ".", ".."
- if (Name == "." || Name == ".." || !Name.startswith(PartialItem))
+ if (Name == "." || Name == ".." || !Name.starts_with(PartialItem))
continue;
bool is_dir = Status->isDirectory();
@@ -606,7 +608,7 @@ void CommandCompletions::Registers(CommandInterpreter &interpreter,
CompletionRequest &request,
SearchFilter *searcher) {
std::string reg_prefix;
- if (request.GetCursorArgumentPrefix().startswith("$"))
+ if (request.GetCursorArgumentPrefix().starts_with("$"))
reg_prefix = "$";
RegisterContext *reg_ctx =
@@ -807,6 +809,23 @@ void CommandCompletions::TypeCategoryNames(CommandInterpreter &interpreter,
});
}
+void CommandCompletions::ThreadIDs(CommandInterpreter &interpreter,
+ CompletionRequest &request,
+ SearchFilter *searcher) {
+ const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
+ if (!exe_ctx.HasProcessScope())
+ return;
+
+ ThreadList &threads = exe_ctx.GetProcessPtr()->GetThreadList();
+ lldb::ThreadSP thread_sp;
+ for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) {
+ StreamString strm;
+ thread_sp->GetStatus(strm, 0, 1, 1, true);
+ request.TryCompleteCurrentArg(std::to_string(thread_sp->GetID()),
+ strm.GetString());
+ }
+}
+
void CommandCompletions::CompleteModifiableCmdPathArgs(
CommandInterpreter &interpreter, CompletionRequest &request,
OptionElementVector &opt_element_vector) {
diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp
index 74d97b0db16c..5b9af4a3e1b8 100644
--- a/lldb/source/Commands/CommandObjectCommands.cpp
+++ b/lldb/source/Commands/CommandObjectCommands.cpp
@@ -411,7 +411,7 @@ protected:
// Get the alias command.
auto alias_command = args[0].ref();
- if (alias_command.startswith("-")) {
+ if (alias_command.starts_with("-")) {
result.AppendError("aliases starting with a dash are not supported");
if (alias_command == "--help" || alias_command == "--long-help") {
result.AppendWarning("if trying to pass options to 'command alias' add "
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
index b02b7dee5619..b78a0492cca5 100644
--- a/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -372,8 +372,6 @@ protected:
if (view_as_type_cstr && view_as_type_cstr[0]) {
// We are viewing memory as a type
- const bool exact_match = false;
- TypeList type_list;
uint32_t reference_count = 0;
uint32_t pointer_count = 0;
size_t idx;
@@ -452,18 +450,18 @@ protected:
}
}
- llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
ConstString lookup_type_name(type_str.c_str());
StackFrame *frame = m_exe_ctx.GetFramePtr();
ModuleSP search_first;
- if (frame) {
+ if (frame)
search_first = frame->GetSymbolContext(eSymbolContextModule).module_sp;
- }
- target->GetImages().FindTypes(search_first.get(), lookup_type_name,
- exact_match, 1, searched_symbol_files,
- type_list);
+ TypeQuery query(lookup_type_name.GetStringRef(),
+ TypeQueryOptions::e_find_one);
+ TypeResults results;
+ target->GetImages().FindTypes(search_first.get(), query, results);
+ TypeSP type_sp = results.GetFirstType();
- if (type_list.GetSize() == 0 && lookup_type_name.GetCString()) {
+ if (!type_sp && lookup_type_name.GetCString()) {
LanguageType language_for_type =
m_memory_options.m_language_for_type.GetCurrentValue();
std::set<LanguageType> languages_to_check;
@@ -499,15 +497,14 @@ protected:
}
if (!compiler_type.IsValid()) {
- if (type_list.GetSize() == 0) {
+ if (type_sp) {
+ compiler_type = type_sp->GetFullCompilerType();
+ } else {
result.AppendErrorWithFormat("unable to find any types that match "
"the raw type '%s' for full type '%s'\n",
lookup_type_name.GetCString(),
view_as_type_cstr);
return;
- } else {
- TypeSP type_sp(type_list.GetTypeAtIndex(0));
- compiler_type = type_sp->GetFullCompilerType();
}
}
@@ -1424,7 +1421,7 @@ protected:
// Be careful, getAsInteger with a radix of 16 rejects "0xab" so we
// have to special case that:
bool success = false;
- if (entry.ref().startswith("0x"))
+ if (entry.ref().starts_with("0x"))
success = !entry.ref().getAsInteger(0, uval64);
if (!success)
success = !entry.ref().getAsInteger(16, uval64);
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 63232c221ad1..bc8bc51356c8 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -1706,16 +1706,18 @@ static size_t LookupTypeInModule(Target *target,
CommandInterpreter &interpreter, Stream &strm,
Module *module, const char *name_cstr,
bool name_is_regex) {
- TypeList type_list;
if (module && name_cstr && name_cstr[0]) {
- const uint32_t max_num_matches = UINT32_MAX;
- bool name_is_fully_qualified = false;
-
- ConstString name(name_cstr);
- llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
- module->FindTypes(name, name_is_fully_qualified, max_num_matches,
- searched_symbol_files, type_list);
+ TypeQuery query(name_cstr);
+ TypeResults results;
+ module->FindTypes(query, results);
+ TypeList type_list;
+ SymbolContext sc;
+ if (module)
+ sc.module_sp = module->shared_from_this();
+ // Sort the type results and put the results that matched in \a module
+ // first if \a module was specified.
+ sc.SortTypeList(results.GetTypeMap(), type_list);
if (type_list.Empty())
return 0;
@@ -1748,22 +1750,21 @@ static size_t LookupTypeInModule(Target *target,
}
strm.EOL();
}
+ return type_list.GetSize();
}
- return type_list.GetSize();
+ return 0;
}
static size_t LookupTypeHere(Target *target, CommandInterpreter &interpreter,
Stream &strm, Module &module,
const char *name_cstr, bool name_is_regex) {
+ TypeQuery query(name_cstr);
+ TypeResults results;
+ module.FindTypes(query, results);
TypeList type_list;
- const uint32_t max_num_matches = UINT32_MAX;
- bool name_is_fully_qualified = false;
-
- ConstString name(name_cstr);
- llvm::DenseSet<SymbolFile *> searched_symbol_files;
- module.FindTypes(name, name_is_fully_qualified, max_num_matches,
- searched_symbol_files, type_list);
-
+ SymbolContext sc;
+ sc.module_sp = module.shared_from_this();
+ sc.SortTypeList(results.GetTypeMap(), type_list);
if (type_list.Empty())
return 0;
@@ -2082,7 +2083,7 @@ protected:
result.GetOutputStream().EOL();
result.GetOutputStream().EOL();
}
- if (INTERRUPT_REQUESTED(GetDebugger(),
+ if (INTERRUPT_REQUESTED(GetDebugger(),
"Interrupted in dump all symtabs with {0} "
"of {1} dumped.", num_dumped, num_modules))
break;
@@ -2112,8 +2113,8 @@ protected:
result.GetOutputStream().EOL();
result.GetOutputStream().EOL();
}
- if (INTERRUPT_REQUESTED(GetDebugger(),
- "Interrupted in dump symtab list with {0} of {1} dumped.",
+ if (INTERRUPT_REQUESTED(GetDebugger(),
+ "Interrupted in dump symtab list with {0} of {1} dumped.",
num_dumped, num_matches))
break;
@@ -2175,7 +2176,7 @@ protected:
result.GetOutputStream().Format("Dumping sections for {0} modules.\n",
num_modules);
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
- if (INTERRUPT_REQUESTED(GetDebugger(),
+ if (INTERRUPT_REQUESTED(GetDebugger(),
"Interrupted in dump all sections with {0} of {1} dumped",
image_idx, num_modules))
break;
@@ -2196,7 +2197,7 @@ protected:
FindModulesByName(target, arg_cstr, module_list, true);
if (num_matches > 0) {
for (size_t i = 0; i < num_matches; ++i) {
- if (INTERRUPT_REQUESTED(GetDebugger(),
+ if (INTERRUPT_REQUESTED(GetDebugger(),
"Interrupted in dump section list with {0} of {1} dumped.",
i, num_matches))
break;
@@ -2338,7 +2339,7 @@ protected:
}
for (size_t i = 0; i < num_matches; ++i) {
- if (INTERRUPT_REQUESTED(GetDebugger(),
+ if (INTERRUPT_REQUESTED(GetDebugger(),
"Interrupted in dump clang ast list with {0} of {1} dumped.",
i, num_matches))
break;
@@ -2477,9 +2478,9 @@ protected:
if (num_modules > 0) {
uint32_t num_dumped = 0;
for (ModuleSP module_sp : target_modules.ModulesNoLocking()) {
- if (INTERRUPT_REQUESTED(GetDebugger(),
+ if (INTERRUPT_REQUESTED(GetDebugger(),
"Interrupted in dump all line tables with "
- "{0} of {1} dumped", num_dumped,
+ "{0} of {1} dumped", num_dumped,
num_modules))
break;
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index a9f5a4f8a4fb..a1e7e3f11361 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -145,14 +145,14 @@ public:
for (size_t idx = 0; idx < num_entries; idx++) {
llvm::StringRef arg_string = copy_args[idx].ref();
- if (arg_string.equals("-c") || count_opt.startswith(arg_string)) {
+ if (arg_string.equals("-c") || count_opt.starts_with(arg_string)) {
idx++;
if (idx == num_entries)
return std::nullopt;
count_idx = idx;
if (copy_args[idx].ref().getAsInteger(0, count_val))
return std::nullopt;
- } else if (arg_string.equals("-s") || start_opt.startswith(arg_string)) {
+ } else if (arg_string.equals("-s") || start_opt.starts_with(arg_string)) {
idx++;
if (idx == num_entries)
return std::nullopt;
@@ -1129,11 +1129,51 @@ protected:
// CommandObjectThreadSelect
+#define LLDB_OPTIONS_thread_select
+#include "CommandOptions.inc"
+
class CommandObjectThreadSelect : public CommandObjectParsed {
public:
+ class OptionGroupThreadSelect : public OptionGroup {
+ public:
+ OptionGroupThreadSelect() { OptionParsingStarting(nullptr); }
+
+ ~OptionGroupThreadSelect() override = default;
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ }
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ const int short_option = g_thread_select_options[option_idx].short_option;
+ switch (short_option) {
+ case 't': {
+ if (option_arg.getAsInteger(0, m_thread_id)) {
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ return Status("Invalid thread ID: '%s'.", option_arg.str().c_str());
+ }
+ break;
+ }
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return {};
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::ArrayRef(g_thread_select_options);
+ }
+
+ lldb::tid_t m_thread_id;
+ };
+
CommandObjectThreadSelect(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "thread select",
- "Change the currently selected thread.", nullptr,
+ "Change the currently selected thread.",
+ "thread select <thread-index> (or -t <thread-id>)",
eCommandRequiresProcess | eCommandTryTargetAPILock |
eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused) {
@@ -1143,6 +1183,7 @@ public:
// Define the first (and only) variant of this arg.
thread_idx_arg.arg_type = eArgTypeThreadIndex;
thread_idx_arg.arg_repetition = eArgRepeatPlain;
+ thread_idx_arg.arg_opt_set_association = LLDB_OPT_SET_1;
// There is only one variant this argument could be; put it into the
// argument entry.
@@ -1150,6 +1191,9 @@ public:
// Push the data for the first argument into the m_arguments vector.
m_arguments.push_back(arg);
+
+ m_option_group.Append(&m_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
+ m_option_group.Finalize();
}
~CommandObjectThreadSelect() override = default;
@@ -1165,37 +1209,59 @@ public:
nullptr);
}
+ Options *GetOptions() override { return &m_option_group; }
+
protected:
void DoExecute(Args &command, CommandReturnObject &result) override {
Process *process = m_exe_ctx.GetProcessPtr();
if (process == nullptr) {
result.AppendError("no process");
return;
- } else if (command.GetArgumentCount() != 1) {
+ } else if (m_options.m_thread_id == LLDB_INVALID_THREAD_ID &&
+ command.GetArgumentCount() != 1) {
result.AppendErrorWithFormat(
- "'%s' takes exactly one thread index argument:\nUsage: %s\n",
+ "'%s' takes exactly one thread index argument, or a thread ID "
+ "option:\nUsage: %s\n",
m_cmd_name.c_str(), m_cmd_syntax.c_str());
return;
- }
-
- uint32_t index_id;
- if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) {
- result.AppendErrorWithFormat("Invalid thread index '%s'",
- command.GetArgumentAtIndex(0));
+ } else if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID &&
+ command.GetArgumentCount() != 0) {
+ result.AppendErrorWithFormat("'%s' cannot take both a thread ID option "
+ "and a thread index argument:\nUsage: %s\n",
+ m_cmd_name.c_str(), m_cmd_syntax.c_str());
return;
}
- Thread *new_thread =
- process->GetThreadList().FindThreadByIndexID(index_id).get();
- if (new_thread == nullptr) {
- result.AppendErrorWithFormat("invalid thread #%s.\n",
- command.GetArgumentAtIndex(0));
- return;
+ Thread *new_thread = nullptr;
+ if (command.GetArgumentCount() == 1) {
+ uint32_t index_id;
+ if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) {
+ result.AppendErrorWithFormat("Invalid thread index '%s'",
+ command.GetArgumentAtIndex(0));
+ return;
+ }
+ new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();
+ if (new_thread == nullptr) {
+ result.AppendErrorWithFormat("Invalid thread index #%s.\n",
+ command.GetArgumentAtIndex(0));
+ return;
+ }
+ } else {
+ new_thread =
+ process->GetThreadList().FindThreadByID(m_options.m_thread_id).get();
+ if (new_thread == nullptr) {
+ result.AppendErrorWithFormat("Invalid thread ID %" PRIu64 ".\n",
+ m_options.m_thread_id);
+ return;
+ }
}
process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true);
result.SetStatus(eReturnStatusSuccessFinishNoResult);
}
+
+ OptionGroupThreadSelect m_options;
+ OptionGroupOptions m_option_group;
};
// CommandObjectThreadList
@@ -1509,7 +1575,7 @@ protected:
// I am going to handle this by hand, because I don't want you to have to
// say:
// "thread return -- -5".
- if (command.startswith("-x")) {
+ if (command.starts_with("-x")) {
if (command.size() != 2U)
result.AppendWarning("Return values ignored when returning from user "
"called expressions");
diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp
index 411dc2fb723c..f76420f3cc68 100644
--- a/lldb/source/Commands/CommandObjectType.cpp
+++ b/lldb/source/Commands/CommandObjectType.cpp
@@ -1570,7 +1570,7 @@ void CommandObjectTypeSummaryAdd::DoExecute(Args &command,
static bool FixArrayTypeNameWithRegex(ConstString &type_name) {
llvm::StringRef type_name_ref(type_name.GetStringRef());
- if (type_name_ref.endswith("[]")) {
+ if (type_name_ref.ends_with("[]")) {
std::string type_name_str(type_name.GetCString());
type_name_str.resize(type_name_str.length() - 2);
if (type_name_str.back() != ' ')
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 542c78be5a12..ed3167727bcd 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1117,6 +1117,12 @@ let Command = "thread plan list" in {
Desc<"Display thread plans for unreported threads">;
}
+let Command = "thread select" in {
+ def thread_select_thread_id : Option<"thread-id", "t">, Group<2>,
+ Arg<"ThreadID">, Completion<"ThreadID">,
+ Desc<"Provide a thread ID instead of a thread index.">;
+}
+
let Command = "thread trace dump function calls" in {
def thread_trace_dump_function_calls_file : Option<"file", "F">, Group<1>,
Arg<"Filename">,
diff --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp
index abf0b6b801f3..620e68a28510 100644
--- a/lldb/source/Core/IOHandlerCursesGUI.cpp
+++ b/lldb/source/Core/IOHandlerCursesGUI.cpp
@@ -7052,7 +7052,7 @@ public:
m_file_sp->DisplaySourceLines(curr_line + 1, column, 0, 0,
&lineStream);
StringRef line = lineStream.GetString();
- if (line.endswith("\n"))
+ if (line.ends_with("\n"))
line = line.drop_back();
bool wasWritten = window.OutputColoredStringTruncated(
1, line, m_first_visible_column, is_pc_line);
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index 4587119519e9..23ae3913093f 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -42,20 +42,20 @@ Mangled::ManglingScheme Mangled::GetManglingScheme(llvm::StringRef const name) {
if (name.empty())
return Mangled::eManglingSchemeNone;
- if (name.startswith("?"))
+ if (name.starts_with("?"))
return Mangled::eManglingSchemeMSVC;
- if (name.startswith("_R"))
+ if (name.starts_with("_R"))
return Mangled::eManglingSchemeRustV0;
- if (name.startswith("_D"))
+ if (name.starts_with("_D"))
return Mangled::eManglingSchemeD;
- if (name.startswith("_Z"))
+ if (name.starts_with("_Z"))
return Mangled::eManglingSchemeItanium;
// ___Z is a clang extension of block invocations
- if (name.startswith("___Z"))
+ if (name.starts_with("___Z"))
return Mangled::eManglingSchemeItanium;
// Swift's older style of mangling used "_T" as a mangling prefix. This can
@@ -64,16 +64,16 @@ Mangled::ManglingScheme Mangled::GetManglingScheme(llvm::StringRef const name) {
// for select old-style swift mangled names. The known cases are ObjC classes
// and protocols. Classes are either prefixed with "_TtC" or "_TtGC".
// Protocols are prefixed with "_TtP".
- if (name.startswith("_TtC") || name.startswith("_TtGC") ||
- name.startswith("_TtP"))
+ if (name.starts_with("_TtC") || name.starts_with("_TtGC") ||
+ name.starts_with("_TtP"))
return Mangled::eManglingSchemeSwift;
// Swift 4.2 used "$S" and "_$S".
// Swift 5 and onward uses "$s" and "_$s".
// Swift also uses "@__swiftmacro_" as a prefix for mangling filenames.
- if (name.startswith("$S") || name.startswith("_$S") ||
- name.startswith("$s") || name.startswith("_$s") ||
- name.startswith("@__swiftmacro_"))
+ if (name.starts_with("$S") || name.starts_with("_$S") ||
+ name.starts_with("$s") || name.starts_with("_$s") ||
+ name.starts_with("@__swiftmacro_"))
return Mangled::eManglingSchemeSwift;
return Mangled::eManglingSchemeNone;
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index e6279a0feda8..c0574b724ace 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -949,99 +949,9 @@ void Module::FindAddressesForLine(const lldb::TargetSP target_sp,
}
}
-void Module::FindTypes_Impl(
- ConstString name, const CompilerDeclContext &parent_decl_ctx,
- size_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types) {
+void Module::FindTypes(const TypeQuery &query, TypeResults &results) {
if (SymbolFile *symbols = GetSymbolFile())
- symbols->FindTypes(name, parent_decl_ctx, max_matches,
- searched_symbol_files, types);
-}
-
-void Module::FindTypesInNamespace(ConstString type_name,
- const CompilerDeclContext &parent_decl_ctx,
- size_t max_matches, TypeList &type_list) {
- TypeMap types_map;
- llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
- FindTypes_Impl(type_name, parent_decl_ctx, max_matches, searched_symbol_files,
- types_map);
- if (types_map.GetSize()) {
- SymbolContext sc;
- sc.module_sp = shared_from_this();
- sc.SortTypeList(types_map, type_list);
- }
-}
-
-lldb::TypeSP Module::FindFirstType(const SymbolContext &sc, ConstString name,
- bool exact_match) {
- TypeList type_list;
- llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
- FindTypes(name, exact_match, 1, searched_symbol_files, type_list);
- if (type_list.GetSize())
- return type_list.GetTypeAtIndex(0);
- return TypeSP();
-}
-
-void Module::FindTypes(
- ConstString name, bool exact_match, size_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeList &types) {
- const char *type_name_cstr = name.GetCString();
- llvm::StringRef type_scope;
- llvm::StringRef type_basename;
- TypeClass type_class = eTypeClassAny;
- TypeMap typesmap;
-
- if (Type::GetTypeScopeAndBasename(type_name_cstr, type_scope, type_basename,
- type_class)) {
- // Check if "name" starts with "::" which means the qualified type starts
- // from the root namespace and implies and exact match. The typenames we
- // get back from clang do not start with "::" so we need to strip this off
- // in order to get the qualified names to match
- exact_match = type_scope.consume_front("::");
-
- ConstString type_basename_const_str(type_basename);
- FindTypes_Impl(type_basename_const_str, CompilerDeclContext(), max_matches,
- searched_symbol_files, typesmap);
- if (typesmap.GetSize())
- typesmap.RemoveMismatchedTypes(type_scope, type_basename, type_class,
- exact_match);
- } else {
- // The type is not in a namespace/class scope, just search for it by
- // basename
- if (type_class != eTypeClassAny && !type_basename.empty()) {
- // The "type_name_cstr" will have been modified if we have a valid type
- // class prefix (like "struct", "class", "union", "typedef" etc).
- FindTypes_Impl(ConstString(type_basename), CompilerDeclContext(),
- UINT_MAX, searched_symbol_files, typesmap);
- typesmap.RemoveMismatchedTypes(type_scope, type_basename, type_class,
- exact_match);
- } else {
- FindTypes_Impl(name, CompilerDeclContext(), UINT_MAX,
- searched_symbol_files, typesmap);
- if (exact_match) {
- typesmap.RemoveMismatchedTypes(type_scope, name, type_class,
- exact_match);
- }
- }
- }
- if (typesmap.GetSize()) {
- SymbolContext sc;
- sc.module_sp = shared_from_this();
- sc.SortTypeList(typesmap, types);
- }
-}
-
-void Module::FindTypes(
- llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types) {
- // If a scoped timer is needed, place it in a SymbolFile::FindTypes override.
- // A timer here is too high volume for some cases, for example when calling
- // FindTypes on each object file.
- if (SymbolFile *symbols = GetSymbolFile())
- symbols->FindTypes(pattern, languages, searched_symbol_files, types);
+ symbols->FindTypes(query, results);
}
static Debugger::DebuggerList
@@ -1444,7 +1354,7 @@ void Module::SetSymbolFileFileSpec(const FileSpec &file) {
if (FileSystem::Instance().IsDirectory(file)) {
std::string new_path(file.GetPath());
std::string old_path(obj_file->GetFileSpec().GetPath());
- if (llvm::StringRef(old_path).startswith(new_path)) {
+ if (llvm::StringRef(old_path).starts_with(new_path)) {
// We specified the same bundle as the symbol file that we already
// have
return;
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index 04a9df7dd63b..aa89c93c8d05 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -557,36 +557,21 @@ ModuleSP ModuleList::FindModule(const UUID &uuid) const {
return module_sp;
}
-void ModuleList::FindTypes(Module *search_first, ConstString name,
- bool name_is_fully_qualified, size_t max_matches,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeList &types) const {
+void ModuleList::FindTypes(Module *search_first, const TypeQuery &query,
+ TypeResults &results) const {
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
-
- collection::const_iterator pos, end = m_modules.end();
if (search_first) {
- for (pos = m_modules.begin(); pos != end; ++pos) {
- if (search_first == pos->get()) {
- search_first->FindTypes(name, name_is_fully_qualified, max_matches,
- searched_symbol_files, types);
-
- if (types.GetSize() >= max_matches)
- return;
- }
- }
- }
-
- for (pos = m_modules.begin(); pos != end; ++pos) {
- // Search the module if the module is not equal to the one in the symbol
- // context "sc". If "sc" contains a empty module shared pointer, then the
- // comparison will always be true (valid_module_ptr != nullptr).
- if (search_first != pos->get())
- (*pos)->FindTypes(name, name_is_fully_qualified, max_matches,
- searched_symbol_files, types);
-
- if (types.GetSize() >= max_matches)
+ search_first->FindTypes(query, results);
+ if (results.Done(query))
return;
}
+ for (const auto &module_sp : m_modules) {
+ if (search_first != module_sp.get()) {
+ module_sp->FindTypes(query, results);
+ if (results.Done(query))
+ return;
+ }
+ }
}
bool ModuleList::FindSourceFile(const FileSpec &orig_spec,
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index dea380e47f4e..b428370d7f33 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -821,7 +821,7 @@ PluginManager::GetPlatformCreateCallbackForPluginName(llvm::StringRef name) {
void PluginManager::AutoCompletePlatformName(llvm::StringRef name,
CompletionRequest &request) {
for (const auto &instance : GetPlatformInstances().GetInstances()) {
- if (instance.name.startswith(name))
+ if (instance.name.starts_with(name))
request.AddCompletion(instance.name);
}
}
@@ -869,7 +869,7 @@ PluginManager::GetProcessCreateCallbackForPluginName(llvm::StringRef name) {
void PluginManager::AutoCompleteProcessName(llvm::StringRef name,
CompletionRequest &request) {
for (const auto &instance : GetProcessInstances().GetInstances()) {
- if (instance.name.startswith(name))
+ if (instance.name.starts_with(name))
request.AddCompletion(instance.name, instance.description);
}
}
diff --git a/lldb/source/Core/RichManglingContext.cpp b/lldb/source/Core/RichManglingContext.cpp
index 08c9b280b8cc..b68c9e11581b 100644
--- a/lldb/source/Core/RichManglingContext.cpp
+++ b/lldb/source/Core/RichManglingContext.cpp
@@ -72,7 +72,7 @@ bool RichManglingContext::IsCtorOrDtor() const {
// We can only check for destructors here.
auto base_name =
get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
- return base_name.startswith("~");
+ return base_name.starts_with("~");
}
case None:
return false;
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index a7f7ee64282d..b82e6082eebd 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -398,13 +398,16 @@ ValueObject::GetChildAtIndexPath(llvm::ArrayRef<size_t> idxs,
if (idxs.size() == 0)
return GetSP();
ValueObjectSP root(GetSP());
+
+ size_t current_index = 0;
for (size_t idx : idxs) {
root = root->GetChildAtIndex(idx);
if (!root) {
if (index_of_error)
- *index_of_error = idx;
+ *index_of_error = current_index;
return root;
}
+ current_index += 1;
}
return root;
}
@@ -414,13 +417,17 @@ lldb::ValueObjectSP ValueObject::GetChildAtIndexPath(
if (idxs.size() == 0)
return GetSP();
ValueObjectSP root(GetSP());
+
+ size_t current_index = 0;
for (std::pair<size_t, bool> idx : idxs) {
root = root->GetChildAtIndex(idx.first, idx.second);
if (!root) {
if (index_of_error)
- *index_of_error = idx.first;
+ *index_of_error = current_index;
return root;
}
+
+ current_index += 1;
}
return root;
}
@@ -2105,7 +2112,7 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl(
*final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
return ValueObjectSP();
}
- if (!temp_expression.startswith(">")) {
+ if (!temp_expression.starts_with(">")) {
*reason_to_stop =
ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
*final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
diff --git a/lldb/source/DataFormatters/TypeFormat.cpp b/lldb/source/DataFormatters/TypeFormat.cpp
index 126240aeca65..409c452110bd 100644
--- a/lldb/source/DataFormatters/TypeFormat.cpp
+++ b/lldb/source/DataFormatters/TypeFormat.cpp
@@ -161,13 +161,12 @@ bool TypeFormatImpl_EnumType::FormatObject(ValueObject *valobj,
if (!target_sp)
return false;
const ModuleList &images(target_sp->GetImages());
- TypeList types;
- llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
- images.FindTypes(nullptr, m_enum_type, false, UINT32_MAX,
- searched_symbol_files, types);
- if (types.Empty())
+ TypeQuery query(m_enum_type.GetStringRef());
+ TypeResults results;
+ images.FindTypes(nullptr, query, results);
+ if (results.GetTypeMap().Empty())
return false;
- for (lldb::TypeSP type_sp : types.Types()) {
+ for (lldb::TypeSP type_sp : results.GetTypeMap().Types()) {
if (!type_sp)
continue;
if ((type_sp->GetForwardCompilerType().GetTypeInfo() &
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 562bf3cdd2ed..0682746e448e 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -537,7 +537,7 @@ lldb::SectionType IRExecutionUnit::GetSectionTypeFromSectionName(
sect_type = lldb::eSectionTypeCode;
else if (name.equals("__data") || name.equals(".data"))
sect_type = lldb::eSectionTypeCode;
- else if (name.startswith("__debug_") || name.startswith(".debug_")) {
+ else if (name.starts_with("__debug_") || name.starts_with(".debug_")) {
const uint32_t name_idx = name[0] == '_' ? 8 : 7;
llvm::StringRef dwarf_name(name.substr(name_idx));
switch (dwarf_name[0]) {
@@ -596,7 +596,7 @@ lldb::SectionType IRExecutionUnit::GetSectionTypeFromSectionName(
default:
break;
}
- } else if (name.startswith("__apple_") || name.startswith(".apple_"))
+ } else if (name.starts_with("__apple_") || name.starts_with(".apple_"))
sect_type = lldb::eSectionTypeInvalid;
else if (name.equals("__objc_imageinfo"))
sect_type = lldb::eSectionTypeOther;
diff --git a/lldb/source/Expression/REPL.cpp b/lldb/source/Expression/REPL.cpp
index 07d5b5b3dd93..a6a4ffb5e0af 100644
--- a/lldb/source/Expression/REPL.cpp
+++ b/lldb/source/Expression/REPL.cpp
@@ -497,7 +497,7 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
void REPL::IOHandlerComplete(IOHandler &io_handler,
CompletionRequest &request) {
// Complete an LLDB command if the first character is a colon...
- if (request.GetRawLine().startswith(":")) {
+ if (request.GetRawLine().starts_with(":")) {
Debugger &debugger = m_target.GetDebugger();
// auto complete LLDB commands
diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp
index 82e17ec753ab..ce707e530d00 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -978,8 +978,14 @@ void Editline::DisplayCompletions(
break;
fprintf(editline.m_output_file, "More (Y/n/a): ");
- char reply = 'n';
- int got_char = el_getc(editline.m_editline, &reply);
+ // The type for the output and the type for the parameter are different,
+ // to allow interoperability with older versions of libedit. The container
+ // for the reply must be as wide as what our implementation is using,
+ // but libedit may use a narrower type depending on the build
+ // configuration.
+ EditLineGetCharType reply = L'n';
+ int got_char = el_wgetc(editline.m_editline,
+ reinterpret_cast<EditLineCharType *>(&reply));
// Check for a ^C or other interruption.
if (editline.m_editor_status == EditorStatus::Interrupted) {
editline.m_editor_status = EditorStatus::Editing;
diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp
index 8314d3581f6a..f4cec97f5af6 100644
--- a/lldb/source/Host/common/Host.cpp
+++ b/lldb/source/Host/common/Host.cpp
@@ -554,7 +554,7 @@ bool Host::IsInteractiveGraphicSession() { return false; }
std::unique_ptr<Connection> Host::CreateDefaultConnection(llvm::StringRef url) {
#if defined(_WIN32)
- if (url.startswith("file://"))
+ if (url.starts_with("file://"))
return std::unique_ptr<Connection>(new ConnectionGenericFile());
#endif
return std::unique_ptr<Connection>(new ConnectionFileDescriptor());
diff --git a/lldb/source/Interpreter/CommandAlias.cpp b/lldb/source/Interpreter/CommandAlias.cpp
index b95d3c91fcbc..c5971b52f837 100644
--- a/lldb/source/Interpreter/CommandAlias.cpp
+++ b/lldb/source/Interpreter/CommandAlias.cpp
@@ -182,7 +182,7 @@ bool CommandAlias::IsDashDashCommand() {
for (const auto &opt_entry : *GetOptionArguments()) {
std::tie(opt, std::ignore, value) = opt_entry;
if (opt == CommandInterpreter::g_argument && !value.empty() &&
- llvm::StringRef(value).endswith("--")) {
+ llvm::StringRef(value).ends_with("--")) {
m_is_dashdash_alias = eLazyBoolYes;
break;
}
diff --git a/lldb/source/Interpreter/OptionArgParser.cpp b/lldb/source/Interpreter/OptionArgParser.cpp
index 8a92c7d08c47..d13805a75ffb 100644
--- a/lldb/source/Interpreter/OptionArgParser.cpp
+++ b/lldb/source/Interpreter/OptionArgParser.cpp
@@ -61,7 +61,7 @@ int64_t OptionArgParser::ToOptionEnum(llvm::StringRef s,
for (const auto &enum_value : enum_values) {
llvm::StringRef this_enum(enum_value.string_value);
- if (this_enum.startswith(s))
+ if (this_enum.starts_with(s))
return enum_value.value;
}
diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp
index acbde7660440..89fe69009d90 100644
--- a/lldb/source/Interpreter/Options.cpp
+++ b/lldb/source/Interpreter/Options.cpp
@@ -636,7 +636,7 @@ bool Options::HandleOptionCompletion(CompletionRequest &request,
// upper level code will know this is a full match and add the " ".
const OptionDefinition &opt = opt_defs[opt_defs_index];
llvm::StringRef long_option = opt.long_option;
- if (cur_opt_str.startswith("--") && cur_opt_str != long_option) {
+ if (cur_opt_str.starts_with("--") && cur_opt_str != long_option) {
request.AddCompletion("--" + long_option.str(), opt.usage_text);
return true;
} else
@@ -652,7 +652,7 @@ bool Options::HandleOptionCompletion(CompletionRequest &request,
if (cur_opt_str.consume_front("--")) {
for (auto &def : opt_defs) {
llvm::StringRef long_option(def.long_option);
- if (long_option.startswith(cur_opt_str))
+ if (long_option.starts_with(cur_opt_str))
request.AddCompletion("--" + long_option.str(), def.usage_text);
}
}
@@ -890,8 +890,8 @@ static size_t FindArgumentIndexForOption(const Args &args,
std::string long_opt =
std::string(llvm::formatv("--{0}", long_option.definition->long_option));
for (const auto &entry : llvm::enumerate(args)) {
- if (entry.value().ref().startswith(short_opt) ||
- entry.value().ref().startswith(long_opt))
+ if (entry.value().ref().starts_with(short_opt) ||
+ entry.value().ref().starts_with(long_opt))
return entry.index();
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 5d7e1252038d..79dd306f7627 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -201,19 +201,17 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
LLDB_LOG(log, " CTD Searching namespace {0} in module {1}",
item.second.GetName(), item.first->GetFileSpec().GetFilename());
- TypeList types;
-
ConstString name(decl->getName());
- item.first->FindTypesInNamespace(name, item.second, UINT32_MAX, types);
-
- for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) {
- lldb::TypeSP type = types.GetTypeAtIndex(ti);
-
- if (!type)
- continue;
+ // Create a type matcher using the CompilerDeclContext for the namespace
+ // as the context (item.second) and search for the name inside of this
+ // context.
+ TypeQuery query(item.second, name);
+ TypeResults results;
+ item.first->FindTypes(query, results);
- CompilerType clang_type(type->GetFullCompilerType());
+ for (const lldb::TypeSP &type_sp : results.GetTypeMap().Types()) {
+ CompilerType clang_type(type_sp->GetFullCompilerType());
if (!ClangUtil::IsClangType(clang_type))
continue;
@@ -233,24 +231,15 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
}
}
} else {
- TypeList types;
-
- ConstString name(decl->getName());
-
const ModuleList &module_list = m_target->GetImages();
+ // Create a type matcher using a CompilerDecl. Each TypeSystem class knows
+ // how to fill out a CompilerContext array using a CompilerDecl.
+ TypeQuery query(CompilerDecl(m_clang_ast_context, (void *)decl));
+ TypeResults results;
+ module_list.FindTypes(nullptr, query, results);
+ for (const lldb::TypeSP &type_sp : results.GetTypeMap().Types()) {
- bool exact_match = false;
- llvm::DenseSet<SymbolFile *> searched_symbol_files;
- module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX,
- searched_symbol_files, types);
-
- for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) {
- lldb::TypeSP type = types.GetTypeAtIndex(ti);
-
- if (!type)
- continue;
-
- CompilerType clang_type(type->GetFullCompilerType());
+ CompilerType clang_type(type_sp->GetFullCompilerType());
if (!ClangUtil::IsClangType(clang_type))
continue;
@@ -263,13 +252,6 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
TagDecl *candidate_tag_decl = const_cast<TagDecl *>(tag_type->getDecl());
- // We have found a type by basename and we need to make sure the decl
- // contexts are the same before we can try to complete this type with
- // another
- if (!TypeSystemClang::DeclsAreEquivalent(const_cast<TagDecl *>(decl),
- candidate_tag_decl))
- continue;
-
if (TypeSystemClang::GetCompleteDecl(&candidate_tag_decl->getASTContext(),
candidate_tag_decl))
return candidate_tag_decl;
@@ -589,8 +571,8 @@ bool ClangASTSource::IgnoreName(const ConstString name,
// The ClangASTSource is not responsible for finding $-names.
return name_string_ref.empty() ||
- (ignore_all_dollar_names && name_string_ref.startswith("$")) ||
- name_string_ref.startswith("_$");
+ (ignore_all_dollar_names && name_string_ref.starts_with("$")) ||
+ name_string_ref.starts_with("_$");
}
void ClangASTSource::FindExternalVisibleDecls(
@@ -614,41 +596,40 @@ void ClangASTSource::FindExternalVisibleDecls(
if (context.m_found_type)
return;
- TypeList types;
- const bool exact_match = true;
- llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
- if (module_sp && namespace_decl)
- module_sp->FindTypesInNamespace(name, namespace_decl, 1, types);
- else {
- m_target->GetImages().FindTypes(module_sp.get(), name, exact_match, 1,
- searched_symbol_files, types);
+ lldb::TypeSP type_sp;
+ TypeResults results;
+ if (module_sp && namespace_decl) {
+ // Match the name in the specified decl context.
+ TypeQuery query(namespace_decl, name, TypeQueryOptions::e_find_one);
+ module_sp->FindTypes(query, results);
+ type_sp = results.GetFirstType();
+ } else {
+ // Match the exact name of the type at the root level.
+ TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_exact_match |
+ TypeQueryOptions::e_find_one);
+ m_target->GetImages().FindTypes(nullptr, query, results);
+ type_sp = results.GetFirstType();
}
- if (size_t num_types = types.GetSize()) {
- for (size_t ti = 0; ti < num_types; ++ti) {
- lldb::TypeSP type_sp = types.GetTypeAtIndex(ti);
-
- if (log) {
- const char *name_string = type_sp->GetName().GetCString();
-
- LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\": {1}", name,
- (name_string ? name_string : "<anonymous>"));
- }
+ if (type_sp) {
+ if (log) {
+ const char *name_string = type_sp->GetName().GetCString();
- CompilerType full_type = type_sp->GetFullCompilerType();
+ LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\": {1}", name,
+ (name_string ? name_string : "<anonymous>"));
+ }
- CompilerType copied_clang_type(GuardedCopyType(full_type));
+ CompilerType full_type = type_sp->GetFullCompilerType();
- if (!copied_clang_type) {
- LLDB_LOG(log, " CAS::FEVD - Couldn't export a type");
+ CompilerType copied_clang_type(GuardedCopyType(full_type));
- continue;
- }
+ if (!copied_clang_type) {
+ LLDB_LOG(log, " CAS::FEVD - Couldn't export a type");
+ } else {
context.AddTypeDecl(copied_clang_type);
context.m_found_type = true;
- break;
}
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 6fbc0bb22f82..2d306b42760b 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1369,7 +1369,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
if (!namespace_decl)
SearchPersistenDecls(context, name);
- if (name.GetStringRef().startswith("$") && !namespace_decl) {
+ if (name.GetStringRef().starts_with("$") && !namespace_decl) {
if (name == "$__lldb_class") {
LookUpLldbClass(context);
return;
@@ -1385,7 +1385,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
}
// any other $__lldb names should be weeded out now
- if (name.GetStringRef().startswith("$__lldb"))
+ if (name.GetStringRef().starts_with("$__lldb"))
return;
// No ParserVars means we can't do register or variable lookup.
@@ -1400,7 +1400,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
return;
}
- assert(name.GetStringRef().startswith("$"));
+ assert(name.GetStringRef().starts_with("$"));
llvm::StringRef reg_name = name.GetStringRef().substr(1);
if (m_parser_vars->m_exe_ctx.GetRegisterContext()) {
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index f6856b1a2558..574d661e2a21 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -834,13 +834,13 @@ public:
case CodeCompletionResult::RK_Declaration:
return !(
Result.Declaration->getIdentifier() &&
- Result.Declaration->getIdentifier()->getName().startswith(Filter));
+ Result.Declaration->getIdentifier()->getName().starts_with(Filter));
case CodeCompletionResult::RK_Keyword:
- return !StringRef(Result.Keyword).startswith(Filter);
+ return !StringRef(Result.Keyword).starts_with(Filter);
case CodeCompletionResult::RK_Macro:
- return !Result.Macro->getName().startswith(Filter);
+ return !Result.Macro->getName().starts_with(Filter);
case CodeCompletionResult::RK_Pattern:
- return !StringRef(Result.Pattern->getAsString()).startswith(Filter);
+ return !StringRef(Result.Pattern->getAsString()).starts_with(Filter);
}
// If we trigger this assert or the above switch yields a warning, then
// CodeCompletionResult has been enhanced with more kinds of completion
@@ -904,7 +904,7 @@ private:
}
// We also filter some internal lldb identifiers here. The user
// shouldn't see these.
- if (llvm::StringRef(ToInsert).startswith("$__lldb_"))
+ if (llvm::StringRef(ToInsert).starts_with("$__lldb_"))
return std::nullopt;
if (ToInsert.empty())
return std::nullopt;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
index 847dab6592b8..62443d1290dc 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
@@ -72,7 +72,7 @@ bool CppModuleConfiguration::analyzeFile(const FileSpec &f,
// path. Ignore subdirectories such as /c++/v1/experimental as those don't
// need to be specified in the header search.
if (libcpp_regex.match(f.GetPath()) &&
- parent_path(posix_dir, Style::posix).endswith("c++")) {
+ parent_path(posix_dir, Style::posix).ends_with("c++")) {
if (!m_std_inc.TrySet(posix_dir))
return false;
if (triple.str().empty())
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
index 33e5dd0015ae..597873af8b2a 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
@@ -154,9 +154,10 @@ clang::NamedDecl *IRForTarget::DeclForGlobal(GlobalValue *global_val) {
/// Returns true iff the mangled symbol is for a static guard variable.
static bool isGuardVariableSymbol(llvm::StringRef mangled_symbol,
bool check_ms_abi = true) {
- bool result = mangled_symbol.startswith("_ZGV"); // Itanium ABI guard variable
+ bool result =
+ mangled_symbol.starts_with("_ZGV"); // Itanium ABI guard variable
if (check_ms_abi)
- result |= mangled_symbol.endswith("@4IA"); // Microsoft ABI
+ result |= mangled_symbol.ends_with("@4IA"); // Microsoft ABI
return result;
}
@@ -720,8 +721,9 @@ bool IRForTarget::RewriteObjCConstStrings() {
static bool IsObjCSelectorRef(Value *value) {
GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value);
- return !(!global_variable || !global_variable->hasName() ||
- !global_variable->getName().startswith("OBJC_SELECTOR_REFERENCES_"));
+ return !(
+ !global_variable || !global_variable->hasName() ||
+ !global_variable->getName().starts_with("OBJC_SELECTOR_REFERENCES_"));
}
// This function does not report errors; its callers are responsible.
@@ -940,7 +942,7 @@ bool IRForTarget::RewritePersistentAllocs(llvm::BasicBlock &basic_block) {
if (AllocaInst *alloc = dyn_cast<AllocaInst>(&inst)) {
llvm::StringRef alloc_name = alloc->getName();
- if (alloc_name.startswith("$") && !alloc_name.startswith("$__lldb")) {
+ if (alloc_name.starts_with("$") && !alloc_name.starts_with("$__lldb")) {
if (alloc_name.find_first_of("0123456789") == 1) {
LLDB_LOG(log, "Rejecting a numeric persistent variable.");
@@ -1017,7 +1019,7 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) {
const Type *value_type = nullptr;
- if (name.startswith("$")) {
+ if (name.starts_with("$")) {
// The $__lldb_expr_result name indicates the return value has allocated
// as a static variable. Per the comment at
// ASTResultSynthesizer::SynthesizeBodyResult, accesses to this static
@@ -1223,7 +1225,7 @@ bool IRForTarget::ResolveExternals(Function &llvm_function) {
LLDB_LOG(log, "Examining {0}, DeclForGlobalValue returns {1}", global_name,
static_cast<void *>(DeclForGlobal(&global_var)));
- if (global_name.startswith("OBJC_IVAR")) {
+ if (global_name.starts_with("OBJC_IVAR")) {
if (!HandleSymbol(&global_var)) {
m_error_stream.Format("Error [IRForTarget]: Couldn't find Objective-C "
"indirect ivar symbol {0}\n",
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index f4537b4133b9..586cc08a6f12 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -466,7 +466,7 @@ protected:
}
void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
- if (!llvm::StringRef(currentParserPos(), this->numLeft()).startswith(From))
+ if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
return;
// We found a match. Append unmodified input up to this point.
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 2e8da396a4a7..ff7043bdf97f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -84,7 +84,7 @@ static bool isStdTemplate(ConstString type_name, llvm::StringRef type) {
// The type name may be prefixed with `std::__<inline-namespace>::`.
if (name.consume_front("std::"))
consumeInlineNamespace(name);
- return name.consume_front(type) && name.startswith("<");
+ return name.consume_front(type) && name.starts_with("<");
}
static bool isUnorderedMap(ConstString type_name) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
index aef7cbac603f..f1bfeae5099b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
@@ -69,9 +69,9 @@ bool LibStdcppTupleSyntheticFrontEnd::Update() {
for (size_t i = 0; i < child_count; ++i) {
ValueObjectSP child_sp = current_child->GetChildAtIndex(i);
llvm::StringRef name_str = child_sp->GetName().GetStringRef();
- if (name_str.startswith("std::_Tuple_impl<")) {
+ if (name_str.starts_with("std::_Tuple_impl<")) {
next_child_sp = child_sp;
- } else if (name_str.startswith("std::_Head_base<")) {
+ } else if (name_str.starts_with("std::_Head_base<")) {
ValueObjectSP value_sp =
child_sp->GetChildMemberWithName("_M_head_impl");
if (value_sp) {
diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
index 605c79cbd9b5..5ae0751cb065 100644
--- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -37,7 +37,7 @@ NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(
ConstString class_name) {
- return class_name.GetStringRef().startswith(m_prefix.GetStringRef());
+ return class_name.GetStringRef().starts_with(m_prefix.GetStringRef());
}
NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)
diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
index 82b037129c24..742ae7b14945 100644
--- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -81,9 +81,9 @@ ObjCLanguage::MethodName::Create(llvm::StringRef name, bool strict) {
// Figure out type
Type type = eTypeUnspecified;
- if (name.startswith("+["))
+ if (name.starts_with("+["))
type = eTypeClassMethod;
- else if (name.startswith("-["))
+ else if (name.starts_with("-["))
type = eTypeInstanceMethod;
// If there's no type and it's strict, this is invalid
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
index e65b99f44be6..300ecc8e8ed5 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
@@ -220,7 +220,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
llvm::StringRef vtable_name(symbol->GetName().GetStringRef());
bool found_expected_start_string =
- vtable_name.startswith("vtable for std::__1::__function::__func<");
+ vtable_name.starts_with("vtable for std::__1::__function::__func<");
if (!found_expected_start_string)
return optional_info;
@@ -277,7 +277,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
}
// Case 4 or 5
- if (symbol && !symbol->GetName().GetStringRef().startswith("vtable for") &&
+ if (symbol && !symbol->GetName().GetStringRef().starts_with("vtable for") &&
!contains_lambda_identifier(first_template_parameter) && !has_invoke) {
optional_info.callable_case =
LibCppStdFunctionCallableCase::FreeOrMemberFunction;
@@ -312,7 +312,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
lldb::FunctionSP func_sp =
vtable_cu->FindFunction([name_to_use](const FunctionSP &f) {
auto name = f->GetName().GetStringRef();
- if (name.startswith(name_to_use) && name.contains("operator"))
+ if (name.starts_with(name_to_use) && name.contains("operator"))
return true;
return false;
@@ -373,7 +373,7 @@ CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread,
// step into the wrapped callable.
//
bool found_expected_start_string =
- function_name.startswith("std::__1::function<");
+ function_name.starts_with("std::__1::function<");
if (!found_expected_start_string)
return ret_plan_sp;
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index a5c9ead55f4c..47b1db16f1e9 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -82,24 +82,30 @@ TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfo(
lookup_name.append(class_name.data(), class_name.size());
type_info.SetName(class_name);
- const bool exact_match = true;
+ ConstString const_lookup_name(lookup_name);
TypeList class_types;
-
+ ModuleSP module_sp = vtable_info.symbol->CalculateSymbolContextModule();
// First look in the module that the vtable symbol came from and
// look for a single exact match.
- llvm::DenseSet<SymbolFile *> searched_symbol_files;
- ModuleSP module_sp = vtable_info.symbol->CalculateSymbolContextModule();
- if (module_sp)
- module_sp->FindTypes(ConstString(lookup_name), exact_match, 1,
- searched_symbol_files, class_types);
+ TypeResults results;
+ TypeQuery query(const_lookup_name.GetStringRef(),
+ TypeQueryOptions::e_exact_match |
+ TypeQueryOptions::e_find_one);
+ if (module_sp) {
+ module_sp->FindTypes(query, results);
+ TypeSP type_sp = results.GetFirstType();
+ if (type_sp)
+ class_types.Insert(type_sp);
+ }
// If we didn't find a symbol, then move on to the entire module
// list in the target and get as many unique matches as possible
- Target &target = m_process->GetTarget();
- if (class_types.Empty())
- target.GetImages().FindTypes(nullptr, ConstString(lookup_name),
- exact_match, UINT32_MAX,
- searched_symbol_files, class_types);
+ if (class_types.Empty()) {
+ query.SetFindOne(false);
+ m_process->GetTarget().GetImages().FindTypes(nullptr, query, results);
+ for (const auto &type_sp : results.GetTypeMap().Types())
+ class_types.Insert(type_sp);
+ }
lldb::TypeSP type_sp;
if (class_types.Empty()) {
@@ -268,7 +274,7 @@ llvm::Expected<LanguageRuntime::VTableInfo>
"no symbol found for 0x%" PRIx64,
vtable_load_addr);
llvm::StringRef name = symbol->GetMangled().GetDemangledName().GetStringRef();
- if (name.startswith(vtable_demangled_prefix)) {
+ if (name.starts_with(vtable_demangled_prefix)) {
VTableInfo info = {vtable_addr, symbol};
std::lock_guard<std::mutex> locker(m_mutex);
auto pos = m_vtable_info_map[vtable_addr] = info;
@@ -444,7 +450,7 @@ protected:
// on behalf of the user. This is the moral equivalent of the -_/-n
// options to c++filt
auto name = entry.ref();
- if (name.startswith("__Z"))
+ if (name.starts_with("__Z"))
name = name.drop_front();
Mangled mangled(name);
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 1fd7d027731d..dc492ac0f06d 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -2641,7 +2641,7 @@ static bool DoesProcessHaveSharedCache(Process &process) {
return true; // this should not happen
llvm::StringRef platform_plugin_name_sr = platform_sp->GetPluginName();
- if (platform_plugin_name_sr.endswith("-simulator"))
+ if (platform_plugin_name_sr.ends_with("-simulator"))
return false;
return true;
@@ -2731,7 +2731,7 @@ lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(ConstString name) {
llvm::StringRef ivar_prefix("OBJC_IVAR_$_");
llvm::StringRef class_prefix("OBJC_CLASS_$_");
- if (name_strref.startswith(ivar_prefix)) {
+ if (name_strref.starts_with(ivar_prefix)) {
llvm::StringRef ivar_skipped_prefix =
name_strref.substr(ivar_prefix.size());
std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar =
@@ -2764,7 +2764,7 @@ lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(ConstString name) {
ivar_func);
}
}
- } else if (name_strref.startswith(class_prefix)) {
+ } else if (name_strref.starts_with(class_prefix)) {
llvm::StringRef class_skipped_prefix =
name_strref.substr(class_prefix.size());
const ConstString class_name_cs(class_skipped_prefix);
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
index 289288a86245..ba52444f0c2f 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
@@ -139,17 +139,10 @@ ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) {
if (!module_sp)
return TypeSP();
- const bool exact_match = true;
- const uint32_t max_matches = UINT32_MAX;
- TypeList types;
-
- llvm::DenseSet<SymbolFile *> searched_symbol_files;
- module_sp->FindTypes(name, exact_match, max_matches, searched_symbol_files,
- types);
-
- for (uint32_t i = 0; i < types.GetSize(); ++i) {
- TypeSP type_sp(types.GetTypeAtIndex(i));
-
+ TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_exact_match);
+ TypeResults results;
+ module_sp->FindTypes(query, results);
+ for (const TypeSP &type_sp : results.GetTypeMap().Types()) {
if (TypeSystemClang::IsObjCObjectOrInterfaceType(
type_sp->GetForwardCompilerType())) {
if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) {
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index a4540de4acc4..7723009787f7 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -832,7 +832,7 @@ llvm::Error ProcessElfCore::parseOpenBSDNotes(llvm::ArrayRef<CoreNote> notes) {
for (const auto &note : notes) {
// OpenBSD per-thread information is stored in notes named "OpenBSD@nnn" so
// match on the initial part of the string.
- if (!llvm::StringRef(note.info.n_name).startswith("OpenBSD"))
+ if (!llvm::StringRef(note.info.n_name).starts_with("OpenBSD"))
continue;
switch (note.info.n_type) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 2cf8c29bf9d2..ad72b3d121e6 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -4042,7 +4042,7 @@ void GDBRemoteCommunicationClient::ServeSymbolLookups(
return;
} else {
llvm::StringRef response_str(response.GetStringRef());
- if (response_str.startswith("qSymbol:")) {
+ if (response_str.starts_with("qSymbol:")) {
response.SetFilePos(strlen("qSymbol:"));
std::string symbol_name;
if (response.GetHexByteString(symbol_name)) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 187c23a20609..3d37bb226a65 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -3921,7 +3921,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qSaveCore(
std::string path_hint;
StringRef packet_str{packet.GetStringRef()};
- assert(packet_str.startswith("qSaveCore"));
+ assert(packet_str.starts_with("qSaveCore"));
if (packet_str.consume_front("qSaveCore;")) {
for (auto x : llvm::split(packet_str, ';')) {
if (x.consume_front("path-hint:"))
@@ -3947,7 +3947,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QNonStop(
Log *log = GetLog(LLDBLog::Process);
StringRef packet_str{packet.GetStringRef()};
- assert(packet_str.startswith("QNonStop:"));
+ assert(packet_str.starts_with("QNonStop:"));
packet_str.consume_front("QNonStop:");
if (packet_str == "0") {
if (m_non_stop)
@@ -4306,7 +4306,7 @@ lldb_private::process_gdb_remote::LLGSArgToURL(llvm::StringRef url_arg,
std::string host_port = url_arg.str();
// If host_and_port starts with ':', default the host to be "localhost" and
// expect the remainder to be the port.
- if (url_arg.startswith(":"))
+ if (url_arg.starts_with(":"))
host_port.insert(0, "localhost");
// Try parsing the (preprocessed) argument as host:port pair.
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index d5e557b4b88c..316be471df92 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -4472,7 +4472,7 @@ bool ParseRegisters(
// and a simple type. Just in case, look for that too (setting both
// does no harm).
if (!gdb_type.empty() && !(encoding_set || format_set)) {
- if (llvm::StringRef(gdb_type).startswith("int")) {
+ if (llvm::StringRef(gdb_type).starts_with("int")) {
reg_info.format = eFormatHex;
reg_info.encoding = eEncodingUint;
} else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") {
@@ -4482,7 +4482,7 @@ bool ParseRegisters(
reg_info.format = eFormatFloat;
reg_info.encoding = eEncodingIEEE754;
} else if (gdb_type == "aarch64v" ||
- llvm::StringRef(gdb_type).startswith("vec") ||
+ llvm::StringRef(gdb_type).starts_with("vec") ||
gdb_type == "i387_ext" || gdb_type == "uint128") {
// lldb doesn't handle 128-bit uints correctly (for ymm*h), so
// treat them as vector (similarly to xmm/ymm)
diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
index cd52233cc8cc..729d6af02402 100644
--- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
+++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
@@ -448,15 +448,6 @@ void SymbolFileBreakpad::FindFunctions(const RegularExpression &regex,
// TODO
}
-void SymbolFileBreakpad::FindTypes(
- ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) {}
-
-void SymbolFileBreakpad::FindTypes(
- llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {}
-
void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
Log *log = GetLog(LLDBLog::Symbols);
Module &module = *m_objfile_sp->GetModule();
diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
index 4a01a64202ee..214fbdd3ff3a 100644
--- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
+++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
@@ -118,15 +118,6 @@ public:
void FindFunctions(const RegularExpression &regex, bool include_inlines,
SymbolContextList &sc_list) override;
- void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) override;
-
- void FindTypes(llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) override;
-
llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language) override {
return llvm::make_error<llvm::StringError>(
diff --git a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp
index 7a2b4c00eedf..d192944bb9d0 100644
--- a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp
+++ b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp
@@ -1020,23 +1020,18 @@ lldb_private::Type *SymbolFileCTF::ResolveTypeUID(lldb::user_id_t type_uid) {
return type_sp.get();
}
-void SymbolFileCTF::FindTypes(
- lldb_private::ConstString name,
- const lldb_private::CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- lldb_private::TypeMap &types) {
-
- searched_symbol_files.clear();
- searched_symbol_files.insert(this);
+void SymbolFileCTF::FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) {
+ // Make sure we haven't already searched this SymbolFile before.
+ if (results.AlreadySearched(this))
+ return;
- size_t matches = 0;
+ ConstString name = match.GetTypeBasename();
for (TypeSP type_sp : GetTypeList().Types()) {
- if (matches == max_matches)
- break;
if (type_sp && type_sp->GetName() == name) {
- types.Insert(type_sp);
- matches++;
+ results.InsertUnique(type_sp);
+ if (results.Done(match))
+ return;
}
}
}
diff --git a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
index 787dc1892bb3..f111937dbd6e 100644
--- a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
+++ b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
@@ -105,12 +105,8 @@ public:
lldb::TypeClass type_mask,
lldb_private::TypeList &type_list) override {}
- void
- FindTypes(lldb_private::ConstString name,
- const lldb_private::CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- lldb_private::TypeMap &types) override;
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
void FindTypesByRegex(const lldb_private::RegularExpression &regex,
uint32_t max_matches, lldb_private::TypeMap &types);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index e3c64640c791..334876620249 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -152,16 +152,16 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
// If this type comes from a Clang module, recursively look in the
// DWARF section of the .pcm file in the module cache. Clang
// generates DWO skeleton units as breadcrumbs to find them.
- std::vector<CompilerContext> decl_context = die.GetDeclContext();
- TypeMap pcm_types;
+ std::vector<lldb_private::CompilerContext> die_context = die.GetDeclContext();
+ TypeQuery query(die_context, TypeQueryOptions::e_module_search |
+ TypeQueryOptions::e_find_one);
+ TypeResults results;
// The type in the Clang module must have the same language as the current CU.
- LanguageSet languages;
- languages.Insert(SymbolFileDWARF::GetLanguageFamily(*die.GetCU()));
- llvm::DenseSet<SymbolFile *> searched_symbol_files;
- clang_module_sp->GetSymbolFile()->FindTypes(decl_context, languages,
- searched_symbol_files, pcm_types);
- if (pcm_types.Empty()) {
+ query.AddLanguage(SymbolFileDWARF::GetLanguageFamily(*die.GetCU()));
+ clang_module_sp->FindTypes(query, results);
+ TypeSP pcm_type_sp = results.GetTypeMap().FirstType();
+ if (!pcm_type_sp) {
// Since this type is defined in one of the Clang modules imported
// by this symbol file, search all of them. Instead of calling
// sym_file->FindTypes(), which would return this again, go straight
@@ -170,24 +170,20 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
// Well-formed clang modules never form cycles; guard against corrupted
// ones by inserting the current file.
- searched_symbol_files.insert(&sym_file);
+ results.AlreadySearched(&sym_file);
sym_file.ForEachExternalModule(
- *sc.comp_unit, searched_symbol_files, [&](Module &module) {
- module.GetSymbolFile()->FindTypes(decl_context, languages,
- searched_symbol_files, pcm_types);
- return pcm_types.GetSize();
+ *sc.comp_unit, results.GetSearchedSymbolFiles(), [&](Module &module) {
+ module.FindTypes(query, results);
+ pcm_type_sp = results.GetTypeMap().FirstType();
+ return !pcm_type_sp;
});
}
- if (!pcm_types.GetSize())
+ if (!pcm_type_sp)
return TypeSP();
// We found a real definition for this type in the Clang module, so lets use
// it and cache the fact that we found a complete type for this die.
- TypeSP pcm_type_sp = pcm_types.GetTypeAtIndex(0);
- if (!pcm_type_sp)
- return TypeSP();
-
lldb_private::CompilerType pcm_type = pcm_type_sp->GetForwardCompilerType();
lldb_private::CompilerType type =
GetClangASTImporter().CopyType(m_ast, pcm_type);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
index 1f9524f8add9..bed68f45426f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
@@ -418,6 +418,54 @@ std::vector<lldb_private::CompilerContext> DWARFDIE::GetDeclContext() const {
return context;
}
+std::vector<lldb_private::CompilerContext>
+DWARFDIE::GetTypeLookupContext() const {
+ std::vector<lldb_private::CompilerContext> context;
+ // If there is no name, then there is no need to look anything up for this
+ // DIE.
+ const char *name = GetName();
+ if (!name || !name[0])
+ return context;
+ const dw_tag_t tag = Tag();
+ if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit)
+ return context;
+ DWARFDIE parent = GetParent();
+ if (parent)
+ context = parent.GetTypeLookupContext();
+ auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) {
+ context.push_back({kind, ConstString(name)});
+ };
+ switch (tag) {
+ case DW_TAG_namespace:
+ push_ctx(CompilerContextKind::Namespace, name);
+ break;
+ case DW_TAG_structure_type:
+ push_ctx(CompilerContextKind::Struct, name);
+ break;
+ case DW_TAG_union_type:
+ push_ctx(CompilerContextKind::Union, name);
+ break;
+ case DW_TAG_class_type:
+ push_ctx(CompilerContextKind::Class, name);
+ break;
+ case DW_TAG_enumeration_type:
+ push_ctx(CompilerContextKind::Enum, name);
+ break;
+ case DW_TAG_variable:
+ push_ctx(CompilerContextKind::Variable, GetPubname());
+ break;
+ case DW_TAG_typedef:
+ push_ctx(CompilerContextKind::Typedef, name);
+ break;
+ case DW_TAG_base_type:
+ push_ctx(CompilerContextKind::Builtin, name);
+ break;
+ default:
+ break;
+ }
+ return context;
+}
+
DWARFDIE
DWARFDIE::GetParentDeclContextDIE() const {
if (IsValid())
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
index a68af62c8b3e..511ca62d0197 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
@@ -73,9 +73,22 @@ public:
std::vector<DWARFDIE> GetDeclContextDIEs() const;
/// Return this DIE's decl context as it is needed to look up types
- /// in Clang's -gmodules debug info format.
+ /// in Clang modules. This context will include any modules or functions that
+ /// the type is declared in so an exact module match can be efficiently made.
std::vector<CompilerContext> GetDeclContext() const;
+ /// Get a context to a type so it can be looked up.
+ ///
+ /// This function uses the current DIE to fill in a CompilerContext array
+ /// that is suitable for type lookup for comparison to a TypeQuery's compiler
+ /// context (TypeQuery::GetContextRef()). If this DIE represents a named type,
+ /// it should fill out the compiler context with the type itself as the last
+ /// entry. The declaration context should be above the type and stop at an
+ /// appropriate time, like either the translation unit or at a function
+ /// context. This is designed to allow users to efficiently look for types
+ /// using a full or partial CompilerContext array.
+ std::vector<CompilerContext> GetTypeLookupContext() const;
+
// Getting attribute values from the DIE.
//
// GetAttributeValueAsXXX() functions should only be used if you are
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
index 44e760227901..44421c0eda3e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
@@ -7,10 +7,27 @@
//===----------------------------------------------------------------------===//
#include "DWARFDeclContext.h"
+#include "llvm/Support/raw_ostream.h"
using namespace lldb_private::dwarf;
using namespace lldb_private::plugin::dwarf;
+/// Returns the name of `entry` if it has one, or the appropriate "anonymous
+/// {namespace, class, struct, union}".
+static const char *GetName(DWARFDeclContext::Entry entry) {
+ if (entry.name != nullptr)
+ return entry.name;
+ if (entry.tag == DW_TAG_namespace)
+ return "(anonymous namespace)";
+ if (entry.tag == DW_TAG_class_type)
+ return "(anonymous class)";
+ if (entry.tag == DW_TAG_structure_type)
+ return "(anonymous struct)";
+ if (entry.tag == DW_TAG_union_type)
+ return "(anonymous union)";
+ return "(anonymous)";
+}
+
const char *DWARFDeclContext::GetQualifiedName() const {
if (m_qualified_name.empty()) {
// The declaration context array for a class named "foo" in namespace
@@ -26,26 +43,10 @@ const char *DWARFDeclContext::GetQualifiedName() const {
m_qualified_name.append(m_entries[0].name);
}
} else {
- collection::const_reverse_iterator pos;
- collection::const_reverse_iterator begin = m_entries.rbegin();
- collection::const_reverse_iterator end = m_entries.rend();
- for (pos = begin; pos != end; ++pos) {
- if (pos != begin)
- m_qualified_name.append("::");
- if (pos->name == nullptr) {
- if (pos->tag == DW_TAG_namespace)
- m_qualified_name.append("(anonymous namespace)");
- else if (pos->tag == DW_TAG_class_type)
- m_qualified_name.append("(anonymous class)");
- else if (pos->tag == DW_TAG_structure_type)
- m_qualified_name.append("(anonymous struct)");
- else if (pos->tag == DW_TAG_union_type)
- m_qualified_name.append("(anonymous union)");
- else
- m_qualified_name.append("(anonymous)");
- } else
- m_qualified_name.append(pos->name);
- }
+ llvm::raw_string_ostream string_stream(m_qualified_name);
+ llvm::interleave(
+ llvm::reverse(m_entries), string_stream,
+ [&](auto entry) { string_stream << GetName(entry); }, "::");
}
}
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
index 6f771c66a725..0e2f4d45543b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -809,7 +809,7 @@ removeHostnameFromPathname(llvm::StringRef path_from_dwarf) {
// check whether we have a windows path, and so the first character is a
// drive-letter not a hostname.
if (host.size() == 1 && llvm::isAlpha(host[0]) &&
- (path.startswith("\\") || path.startswith("/")))
+ (path.starts_with("\\") || path.starts_with("/")))
return path_from_dwarf;
return path;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index d4cc26a3c329..505ea29ca4d4 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -132,6 +132,11 @@ public:
} // namespace
+bool IsStructOrClassTag(llvm::dwarf::Tag Tag) {
+ return Tag == llvm::dwarf::Tag::DW_TAG_class_type ||
+ Tag == llvm::dwarf::Tag::DW_TAG_structure_type;
+}
+
static PluginProperties &GetGlobalPluginProperties() {
static PluginProperties g_settings;
return g_settings;
@@ -1977,7 +1982,7 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() {
// (corresponding to .dwo) so we simply skip it.
if (m_objfile_sp->GetFileSpec().GetFileNameExtension() == ".dwo" &&
llvm::StringRef(m_objfile_sp->GetFileSpec().GetPath())
- .endswith(dwo_module_spec.GetFileSpec().GetPath())) {
+ .ends_with(dwo_module_spec.GetFileSpec().GetPath())) {
continue;
}
@@ -2591,177 +2596,157 @@ void SymbolFileDWARF::GetMangledNamesForFunction(
}
}
-void SymbolFileDWARF::FindTypes(
- ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types) {
- std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- // Make sure we haven't already searched this SymbolFile before.
- if (!searched_symbol_files.insert(this).second)
- return;
-
- Log *log = GetLog(DWARFLog::Lookups);
+/// Split a name up into a basename and template parameters.
+static bool SplitTemplateParams(llvm::StringRef fullname,
+ llvm::StringRef &basename,
+ llvm::StringRef &template_params) {
+ auto it = fullname.find('<');
+ if (it == llvm::StringRef::npos) {
+ basename = fullname;
+ template_params = llvm::StringRef();
+ return false;
+ }
+ basename = fullname.slice(0, it);
+ template_params = fullname.slice(it, fullname.size());
+ return true;
+}
- if (log) {
- if (parent_decl_ctx)
- GetObjectFile()->GetModule()->LogMessage(
- log,
- "SymbolFileDWARF::FindTypes (sc, name=\"{0}\", parent_decl_ctx = "
- "{1:p} (\"{2}\"), max_matches={3}, type_list)",
- name.GetCString(), static_cast<const void *>(&parent_decl_ctx),
- parent_decl_ctx.GetName().AsCString("<NULL>"), max_matches);
- else
- GetObjectFile()->GetModule()->LogMessage(
- log,
- "SymbolFileDWARF::FindTypes (sc, name=\"{0}\", parent_decl_ctx = "
- "NULL, max_matches={1}, type_list)",
- name.GetCString(), max_matches);
+static bool UpdateCompilerContextForSimpleTemplateNames(TypeQuery &match) {
+ // We need to find any names in the context that have template parameters
+ // and strip them so the context can be matched when -gsimple-template-names
+ // is being used. Returns true if any of the context items were updated.
+ bool any_context_updated = false;
+ for (auto &context : match.GetContextRef()) {
+ llvm::StringRef basename, params;
+ if (SplitTemplateParams(context.name.GetStringRef(), basename, params)) {
+ context.name = ConstString(basename);
+ any_context_updated = true;
+ }
}
+ return any_context_updated;
+}
+void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) {
- if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
+ // Make sure we haven't already searched this SymbolFile before.
+ if (results.AlreadySearched(this))
return;
- // Unlike FindFunctions(), FindTypes() following cannot produce false
- // positives.
-
- const llvm::StringRef name_ref = name.GetStringRef();
- auto name_bracket_index = name_ref.find('<');
- m_index->GetTypes(name, [&](DWARFDIE die) {
- if (!DIEInDeclContext(parent_decl_ctx, die))
- return true; // The containing decl contexts don't match
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- Type *matching_type = ResolveType(die, true, true);
- if (!matching_type)
- return true;
+ bool have_index_match = false;
+ m_index->GetTypes(query.GetTypeBasename(), [&](DWARFDIE die) {
+ // Check the language, but only if we have a language filter.
+ if (query.HasLanguage()) {
+ if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU())))
+ return true; // Keep iterating over index types, language mismatch.
+ }
- // With -gsimple-template-names, a templated type's DW_AT_name will not
- // contain the template parameters. Make sure that if the original query
- // didn't contain a '<', we filter out entries with template parameters.
- if (name_bracket_index == llvm::StringRef::npos &&
- matching_type->IsTemplateType())
- return true;
+ // Check the context matches
+ std::vector<lldb_private::CompilerContext> die_context;
+ if (query.GetModuleSearch())
+ die_context = die.GetDeclContext();
+ else
+ die_context = die.GetTypeLookupContext();
+ assert(!die_context.empty());
+ if (!query.ContextMatches(die_context))
+ return true; // Keep iterating over index types, context mismatch.
- // We found a type pointer, now find the shared pointer form our type
- // list
- types.InsertUnique(matching_type->shared_from_this());
- return types.GetSize() < max_matches;
+ // Try to resolve the type.
+ if (Type *matching_type = ResolveType(die, true, true)) {
+ if (matching_type->IsTemplateType()) {
+ // We have to watch out for case where we lookup a type by basename and
+ // it matches a template with simple template names. Like looking up
+ // "Foo" and if we have simple template names then we will match
+ // "Foo<int>" and "Foo<double>" because all the DWARF has is "Foo" in
+ // the accelerator tables. The main case we see this in is when the
+ // expression parser is trying to parse "Foo<int>" and it will first do
+ // a lookup on just "Foo". We verify the type basename matches before
+ // inserting the type in the results.
+ auto CompilerTypeBasename =
+ matching_type->GetForwardCompilerType().GetTypeName(true);
+ if (CompilerTypeBasename != query.GetTypeBasename())
+ return true; // Keep iterating over index types, basename mismatch.
+ }
+ have_index_match = true;
+ results.InsertUnique(matching_type->shared_from_this());
+ }
+ return !results.Done(query); // Keep iterating if we aren't done.
});
+ if (results.Done(query))
+ return;
+
// With -gsimple-template-names, a templated type's DW_AT_name will not
// contain the template parameters. Try again stripping '<' and anything
// after, filtering out entries with template parameters that don't match.
- if (types.GetSize() < max_matches) {
- if (name_bracket_index != llvm::StringRef::npos) {
- const llvm::StringRef name_no_template_params =
- name_ref.slice(0, name_bracket_index);
- const llvm::StringRef template_params =
- name_ref.slice(name_bracket_index, name_ref.size());
- m_index->GetTypes(ConstString(name_no_template_params), [&](DWARFDIE die) {
- if (!DIEInDeclContext(parent_decl_ctx, die))
- return true; // The containing decl contexts don't match
-
- const llvm::StringRef base_name = GetTypeForDIE(die)->GetBaseName().AsCString();
- auto it = base_name.find('<');
- // If the candidate qualified name doesn't have '<', it doesn't have
- // template params to compare.
- if (it == llvm::StringRef::npos)
- return true;
-
- // Filter out non-matching instantiations by comparing template params.
- const llvm::StringRef base_name_template_params =
- base_name.slice(it, base_name.size());
-
- if (template_params != base_name_template_params)
- return true;
-
- Type *matching_type = ResolveType(die, true, true);
- if (!matching_type)
- return true;
+ if (!have_index_match) {
+ // Create a type matcher with a compiler context that is tuned for
+ // -gsimple-template-names. We will use this for the index lookup and the
+ // context matching, but will use the original "match" to insert matches
+ // into if things match. The "match_simple" has a compiler context with
+ // all template parameters removed to allow the names and context to match.
+ // The UpdateCompilerContextForSimpleTemplateNames(...) will return true if
+ // it trims any context items down by removing template parameter names.
+ TypeQuery query_simple(query);
+ if (UpdateCompilerContextForSimpleTemplateNames(query_simple)) {
+
+ // Copy our match's context and update the basename we are looking for
+ // so we can use this only to compare the context correctly.
+ m_index->GetTypes(query_simple.GetTypeBasename(), [&](DWARFDIE die) {
+ // Check the language, but only if we have a language filter.
+ if (query.HasLanguage()) {
+ if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU())))
+ return true; // Keep iterating over index types, language mismatch.
+ }
- // We found a type pointer, now find the shared pointer form our type
- // list.
- types.InsertUnique(matching_type->shared_from_this());
- return types.GetSize() < max_matches;
+ // Check the context matches
+ std::vector<lldb_private::CompilerContext> die_context;
+ if (query.GetModuleSearch())
+ die_context = die.GetDeclContext();
+ else
+ die_context = die.GetTypeLookupContext();
+ assert(!die_context.empty());
+ if (!query_simple.ContextMatches(die_context))
+ return true; // Keep iterating over index types, context mismatch.
+
+ // Try to resolve the type.
+ if (Type *matching_type = ResolveType(die, true, true)) {
+ ConstString name = matching_type->GetQualifiedName();
+ // We have found a type that still might not match due to template
+ // parameters. If we create a new TypeQuery that uses the new type's
+ // fully qualified name, we can find out if this type matches at all
+ // context levels. We can't use just the "match_simple" context
+ // because all template parameters were stripped off. The fully
+ // qualified name of the type will have the template parameters and
+ // will allow us to make sure it matches correctly.
+ TypeQuery die_query(name.GetStringRef(),
+ TypeQueryOptions::e_exact_match);
+ if (!query.ContextMatches(die_query.GetContextRef()))
+ return true; // Keep iterating over index types, context mismatch.
+
+ results.InsertUnique(matching_type->shared_from_this());
+ }
+ return !results.Done(query); // Keep iterating if we aren't done.
});
+ if (results.Done(query))
+ return;
}
}
// Next search through the reachable Clang modules. This only applies for
// DWARF objects compiled with -gmodules that haven't been processed by
// dsymutil.
- if (types.GetSize() < max_matches) {
- UpdateExternalModuleListIfNeeded();
-
- for (const auto &pair : m_external_type_modules)
- if (ModuleSP external_module_sp = pair.second)
- if (SymbolFile *sym_file = external_module_sp->GetSymbolFile())
- sym_file->FindTypes(name, parent_decl_ctx, max_matches,
- searched_symbol_files, types);
- }
+ UpdateExternalModuleListIfNeeded();
- if (log && types.GetSize()) {
- if (parent_decl_ctx) {
- GetObjectFile()->GetModule()->LogMessage(
- log,
- "SymbolFileDWARF::FindTypes (sc, name=\"{0}\", parent_decl_ctx "
- "= {1:p} (\"{2}\"), max_matches={3}, type_list) => {4}",
- name.GetCString(), static_cast<const void *>(&parent_decl_ctx),
- parent_decl_ctx.GetName().AsCString("<NULL>"), max_matches,
- types.GetSize());
- } else {
- GetObjectFile()->GetModule()->LogMessage(
- log,
- "SymbolFileDWARF::FindTypes (sc, name=\"{0}\", parent_decl_ctx "
- "= NULL, max_matches={1}, type_list) => {2}",
- name.GetCString(), max_matches, types.GetSize());
+ for (const auto &pair : m_external_type_modules) {
+ if (ModuleSP external_module_sp = pair.second) {
+ external_module_sp->FindTypes(query, results);
+ if (results.Done(query))
+ return;
}
}
}
-void SymbolFileDWARF::FindTypes(
- llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {
- // Make sure we haven't already searched this SymbolFile before.
- if (!searched_symbol_files.insert(this).second)
- return;
-
- std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- if (pattern.empty())
- return;
-
- ConstString name = pattern.back().name;
-
- if (!name)
- return;
-
- m_index->GetTypes(name, [&](DWARFDIE die) {
- if (!languages[GetLanguageFamily(*die.GetCU())])
- return true;
-
- std::vector<CompilerContext> die_context = die.GetDeclContext();
- if (!contextMatches(die_context, pattern))
- return true;
-
- if (Type *matching_type = ResolveType(die, true, true)) {
- // We found a type pointer, now find the shared pointer form our type
- // list.
- types.InsertUnique(matching_type->shared_from_this());
- }
- return true;
- });
-
- // Next search through the reachable Clang modules. This only applies for
- // DWARF objects compiled with -gmodules that haven't been processed by
- // dsymutil.
- UpdateExternalModuleListIfNeeded();
-
- for (const auto &pair : m_external_type_modules)
- if (ModuleSP external_module_sp = pair.second)
- external_module_sp->FindTypes(pattern, languages, searched_symbol_files,
- types);
-}
-
CompilerDeclContext
SymbolFileDWARF::FindNamespace(ConstString name,
const CompilerDeclContext &parent_decl_ctx,
@@ -2947,29 +2932,18 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE(
m_index->GetCompleteObjCClass(
type_name, must_be_implementation, [&](DWARFDIE type_die) {
- bool try_resolving_type = false;
-
// Don't try and resolve the DIE we are looking for with the DIE
// itself!
- if (type_die != die) {
- switch (type_die.Tag()) {
- case DW_TAG_class_type:
- case DW_TAG_structure_type:
- try_resolving_type = true;
- break;
- default:
- break;
- }
- }
- if (!try_resolving_type)
+ if (type_die == die || !IsStructOrClassTag(type_die.Tag()))
return true;
if (must_be_implementation &&
- type_die.Supports_DW_AT_APPLE_objc_complete_type())
- try_resolving_type = type_die.GetAttributeValueAsUnsigned(
+ type_die.Supports_DW_AT_APPLE_objc_complete_type()) {
+ const bool try_resolving_type = type_die.GetAttributeValueAsUnsigned(
DW_AT_APPLE_objc_complete_type, 0);
- if (!try_resolving_type)
- return true;
+ if (!try_resolving_type)
+ return true;
+ }
Type *resolved_type = ResolveType(type_die, false, true);
if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED)
@@ -3128,36 +3102,12 @@ SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) {
if (type_system &&
!type_system->SupportsLanguage(GetLanguage(*type_die.GetCU())))
return true;
- bool try_resolving_type = false;
- // Don't try and resolve the DIE we are looking for with the DIE
- // itself!
const dw_tag_t type_tag = type_die.Tag();
- // Make sure the tags match
- if (type_tag == tag) {
- // The tags match, lets try resolving this type
- try_resolving_type = true;
- } else {
- // The tags don't match, but we need to watch our for a forward
- // declaration for a struct and ("struct foo") ends up being a
- // class ("class foo { ... };") or vice versa.
- switch (type_tag) {
- case DW_TAG_class_type:
- // We had a "class foo", see if we ended up with a "struct foo
- // { ... };"
- try_resolving_type = (tag == DW_TAG_structure_type);
- break;
- case DW_TAG_structure_type:
- // We had a "struct foo", see if we ended up with a "class foo
- // { ... };"
- try_resolving_type = (tag == DW_TAG_class_type);
- break;
- default:
- // Tags don't match, don't event try to resolve using this type
- // whose name matches....
- break;
- }
- }
+ // Resolve the type if both have the same tag or {class, struct} tags.
+ const bool try_resolving_type =
+ type_tag == tag ||
+ (IsStructOrClassTag(type_tag) && IsStructOrClassTag(tag));
if (!try_resolving_type) {
if (log) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index e6efbba7e249..78819edd0062 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -186,14 +186,8 @@ public:
GetMangledNamesForFunction(const std::string &scope_qualified_name,
std::vector<ConstString> &mangled_names) override;
- void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) override;
-
- void FindTypes(llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) override;
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
void GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask,
TypeList &type_list) override;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index 263ada9cbb87..e5b59460cb85 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1227,27 +1227,12 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE(
return TypeSP();
}
-void SymbolFileDWARFDebugMap::FindTypes(
- ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types) {
+void SymbolFileDWARFDebugMap::FindTypes(const TypeQuery &query,
+ TypeResults &results) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
- oso_dwarf->FindTypes(name, parent_decl_ctx, max_matches,
- searched_symbol_files, types);
- return types.GetSize() >= max_matches;
- });
-}
-
-void SymbolFileDWARFDebugMap::FindTypes(
- llvm::ArrayRef<CompilerContext> context, LanguageSet languages,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types) {
- LLDB_SCOPED_TIMER();
- ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
- oso_dwarf->FindTypes(context, languages, searched_symbol_files, types);
- return false;
+ oso_dwarf->FindTypes(query, results);
+ return !results.Done(query); // Keep iterating if we aren't done.
});
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index 13f94f6d93e9..cd0a4bb6e41c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -118,13 +118,8 @@ public:
bool include_inlines, SymbolContextList &sc_list) override;
void FindFunctions(const RegularExpression &regex, bool include_inlines,
SymbolContextList &sc_list) override;
- void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) override;
- void FindTypes(llvm::ArrayRef<CompilerContext> context, LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) override;
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
CompilerDeclContext FindNamespace(ConstString name,
const CompilerDeclContext &parent_decl_ctx,
bool only_root_namespaces) override;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
index 06cb720b1e9f..25d04f999ad6 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
@@ -236,7 +236,7 @@ CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const {
llvm::cantFail(
TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name));
- llvm::sys::path::Style style = working_dir.String.startswith("/")
+ llvm::sys::path::Style style = working_dir.String.starts_with("/")
? llvm::sys::path::Style::posix
: llvm::sys::path::Style::windows;
if (llvm::sys::path::is_absolute(file_name.String, style))
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index 5b690ead1e8d..b79d3e63f72b 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -1264,9 +1264,9 @@ void PdbAstBuilder::ParseNamespace(clang::DeclContext &context) {
clang::NamespaceDecl *ns = llvm::cast<clang::NamespaceDecl>(context);
llvm::StringRef ns_name = ns->getName();
- if (ns_name.startswith(qname)) {
+ if (ns_name.starts_with(qname)) {
ns_name = ns_name.drop_front(qname.size());
- if (ns_name.startswith("::"))
+ if (ns_name.starts_with("::"))
GetOrCreateType(tid);
}
}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index eaca4761a485..ad0801339936 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1379,7 +1379,7 @@ bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
for (llvm::StringRef f : cci->m_file_list) {
FileSpec::Style style =
- f.startswith("/") ? FileSpec::Style::posix : FileSpec::Style::windows;
+ f.starts_with("/") ? FileSpec::Style::posix : FileSpec::Style::windows;
FileSpec spec(f, style);
support_files.Append(spec);
}
@@ -1717,24 +1717,33 @@ void SymbolFileNativePDB::FindFunctions(const RegularExpression &regex,
bool include_inlines,
SymbolContextList &sc_list) {}
-void SymbolFileNativePDB::FindTypes(
- ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) {
- std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- if (!name)
+void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &query,
+ lldb_private::TypeResults &results) {
+
+ // Make sure we haven't already searched this SymbolFile before.
+ if (results.AlreadySearched(this))
return;
- searched_symbol_files.clear();
- searched_symbol_files.insert(this);
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- // There is an assumption 'name' is not a regex
- FindTypesByName(name.GetStringRef(), max_matches, types);
-}
+ std::vector<TypeIndex> matches =
+ m_index->tpi().findRecordsByName(query.GetTypeBasename().GetStringRef());
-void SymbolFileNativePDB::FindTypes(
- llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {}
+ for (TypeIndex type_idx : matches) {
+ TypeSP type_sp = GetOrCreateType(type_idx);
+ if (!type_sp)
+ continue;
+
+ // We resolved a type. Get the fully qualified name to ensure it matches.
+ ConstString name = type_sp->GetQualifiedName();
+ TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match);
+ if (query.ContextMatches(type_match.GetContextRef())) {
+ results.InsertUnique(type_sp);
+ if (results.Done(query))
+ return;
+ }
+ }
+}
void SymbolFileNativePDB::FindTypesByName(llvm::StringRef name,
uint32_t max_matches,
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index bf64cd330c1f..9d0458cf7ebf 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -140,14 +140,8 @@ public:
std::optional<PdbCompilandSymId> FindSymbolScope(PdbCompilandSymId id);
- void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) override;
-
- void FindTypes(llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) override;
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language) override;
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index 78eabc35ebf9..9e1cd8360660 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -1446,24 +1446,6 @@ void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) {
symtab.Finalize();
}
-void SymbolFilePDB::FindTypes(
- lldb_private::ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- lldb_private::TypeMap &types) {
- std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- if (!name)
- return;
- if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
- return;
-
- searched_symbol_files.clear();
- searched_symbol_files.insert(this);
-
- // There is an assumption 'name' is not a regex
- FindTypesByName(name.GetStringRef(), parent_decl_ctx, max_matches, types);
-}
-
void SymbolFilePDB::DumpClangAST(Stream &s) {
auto type_system_or_err =
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
@@ -1536,26 +1518,24 @@ void SymbolFilePDB::FindTypesByRegex(
}
}
-void SymbolFilePDB::FindTypesByName(
- llvm::StringRef name,
- const lldb_private::CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches, lldb_private::TypeMap &types) {
+void SymbolFilePDB::FindTypes(const lldb_private::TypeQuery &query,
+ lldb_private::TypeResults &type_results) {
+
+ // Make sure we haven't already searched this SymbolFile before.
+ if (type_results.AlreadySearched(this))
+ return;
+
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
std::unique_ptr<IPDBEnumSymbols> results;
- if (name.empty())
+ llvm::StringRef basename = query.GetTypeBasename().GetStringRef();
+ if (basename.empty())
return;
results = m_global_scope_up->findAllChildren(PDB_SymType::None);
if (!results)
return;
- uint32_t matches = 0;
-
while (auto result = results->getNext()) {
- if (max_matches > 0 && matches >= max_matches)
- break;
-
- if (MSVCUndecoratedNameParser::DropScope(
- result->getRawSymbol().getName()) != name)
- continue;
switch (result->getSymTag()) {
case PDB_SymType::Enum:
@@ -1568,28 +1548,29 @@ void SymbolFilePDB::FindTypesByName(
continue;
}
+ if (MSVCUndecoratedNameParser::DropScope(
+ result->getRawSymbol().getName()) != basename)
+ continue;
+
// This should cause the type to get cached and stored in the `m_types`
// lookup.
if (!ResolveTypeUID(result->getSymIndexId()))
continue;
- if (parent_decl_ctx.IsValid() &&
- GetDeclContextContainingUID(result->getSymIndexId()) != parent_decl_ctx)
- continue;
-
auto iter = m_types.find(result->getSymIndexId());
if (iter == m_types.end())
continue;
- types.Insert(iter->second);
- ++matches;
+ // We resolved a type. Get the fully qualified name to ensure it matches.
+ ConstString name = iter->second->GetQualifiedName();
+ TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match);
+ if (query.ContextMatches(type_match.GetContextRef())) {
+ type_results.InsertUnique(iter->second);
+ if (type_results.Done(query))
+ return;
+ }
}
}
-void SymbolFilePDB::FindTypes(
- llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- lldb_private::TypeMap &types) {}
-
void SymbolFilePDB::GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol,
uint32_t type_mask,
TypeCollection &type_collection) {
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
index 5b98c6e8b486..01851f1418f3 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -134,19 +134,8 @@ public:
std::vector<lldb_private::ConstString> &mangled_names) override;
void AddSymbols(lldb_private::Symtab &symtab) override;
-
- void
- FindTypes(lldb_private::ConstString name,
- const lldb_private::CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- lldb_private::TypeMap &types) override;
-
- void FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> pattern,
- lldb_private::LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- lldb_private::TypeMap &types) override;
-
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
void FindTypesByRegex(const lldb_private::RegularExpression &regex,
uint32_t max_matches, lldb_private::TypeMap &types);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 7c28935f5741..797df8c098af 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2461,89 +2461,6 @@ void TypeSystemClang::DumpDeclHiearchy(clang::Decl *decl) {
}
}
-bool TypeSystemClang::DeclsAreEquivalent(clang::Decl *lhs_decl,
- clang::Decl *rhs_decl) {
- if (lhs_decl && rhs_decl) {
- // Make sure the decl kinds match first
- const clang::Decl::Kind lhs_decl_kind = lhs_decl->getKind();
- const clang::Decl::Kind rhs_decl_kind = rhs_decl->getKind();
-
- if (lhs_decl_kind == rhs_decl_kind) {
- // Now check that the decl contexts kinds are all equivalent before we
- // have to check any names of the decl contexts...
- clang::DeclContext *lhs_decl_ctx = lhs_decl->getDeclContext();
- clang::DeclContext *rhs_decl_ctx = rhs_decl->getDeclContext();
- if (lhs_decl_ctx && rhs_decl_ctx) {
- while (true) {
- if (lhs_decl_ctx && rhs_decl_ctx) {
- const clang::Decl::Kind lhs_decl_ctx_kind =
- lhs_decl_ctx->getDeclKind();
- const clang::Decl::Kind rhs_decl_ctx_kind =
- rhs_decl_ctx->getDeclKind();
- if (lhs_decl_ctx_kind == rhs_decl_ctx_kind) {
- lhs_decl_ctx = lhs_decl_ctx->getParent();
- rhs_decl_ctx = rhs_decl_ctx->getParent();
-
- if (lhs_decl_ctx == nullptr && rhs_decl_ctx == nullptr)
- break;
- } else
- return false;
- } else
- return false;
- }
-
- // Now make sure the name of the decls match
- clang::NamedDecl *lhs_named_decl =
- llvm::dyn_cast<clang::NamedDecl>(lhs_decl);
- clang::NamedDecl *rhs_named_decl =
- llvm::dyn_cast<clang::NamedDecl>(rhs_decl);
- if (lhs_named_decl && rhs_named_decl) {
- clang::DeclarationName lhs_decl_name = lhs_named_decl->getDeclName();
- clang::DeclarationName rhs_decl_name = rhs_named_decl->getDeclName();
- if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) {
- if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString())
- return false;
- } else
- return false;
- } else
- return false;
-
- // We know that the decl context kinds all match, so now we need to
- // make sure the names match as well
- lhs_decl_ctx = lhs_decl->getDeclContext();
- rhs_decl_ctx = rhs_decl->getDeclContext();
- while (true) {
- switch (lhs_decl_ctx->getDeclKind()) {
- case clang::Decl::TranslationUnit:
- // We don't care about the translation unit names
- return true;
- default: {
- clang::NamedDecl *lhs_named_decl =
- llvm::dyn_cast<clang::NamedDecl>(lhs_decl_ctx);
- clang::NamedDecl *rhs_named_decl =
- llvm::dyn_cast<clang::NamedDecl>(rhs_decl_ctx);
- if (lhs_named_decl && rhs_named_decl) {
- clang::DeclarationName lhs_decl_name =
- lhs_named_decl->getDeclName();
- clang::DeclarationName rhs_decl_name =
- rhs_named_decl->getDeclName();
- if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) {
- if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString())
- return false;
- } else
- return false;
- } else
- return false;
- } break;
- }
- lhs_decl_ctx = lhs_decl_ctx->getParent();
- rhs_decl_ctx = rhs_decl_ctx->getParent();
- }
- }
- }
- }
- return false;
-}
bool TypeSystemClang::GetCompleteDecl(clang::ASTContext *ast,
clang::Decl *decl) {
if (!decl)
@@ -7676,7 +7593,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
nullptr /*expr*/, is_explicit ? clang::ExplicitSpecKind::ResolvedTrue
: clang::ExplicitSpecKind::ResolvedFalse);
- if (name.startswith("~")) {
+ if (name.starts_with("~")) {
cxx_dtor_decl =
clang::CXXDestructorDecl::CreateDeserialized(getASTContext(), 0);
cxx_dtor_decl->setDeclContext(cxx_record_decl);
@@ -9070,6 +8987,66 @@ size_t TypeSystemClang::DeclGetFunctionNumArguments(void *opaque_decl) {
return 0;
}
+static CompilerContextKind GetCompilerKind(clang::Decl::Kind clang_kind,
+ clang::DeclContext const *decl_ctx) {
+ switch (clang_kind) {
+ case Decl::TranslationUnit:
+ return CompilerContextKind::TranslationUnit;
+ case Decl::Namespace:
+ return CompilerContextKind::Namespace;
+ case Decl::Var:
+ return CompilerContextKind::Variable;
+ case Decl::Enum:
+ return CompilerContextKind::Enum;
+ case Decl::Typedef:
+ return CompilerContextKind::Typedef;
+ default:
+ // Many other kinds have multiple values
+ if (decl_ctx) {
+ if (decl_ctx->isFunctionOrMethod())
+ return CompilerContextKind::Function;
+ else if (decl_ctx->isRecord())
+ return (CompilerContextKind)((uint16_t)CompilerContextKind::Class |
+ (uint16_t)CompilerContextKind::Struct |
+ (uint16_t)CompilerContextKind::Union);
+ }
+ break;
+ }
+ return CompilerContextKind::Any;
+}
+
+static void
+InsertCompilerContext(TypeSystemClang *ts, clang::DeclContext *decl_ctx,
+ std::vector<lldb_private::CompilerContext> &context) {
+ if (decl_ctx == nullptr)
+ return;
+ InsertCompilerContext(ts, decl_ctx->getParent(), context);
+ clang::Decl::Kind clang_kind = decl_ctx->getDeclKind();
+ if (clang_kind == Decl::TranslationUnit)
+ return; // Stop at the translation unit.
+ const CompilerContextKind compiler_kind =
+ GetCompilerKind(clang_kind, decl_ctx);
+ ConstString decl_ctx_name = ts->DeclContextGetName(decl_ctx);
+ context.push_back({compiler_kind, decl_ctx_name});
+}
+
+std::vector<lldb_private::CompilerContext>
+TypeSystemClang::DeclGetCompilerContext(void *opaque_decl) {
+ std::vector<lldb_private::CompilerContext> context;
+ ConstString decl_name = DeclGetName(opaque_decl);
+ if (decl_name) {
+ clang::Decl *decl = (clang::Decl *)opaque_decl;
+ // Add the entire decl context first
+ clang::DeclContext *decl_ctx = decl->getDeclContext();
+ InsertCompilerContext(this, decl_ctx, context);
+ // Now add the decl information
+ auto compiler_kind =
+ GetCompilerKind(decl->getKind(), dyn_cast<DeclContext>(decl));
+ context.push_back({compiler_kind, decl_name});
+ }
+ return context;
+}
+
CompilerType TypeSystemClang::DeclGetFunctionArgumentType(void *opaque_decl,
size_t idx) {
if (clang::FunctionDecl *func_decl =
@@ -9308,6 +9285,14 @@ bool TypeSystemClang::DeclContextIsClassMethod(void *opaque_decl_ctx) {
return false;
}
+std::vector<lldb_private::CompilerContext>
+TypeSystemClang::DeclContextGetCompilerContext(void *opaque_decl_ctx) {
+ auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
+ std::vector<lldb_private::CompilerContext> context;
+ InsertCompilerContext(this, decl_ctx, context);
+ return context;
+}
+
bool TypeSystemClang::DeclContextIsContainedInLookup(
void *opaque_decl_ctx, void *other_opaque_decl_ctx) {
auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 19f267396e0f..a73164895baa 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -183,8 +183,6 @@ public:
static void DumpDeclContextHiearchy(clang::DeclContext *decl_ctx);
- static bool DeclsAreEquivalent(clang::Decl *lhs_decl, clang::Decl *rhs_decl);
-
static bool GetCompleteDecl(clang::ASTContext *ast, clang::Decl *decl);
void SetMetadataAsUserID(const clang::Decl *decl, lldb::user_id_t user_id);
@@ -558,6 +556,9 @@ public:
CompilerType DeclGetFunctionArgumentType(void *opaque_decl,
size_t arg_idx) override;
+ std::vector<lldb_private::CompilerContext>
+ DeclGetCompilerContext(void *opaque_decl) override;
+
CompilerType GetTypeForDecl(void *opaque_decl) override;
// CompilerDeclContext override functions
@@ -587,6 +588,9 @@ public:
lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) override;
+ std::vector<lldb_private::CompilerContext>
+ DeclContextGetCompilerContext(void *opaque_decl_ctx) override;
+
// Clang specific clang::DeclContext functions
static clang::DeclContext *
diff --git a/lldb/source/Symbol/CompilerDecl.cpp b/lldb/source/Symbol/CompilerDecl.cpp
index 3cafa9535a72..0eb630e5b9e1 100644
--- a/lldb/source/Symbol/CompilerDecl.cpp
+++ b/lldb/source/Symbol/CompilerDecl.cpp
@@ -47,3 +47,8 @@ bool lldb_private::operator!=(const lldb_private::CompilerDecl &lhs,
return lhs.GetTypeSystem() != rhs.GetTypeSystem() ||
lhs.GetOpaqueDecl() != rhs.GetOpaqueDecl();
}
+
+std::vector<lldb_private::CompilerContext>
+CompilerDecl::GetCompilerContext() const {
+ return m_type_system->DeclGetCompilerContext(m_opaque_decl);
+}
diff --git a/lldb/source/Symbol/CompilerDeclContext.cpp b/lldb/source/Symbol/CompilerDeclContext.cpp
index a188e60251f7..b40a08e9b195 100644
--- a/lldb/source/Symbol/CompilerDeclContext.cpp
+++ b/lldb/source/Symbol/CompilerDeclContext.cpp
@@ -59,6 +59,13 @@ bool CompilerDeclContext::IsContainedInLookup(CompilerDeclContext other) const {
other.m_opaque_decl_ctx);
}
+std::vector<lldb_private::CompilerContext>
+CompilerDeclContext::GetCompilerContext() const {
+ if (IsValid())
+ return m_type_system->DeclContextGetCompilerContext(m_opaque_decl_ctx);
+ return {};
+}
+
bool lldb_private::operator==(const lldb_private::CompilerDeclContext &lhs,
const lldb_private::CompilerDeclContext &rhs) {
return lhs.GetTypeSystem() == rhs.GetTypeSystem() &&
diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp
index 78cc8dad94a9..76b79daa6ac1 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -302,6 +302,192 @@ bool CompilerType::IsBeingDefined() const {
return false;
}
+bool CompilerType::IsInteger() const {
+ bool is_signed = false; // May be reset by the call below.
+ return IsIntegerType(is_signed);
+}
+
+bool CompilerType::IsFloat() const {
+ uint32_t count = 0;
+ bool is_complex = false;
+ return IsFloatingPointType(count, is_complex);
+}
+
+bool CompilerType::IsEnumerationType() const {
+ bool is_signed = false; // May be reset by the call below.
+ return IsEnumerationType(is_signed);
+}
+
+bool CompilerType::IsUnscopedEnumerationType() const {
+ return IsEnumerationType() && !IsScopedEnumerationType();
+}
+
+bool CompilerType::IsIntegerOrUnscopedEnumerationType() const {
+ return IsInteger() || IsUnscopedEnumerationType();
+}
+
+bool CompilerType::IsSigned() const {
+ return GetTypeInfo() & lldb::eTypeIsSigned;
+}
+
+bool CompilerType::IsNullPtrType() const {
+ return GetCanonicalType().GetBasicTypeEnumeration() ==
+ lldb::eBasicTypeNullPtr;
+}
+
+bool CompilerType::IsBoolean() const {
+ return GetCanonicalType().GetBasicTypeEnumeration() == lldb::eBasicTypeBool;
+}
+
+bool CompilerType::IsEnumerationIntegerTypeSigned() const {
+ if (IsValid())
+ return GetEnumerationIntegerType().GetTypeInfo() & lldb::eTypeIsSigned;
+
+ return false;
+}
+
+bool CompilerType::IsScalarOrUnscopedEnumerationType() const {
+ return IsScalarType() || IsUnscopedEnumerationType();
+}
+
+bool CompilerType::IsPromotableIntegerType() const {
+ // Unscoped enums are always considered as promotable, even if their
+ // underlying type does not need to be promoted (e.g. "int").
+ if (IsUnscopedEnumerationType())
+ return true;
+
+ switch (GetCanonicalType().GetBasicTypeEnumeration()) {
+ case lldb::eBasicTypeBool:
+ case lldb::eBasicTypeChar:
+ case lldb::eBasicTypeSignedChar:
+ case lldb::eBasicTypeUnsignedChar:
+ case lldb::eBasicTypeShort:
+ case lldb::eBasicTypeUnsignedShort:
+ case lldb::eBasicTypeWChar:
+ case lldb::eBasicTypeSignedWChar:
+ case lldb::eBasicTypeUnsignedWChar:
+ case lldb::eBasicTypeChar16:
+ case lldb::eBasicTypeChar32:
+ return true;
+
+ default:
+ return false;
+ }
+
+ llvm_unreachable("All cases handled above.");
+}
+
+bool CompilerType::IsPointerToVoid() const {
+ if (!IsValid())
+ return false;
+
+ return IsPointerType() &&
+ GetPointeeType().GetBasicTypeEnumeration() == lldb::eBasicTypeVoid;
+}
+
+bool CompilerType::IsRecordType() const {
+ if (!IsValid())
+ return false;
+
+ return GetCanonicalType().GetTypeClass() &
+ (lldb::eTypeClassClass | lldb::eTypeClassStruct |
+ lldb::eTypeClassUnion);
+}
+
+bool CompilerType::IsVirtualBase(CompilerType target_base,
+ CompilerType *virtual_base,
+ bool carry_virtual) const {
+ if (CompareTypes(target_base))
+ return carry_virtual;
+
+ if (!carry_virtual) {
+ uint32_t num_virtual_bases = GetNumVirtualBaseClasses();
+ for (uint32_t i = 0; i < num_virtual_bases; ++i) {
+ uint32_t bit_offset;
+ auto base = GetVirtualBaseClassAtIndex(i, &bit_offset);
+ if (base.IsVirtualBase(target_base, virtual_base,
+ /*carry_virtual*/ true)) {
+ if (virtual_base)
+ *virtual_base = base;
+
+ return true;
+ }
+ }
+ }
+
+ uint32_t num_direct_bases = GetNumDirectBaseClasses();
+ for (uint32_t i = 0; i < num_direct_bases; ++i) {
+ uint32_t bit_offset;
+ auto base = GetDirectBaseClassAtIndex(i, &bit_offset);
+ if (base.IsVirtualBase(target_base, virtual_base, carry_virtual))
+ return true;
+ }
+
+ return false;
+}
+
+bool CompilerType::IsContextuallyConvertibleToBool() const {
+ return IsScalarType() || IsUnscopedEnumerationType() || IsPointerType() ||
+ IsNullPtrType() || IsArrayType();
+}
+
+bool CompilerType::IsBasicType() const {
+ return GetCanonicalType().GetBasicTypeEnumeration() !=
+ lldb::eBasicTypeInvalid;
+}
+
+std::string CompilerType::TypeDescription() {
+ auto name = GetTypeName();
+ auto canonical_name = GetCanonicalType().GetTypeName();
+ if (name.IsEmpty() || canonical_name.IsEmpty())
+ return "''"; // Should not happen, unless the input is broken somehow.
+
+ if (name == canonical_name)
+ return llvm::formatv("'{0}'", name);
+
+ return llvm::formatv("'{0}' (canonically referred to as '{1}')", name,
+ canonical_name);
+}
+
+bool CompilerType::CompareTypes(CompilerType rhs) const {
+ if (*this == rhs)
+ return true;
+
+ const ConstString name = GetFullyUnqualifiedType().GetTypeName();
+ const ConstString rhs_name = rhs.GetFullyUnqualifiedType().GetTypeName();
+ return name == rhs_name;
+}
+
+const char *CompilerType::GetTypeTag() {
+ switch (GetTypeClass()) {
+ case lldb::eTypeClassClass:
+ return "class";
+ case lldb::eTypeClassEnumeration:
+ return "enum";
+ case lldb::eTypeClassStruct:
+ return "struct";
+ case lldb::eTypeClassUnion:
+ return "union";
+ default:
+ return "unknown";
+ }
+ llvm_unreachable("All cases are covered by code above.");
+}
+
+uint32_t CompilerType::GetNumberOfNonEmptyBaseClasses() {
+ uint32_t ret = 0;
+ uint32_t num_direct_bases = GetNumDirectBaseClasses();
+
+ for (uint32_t i = 0; i < num_direct_bases; ++i) {
+ uint32_t bit_offset;
+ CompilerType base_type = GetDirectBaseClassAtIndex(i, &bit_offset);
+ if (base_type.GetNumFields() > 0 ||
+ base_type.GetNumberOfNonEmptyBaseClasses() > 0)
+ ret += 1;
+ }
+ return ret;
+}
+
// Type Completion
bool CompilerType::GetCompleteType() const {
diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp
index 07f79aaedab8..d890ad92e831 100644
--- a/lldb/source/Symbol/ObjectFile.cpp
+++ b/lldb/source/Symbol/ObjectFile.cpp
@@ -607,15 +607,15 @@ lldb::SymbolType
ObjectFile::GetSymbolTypeFromName(llvm::StringRef name,
lldb::SymbolType symbol_type_hint) {
if (!name.empty()) {
- if (name.startswith("_OBJC_")) {
+ if (name.starts_with("_OBJC_")) {
// ObjC
- if (name.startswith("_OBJC_CLASS_$_"))
+ if (name.starts_with("_OBJC_CLASS_$_"))
return lldb::eSymbolTypeObjCClass;
- if (name.startswith("_OBJC_METACLASS_$_"))
+ if (name.starts_with("_OBJC_METACLASS_$_"))
return lldb::eSymbolTypeObjCMetaClass;
- if (name.startswith("_OBJC_IVAR_$_"))
+ if (name.starts_with("_OBJC_IVAR_$_"))
return lldb::eSymbolTypeObjCIVar;
- } else if (name.startswith(".objc_class_name_")) {
+ } else if (name.starts_with(".objc_class_name_")) {
// ObjC v1
return lldb::eSymbolTypeObjCClass;
}
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index fcc45f861c22..08900a3ef349 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -634,7 +634,7 @@ bool Symbol::IsSyntheticWithAutoGeneratedName() const {
if (!m_mangled)
return true;
ConstString demangled = m_mangled.GetDemangledName();
- return demangled.GetStringRef().startswith(GetSyntheticSymbolPrefix());
+ return demangled.GetStringRef().starts_with(GetSyntheticSymbolPrefix());
}
void Symbol::SynthesizeNameIfNeeded() const {
diff --git a/lldb/source/Symbol/SymbolFile.cpp b/lldb/source/Symbol/SymbolFile.cpp
index 4b9c3863e461..e318e2beb654 100644
--- a/lldb/source/Symbol/SymbolFile.cpp
+++ b/lldb/source/Symbol/SymbolFile.cpp
@@ -134,17 +134,6 @@ void SymbolFile::GetMangledNamesForFunction(
const std::string &scope_qualified_name,
std::vector<ConstString> &mangled_names) {}
-void SymbolFile::FindTypes(
- ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types) {}
-
-void SymbolFile::FindTypes(llvm::ArrayRef<CompilerContext> pattern,
- LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files,
- TypeMap &types) {}
-
void SymbolFile::AssertModuleLock() {
// The code below is too expensive to leave enabled in release builds. It's
// enabled in debug builds or when the correct macro is set.
diff --git a/lldb/source/Symbol/SymbolFileOnDemand.cpp b/lldb/source/Symbol/SymbolFileOnDemand.cpp
index 19b519c63a8a..33995252bfe2 100644
--- a/lldb/source/Symbol/SymbolFileOnDemand.cpp
+++ b/lldb/source/Symbol/SymbolFileOnDemand.cpp
@@ -431,31 +431,14 @@ void SymbolFileOnDemand::GetMangledNamesForFunction(
mangled_names);
}
-void SymbolFileOnDemand::FindTypes(
- ConstString name, const CompilerDeclContext &parent_decl_ctx,
- uint32_t max_matches,
- llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
- TypeMap &types) {
- if (!m_debug_info_enabled) {
- Log *log = GetLog();
- LLDB_LOG(log, "[{0}] {1}({2}) is skipped", GetSymbolFileName(),
- __FUNCTION__, name);
- return;
- }
- return m_sym_file_impl->FindTypes(name, parent_decl_ctx, max_matches,
- searched_symbol_files, types);
-}
-
-void SymbolFileOnDemand::FindTypes(
- llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
- llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {
+void SymbolFileOnDemand::FindTypes(const TypeQuery &match,
+ TypeResults &results) {
if (!m_debug_info_enabled) {
LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(),
__FUNCTION__);
return;
}
- return m_sym_file_impl->FindTypes(pattern, languages, searched_symbol_files,
- types);
+ return m_sym_file_impl->FindTypes(match, results);
}
void SymbolFileOnDemand::GetTypes(SymbolContextScope *sc_scope,
diff --git a/lldb/source/Symbol/Symtab.cpp b/lldb/source/Symbol/Symtab.cpp
index 1aebe198f9e7..564a3a94cfa2 100644
--- a/lldb/source/Symbol/Symtab.cpp
+++ b/lldb/source/Symbol/Symtab.cpp
@@ -233,7 +233,7 @@ static bool lldb_skip_name(llvm::StringRef mangled,
Mangled::ManglingScheme scheme) {
switch (scheme) {
case Mangled::eManglingSchemeItanium: {
- if (mangled.size() < 3 || !mangled.startswith("_Z"))
+ if (mangled.size() < 3 || !mangled.starts_with("_Z"))
return true;
// Avoid the following types of symbols in the index.
diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp
index 54eeace93b96..293fe1b78f4a 100644
--- a/lldb/source/Symbol/Type.cpp
+++ b/lldb/source/Symbol/Type.cpp
@@ -64,6 +64,127 @@ bool lldb_private::contextMatches(llvm::ArrayRef<CompilerContext> context_chain,
return true;
}
+static CompilerContextKind ConvertTypeClass(lldb::TypeClass type_class) {
+ if (type_class == eTypeClassAny)
+ return CompilerContextKind::AnyType;
+ uint16_t result = 0;
+ if (type_class & lldb::eTypeClassClass)
+ result |= (uint16_t)CompilerContextKind::Class;
+ if (type_class & lldb::eTypeClassStruct)
+ result |= (uint16_t)CompilerContextKind::Struct;
+ if (type_class & lldb::eTypeClassUnion)
+ result |= (uint16_t)CompilerContextKind::Union;
+ if (type_class & lldb::eTypeClassEnumeration)
+ result |= (uint16_t)CompilerContextKind::Enum;
+ if (type_class & lldb::eTypeClassFunction)
+ result |= (uint16_t)CompilerContextKind::Function;
+ if (type_class & lldb::eTypeClassTypedef)
+ result |= (uint16_t)CompilerContextKind::Typedef;
+ return (CompilerContextKind)result;
+}
+
+TypeQuery::TypeQuery(llvm::StringRef name, TypeQueryOptions options)
+ : m_options(options) {
+ llvm::StringRef scope, basename;
+ lldb::TypeClass type_class = lldb::eTypeClassAny;
+ if (Type::GetTypeScopeAndBasename(name, scope, basename, type_class)) {
+ if (scope.consume_front("::"))
+ m_options |= e_exact_match;
+ if (!scope.empty()) {
+ std::pair<llvm::StringRef, llvm::StringRef> scope_pair =
+ scope.split("::");
+ while (!scope_pair.second.empty()) {
+ m_context.push_back({CompilerContextKind::AnyDeclContext,
+ ConstString(scope_pair.first.str())});
+ scope_pair = scope_pair.second.split("::");
+ }
+ m_context.push_back({CompilerContextKind::AnyDeclContext,
+ ConstString(scope_pair.first.str())});
+ }
+ m_context.push_back(
+ {ConvertTypeClass(type_class), ConstString(basename.str())});
+ } else {
+ m_context.push_back(
+ {CompilerContextKind::AnyType, ConstString(name.str())});
+ }
+}
+
+TypeQuery::TypeQuery(const CompilerDeclContext &decl_ctx,
+ ConstString type_basename, TypeQueryOptions options)
+ : m_options(options) {
+ // Always use an exact match if we are looking for a type in compiler context.
+ m_options |= e_exact_match;
+ m_context = decl_ctx.GetCompilerContext();
+ m_context.push_back({CompilerContextKind::AnyType, type_basename});
+}
+
+TypeQuery::TypeQuery(
+ const llvm::ArrayRef<lldb_private::CompilerContext> &context,
+ TypeQueryOptions options)
+ : m_context(context), m_options(options) {
+ // Always use an exact match if we are looking for a type in compiler context.
+ m_options |= e_exact_match;
+}
+
+TypeQuery::TypeQuery(const CompilerDecl &decl, TypeQueryOptions options)
+ : m_options(options) {
+ // Always for an exact match if we are looking for a type using a declaration.
+ m_options |= e_exact_match;
+ m_context = decl.GetCompilerContext();
+}
+
+ConstString TypeQuery::GetTypeBasename() const {
+ if (m_context.empty())
+ return ConstString();
+ return m_context.back().name;
+}
+
+void TypeQuery::AddLanguage(LanguageType language) {
+ if (!m_languages)
+ m_languages = LanguageSet();
+ m_languages->Insert(language);
+}
+
+bool TypeQuery::ContextMatches(
+ llvm::ArrayRef<CompilerContext> context_chain) const {
+ if (GetExactMatch() || context_chain.size() == m_context.size())
+ return ::contextMatches(context_chain, m_context);
+
+ // We don't have an exact match, we need to bottom m_context.size() items to
+ // match for a successful lookup.
+ if (context_chain.size() < m_context.size())
+ return false; // Not enough items in context_chain to allow for a match.
+
+ size_t compare_count = context_chain.size() - m_context.size();
+ return ::contextMatches(
+ llvm::ArrayRef<CompilerContext>(context_chain.data() + compare_count,
+ m_context.size()),
+ m_context);
+}
+
+bool TypeQuery::LanguageMatches(lldb::LanguageType language) const {
+ // If we have no language filterm language always matches.
+ if (!m_languages.has_value())
+ return true;
+ return (*m_languages)[language];
+}
+
+bool TypeResults::AlreadySearched(lldb_private::SymbolFile *sym_file) {
+ return !m_searched_symbol_files.insert(sym_file).second;
+}
+
+bool TypeResults::InsertUnique(const lldb::TypeSP &type_sp) {
+ if (type_sp)
+ return m_type_map.InsertUnique(type_sp);
+ return false;
+}
+
+bool TypeResults::Done(const TypeQuery &query) const {
+ if (query.GetFindOne())
+ return !m_type_map.Empty();
+ return false;
+}
+
void CompilerContext::Dump(Stream &s) const {
switch (kind) {
default:
@@ -641,6 +762,8 @@ bool Type::GetTypeScopeAndBasename(llvm::StringRef name,
if (name.empty())
return false;
+ // Clear the scope in case we have just a type class and a basename.
+ scope = llvm::StringRef();
basename = name;
if (basename.consume_front("struct "))
type_class = eTypeClassStruct;
@@ -654,8 +777,10 @@ bool Type::GetTypeScopeAndBasename(llvm::StringRef name,
type_class = eTypeClassTypedef;
size_t namespace_separator = basename.find("::");
- if (namespace_separator == llvm::StringRef::npos)
- return false;
+ if (namespace_separator == llvm::StringRef::npos) {
+ // If "name" started a type class we need to return true with no scope.
+ return type_class != eTypeClassAny;
+ }
size_t template_begin = basename.find('<');
while (namespace_separator != llvm::StringRef::npos) {
@@ -1049,16 +1174,19 @@ CompilerType TypeImpl::FindDirectNestedType(llvm::StringRef name) {
return CompilerType();
auto type_system = GetTypeSystem(/*prefer_dynamic*/ false);
auto *symbol_file = type_system->GetSymbolFile();
+ if (!symbol_file)
+ return CompilerType();
auto decl_context = type_system->GetCompilerDeclContextForType(m_static_type);
if (!decl_context.IsValid())
return CompilerType();
- llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
- TypeMap search_result;
- symbol_file->FindTypes(ConstString(name), decl_context, /*max_matches*/ 1,
- searched_symbol_files, search_result);
- if (search_result.Empty())
- return CompilerType();
- return search_result.GetTypeAtIndex(0)->GetFullCompilerType();
+ TypeQuery query(decl_context, ConstString(name),
+ TypeQueryOptions::e_find_one);
+ TypeResults results;
+ symbol_file->FindTypes(query, results);
+ TypeSP type_sp = results.GetFirstType();
+ if (type_sp)
+ return type_sp->GetFullCompilerType();
+ return CompilerType();
}
bool TypeMemberFunctionImpl::IsValid() {
diff --git a/lldb/source/Symbol/TypeMap.cpp b/lldb/source/Symbol/TypeMap.cpp
index 0d5f6d53e5a0..8933de53749c 100644
--- a/lldb/source/Symbol/TypeMap.cpp
+++ b/lldb/source/Symbol/TypeMap.cpp
@@ -91,6 +91,12 @@ TypeSP TypeMap::GetTypeAtIndex(uint32_t idx) {
return TypeSP();
}
+lldb::TypeSP TypeMap::FirstType() const {
+ if (m_types.empty())
+ return TypeSP();
+ return m_types.begin()->second;
+}
+
void TypeMap::ForEach(
std::function<bool(const lldb::TypeSP &type_sp)> const &callback) const {
for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) {
@@ -121,10 +127,10 @@ bool TypeMap::Remove(const lldb::TypeSP &type_sp) {
return false;
}
-void TypeMap::Dump(Stream *s, bool show_context, lldb::DescriptionLevel level) {
- for (iterator pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) {
- pos->second->Dump(s, show_context, level);
- }
+void TypeMap::Dump(Stream *s, bool show_context,
+ lldb::DescriptionLevel level) const {
+ for (const auto &pair : m_types)
+ pair.second->Dump(s, show_context, level);
}
void TypeMap::RemoveMismatchedTypes(llvm::StringRef type_scope,
diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp
index 874f12573eca..59b1b39e635a 100644
--- a/lldb/source/Symbol/TypeSystem.cpp
+++ b/lldb/source/Symbol/TypeSystem.cpp
@@ -171,6 +171,16 @@ CompilerType TypeSystem::DeclGetFunctionArgumentType(void *opaque_decl,
return CompilerType();
}
+std::vector<lldb_private::CompilerContext>
+TypeSystem::DeclGetCompilerContext(void *opaque_decl) {
+ return {};
+}
+
+std::vector<lldb_private::CompilerContext>
+TypeSystem::DeclContextGetCompilerContext(void *opaque_decl_ctx) {
+ return {};
+}
+
std::vector<CompilerDecl>
TypeSystem::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name,
bool ignore_imported_decls) {
diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp
index db740cb7cb6e..2bb2ff7db4b7 100644
--- a/lldb/source/Symbol/Variable.cpp
+++ b/lldb/source/Symbol/Variable.cpp
@@ -510,7 +510,7 @@ static void PrivateAutoCompleteMembers(
i, member_name, nullptr, nullptr, nullptr);
if (partial_member_name.empty() ||
- llvm::StringRef(member_name).startswith(partial_member_name)) {
+ llvm::StringRef(member_name).starts_with(partial_member_name)) {
if (member_name == partial_member_name) {
PrivateAutoComplete(
frame, partial_path,
@@ -685,7 +685,7 @@ static void PrivateAutoComplete(
continue;
llvm::StringRef variable_name = var_sp->GetName().GetStringRef();
- if (variable_name.startswith(token)) {
+ if (variable_name.starts_with(token)) {
if (variable_name == token) {
Type *variable_type = var_sp->GetType();
if (variable_type) {
diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp
index 42c3350806d9..caf3e6636c1d 100644
--- a/lldb/source/Target/Language.cpp
+++ b/lldb/source/Target/Language.cpp
@@ -434,12 +434,10 @@ bool Language::ImageListTypeScavenger::Find_Impl(
Target *target = exe_scope->CalculateTarget().get();
if (target) {
const auto &images(target->GetImages());
- ConstString cs_key(key);
- llvm::DenseSet<SymbolFile *> searched_sym_files;
- TypeList matches;
- images.FindTypes(nullptr, cs_key, false, UINT32_MAX, searched_sym_files,
- matches);
- for (const auto &match : matches.Types()) {
+ TypeQuery query(key);
+ TypeResults type_results;
+ images.FindTypes(nullptr, query, type_results);
+ for (const auto &match : type_results.GetTypeMap().Types()) {
if (match) {
CompilerType compiler_type(match->GetFullCompilerType());
compiler_type = AdjustForInclusion(compiler_type);
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index f0d78d8aa5fe..50cf01e63cd4 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -652,7 +652,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
Status deref_error;
if (valobj_sp->GetCompilerType().IsReferenceType()) {
valobj_sp = valobj_sp->GetSyntheticValue()->Dereference(deref_error);
- if (error.Fail()) {
+ if (!valobj_sp || deref_error.Fail()) {
error.SetErrorStringWithFormatv(
"Failed to dereference reference type: %s", deref_error);
return ValueObjectSP();
@@ -660,7 +660,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
}
valobj_sp = valobj_sp->Dereference(deref_error);
- if (error.Fail()) {
+ if (!valobj_sp || deref_error.Fail()) {
error.SetErrorStringWithFormatv(
"Failed to dereference sythetic value: {0}", deref_error);
return ValueObjectSP();
@@ -795,9 +795,9 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// what we have is *ptr[low]. the most similar C++ syntax is to deref
// ptr and extract bit low out of it. reading array item low would be
// done by saying ptr[low], without a deref * sign
- Status error;
- ValueObjectSP temp(valobj_sp->Dereference(error));
- if (error.Fail()) {
+ Status deref_error;
+ ValueObjectSP temp(valobj_sp->Dereference(deref_error));
+ if (!temp || deref_error.Fail()) {
valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"could not dereference \"(%s) %s\"",
@@ -813,9 +813,8 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// arr[0] (an operation that is equivalent to deref-ing arr) and
// extract bit low out of it. reading array item low would be done by
// saying arr[low], without a deref * sign
- Status error;
ValueObjectSP temp(valobj_sp->GetChildAtIndex(0));
- if (error.Fail()) {
+ if (!temp) {
valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"could not get item 0 for \"(%s) %s\"",
@@ -994,9 +993,9 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// deref ptr and extract bits low thru high out of it. reading array
// items low thru high would be done by saying ptr[low-high], without a
// deref * sign
- Status error;
- ValueObjectSP temp(valobj_sp->Dereference(error));
- if (error.Fail()) {
+ Status deref_error;
+ ValueObjectSP temp(valobj_sp->Dereference(deref_error));
+ if (!temp || deref_error.Fail()) {
valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"could not dereference \"(%s) %s\"",
@@ -1011,9 +1010,8 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// get arr[0] (an operation that is equivalent to deref-ing arr) and
// extract bits low thru high out of it. reading array items low thru
// high would be done by saying arr[low-high], without a deref * sign
- Status error;
ValueObjectSP temp(valobj_sp->GetChildAtIndex(0));
- if (error.Fail()) {
+ if (!temp) {
valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"could not get item 0 for \"(%s) %s\"",
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
index 3ec523b94101..121b6253d2a5 100644
--- a/lldb/source/Target/TargetList.cpp
+++ b/lldb/source/Target/TargetList.cpp
@@ -271,7 +271,7 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
arch = specified_arch;
FileSpec file(user_exe_path);
- if (!FileSystem::Instance().Exists(file) && user_exe_path.startswith("~")) {
+ if (!FileSystem::Instance().Exists(file) && user_exe_path.starts_with("~")) {
// we want to expand the tilde but we don't want to resolve any symbolic
// links so we can't use the FileSpec constructor's resolve flag
llvm::SmallString<64> unglobbed_path;
diff --git a/lldb/source/Utility/Args.cpp b/lldb/source/Utility/Args.cpp
index 152be96a2212..13b993bc74c9 100644
--- a/lldb/source/Utility/Args.cpp
+++ b/lldb/source/Utility/Args.cpp
@@ -641,7 +641,7 @@ void OptionsWithRaw::SetFromString(llvm::StringRef arg_string) {
// If the string doesn't start with a dash, we just have no options and just
// a raw part.
- if (!arg_string.startswith("-")) {
+ if (!arg_string.starts_with("-")) {
m_suffix = std::string(original_args);
return;
}
diff --git a/lldb/source/Utility/CompletionRequest.cpp b/lldb/source/Utility/CompletionRequest.cpp
index 8f9dbb79d37b..e12609ca75e7 100644
--- a/lldb/source/Utility/CompletionRequest.cpp
+++ b/lldb/source/Utility/CompletionRequest.cpp
@@ -36,8 +36,8 @@ CompletionRequest::CompletionRequest(llvm::StringRef command_line,
// The cursor is after a space but the space is not part of the argument.
// Let's add an empty fake argument to the end to make sure the completion
// code. Note: The space could be part of the last argument when it's quoted.
- if (partial_command.endswith(" ") &&
- !GetCursorArgumentPrefix().endswith(" "))
+ if (partial_command.ends_with(" ") &&
+ !GetCursorArgumentPrefix().ends_with(" "))
AppendEmptyArgument();
}
diff --git a/lldb/source/Utility/FileSpec.cpp b/lldb/source/Utility/FileSpec.cpp
index 4bbfbb7c1fab..5387be9a681f 100644
--- a/lldb/source/Utility/FileSpec.cpp
+++ b/lldb/source/Utility/FileSpec.cpp
@@ -311,9 +311,9 @@ bool FileSpec::Match(const FileSpec &pattern, const FileSpec &file) {
std::optional<FileSpec::Style>
FileSpec::GuessPathStyle(llvm::StringRef absolute_path) {
- if (absolute_path.startswith("/"))
+ if (absolute_path.starts_with("/"))
return Style::posix;
- if (absolute_path.startswith(R"(\\)"))
+ if (absolute_path.starts_with(R"(\\)"))
return Style::windows;
if (absolute_path.size() >= 3 && llvm::isAlpha(absolute_path[0]) &&
(absolute_path.substr(1, 2) == R"(:\)" ||
diff --git a/lldb/source/Utility/FileSpecList.cpp b/lldb/source/Utility/FileSpecList.cpp
index d5369ac4bbe5..e3d8ea650c75 100644
--- a/lldb/source/Utility/FileSpecList.cpp
+++ b/lldb/source/Utility/FileSpecList.cpp
@@ -117,7 +117,7 @@ size_t FileSpecList::FindCompatibleIndex(size_t start_idx,
auto is_suffix = [](llvm::StringRef a, llvm::StringRef b,
bool case_sensitive) -> bool {
if (case_sensitive ? a.consume_back(b) : a.consume_back_insensitive(b))
- return a.empty() || a.endswith("/");
+ return a.empty() || a.ends_with("/");
return false;
};
const bool case_sensitive =
diff --git a/lldb/source/Utility/NameMatches.cpp b/lldb/source/Utility/NameMatches.cpp
index 1c8cd6a0ca31..f002b86f163b 100644
--- a/lldb/source/Utility/NameMatches.cpp
+++ b/lldb/source/Utility/NameMatches.cpp
@@ -22,9 +22,9 @@ bool lldb_private::NameMatches(llvm::StringRef name, NameMatch match_type,
case NameMatch::Contains:
return name.contains(match);
case NameMatch::StartsWith:
- return name.startswith(match);
+ return name.starts_with(match);
case NameMatch::EndsWith:
- return name.endswith(match);
+ return name.ends_with(match);
case NameMatch::RegularExpression: {
RegularExpression regex(match);
return regex.Execute(name);
diff --git a/lldb/source/Utility/StringExtractor.cpp b/lldb/source/Utility/StringExtractor.cpp
index c7e4ac794284..579faa3da42f 100644
--- a/lldb/source/Utility/StringExtractor.cpp
+++ b/lldb/source/Utility/StringExtractor.cpp
@@ -254,7 +254,7 @@ uint64_t StringExtractor::GetHexMaxU64(bool little_endian,
bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {
llvm::StringRef S = GetStringRef();
- if (!S.startswith(str))
+ if (!S.starts_with(str))
return false;
else
m_index += str.size();
diff --git a/lldb/source/Utility/TildeExpressionResolver.cpp b/lldb/source/Utility/TildeExpressionResolver.cpp
index 6311ae062f1f..2e334b2aae54 100644
--- a/lldb/source/Utility/TildeExpressionResolver.cpp
+++ b/lldb/source/Utility/TildeExpressionResolver.cpp
@@ -60,7 +60,7 @@ bool StandardTildeExpressionResolver::ResolvePartial(StringRef Expr,
while ((user_entry = getpwent()) != nullptr) {
StringRef ThisName(user_entry->pw_name);
- if (!ThisName.startswith(Expr))
+ if (!ThisName.starts_with(Expr))
continue;
Buffer.resize(1);
@@ -75,7 +75,7 @@ bool StandardTildeExpressionResolver::ResolvePartial(StringRef Expr,
bool TildeExpressionResolver::ResolveFullPath(
StringRef Expr, llvm::SmallVectorImpl<char> &Output) {
- if (!Expr.startswith("~")) {
+ if (!Expr.starts_with("~")) {
Output.assign(Expr.begin(), Expr.end());
return false;
}
diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp
index 154ddbebe8b3..d744336373b2 100644
--- a/lldb/source/Utility/XcodeSDK.cpp
+++ b/lldb/source/Utility/XcodeSDK.cpp
@@ -152,7 +152,7 @@ void XcodeSDK::Merge(const XcodeSDK &other) {
*this = other;
else {
// The Internal flag always wins.
- if (llvm::StringRef(m_name).endswith(".sdk"))
+ if (llvm::StringRef(m_name).ends_with(".sdk"))
if (!l.internal && r.internal)
m_name =
m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");
@@ -291,7 +291,7 @@ std::string XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path) {
// .app. If the next component is Contents then we've found the Contents
// directory.
for (auto it = begin; it != end; ++it) {
- if (it->endswith(".app")) {
+ if (it->ends_with(".app")) {
auto next = it;
if (++next != end && *next == "Contents") {
llvm::SmallString<128> buffer;
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index a575ec3709fe..83530ae7b513 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -483,6 +483,29 @@ typedef enum {
typedef unsigned LLVMAttributeIndex;
+enum {
+ LLVMFastMathAllowReassoc = (1 << 0),
+ LLVMFastMathNoNaNs = (1 << 1),
+ LLVMFastMathNoInfs = (1 << 2),
+ LLVMFastMathNoSignedZeros = (1 << 3),
+ LLVMFastMathAllowReciprocal = (1 << 4),
+ LLVMFastMathAllowContract = (1 << 5),
+ LLVMFastMathApproxFunc = (1 << 6),
+ LLVMFastMathNone = 0,
+ LLVMFastMathAll = LLVMFastMathAllowReassoc | LLVMFastMathNoNaNs |
+ LLVMFastMathNoInfs | LLVMFastMathNoSignedZeros |
+ LLVMFastMathAllowReciprocal | LLVMFastMathAllowContract |
+ LLVMFastMathApproxFunc,
+};
+
+/**
+ * Flags to indicate what fast-math-style optimizations are allowed
+ * on operations.
+ *
+ * See https://llvm.org/docs/LangRef.html#fast-math-flags
+ */
+typedef unsigned LLVMFastMathFlags;
+
/**
* @}
*/
@@ -3005,6 +3028,74 @@ LLVMValueRef LLVMMDNode(LLVMValueRef *Vals, unsigned Count);
*/
/**
+ * @defgroup LLVMCCoreOperandBundle Operand Bundles
+ *
+ * Functions in this group operate on LLVMOperandBundleRef instances that
+ * correspond to llvm::OperandBundleDef instances.
+ *
+ * @see llvm::OperandBundleDef
+ *
+ * @{
+ */
+
+/**
+ * Create a new operand bundle.
+ *
+ * Every invocation should be paired with LLVMDisposeOperandBundle() or memory
+ * will be leaked.
+ *
+ * @param Tag Tag name of the operand bundle
+ * @param TagLen Length of Tag
+ * @param Args Memory address of an array of bundle operands
+ * @param NumArgs Length of Args
+ */
+LLVMOperandBundleRef LLVMCreateOperandBundle(const char *Tag, size_t TagLen,
+ LLVMValueRef *Args,
+ unsigned NumArgs);
+
+/**
+ * Destroy an operand bundle.
+ *
+ * This must be called for every created operand bundle or memory will be
+ * leaked.
+ */
+void LLVMDisposeOperandBundle(LLVMOperandBundleRef Bundle);
+
+/**
+ * Obtain the tag of an operand bundle as a string.
+ *
+ * @param Bundle Operand bundle to obtain tag of.
+ * @param Len Out parameter which holds the length of the returned string.
+ * @return The tag name of Bundle.
+ * @see OperandBundleDef::getTag()
+ */
+const char *LLVMGetOperandBundleTag(LLVMOperandBundleRef Bundle, size_t *Len);
+
+/**
+ * Obtain the number of operands for an operand bundle.
+ *
+ * @param Bundle Operand bundle to obtain operand count of.
+ * @return The number of operands.
+ * @see OperandBundleDef::input_size()
+ */
+unsigned LLVMGetNumOperandBundleArgs(LLVMOperandBundleRef Bundle);
+
+/**
+ * Obtain the operand for an operand bundle at the given index.
+ *
+ * @param Bundle Operand bundle to obtain operand of.
+ * @param Index An operand index, must be less than
+ * LLVMGetNumOperandBundleArgs().
+ * @return The operand.
+ */
+LLVMValueRef LLVMGetOperandBundleArgAtIndex(LLVMOperandBundleRef Bundle,
+ unsigned Index);
+
+/**
+ * @}
+ */
+
+/**
* @defgroup LLVMCCoreValueBasicBlock Basic Block
*
* A basic block represents a single entry single exit section of code.
@@ -3452,6 +3543,24 @@ LLVMTypeRef LLVMGetCalledFunctionType(LLVMValueRef C);
LLVMValueRef LLVMGetCalledValue(LLVMValueRef Instr);
/**
+ * Obtain the number of operand bundles attached to this instruction.
+ *
+ * This only works on llvm::CallInst and llvm::InvokeInst instructions.
+ *
+ * @see llvm::CallBase::getNumOperandBundles()
+ */
+unsigned LLVMGetNumOperandBundles(LLVMValueRef C);
+
+/**
+ * Obtain the operand bundle attached to this instruction at the given index.
+ * Use LLVMDisposeOperandBundle to free the operand bundle.
+ *
+ * This only works on llvm::CallInst and llvm::InvokeInst instructions.
+ */
+LLVMOperandBundleRef LLVMGetOperandBundleAtIndex(LLVMValueRef C,
+ unsigned Index);
+
+/**
* Obtain whether a call instruction is a tail call.
*
* This only works on llvm::CallInst instructions.
@@ -3815,6 +3924,10 @@ LLVMValueRef LLVMBuildInvoke2(LLVMBuilderRef, LLVMTypeRef Ty, LLVMValueRef Fn,
LLVMValueRef *Args, unsigned NumArgs,
LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
const char *Name);
+LLVMValueRef LLVMBuildInvokeWithOperandBundles(
+ LLVMBuilderRef, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args,
+ unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
+ LLVMOperandBundleRef *Bundles, unsigned NumBundles, const char *Name);
LLVMValueRef LLVMBuildUnreachable(LLVMBuilderRef);
/* Exception Handling */
@@ -3986,6 +4099,33 @@ LLVMBool LLVMGetNNeg(LLVMValueRef NonNegInst);
void LLVMSetNNeg(LLVMValueRef NonNegInst, LLVMBool IsNonNeg);
/**
+ * Get the flags for which fast-math-style optimizations are allowed for this
+ * value.
+ *
+ * Only valid on floating point instructions.
+ * @see LLVMCanValueUseFastMathFlags
+ */
+LLVMFastMathFlags LLVMGetFastMathFlags(LLVMValueRef FPMathInst);
+
+/**
+ * Sets the flags for which fast-math-style optimizations are allowed for this
+ * value.
+ *
+ * Only valid on floating point instructions.
+ * @see LLVMCanValueUseFastMathFlags
+ */
+void LLVMSetFastMathFlags(LLVMValueRef FPMathInst, LLVMFastMathFlags FMF);
+
+/**
+ * Check if a given value can potentially have fast math flags.
+ *
+ * Will return true for floating point arithmetic instructions, and for select,
+ * phi, and call instructions whose type is a floating point type, or a vector
+ * or array thereof. See https://llvm.org/docs/LangRef.html#fast-math-flags
+ */
+LLVMBool LLVMCanValueUseFastMathFlags(LLVMValueRef Inst);
+
+/**
* Gets whether the instruction has the disjoint flag set.
* Only valid for or instructions.
*/
@@ -4121,6 +4261,11 @@ LLVMValueRef LLVMBuildPhi(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name);
LLVMValueRef LLVMBuildCall2(LLVMBuilderRef, LLVMTypeRef, LLVMValueRef Fn,
LLVMValueRef *Args, unsigned NumArgs,
const char *Name);
+LLVMValueRef
+LLVMBuildCallWithOperandBundles(LLVMBuilderRef, LLVMTypeRef, LLVMValueRef Fn,
+ LLVMValueRef *Args, unsigned NumArgs,
+ LLVMOperandBundleRef *Bundles,
+ unsigned NumBundles, const char *Name);
LLVMValueRef LLVMBuildSelect(LLVMBuilderRef, LLVMValueRef If,
LLVMValueRef Then, LLVMValueRef Else,
const char *Name);
diff --git a/llvm/include/llvm-c/LLJIT.h b/llvm/include/llvm-c/LLJIT.h
index a06133aac4fb..a58c3b8bbef7 100644
--- a/llvm/include/llvm-c/LLJIT.h
+++ b/llvm/include/llvm-c/LLJIT.h
@@ -1,4 +1,4 @@
-/*===----------- llvm-c/LLJIT.h - OrcV2 LLJIT C bindings --------*- C++ -*-===*\
+/*===----------- llvm-c/LLJIT.h - OrcV2 LLJIT C bindings ----------*- C -*-===*\
|* *|
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
|* Exceptions. *|
diff --git a/llvm/include/llvm-c/LLJITUtils.h b/llvm/include/llvm-c/LLJITUtils.h
new file mode 100644
index 000000000000..940097432b78
--- /dev/null
+++ b/llvm/include/llvm-c/LLJITUtils.h
@@ -0,0 +1,52 @@
+/*===------- llvm-c/LLJITUtils.h - Advanced LLJIT features --------*- C -*-===*\
+|* *|
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
+|* Exceptions. *|
+|* See https://llvm.org/LICENSE.txt for license information. *|
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* This header declares the C interface for extra utilities to be used with *|
+|* the LLJIT class from the llvm-c/LLJIT.h header. It requires to following *|
+|* link libraries in addition to libLLVMOrcJIT.a: *|
+|* - libLLVMOrcDebugging.a *|
+|* *|
+|* Many exotic languages can interoperate with C code but have a harder time *|
+|* with C++ due to name mangling. So in addition to C, this interface enables *|
+|* tools written in such languages. *|
+|* *|
+|* Note: This interface is experimental. It is *NOT* stable, and may be *|
+|* changed without warning. Only C API usage documentation is *|
+|* provided. See the C++ documentation for all higher level ORC API *|
+|* details. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_C_LLJITUTILS_H
+#define LLVM_C_LLJITUTILS_H
+
+#include "llvm-c/LLJIT.h"
+
+LLVM_C_EXTERN_C_BEGIN
+
+/**
+ * @defgroup LLVMCExecutionEngineLLJITUtils LLJIT Utilities
+ * @ingroup LLVMCExecutionEngineLLJIT
+ *
+ * @{
+ */
+
+/**
+ * Install the plugin that submits debug objects to the executor. Executors must
+ * expose the llvm_orc_registerJITLoaderGDBWrapper symbol.
+ */
+LLVMErrorRef LLVMOrcLLJITEnableDebugSupport(LLVMOrcLLJITRef J);
+
+/**
+ * @}
+ */
+
+LLVM_C_EXTERN_C_END
+
+#endif /* LLVM_C_LLJITUTILS_H */
diff --git a/llvm/include/llvm-c/Types.h b/llvm/include/llvm-c/Types.h
index 4e9967372d79..d5474d986309 100644
--- a/llvm/include/llvm-c/Types.h
+++ b/llvm/include/llvm-c/Types.h
@@ -133,6 +133,11 @@ typedef struct LLVMOpaquePassManager *LLVMPassManagerRef;
typedef struct LLVMOpaqueUse *LLVMUseRef;
/**
+ * @see llvm::OperandBundleDef
+ */
+typedef struct LLVMOpaqueOperandBundle *LLVMOperandBundleRef;
+
+/**
* Used to represent an attributes.
*
* @see llvm::Attribute
diff --git a/llvm/include/llvm/ADT/SmallString.h b/llvm/include/llvm/ADT/SmallString.h
index 0052c86fb37b..02fa28fc856d 100644
--- a/llvm/include/llvm/ADT/SmallString.h
+++ b/llvm/include/llvm/ADT/SmallString.h
@@ -120,15 +120,11 @@ public:
/// @name String Predicates
/// @{
- /// startswith - Check if this string starts with the given \p Prefix.
- bool startswith(StringRef Prefix) const {
- return str().startswith(Prefix);
- }
+ /// starts_with - Check if this string starts with the given \p Prefix.
+ bool starts_with(StringRef Prefix) const { return str().starts_with(Prefix); }
- /// endswith - Check if this string ends with the given \p Suffix.
- bool endswith(StringRef Suffix) const {
- return str().endswith(Suffix);
- }
+ /// ends_with - Check if this string ends with the given \p Suffix.
+ bool ends_with(StringRef Suffix) const { return str().ends_with(Suffix); }
/// @}
/// @name String Searching
diff --git a/llvm/include/llvm/ADT/SparseBitVector.h b/llvm/include/llvm/ADT/SparseBitVector.h
index 1e00c1386187..7151af6146e6 100644
--- a/llvm/include/llvm/ADT/SparseBitVector.h
+++ b/llvm/include/llvm/ADT/SparseBitVector.h
@@ -15,8 +15,8 @@
#ifndef LLVM_ADT_SPARSEBITVECTOR_H
#define LLVM_ADT_SPARSEBITVECTOR_H
+#include "llvm/ADT/bit.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <climits>
diff --git a/llvm/include/llvm/ADT/StringRef.h b/llvm/include/llvm/ADT/StringRef.h
index 235a7b27c384..4e69d5b63354 100644
--- a/llvm/include/llvm/ADT/StringRef.h
+++ b/llvm/include/llvm/ADT/StringRef.h
@@ -264,12 +264,6 @@ namespace llvm {
/// Check if this string starts with the given \p Prefix, ignoring case.
[[nodiscard]] bool starts_with_insensitive(StringRef Prefix) const;
- [[nodiscard]] LLVM_DEPRECATED(
- "Use starts_with_insensitive instead",
- "starts_with_insensitive") bool startswith_insensitive(StringRef Prefix)
- const {
- return starts_with_insensitive(Prefix);
- }
/// Check if this string ends with the given \p Suffix.
[[nodiscard]] bool ends_with(StringRef Suffix) const {
@@ -283,12 +277,6 @@ namespace llvm {
/// Check if this string ends with the given \p Suffix, ignoring case.
[[nodiscard]] bool ends_with_insensitive(StringRef Suffix) const;
- [[nodiscard]] LLVM_DEPRECATED(
- "Use ends_with_insensitive instead",
- "ends_with_insensitive") bool endswith_insensitive(StringRef Suffix)
- const {
- return ends_with_insensitive(Suffix);
- }
/// @}
/// @name String Searching
diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h
index 081783e24367..e1cfb025fb65 100644
--- a/llvm/include/llvm/Analysis/AliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/AliasAnalysis.h
@@ -64,7 +64,6 @@ class LoopInfo;
class PreservedAnalyses;
class TargetLibraryInfo;
class Value;
-template <typename> class SmallPtrSetImpl;
/// The possible results of an alias query.
///
diff --git a/llvm/include/llvm/Analysis/AliasAnalysisEvaluator.h b/llvm/include/llvm/Analysis/AliasAnalysisEvaluator.h
index 20bcbc592afb..e4f152c232aa 100644
--- a/llvm/include/llvm/Analysis/AliasAnalysisEvaluator.h
+++ b/llvm/include/llvm/Analysis/AliasAnalysisEvaluator.h
@@ -29,7 +29,6 @@
namespace llvm {
class AAResults;
class Function;
-class FunctionPass;
class AAEvaluator : public PassInfoMixin<AAEvaluator> {
int64_t FunctionCount = 0;
diff --git a/llvm/include/llvm/Analysis/AliasSetTracker.h b/llvm/include/llvm/Analysis/AliasSetTracker.h
index e485e1ff2f4c..4a952ccae7a0 100644
--- a/llvm/include/llvm/Analysis/AliasSetTracker.h
+++ b/llvm/include/llvm/Analysis/AliasSetTracker.h
@@ -330,7 +330,7 @@ public:
/// These methods return true if inserting the instruction resulted in the
/// addition of a new alias set (i.e., the pointer did not alias anything).
///
- void add(Value *Ptr, LocationSize Size, const AAMDNodes &AAInfo); // Add a loc
+ void add(const MemoryLocation &Loc);
void add(LoadInst *LI);
void add(StoreInst *SI);
void add(VAArgInst *VAAI);
diff --git a/llvm/include/llvm/Analysis/InstructionSimplify.h b/llvm/include/llvm/Analysis/InstructionSimplify.h
index c626a6522d01..a29955a06cf4 100644
--- a/llvm/include/llvm/Analysis/InstructionSimplify.h
+++ b/llvm/include/llvm/Analysis/InstructionSimplify.h
@@ -45,7 +45,6 @@ class DominatorTree;
class Function;
class Instruction;
struct LoopStandardAnalysisResults;
-class MDNode;
class Pass;
template <class T, unsigned n> class SmallSetVector;
class TargetLibraryInfo;
diff --git a/llvm/include/llvm/Analysis/LazyValueInfo.h b/llvm/include/llvm/Analysis/LazyValueInfo.h
index ead9f5f0225c..cb5fa35d2995 100644
--- a/llvm/include/llvm/Analysis/LazyValueInfo.h
+++ b/llvm/include/llvm/Analysis/LazyValueInfo.h
@@ -95,11 +95,11 @@ namespace llvm {
/// specified value at the specified instruction. This may only be called
/// on integer-typed Values.
ConstantRange getConstantRange(Value *V, Instruction *CxtI,
- bool UndefAllowed = true);
+ bool UndefAllowed);
/// Return the ConstantRange constraint that is known to hold for the value
/// at a specific use-site.
- ConstantRange getConstantRangeAtUse(const Use &U, bool UndefAllowed = true);
+ ConstantRange getConstantRangeAtUse(const Use &U, bool UndefAllowed);
/// Determine whether the specified value is known to be a
/// constant on the specified edge. Return null if not.
diff --git a/llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h b/llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h
index 20ff5a5bc6e0..ccf859922e16 100644
--- a/llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h
+++ b/llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h
@@ -203,7 +203,7 @@ inline bool IsObjCIdentifiedObject(const Value *V) {
StringRef Name = GV->getName();
// These special variables are known to hold values which are not
// reference-counted pointers.
- if (Name.startswith("\01l_objc_msgSend_fixup_"))
+ if (Name.starts_with("\01l_objc_msgSend_fixup_"))
return true;
StringRef Section = GV->getSection();
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index fb6f3287e3d2..f5114fa40c70 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -1002,6 +1002,16 @@ public:
/// more beneficial constant hoisting is).
InstructionCost getIntImmCodeSizeCost(unsigned Opc, unsigned Idx,
const APInt &Imm, Type *Ty) const;
+
+ /// It can be advantageous to detach complex constants from their uses to make
+ /// their generation cheaper. This hook allows targets to report when such
+ /// transformations might negatively effect the code generation of the
+ /// underlying operation. The motivating example is divides whereby hoisting
+ /// constants prevents the code generator's ability to transform them into
+ /// combinations of simpler operations.
+ bool preferToKeepConstantsAttached(const Instruction &Inst,
+ const Function &Fn) const;
+
/// @}
/// \name Vector Target Information
@@ -1873,6 +1883,8 @@ public:
virtual InstructionCost getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
const APInt &Imm, Type *Ty,
TargetCostKind CostKind) = 0;
+ virtual bool preferToKeepConstantsAttached(const Instruction &Inst,
+ const Function &Fn) const = 0;
virtual unsigned getNumberOfRegisters(unsigned ClassID) const = 0;
virtual unsigned getRegisterClassForType(bool Vector,
Type *Ty = nullptr) const = 0;
@@ -2430,6 +2442,10 @@ public:
TargetCostKind CostKind) override {
return Impl.getIntImmCostIntrin(IID, Idx, Imm, Ty, CostKind);
}
+ bool preferToKeepConstantsAttached(const Instruction &Inst,
+ const Function &Fn) const override {
+ return Impl.preferToKeepConstantsAttached(Inst, Fn);
+ }
unsigned getNumberOfRegisters(unsigned ClassID) const override {
return Impl.getNumberOfRegisters(ClassID);
}
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
index 5b612fd81306..1d8f523e9792 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -427,6 +427,11 @@ public:
return TTI::TCC_Free;
}
+ bool preferToKeepConstantsAttached(const Instruction &Inst,
+ const Function &Fn) const {
+ return false;
+ }
+
unsigned getNumberOfRegisters(unsigned ClassID) const { return 8; }
unsigned getRegisterClassForType(bool Vector, Type *Ty = nullptr) const {
@@ -709,6 +714,7 @@ public:
case Intrinsic::coro_subfn_addr:
case Intrinsic::threadlocal_address:
case Intrinsic::experimental_widenable_condition:
+ case Intrinsic::ssa_copy:
// These intrinsics don't actually represent code after lowering.
return 0;
}
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 40c795410f95..0f968eac36e7 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -846,6 +846,49 @@ enum {
#include "ELFRelocs/AMDGPU.def"
};
+// NVPTX specific e_flags.
+enum : unsigned {
+ // Processor selection mask for EF_CUDA_SM* values.
+ EF_CUDA_SM = 0xff,
+
+ // SM based processor values.
+ EF_CUDA_SM20 = 0x14,
+ EF_CUDA_SM21 = 0x15,
+ EF_CUDA_SM30 = 0x1e,
+ EF_CUDA_SM32 = 0x20,
+ EF_CUDA_SM35 = 0x23,
+ EF_CUDA_SM37 = 0x25,
+ EF_CUDA_SM50 = 0x32,
+ EF_CUDA_SM52 = 0x34,
+ EF_CUDA_SM53 = 0x35,
+ EF_CUDA_SM60 = 0x3c,
+ EF_CUDA_SM61 = 0x3d,
+ EF_CUDA_SM62 = 0x3e,
+ EF_CUDA_SM70 = 0x46,
+ EF_CUDA_SM72 = 0x48,
+ EF_CUDA_SM75 = 0x4b,
+ EF_CUDA_SM80 = 0x50,
+ EF_CUDA_SM86 = 0x56,
+ EF_CUDA_SM87 = 0x57,
+ EF_CUDA_SM89 = 0x59,
+ // The sm_90a variant uses the same machine flag.
+ EF_CUDA_SM90 = 0x5a,
+
+ // Unified texture binding is enabled.
+ EF_CUDA_TEXMODE_UNIFIED = 0x100,
+ // Independent texture binding is enabled.
+ EF_CUDA_TEXMODE_INDEPENDANT = 0x200,
+ // The target is using 64-bit addressing.
+ EF_CUDA_64BIT_ADDRESS = 0x400,
+ // Set when using the sm_90a processor.
+ EF_CUDA_ACCELERATORS = 0x800,
+ // Undocumented software feature.
+ EF_CUDA_SW_FLAG_V2 = 0x1000,
+
+ // Virtual processor selection mask for EF_CUDA_VIRTUAL_SM* values.
+ EF_CUDA_VIRTUAL_SM = 0xff0000,
+};
+
// ELF Relocation types for BPF
enum {
#include "ELFRelocs/BPF.def"
@@ -1693,6 +1736,7 @@ enum : unsigned {
enum : unsigned {
GNU_PROPERTY_AARCH64_FEATURE_1_BTI = 1 << 0,
GNU_PROPERTY_AARCH64_FEATURE_1_PAC = 1 << 1,
+ GNU_PROPERTY_AARCH64_FEATURE_1_GCS = 1 << 2,
};
// x86 processor feature bits.
diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def
index b8ab5113bedf..30375de420e3 100644
--- a/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def
@@ -121,6 +121,7 @@ ELF_RELOC(R_AARCH64_TLSLE_LDST128_TPREL_LO12, 0x23a)
ELF_RELOC(R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC, 0x23b)
ELF_RELOC(R_AARCH64_TLSLD_LDST128_DTPREL_LO12, 0x23c)
ELF_RELOC(R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC, 0x23d)
+ELF_RELOC(R_AARCH64_AUTH_ABS64, 0x244)
// Dynamic relocations start
ELF_RELOC(R_AARCH64_COPY, 0x400)
ELF_RELOC(R_AARCH64_GLOB_DAT, 0x401)
@@ -134,8 +135,7 @@ ELF_RELOC(R_AARCH64_TLS_DTPREL64, 0x405)
ELF_RELOC(R_AARCH64_TLS_TPREL64, 0x406)
ELF_RELOC(R_AARCH64_TLSDESC, 0x407)
ELF_RELOC(R_AARCH64_IRELATIVE, 0x408)
-ELF_RELOC(R_AARCH64_AUTH_ABS64, 0xe100)
-ELF_RELOC(R_AARCH64_AUTH_RELATIVE, 0xe200)
+ELF_RELOC(R_AARCH64_AUTH_RELATIVE, 0x411)
// ELF_RELOC(R_AARCH64_P32_NONE, 0)
ELF_RELOC(R_AARCH64_P32_ABS32, 0x001)
diff --git a/llvm/include/llvm/BinaryFormat/Magic.h b/llvm/include/llvm/BinaryFormat/Magic.h
index a28710dcdfaf..c635a2695765 100644
--- a/llvm/include/llvm/BinaryFormat/Magic.h
+++ b/llvm/include/llvm/BinaryFormat/Magic.h
@@ -57,6 +57,7 @@ struct file_magic {
dxcontainer_object, ///< DirectX container file
offload_bundle, ///< Clang offload bundle file
offload_bundle_compressed, ///< Compressed clang offload bundle file
+ spirv_object, ///< A binary SPIR-V file
};
bool is_object() const { return V != unknown; }
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 6549f5660cc3..c6f0ddf29a6d 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -723,6 +723,7 @@ enum AttributeKindCodes {
ATTR_KIND_OPTIMIZE_FOR_DEBUGGING = 88,
ATTR_KIND_WRITABLE = 89,
ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE = 90,
+ ATTR_KIND_DEAD_ON_UNWIND = 91,
};
enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/CodeGen/AccelTable.h b/llvm/include/llvm/CodeGen/AccelTable.h
index 0f35fd3514fa..af874aa5e91a 100644
--- a/llvm/include/llvm/CodeGen/AccelTable.h
+++ b/llvm/include/llvm/CodeGen/AccelTable.h
@@ -103,7 +103,6 @@
namespace llvm {
class AsmPrinter;
-class DwarfUnit;
class DwarfDebug;
class DwarfTypeUnit;
class MCSymbol;
diff --git a/llvm/include/llvm/CodeGen/AntiDepBreaker.h b/llvm/include/llvm/CodeGen/AntiDepBreaker.h
index c5c2b5748613..eba642684c95 100644
--- a/llvm/include/llvm/CodeGen/AntiDepBreaker.h
+++ b/llvm/include/llvm/CodeGen/AntiDepBreaker.h
@@ -19,7 +19,6 @@
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Support/Compiler.h"
-#include <cassert>
#include <utility>
#include <vector>
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 2731ef452c79..5ec246ee7015 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -599,6 +599,26 @@ public:
/// instructions in verbose mode.
virtual void emitImplicitDef(const MachineInstr *MI) const;
+ /// getSubtargetInfo() cannot be used where this is needed because we don't
+ /// have a MachineFunction when we're lowering a GlobalIFunc, and
+ /// getSubtargetInfo requires one. Override the implementation in targets
+ /// that support the Mach-O IFunc lowering.
+ virtual const MCSubtargetInfo *getIFuncMCSubtargetInfo() const {
+ return nullptr;
+ }
+
+ virtual void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) {
+ llvm_unreachable(
+ "Mach-O IFunc lowering is not yet supported on this target");
+ }
+
+ virtual void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) {
+ llvm_unreachable(
+ "Mach-O IFunc lowering is not yet supported on this target");
+ }
+
/// Emit N NOP instructions.
void emitNops(unsigned N);
@@ -614,7 +634,7 @@ public:
StringRef Suffix) const;
/// Return the MCSymbol for the specified ExternalSymbol.
- MCSymbol *GetExternalSymbolSymbol(StringRef Sym) const;
+ MCSymbol *GetExternalSymbolSymbol(Twine Sym) const;
/// Return the symbol for the specified jump table entry.
MCSymbol *GetJTISymbol(unsigned JTID, bool isLinkerPrivate = false) const;
@@ -884,6 +904,7 @@ private:
void emitGlobalAlias(Module &M, const GlobalAlias &GA);
void emitGlobalIFunc(Module &M, const GlobalIFunc &GI);
+private:
/// This method decides whether the specified basic block requires a label.
bool shouldEmitLabelForBasicBlock(const MachineBasicBlock &MBB) const;
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index e05ce2890a08..5e7bdcdf72a4 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -545,6 +545,25 @@ public:
return TargetTransformInfo::TCC_Expensive;
}
+ bool preferToKeepConstantsAttached(const Instruction &Inst,
+ const Function &Fn) const {
+ switch (Inst.getOpcode()) {
+ default:
+ break;
+ case Instruction::SDiv:
+ case Instruction::SRem:
+ case Instruction::UDiv:
+ case Instruction::URem: {
+ if (!isa<ConstantInt>(Inst.getOperand(1)))
+ return false;
+ EVT VT = getTLI()->getValueType(DL, Inst.getType());
+ return !getTLI()->isIntDivCheap(VT, Fn.getAttributes());
+ }
+ };
+
+ return false;
+ }
+
unsigned getInliningThresholdMultiplier() const { return 1; }
unsigned adjustInliningThreshold(const CallBase *CB) { return 0; }
unsigned getCallerAllocaCost(const CallBase *CB, const AllocaInst *AI) const {
diff --git a/llvm/include/llvm/CodeGen/CallingConvLower.h b/llvm/include/llvm/CodeGen/CallingConvLower.h
index 0989fae54b3a..932a2a94ab1f 100644
--- a/llvm/include/llvm/CodeGen/CallingConvLower.h
+++ b/llvm/include/llvm/CodeGen/CallingConvLower.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CODEGEN_CALLINGCONVLOWER_H
#define LLVM_CODEGEN_CALLINGCONVLOWER_H
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/Register.h"
#include "llvm/CodeGen/TargetCallingConv.h"
diff --git a/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h b/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h
index 076719abd035..ac9e66c4dc2f 100644
--- a/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h
@@ -19,15 +19,25 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
+#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/ScopedNoAliasAA.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/TypeBasedAliasAnalysis.h"
#include "llvm/CodeGen/CallBrPrepare.h"
+#include "llvm/CodeGen/DwarfEHPrepare.h"
+#include "llvm/CodeGen/ExpandMemCmp.h"
#include "llvm/CodeGen/ExpandReductions.h"
+#include "llvm/CodeGen/GCMetadata.h"
+#include "llvm/CodeGen/IndirectBrExpand.h"
+#include "llvm/CodeGen/InterleavedAccess.h"
+#include "llvm/CodeGen/InterleavedLoadCombine.h"
+#include "llvm/CodeGen/JMCInstrumenter.h"
#include "llvm/CodeGen/MachinePassManager.h"
#include "llvm/CodeGen/PreISelIntrinsicLowering.h"
#include "llvm/CodeGen/ReplaceWithVeclib.h"
#include "llvm/CodeGen/SafeStack.h"
+#include "llvm/CodeGen/SelectOptimize.h"
+#include "llvm/CodeGen/SjLjEHPrepare.h"
#include "llvm/CodeGen/UnreachableBlockElim.h"
#include "llvm/CodeGen/WasmEHPrepare.h"
#include "llvm/CodeGen/WinEHPrepare.h"
@@ -42,6 +52,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/CGPassBuilderOption.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/CFGuard.h"
#include "llvm/Transforms/Scalar/ConstantHoisting.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
#include "llvm/Transforms/Scalar/LoopStrengthReduce.h"
@@ -74,7 +85,7 @@ namespace llvm {
} \
};
#define DUMMY_MACHINE_MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR) \
- struct PASS_NAME : public PassInfoMixin<PASS_NAME> { \
+ struct PASS_NAME : public MachinePassInfoMixin<PASS_NAME> { \
template <typename... Ts> PASS_NAME(Ts &&...) {} \
Error run(Module &, MachineFunctionAnalysisManager &) { \
return Error::success(); \
@@ -83,18 +94,29 @@ namespace llvm {
MachineFunctionAnalysisManager &) { \
llvm_unreachable("this api is to make new PM api happy"); \
} \
- static AnalysisKey Key; \
+ static MachinePassKey Key; \
};
#define DUMMY_MACHINE_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR) \
- struct PASS_NAME : public PassInfoMixin<PASS_NAME> { \
+ struct PASS_NAME : public MachinePassInfoMixin<PASS_NAME> { \
template <typename... Ts> PASS_NAME(Ts &&...) {} \
PreservedAnalyses run(MachineFunction &, \
MachineFunctionAnalysisManager &) { \
return PreservedAnalyses::all(); \
} \
+ static MachinePassKey Key; \
+ };
+#define DUMMY_MACHINE_FUNCTION_ANALYSIS(NAME, PASS_NAME, CONSTRUCTOR) \
+ struct PASS_NAME : public AnalysisInfoMixin<PASS_NAME> { \
+ template <typename... Ts> PASS_NAME(Ts &&...) {} \
+ using Result = struct {}; \
+ template <typename IRUnitT, typename AnalysisManagerT, \
+ typename... ExtraArgTs> \
+ Result run(IRUnitT &, AnalysisManagerT &, ExtraArgTs &&...) { \
+ return {}; \
+ } \
static AnalysisKey Key; \
};
-#include "MachinePassRegistry.def"
+#include "llvm/CodeGen/MachinePassRegistry.def"
/// This class provides access to building LLVM's passes.
///
@@ -467,6 +489,8 @@ Error CodeGenPassBuilder<Derived>::buildPipeline(
raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
CodeGenFileType FileType) const {
AddIRPass addIRPass(MPM, Opt.DebugPM);
+ // `ProfileSummaryInfo` is always valid.
+ addIRPass(RequireAnalysisPass<ProfileSummaryAnalysis, Module>());
addISelPasses(addIRPass);
AddMachinePass addPass(MFPM);
@@ -616,7 +640,7 @@ void CodeGenPassBuilder<Derived>::addIRPasses(AddIRPass &addPass) const {
// target lowering hook.
if (!Opt.DisableMergeICmps)
addPass(MergeICmpsPass());
- addPass(ExpandMemCmpPass());
+ addPass(ExpandMemCmpPass(&TM));
}
// Run GC lowering passes for builtin collectors
@@ -654,7 +678,7 @@ void CodeGenPassBuilder<Derived>::addIRPasses(AddIRPass &addPass) const {
// Convert conditional moves to conditional jumps when profitable.
if (getOptLevel() != CodeGenOptLevel::None && !Opt.DisableSelectOptimize)
- addPass(SelectOptimizePass());
+ addPass(SelectOptimizePass(&TM));
}
/// Turn exception handling constructs into something the code generators can
@@ -672,19 +696,19 @@ void CodeGenPassBuilder<Derived>::addPassesToHandleExceptions(
// removed from the parent invoke(s). This could happen when a landing
// pad is shared by multiple invokes and is also a target of a normal
// edge from elsewhere.
- addPass(SjLjEHPreparePass());
+ addPass(SjLjEHPreparePass(&TM));
[[fallthrough]];
case ExceptionHandling::DwarfCFI:
case ExceptionHandling::ARM:
case ExceptionHandling::AIX:
- addPass(DwarfEHPass(getOptLevel()));
+ addPass(DwarfEHPreparePass(&TM));
break;
case ExceptionHandling::WinEH:
// We support using both GCC-style and MSVC-style exceptions on Windows, so
// add both preparation passes. Each pass will only actually run if it
// recognizes the personality function.
addPass(WinEHPreparePass());
- addPass(DwarfEHPass(getOptLevel()));
+ addPass(DwarfEHPreparePass(&TM));
break;
case ExceptionHandling::Wasm:
// Wasm EH uses Windows EH instructions, but it does not need to demote PHIs
diff --git a/llvm/include/llvm/CodeGen/ExpandMemCmp.h b/llvm/include/llvm/CodeGen/ExpandMemCmp.h
new file mode 100644
index 000000000000..94a877854f32
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/ExpandMemCmp.h
@@ -0,0 +1,29 @@
+//===--- ExpandMemCmp.h - Expand memcmp() to load/stores --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_EXPANDMEMCMP_H
+#define LLVM_CODEGEN_EXPANDMEMCMP_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class TargetMachine;
+
+class ExpandMemCmpPass : public PassInfoMixin<ExpandMemCmpPass> {
+ const TargetMachine *TM;
+
+public:
+ explicit ExpandMemCmpPass(const TargetMachine *TM_) : TM(TM_) {}
+
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_EXPANDMEMCMP_H
diff --git a/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h b/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h
index 4c17e8dcc41a..cde7247aeb15 100644
--- a/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h
+++ b/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h
@@ -191,6 +191,7 @@ public:
/// Collection of dbg.declare instructions handled after argument
/// lowering and before ISel proper.
SmallPtrSet<const DbgDeclareInst *, 8> PreprocessedDbgDeclares;
+ SmallPtrSet<const DPValue *, 8> PreprocessedDPVDeclares;
/// set - Initialize this FunctionLoweringInfo with the given Function
/// and its associated MachineFunction.
diff --git a/llvm/include/llvm/CodeGen/GCMetadata.h b/llvm/include/llvm/CodeGen/GCMetadata.h
index 334c5c23b8fa..9e4e8342ea29 100644
--- a/llvm/include/llvm/CodeGen/GCMetadata.h
+++ b/llvm/include/llvm/CodeGen/GCMetadata.h
@@ -38,6 +38,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/GCStrategy.h"
+#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include <algorithm>
#include <cstddef>
@@ -101,6 +102,10 @@ public:
GCFunctionInfo(const Function &F, GCStrategy &S);
~GCFunctionInfo();
+ /// Handle invalidation explicitly.
+ bool invalidate(Function &F, const PreservedAnalyses &PA,
+ FunctionAnalysisManager::Invalidator &Inv);
+
/// getFunction - Return the function to which this metadata applies.
const Function &getFunction() const { return F; }
@@ -146,6 +151,41 @@ public:
size_t live_size(const iterator &p) const { return roots_size(); }
};
+struct GCStrategyMap {
+ StringMap<std::unique_ptr<GCStrategy>> StrategyMap;
+
+ GCStrategyMap() = default;
+ GCStrategyMap(GCStrategyMap &&) = default;
+
+ /// Handle invalidation explicitly.
+ bool invalidate(Module &M, const PreservedAnalyses &PA,
+ ModuleAnalysisManager::Invalidator &Inv);
+};
+
+/// An analysis pass which caches information about the entire Module.
+/// Records a cache of the 'active' gc strategy objects for the current Module.
+class CollectorMetadataAnalysis
+ : public AnalysisInfoMixin<CollectorMetadataAnalysis> {
+ friend struct AnalysisInfoMixin<CollectorMetadataAnalysis>;
+ static AnalysisKey Key;
+
+public:
+ using Result = GCStrategyMap;
+ Result run(Module &M, ModuleAnalysisManager &MAM);
+};
+
+/// An analysis pass which caches information about the Function.
+/// Records the function level information used by GCRoots.
+/// This pass depends on `CollectorMetadataAnalysis`.
+class GCFunctionAnalysis : public AnalysisInfoMixin<GCFunctionAnalysis> {
+ friend struct AnalysisInfoMixin<GCFunctionAnalysis>;
+ static AnalysisKey Key;
+
+public:
+ using Result = GCFunctionInfo;
+ Result run(Function &F, FunctionAnalysisManager &FAM);
+};
+
/// An analysis pass which caches information about the entire Module.
/// Records both the function level information used by GCRoots and a
/// cache of the 'active' gc strategy objects for the current Module.
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index a4e9c92b4897..e7debc652a0a 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -28,11 +28,9 @@
namespace llvm {
class GISelChangeObserver;
-class APFloat;
class APInt;
class ConstantFP;
class GPtrAdd;
-class GStore;
class GZExtLoad;
class MachineIRBuilder;
class MachineInstrBuilder;
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
index f5d9f5f40881..694d3d8004af 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
@@ -54,10 +54,30 @@ enum {
GICXXCustomAction_Invalid = 0,
};
+/// The MatchTable is encoded as an array of bytes.
+/// Thus, opcodes are expected to be <255.
+///
+/// Operands can be variable-sized, their size is always after their name
+/// in the docs, e.g. "Foo(4)" means that "Foo" takes 4 entries in the table,
+/// so 4 bytes. "Foo()"
+///
+/// As a general rule of thumb:
+/// - Instruction & Operand IDs are ULEB128
+/// - LLT IDs are 1 byte
+/// - Predicates and target opcodes, register and register class IDs are 2
+/// bytes.
+/// - Indexes into the table are 4 bytes.
+/// - Inline constants are 8 bytes
+///
+/// Design notes:
+/// - Inst/Op IDs have to be LEB128 because some targets generate
+/// extremely long patterns which need more than 255 temporaries.
+/// We could just use 2 bytes everytime, but then some targets like
+/// X86/AMDGPU that have no need for it will pay the price all the time.
enum {
/// Begin a try-block to attempt a match and jump to OnFail if it is
/// unsuccessful.
- /// - OnFail - The MatchTable entry at which to resume if the match fails.
+ /// - OnFail(4) - The MatchTable entry at which to resume if the match fails.
///
/// FIXME: This ought to take an argument indicating the number of try-blocks
/// to exit on failure. It's usually one but the last match attempt of
@@ -68,100 +88,103 @@ enum {
GIM_Try,
/// Switch over the opcode on the specified instruction
- /// - InsnID - Instruction ID
- /// - LowerBound - numerically minimum opcode supported
- /// - UpperBound - numerically maximum + 1 opcode supported
- /// - Default - failure jump target
- /// - JumpTable... - (UpperBound - LowerBound) (at least 2) jump targets
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - LowerBound(2) - numerically minimum opcode supported
+ /// - UpperBound(2) - numerically maximum + 1 opcode supported
+ /// - Default(4) - failure jump target
+ /// - JumpTable(4)... - (UpperBound - LowerBound) (at least 2) jump targets
GIM_SwitchOpcode,
/// Switch over the LLT on the specified instruction operand
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - LowerBound - numerically minimum Type ID supported
- /// - UpperBound - numerically maximum + 1 Type ID supported
- /// - Default - failure jump target
- /// - JumpTable... - (UpperBound - LowerBound) (at least 2) jump targets
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - LowerBound(2) - numerically minimum Type ID supported
+ /// - UpperBound(2) - numerically maximum + 1 Type ID supported
+ /// - Default(4) - failure jump target
+ /// - JumpTable(4)... - (UpperBound - LowerBound) (at least 2) jump targets
GIM_SwitchType,
/// Record the specified instruction.
/// The IgnoreCopies variant ignores COPY instructions.
- /// - NewInsnID - Instruction ID to define
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
+ /// - NewInsnID(ULEB128) - Instruction ID to define
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
GIM_RecordInsn,
GIM_RecordInsnIgnoreCopies,
/// Check the feature bits
- /// - Expected features
+ /// Feature(2) - Expected features
GIM_CheckFeatures,
/// Check the opcode on the specified instruction
- /// - InsnID - Instruction ID
- /// - Expected opcode
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - Opc(2) - Expected opcode
GIM_CheckOpcode,
/// Check the opcode on the specified instruction, checking 2 acceptable
/// alternatives.
- /// - InsnID - Instruction ID
- /// - Expected opcode
- /// - Alternative expected opcode
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - Opc(2) - Expected opcode
+ /// - Opc(2) - Alternative expected opcode
GIM_CheckOpcodeIsEither,
/// Check the instruction has the right number of operands
- /// - InsnID - Instruction ID
- /// - Expected number of operands
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - Ops(ULEB128) - Expected number of operands
GIM_CheckNumOperands,
+
/// Check an immediate predicate on the specified instruction
- /// - InsnID - Instruction ID
- /// - The predicate to test
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - Pred(2) - The predicate to test
GIM_CheckI64ImmPredicate,
/// Check an immediate predicate on the specified instruction via an APInt.
- /// - InsnID - Instruction ID
- /// - The predicate to test
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - Pred(2) - The predicate to test
GIM_CheckAPIntImmPredicate,
/// Check a floating point immediate predicate on the specified instruction.
- /// - InsnID - Instruction ID
- /// - The predicate to test
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - Pred(2) - The predicate to test
GIM_CheckAPFloatImmPredicate,
/// Check an immediate predicate on the specified instruction
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - The predicate to test
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - Pred(2) - The predicate to test
GIM_CheckImmOperandPredicate,
+
/// Check a memory operation has the specified atomic ordering.
- /// - InsnID - Instruction ID
- /// - Ordering - The AtomicOrdering value
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - Ordering(ULEB128) - The AtomicOrdering value
GIM_CheckAtomicOrdering,
GIM_CheckAtomicOrderingOrStrongerThan,
GIM_CheckAtomicOrderingWeakerThan,
+
/// Check the size of the memory access for the given machine memory operand.
- /// - InsnID - Instruction ID
- /// - MMOIdx - MMO index
- /// - Size - The size in bytes of the memory access
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - MMOIdx(ULEB128) - MMO index
+ /// - Size(4) - The size in bytes of the memory access
GIM_CheckMemorySizeEqualTo,
/// Check the address space of the memory access for the given machine memory
/// operand.
- /// - InsnID - Instruction ID
- /// - MMOIdx - MMO index
- /// - NumAddrSpace - Number of valid address spaces
- /// - AddrSpaceN - An allowed space of the memory access
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - MMOIdx(ULEB128) - MMO index
+ /// - NumAddrSpace(ULEB128) - Number of valid address spaces
+ /// - AddrSpaceN(ULEB128) - An allowed space of the memory access
/// - AddrSpaceN+1 ...
GIM_CheckMemoryAddressSpace,
/// Check the minimum alignment of the memory access for the given machine
/// memory operand.
- /// - InsnID - Instruction ID
- /// - MMOIdx - MMO index
- /// - MinAlign - Minimum acceptable alignment
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - MMOIdx(ULEB128) - MMO index
+ /// - MinAlign(ULEB128) - Minimum acceptable alignment
GIM_CheckMemoryAlignment,
/// Check the size of the memory access for the given machine memory operand
/// against the size of an operand.
- /// - InsnID - Instruction ID
- /// - MMOIdx - MMO index
- /// - OpIdx - The operand index to compare the MMO against
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - MMOIdx(ULEB128) - MMO index
+ /// - OpIdx(ULEB128) - The operand index to compare the MMO against
GIM_CheckMemorySizeEqualToLLT,
GIM_CheckMemorySizeLessThanLLT,
GIM_CheckMemorySizeGreaterThanLLT,
@@ -170,106 +193,117 @@ enum {
/// constant. This is valid for both G_BUILD_VECTOR as well as
/// G_BUILD_VECTOR_TRUNC. For AllOnes refers to individual bits, so a -1
/// element.
- /// - InsnID - Instruction ID
+ /// - InsnID(ULEB128) - Instruction ID
GIM_CheckIsBuildVectorAllOnes,
GIM_CheckIsBuildVectorAllZeros,
/// Check a trivial predicate which takes no arguments.
/// This can be used by executors to implement custom flags that don't fit in
/// target features.
+ /// - Pred(2) - Predicate ID to check.
GIM_CheckSimplePredicate,
/// Check a generic C++ instruction predicate
- /// - InsnID - Instruction ID
- /// - PredicateID - The ID of the predicate function to call
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - PredicateID(2) - The ID of the predicate function to call
GIM_CheckCxxInsnPredicate,
/// Check if there's no use of the first result.
- /// - InsnID - Instruction ID
+ /// - InsnID(ULEB128) - Instruction ID
GIM_CheckHasNoUse,
/// Check the type for the specified operand
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected type
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - Ty(1) - Expected type
GIM_CheckType,
+
/// Check the type of a pointer to any address space.
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - SizeInBits - The size of the pointer value in bits.
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - SizeInBits(ULEB128) - The size of the pointer value in bits.
GIM_CheckPointerToAny,
+
/// Check the register bank for the specified operand
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected register bank (specified as a register class)
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - RC(2) - Expected register bank (specified as a register class)
GIM_CheckRegBankForClass,
/// Check the operand matches a complex predicate
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - RendererID - The renderer to hold the result
- /// - Complex predicate ID
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - RendererID(2) - The renderer to hold the result
+ /// - Pred(2) - Complex predicate ID
GIM_CheckComplexPattern,
/// Check the operand is a specific integer
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected integer
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - Val(8) Expected integer
GIM_CheckConstantInt,
+
+ /// Check the operand is a specific 8-bit signed integer
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - Val(1) Expected integer
+ GIM_CheckConstantInt8,
+
/// Check the operand is a specific literal integer (i.e. MO.isImm() or
/// MO.isCImm() is true).
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected integer
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - Val(8) - Expected integer
GIM_CheckLiteralInt,
+
/// Check the operand is a specific intrinsic ID
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected Intrinsic ID
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - IID(2) - Expected Intrinsic ID
GIM_CheckIntrinsicID,
/// Check the operand is a specific predicate
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected predicate
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - Pred(2) - Expected predicate
GIM_CheckCmpPredicate,
/// Check the specified operand is an MBB
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
GIM_CheckIsMBB,
/// Check the specified operand is an Imm
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
GIM_CheckIsImm,
/// Check if the specified operand is safe to fold into the current
/// instruction.
- /// - InsnID - Instruction ID
+ /// - InsnID(ULEB128) - Instruction ID
GIM_CheckIsSafeToFold,
/// Check the specified operands are identical.
/// The IgnoreCopies variant looks through COPY instructions before
/// comparing the operands.
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - OtherInsnID - Other instruction ID
- /// - OtherOpIdx - Other operand index
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - OtherInsnID(ULEB128) - Other instruction ID
+ /// - OtherOpIdx(ULEB128) - Other operand index
GIM_CheckIsSameOperand,
GIM_CheckIsSameOperandIgnoreCopies,
/// Check we can replace all uses of a register with another.
- /// - OldInsnID
- /// - OldOpIdx
- /// - NewInsnID
- /// - NewOpIdx
+ /// - OldInsnID(ULEB128)
+ /// - OldOpIdx(ULEB128)
+ /// - NewInsnID(ULEB128)
+ /// - NewOpIdx(ULEB128)
GIM_CheckCanReplaceReg,
/// Check that a matched instruction has, or doesn't have a MIFlag.
///
- /// - InsnID - Instruction to check.
- /// - Flag(s) - (can be one or more flags OR'd together)
+ /// - InsnID(ULEB128) - Instruction to check.
+ /// - Flags(4) - (can be one or more flags OR'd together)
GIM_MIFlags,
GIM_MIFlagsNot,
@@ -277,15 +311,15 @@ enum {
/// named operands that will be recorded in RecordedOperands. Names of these
/// operands are referenced in predicate argument list. Emitter determines
/// StoreIdx(corresponds to the order in which names appear in argument list).
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - StoreIdx - Store location in RecordedOperands.
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - StoreIdx(ULEB128) - Store location in RecordedOperands.
GIM_RecordNamedOperand,
/// Records an operand's register type into the set of temporary types.
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - TempTypeIdx - Temp Type Index, always negative.
+ /// - InsnID(ULEB128) - Instruction ID
+ /// - OpIdx(ULEB128) - Operand index
+ /// - TempTypeIdx(1) - Temp Type Index, always negative.
GIM_RecordRegType,
/// Fail the current try-block, or completely fail to match if there is no
@@ -295,121 +329,133 @@ enum {
//=== Renderers ===
/// Mutate an instruction
- /// - NewInsnID - Instruction ID to define
- /// - OldInsnID - Instruction ID to mutate
- /// - NewOpcode - The new opcode to use
+ /// - NewInsnID(ULEB128) - Instruction ID to define
+ /// - OldInsnID(ULEB128) - Instruction ID to mutate
+ /// - NewOpcode(2) - The new opcode to use
GIR_MutateOpcode,
/// Build a new instruction
- /// - InsnID - Instruction ID to define
- /// - Opcode - The new opcode to use
+ /// - InsnID(ULEB128) - Instruction ID to define
+ /// - Opcode(2) - The new opcode to use
GIR_BuildMI,
/// Builds a constant and stores its result in a TempReg.
- /// - TempRegID - Temp Register to define.
- /// - Imm - The immediate to add
+ /// - TempRegID(ULEB128) - Temp Register to define.
+ /// - Imm(8) - The immediate to add
GIR_BuildConstant,
/// Copy an operand to the specified instruction
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
- /// - OpIdx - The operand to copy
+ /// - NewInsnID(ULEB128) - Instruction ID to modify
+ /// - OldInsnID(ULEB128) - Instruction ID to copy from
+ /// - OpIdx(ULEB128) - The operand to copy
GIR_Copy,
/// Copy an operand to the specified instruction or add a zero register if the
/// operand is a zero immediate.
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
- /// - OpIdx - The operand to copy
- /// - ZeroReg - The zero register to use
+ /// - NewInsnID(ULEB128) - Instruction ID to modify
+ /// - OldInsnID(ULEB128) - Instruction ID to copy from
+ /// - OpIdx(ULEB128) - The operand to copy
+ /// - ZeroReg(2) - The zero register to use
GIR_CopyOrAddZeroReg,
/// Copy an operand to the specified instruction
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
- /// - OpIdx - The operand to copy
- /// - SubRegIdx - The subregister to copy
+ /// - NewInsnID(ULEB128) - Instruction ID to modify
+ /// - OldInsnID(ULEB128) - Instruction ID to copy from
+ /// - OpIdx(ULEB128) - The operand to copy
+ /// - SubRegIdx(2) - The subregister to copy
GIR_CopySubReg,
/// Add an implicit register def to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RegNum - The register to add
- /// - Flags - Register Flags
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - RegNum(2) - The register to add
+ /// - Flags(2) - Register Flags
GIR_AddImplicitDef,
/// Add an implicit register use to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RegNum - The register to add
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - RegNum(2) - The register to add
GIR_AddImplicitUse,
/// Add an register to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RegNum - The register to add
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - RegNum(2) - The register to add
+ /// - Flags(2) - Register Flags
GIR_AddRegister,
/// Marks the implicit def of a register as dead.
- /// - InsnID - Instruction ID to modify
- /// - OpIdx - The implicit def operand index
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - OpIdx(ULEB128) - The implicit def operand index
///
/// OpIdx starts at 0 for the first implicit def.
GIR_SetImplicitDefDead,
/// Set or unset a MIFlag on an instruction.
///
- /// - InsnID - Instruction to modify.
- /// - Flag(s) - (can be one or more flags OR'd together)
+ /// - InsnID(ULEB128) - Instruction to modify.
+ /// - Flags(4) - (can be one or more flags OR'd together)
GIR_SetMIFlags,
GIR_UnsetMIFlags,
/// Copy the MIFlags of a matched instruction into an
/// output instruction. The flags are OR'd together.
///
- /// - InsnID - Instruction to modify.
- /// - OldInsnID - Matched instruction to copy flags from.
+ /// - InsnID(ULEB128) - Instruction to modify.
+ /// - OldInsnID(ULEB128) - Matched instruction to copy flags from.
GIR_CopyMIFlags,
/// Add a temporary register to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - TempRegID - The temporary register ID to add
- /// - TempRegFlags - The register flags to set
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - TempRegID(ULEB128) - The temporary register ID to add
+ /// - TempRegFlags(2) - The register flags to set
GIR_AddTempRegister,
+ /// Add a temporary register to the specified instruction without
+ /// setting any flags.
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - TempRegID(ULEB128) - The temporary register ID to add
+ GIR_AddSimpleTempRegister,
+
/// Add a temporary register to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - TempRegID - The temporary register ID to add
- /// - TempRegFlags - The register flags to set
- /// - SubRegIndex - The subregister index to set
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - TempRegID(ULEB128) - The temporary register ID to add
+ /// - TempRegFlags(2) - The register flags to set
+ /// - SubRegIndex(2) - The subregister index to set
GIR_AddTempSubRegister,
/// Add an immediate to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - Imm - The immediate to add
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - Imm(8) - The immediate to add
GIR_AddImm,
+ /// Add signed 8 bit immediate to the specified instruction
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - Imm(1) - The immediate to add
+ GIR_AddImm8,
+
/// Add an CImm to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - Ty - Type of the constant immediate.
- /// - Imm - The immediate to add
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - Ty(1) - Type of the constant immediate.
+ /// - Imm(8) - The immediate to add
GIR_AddCImm,
/// Render complex operands to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RendererID - The renderer to call
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - RendererID(2) - The renderer to call
GIR_ComplexRenderer,
/// Render sub-operands of complex operands to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RendererID - The renderer to call
- /// - RenderOpID - The suboperand to render.
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - RendererID(2) - The renderer to call
+ /// - RenderOpID(ULEB128) - The suboperand to render.
GIR_ComplexSubOperandRenderer,
/// Render subregisters of suboperands of complex operands to the
/// specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RendererID - The renderer to call
- /// - RenderOpID - The suboperand to render
- /// - SubRegIdx - The subregister to extract
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - RendererID(2) - The renderer to call
+ /// - RenderOpID(ULEB128) - The suboperand to render
+ /// - SubRegIdx(2) - The subregister to extract
GIR_ComplexSubOperandSubRegRenderer,
/// Render operands to the specified instruction using a custom function
- /// - InsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to get the matched operand from
- /// - RendererFnID - Custom renderer function to call
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - OldInsnID(ULEB128) - Instruction ID to get the matched operand from
+ /// - RendererFnID(2) - Custom renderer function to call
GIR_CustomRenderer,
/// Calls a C++ function to perform an action when a match is complete.
@@ -418,90 +464,85 @@ enum {
/// This is less constrained than a custom renderer and can update
/// instructions
/// in the state.
- /// - FnID - The function to call.
+ /// - FnID(2) - The function to call.
/// TODO: Remove this at some point when combiners aren't reliant on it. It's
/// a bit of a hack.
GIR_CustomAction,
/// Render operands to the specified instruction using a custom function,
/// reading from a specific operand.
- /// - InsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to get the matched operand from
- /// - OpIdx - Operand index in OldInsnID the render function should read
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - OldInsnID(ULEB128) - Instruction ID to get the matched operand from
+ /// - OpIdx(ULEB128) - Operand index in OldInsnID the render function should
+ /// read
/// from..
- /// - RendererFnID - Custom renderer function to call
+ /// - RendererFnID(2) - Custom renderer function to call
GIR_CustomOperandRenderer,
/// Render a G_CONSTANT operator as a sign-extended immediate.
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
+ /// - NewInsnID(ULEB128) - Instruction ID to modify
+ /// - OldInsnID(ULEB128) - Instruction ID to copy from
/// The operand index is implicitly 1.
GIR_CopyConstantAsSImm,
/// Render a G_FCONSTANT operator as a sign-extended immediate.
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
+ /// - NewInsnID(ULEB128) - Instruction ID to modify
+ /// - OldInsnID(ULEB128) - Instruction ID to copy from
/// The operand index is implicitly 1.
GIR_CopyFConstantAsFPImm,
/// Constrain an instruction operand to a register class.
- /// - InsnID - Instruction ID to modify
- /// - OpIdx - Operand index
- /// - RCEnum - Register class enumeration value
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - OpIdx(ULEB128) - Operand index
+ /// - RCEnum(2) - Register class enumeration value
GIR_ConstrainOperandRC,
/// Constrain an instructions operands according to the instruction
/// description.
- /// - InsnID - Instruction ID to modify
+ /// - InsnID(ULEB128) - Instruction ID to modify
GIR_ConstrainSelectedInstOperands,
/// Merge all memory operands into instruction.
- /// - InsnID - Instruction ID to modify
- /// - MergeInsnID... - One or more Instruction ID to merge into the result.
- /// - GIU_MergeMemOperands_EndOfList - Terminates the list of instructions to
- /// merge.
+ /// - InsnID(ULEB128) - Instruction ID to modify
+ /// - NumInsnID(1) - Number of instruction IDs following this argument
+ /// - MergeInsnID(ULEB128)... - One or more Instruction ID to merge into the
+ /// result.
GIR_MergeMemOperands,
/// Erase from parent.
- /// - InsnID - Instruction ID to erase
+ /// - InsnID(ULEB128) - Instruction ID to erase
GIR_EraseFromParent,
/// Create a new temporary register that's not constrained.
- /// - TempRegID - The temporary register ID to initialize.
- /// - Expected type
+ /// - TempRegID(ULEB128) - The temporary register ID to initialize.
+ /// - Ty(1) - Expected type
GIR_MakeTempReg,
/// Replaces all references to a register from an instruction
/// with another register from another instruction.
- /// - OldInsnID
- /// - OldOpIdx
- /// - NewInsnID
- /// - NewOpIdx
+ /// - OldInsnID(ULEB128)
+ /// - OldOpIdx(ULEB128)
+ /// - NewInsnID(ULEB128)
+ /// - NewOpIdx(ULEB128)
GIR_ReplaceReg,
/// Replaces all references to a register with a temporary register.
- /// - OldInsnID
- /// - OldOpIdx
- /// - TempRegIdx
+ /// - OldInsnID(ULEB128)
+ /// - OldOpIdx(ULEB128)
+ /// - TempRegIdx(ULEB128)
GIR_ReplaceRegWithTempReg,
/// A successful emission
GIR_Done,
/// Increment the rule coverage counter.
- /// - RuleID - The ID of the rule that was covered.
+ /// - RuleID(4) - The ID of the rule that was covered.
GIR_Coverage,
/// Keeping track of the number of the GI opcodes. Must be the last entry.
GIU_NumOpcodes,
};
-enum {
- /// Indicates the end of the variable-length MergeInsnID list in a
- /// GIR_MergeMemOperands opcode.
- GIU_MergeMemOperands_EndOfList = -1,
-};
-
/// Provides the logic to execute GlobalISel match tables, which are used by the
/// instruction selector and instruction combiners as their engine to match and
/// apply MIR patterns.
@@ -595,14 +636,14 @@ protected:
bool executeMatchTable(TgtExecutor &Exec, MatcherState &State,
const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn,
CustomRendererFn> &ExecInfo,
- MachineIRBuilder &Builder, const int64_t *MatchTable,
+ MachineIRBuilder &Builder, const uint8_t *MatchTable,
const TargetInstrInfo &TII, MachineRegisterInfo &MRI,
const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI,
const PredicateBitset &AvailableFeatures,
CodeGenCoverage *CoverageInfo) const;
- virtual const int64_t *getMatchTable() const {
+ virtual const uint8_t *getMatchTable() const {
llvm_unreachable("Should have been overridden by tablegen if used");
}
@@ -647,6 +688,12 @@ protected:
/// MI and IntoMI do not need to be in the same basic blocks, but MI must
/// preceed IntoMI.
bool isObviouslySafeToFold(MachineInstr &MI, MachineInstr &IntoMI) const;
+
+ template <typename Ty> static Ty readBytesAs(const uint8_t *MatchTable) {
+ Ty Ret;
+ memcpy(&Ret, MatchTable, sizeof(Ret));
+ return Ret;
+ }
};
} // end namespace llvm
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
index f0ee76c097bc..0a2709ef216b 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
@@ -33,6 +33,7 @@
#include "llvm/Support/CodeGenCoverage.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstddef>
@@ -46,7 +47,7 @@ bool GIMatchTableExecutor::executeMatchTable(
TgtExecutor &Exec, MatcherState &State,
const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
&ExecInfo,
- MachineIRBuilder &Builder, const int64_t *MatchTable,
+ MachineIRBuilder &Builder, const uint8_t *MatchTable,
const TargetInstrInfo &TII, MachineRegisterInfo &MRI,
const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI,
const PredicateBitset &AvailableFeatures,
@@ -92,28 +93,60 @@ bool GIMatchTableExecutor::executeMatchTable(
// If the index is >= 0, it's an index in the type objects generated by
// TableGen. If the index is <0, it's an index in the recorded types object.
- auto getTypeFromIdx = [&](int64_t Idx) -> LLT {
+ const auto getTypeFromIdx = [&](int64_t Idx) -> LLT {
if (Idx >= 0)
return ExecInfo.TypeObjects[Idx];
return State.RecordedTypes[1 - Idx];
};
+ const auto readULEB = [&]() {
+ unsigned N = 0;
+ uint64_t Val = decodeULEB128(MatchTable + CurrentIdx, &N);
+ CurrentIdx += N;
+ return Val;
+ };
+
+ // Convenience function to return a signed value. This avoids
+ // us forgetting to first cast to int8_t before casting to a
+ // wider signed int type.
+ // if we casted uint8 directly to a wider type we'd lose
+ // negative values.
+ const auto readS8 = [&]() { return (int8_t)MatchTable[CurrentIdx++]; };
+
+ const auto readU16 = [&]() {
+ auto V = readBytesAs<uint16_t>(MatchTable + CurrentIdx);
+ CurrentIdx += 2;
+ return V;
+ };
+
+ const auto readU32 = [&]() {
+ auto V = readBytesAs<uint32_t>(MatchTable + CurrentIdx);
+ CurrentIdx += 4;
+ return V;
+ };
+
+ const auto readU64 = [&]() {
+ auto V = readBytesAs<uint64_t>(MatchTable + CurrentIdx);
+ CurrentIdx += 8;
+ return V;
+ };
+
while (true) {
assert(CurrentIdx != ~0u && "Invalid MatchTable index");
- int64_t MatcherOpcode = MatchTable[CurrentIdx++];
+ uint8_t MatcherOpcode = MatchTable[CurrentIdx++];
switch (MatcherOpcode) {
case GIM_Try: {
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": Begin try-block\n");
- OnFailResumeAt.push_back(MatchTable[CurrentIdx++]);
+ OnFailResumeAt.push_back(readU32());
break;
}
case GIM_RecordInsn:
case GIM_RecordInsnIgnoreCopies: {
- int64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
+ uint64_t NewInsnID = readULEB();
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
// As an optimisation we require that MIs[0] is always the root. Refuse
// any attempt to modify it.
@@ -156,7 +189,7 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_CheckFeatures: {
- int64_t ExpectedBitsetID = MatchTable[CurrentIdx++];
+ uint16_t ExpectedBitsetID = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIM_CheckFeatures(ExpectedBitsetID="
@@ -170,11 +203,11 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_CheckOpcode:
case GIM_CheckOpcodeIsEither: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t Expected0 = MatchTable[CurrentIdx++];
- int64_t Expected1 = -1;
+ uint64_t InsnID = readULEB();
+ uint16_t Expected0 = readU16();
+ uint16_t Expected1 = -1;
if (MatcherOpcode == GIM_CheckOpcodeIsEither)
- Expected1 = MatchTable[CurrentIdx++];
+ Expected1 = readU16();
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
unsigned Opcode = State.MIs[InsnID]->getOpcode();
@@ -193,10 +226,10 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_SwitchOpcode: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t LowerBound = MatchTable[CurrentIdx++];
- int64_t UpperBound = MatchTable[CurrentIdx++];
- int64_t Default = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t LowerBound = readU16();
+ uint16_t UpperBound = readU16();
+ uint32_t Default = readU32();
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
const int64_t Opcode = State.MIs[InsnID]->getOpcode();
@@ -210,7 +243,10 @@ bool GIMatchTableExecutor::executeMatchTable(
CurrentIdx = Default;
break;
}
- CurrentIdx = MatchTable[CurrentIdx + (Opcode - LowerBound)];
+ const auto EntryIdx = (Opcode - LowerBound);
+ // Each entry is 4 bytes
+ CurrentIdx =
+ readBytesAs<uint32_t>(MatchTable + CurrentIdx + (EntryIdx * 4));
if (!CurrentIdx) {
CurrentIdx = Default;
break;
@@ -220,11 +256,11 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_SwitchType: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t LowerBound = MatchTable[CurrentIdx++];
- int64_t UpperBound = MatchTable[CurrentIdx++];
- int64_t Default = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint16_t LowerBound = readU16();
+ uint16_t UpperBound = readU16();
+ int64_t Default = readU32();
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
@@ -254,7 +290,10 @@ bool GIMatchTableExecutor::executeMatchTable(
CurrentIdx = Default;
break;
}
- CurrentIdx = MatchTable[CurrentIdx + (TypeID - LowerBound)];
+ const auto NumEntry = (TypeID - LowerBound);
+ // Each entry is 4 bytes
+ CurrentIdx =
+ readBytesAs<uint32_t>(MatchTable + CurrentIdx + (NumEntry * 4));
if (!CurrentIdx) {
CurrentIdx = Default;
break;
@@ -264,8 +303,8 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_CheckNumOperands: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t Expected = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t Expected = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckNumOperands(MIs["
<< InsnID << "], Expected=" << Expected << ")\n");
@@ -278,11 +317,10 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_CheckI64ImmPredicate:
case GIM_CheckImmOperandPredicate: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatcherOpcode == GIM_CheckImmOperandPredicate
- ? MatchTable[CurrentIdx++]
- : 1;
- int64_t Predicate = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ unsigned OpIdx =
+ MatcherOpcode == GIM_CheckImmOperandPredicate ? readULEB() : 1;
+ uint16_t Predicate = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckImmPredicate(MIs["
<< InsnID << "]->getOperand(" << OpIdx
@@ -306,8 +344,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckAPIntImmPredicate: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t Predicate = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t Predicate = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs()
<< CurrentIdx << ": GIM_CheckAPIntImmPredicate(MIs["
@@ -327,8 +365,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckAPFloatImmPredicate: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t Predicate = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t Predicate = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs()
<< CurrentIdx << ": GIM_CheckAPFloatImmPredicate(MIs["
@@ -349,7 +387,7 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_CheckIsBuildVectorAllOnes:
case GIM_CheckIsBuildVectorAllZeros: {
- int64_t InsnID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
@@ -380,7 +418,7 @@ bool GIMatchTableExecutor::executeMatchTable(
// Note: we don't check for invalid here because this is purely a hook to
// allow some executors (such as the combiner) to check arbitrary,
// contextless predicates, such as whether a rule is enabled or not.
- int64_t Predicate = MatchTable[CurrentIdx++];
+ uint16_t Predicate = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIM_CheckSimplePredicate(Predicate="
@@ -393,8 +431,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckCxxInsnPredicate: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t Predicate = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t Predicate = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs()
<< CurrentIdx << ": GIM_CheckCxxPredicate(MIs["
@@ -408,7 +446,7 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckHasNoUse: {
- int64_t InsnID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckHasNoUse(MIs["
@@ -427,8 +465,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckAtomicOrdering: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- AtomicOrdering Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ auto Ordering = (AtomicOrdering)readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckAtomicOrdering(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n");
@@ -444,8 +482,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckAtomicOrderingOrStrongerThan: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- AtomicOrdering Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ auto Ordering = (AtomicOrdering)readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIM_CheckAtomicOrderingOrStrongerThan(MIs["
@@ -462,8 +500,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckAtomicOrderingWeakerThan: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- AtomicOrdering Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ auto Ordering = (AtomicOrdering)readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIM_CheckAtomicOrderingWeakerThan(MIs["
@@ -480,10 +518,10 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckMemoryAddressSpace: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t MMOIdx = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t MMOIdx = readULEB();
// This accepts a list of possible address spaces.
- const int NumAddrSpace = MatchTable[CurrentIdx++];
+ const uint64_t NumAddrSpace = readULEB();
if (State.MIs[InsnID]->getNumMemOperands() <= MMOIdx) {
if (handleReject() == RejectAndGiveUp)
@@ -500,8 +538,8 @@ bool GIMatchTableExecutor::executeMatchTable(
const unsigned MMOAddrSpace = MMO->getAddrSpace();
bool Success = false;
- for (int I = 0; I != NumAddrSpace; ++I) {
- unsigned AddrSpace = MatchTable[CurrentIdx++];
+ for (unsigned I = 0; I != NumAddrSpace; ++I) {
+ uint64_t AddrSpace = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << "addrspace(" << MMOAddrSpace << ") vs "
<< AddrSpace << '\n');
@@ -518,9 +556,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckMemoryAlignment: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t MMOIdx = MatchTable[CurrentIdx++];
- unsigned MinAlign = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t MMOIdx = readULEB();
+ uint64_t MinAlign = readULEB();
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
@@ -543,9 +581,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckMemorySizeEqualTo: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t MMOIdx = MatchTable[CurrentIdx++];
- uint64_t Size = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t MMOIdx = readULEB();
+ uint32_t Size = readU32();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckMemorySizeEqual(MIs["
@@ -574,9 +612,9 @@ bool GIMatchTableExecutor::executeMatchTable(
case GIM_CheckMemorySizeEqualToLLT:
case GIM_CheckMemorySizeLessThanLLT:
case GIM_CheckMemorySizeGreaterThanLLT: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t MMOIdx = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t MMOIdx = readULEB();
+ uint64_t OpIdx = readULEB();
DEBUG_WITH_TYPE(
TgtExecutor::getName(),
@@ -624,9 +662,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckType: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t TypeID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ int TypeID = readS8();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckType(MIs[" << InsnID
<< "]->getOperand(" << OpIdx
@@ -640,9 +678,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckPointerToAny: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- uint64_t SizeInBits = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint64_t SizeInBits = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckPointerToAny(MIs["
@@ -671,9 +709,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_RecordNamedOperand: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- uint64_t StoreIdx = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint64_t StoreIdx = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_RecordNamedOperand(MIs["
@@ -685,16 +723,16 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_RecordRegType: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t TypeIdx = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ int TypeIdx = readS8();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_RecordRegType(MIs["
<< InsnID << "]->getOperand(" << OpIdx
<< "), TypeIdx=" << TypeIdx << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
- assert(TypeIdx <= 0 && "Temp types always have negative indexes!");
+ assert(TypeIdx < 0 && "Temp types always have negative indexes!");
// Indexes start at -1.
TypeIdx = 1 - TypeIdx;
const auto &Op = State.MIs[InsnID]->getOperand(OpIdx);
@@ -704,9 +742,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckRegBankForClass: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t RCEnum = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint16_t RCEnum = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckRegBankForClass(MIs["
<< InsnID << "]->getOperand(" << OpIdx
@@ -724,10 +762,10 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_CheckComplexPattern: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t RendererID = MatchTable[CurrentIdx++];
- int64_t ComplexPredicateID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint16_t RendererID = readU16();
+ uint16_t ComplexPredicateID = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": State.Renderers[" << RendererID
<< "] = GIM_CheckComplexPattern(MIs[" << InsnID
@@ -746,10 +784,13 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
- case GIM_CheckConstantInt: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t Value = MatchTable[CurrentIdx++];
+ case GIM_CheckConstantInt:
+ case GIM_CheckConstantInt8: {
+ const bool IsInt8 = (MatcherOpcode == GIM_CheckConstantInt8);
+
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint64_t Value = IsInt8 ? (int64_t)readS8() : readU64();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckConstantInt(MIs["
<< InsnID << "]->getOperand(" << OpIdx
@@ -779,9 +820,9 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_CheckLiteralInt: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t Value = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ int64_t Value = readU64();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckLiteralInt(MIs["
<< InsnID << "]->getOperand(" << OpIdx
@@ -801,9 +842,9 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_CheckIntrinsicID: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t Value = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint16_t Value = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIntrinsicID(MIs["
<< InsnID << "]->getOperand(" << OpIdx
@@ -816,9 +857,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckCmpPredicate: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t Value = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint16_t Value = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckCmpPredicate(MIs["
<< InsnID << "]->getOperand(" << OpIdx
@@ -831,8 +872,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckIsMBB: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIsMBB(MIs[" << InsnID
<< "]->getOperand(" << OpIdx << "))\n");
@@ -844,8 +885,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckIsImm: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIsImm(MIs[" << InsnID
<< "]->getOperand(" << OpIdx << "))\n");
@@ -857,7 +898,7 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckIsSafeToFold: {
- int64_t InsnID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIsSafeToFold(MIs["
<< InsnID << "])\n");
@@ -870,10 +911,10 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIM_CheckIsSameOperand:
case GIM_CheckIsSameOperandIgnoreCopies: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t OtherInsnID = MatchTable[CurrentIdx++];
- int64_t OtherOpIdx = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint64_t OtherInsnID = readULEB();
+ uint64_t OtherOpIdx = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIsSameOperand(MIs["
<< InsnID << "][" << OpIdx << "], MIs["
@@ -899,10 +940,10 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_CheckCanReplaceReg: {
- int64_t OldInsnID = MatchTable[CurrentIdx++];
- int64_t OldOpIdx = MatchTable[CurrentIdx++];
- int64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t NewOpIdx = MatchTable[CurrentIdx++];
+ uint64_t OldInsnID = readULEB();
+ uint64_t OldOpIdx = readULEB();
+ uint64_t NewInsnID = readULEB();
+ uint64_t NewOpIdx = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckCanReplaceReg(MIs["
@@ -918,8 +959,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_MIFlags: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- uint32_t Flags = (uint32_t)MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint32_t Flags = readU32();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_MIFlags(MIs[" << InsnID
@@ -931,8 +972,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIM_MIFlagsNot: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- uint32_t Flags = (uint32_t)MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint32_t Flags = readU32();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_MIFlagsNot(MIs[" << InsnID
@@ -950,9 +991,9 @@ bool GIMatchTableExecutor::executeMatchTable(
return false;
break;
case GIR_MutateOpcode: {
- int64_t OldInsnID = MatchTable[CurrentIdx++];
- uint64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t NewOpcode = MatchTable[CurrentIdx++];
+ uint64_t OldInsnID = readULEB();
+ uint64_t NewInsnID = readULEB();
+ uint16_t NewOpcode = readU16();
if (NewInsnID >= OutMIs.size())
OutMIs.resize(NewInsnID + 1);
@@ -971,8 +1012,8 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_BuildMI: {
- uint64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t Opcode = MatchTable[CurrentIdx++];
+ uint64_t NewInsnID = readULEB();
+ uint16_t Opcode = readU16();
if (NewInsnID >= OutMIs.size())
OutMIs.resize(NewInsnID + 1);
@@ -984,8 +1025,8 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_BuildConstant: {
- int64_t TempRegID = MatchTable[CurrentIdx++];
- int64_t Imm = MatchTable[CurrentIdx++];
+ uint64_t TempRegID = readULEB();
+ uint64_t Imm = readU64();
Builder.buildConstant(State.TempRegisters[TempRegID], Imm);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_BuildConstant(TempReg["
@@ -994,9 +1035,9 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_Copy: {
- int64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t OldInsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
+ uint64_t NewInsnID = readULEB();
+ uint64_t OldInsnID = readULEB();
+ uint64_t OpIdx = readULEB();
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
OutMIs[NewInsnID].add(State.MIs[OldInsnID]->getOperand(OpIdx));
DEBUG_WITH_TYPE(TgtExecutor::getName(),
@@ -1007,10 +1048,10 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_CopyOrAddZeroReg: {
- int64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t OldInsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t ZeroReg = MatchTable[CurrentIdx++];
+ uint64_t NewInsnID = readULEB();
+ uint64_t OldInsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint16_t ZeroReg = readU16();
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
MachineOperand &MO = State.MIs[OldInsnID]->getOperand(OpIdx);
if (isOperandImmEqual(MO, 0, MRI))
@@ -1025,10 +1066,10 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_CopySubReg: {
- int64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t OldInsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t SubRegIdx = MatchTable[CurrentIdx++];
+ uint64_t NewInsnID = readULEB();
+ uint64_t OldInsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint16_t SubRegIdx = readU16();
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
OutMIs[NewInsnID].addReg(State.MIs[OldInsnID]->getOperand(OpIdx).getReg(),
0, SubRegIdx);
@@ -1040,9 +1081,9 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_AddImplicitDef: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t RegNum = MatchTable[CurrentIdx++];
- auto Flags = (uint64_t)MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t RegNum = readU16();
+ uint16_t Flags = readU16();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
Flags |= RegState::Implicit;
OutMIs[InsnID].addDef(RegNum, Flags);
@@ -1053,8 +1094,8 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_AddImplicitUse: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t RegNum = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t RegNum = readU16();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
OutMIs[InsnID].addUse(RegNum, RegState::Implicit);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
@@ -1064,9 +1105,9 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_AddRegister: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t RegNum = MatchTable[CurrentIdx++];
- uint64_t RegFlags = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t RegNum = readU16();
+ uint16_t RegFlags = readU16();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
OutMIs[InsnID].addReg(RegNum, RegFlags);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
@@ -1076,8 +1117,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_SetImplicitDefDead: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_SetImplicitDefDead(OutMIs["
<< InsnID << "], OpIdx=" << OpIdx << ")\n");
@@ -1087,8 +1128,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_SetMIFlags: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- uint32_t Flags = (uint32_t)MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint32_t Flags = readU32();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_SetMIFlags(OutMIs["
@@ -1098,8 +1139,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_UnsetMIFlags: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- uint32_t Flags = (uint32_t)MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint32_t Flags = readU32();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_UnsetMIFlags(OutMIs["
@@ -1109,8 +1150,8 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_CopyMIFlags: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OldInsnID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OldInsnID = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_CopyMIFlags(OutMIs["
@@ -1119,14 +1160,17 @@ bool GIMatchTableExecutor::executeMatchTable(
MI->setFlags(MI->getFlags() | State.MIs[OldInsnID]->getFlags());
break;
}
+ case GIR_AddSimpleTempRegister:
case GIR_AddTempRegister:
case GIR_AddTempSubRegister: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t TempRegID = MatchTable[CurrentIdx++];
- uint64_t TempRegFlags = MatchTable[CurrentIdx++];
- unsigned SubReg = 0;
+ uint64_t InsnID = readULEB();
+ uint64_t TempRegID = readULEB();
+ uint16_t TempRegFlags = 0;
+ if (MatcherOpcode != GIR_AddSimpleTempRegister)
+ TempRegFlags = readU16();
+ uint16_t SubReg = 0;
if (MatcherOpcode == GIR_AddTempSubRegister)
- SubReg = MatchTable[CurrentIdx++];
+ SubReg = readU16();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
@@ -1141,9 +1185,11 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
+ case GIR_AddImm8:
case GIR_AddImm: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t Imm = MatchTable[CurrentIdx++];
+ const bool IsAdd8 = (MatcherOpcode == GIR_AddImm8);
+ uint64_t InsnID = readULEB();
+ uint64_t Imm = IsAdd8 ? (int64_t)readS8() : readU64();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
OutMIs[InsnID].addImm(Imm);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
@@ -1153,9 +1199,9 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_AddCImm: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t TypeID = MatchTable[CurrentIdx++];
- int64_t Imm = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ int TypeID = readS8();
+ uint64_t Imm = readU64();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
unsigned Width = ExecInfo.TypeObjects[TypeID].getScalarSizeInBits();
@@ -1170,8 +1216,8 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_ComplexRenderer: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t RendererID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t RendererID = readU16();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
for (const auto &RenderOpFn : State.Renderers[RendererID])
RenderOpFn(OutMIs[InsnID]);
@@ -1181,9 +1227,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_ComplexSubOperandRenderer: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t RendererID = MatchTable[CurrentIdx++];
- int64_t RenderOpID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t RendererID = readU16();
+ uint64_t RenderOpID = readULEB();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
State.Renderers[RendererID][RenderOpID](OutMIs[InsnID]);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
@@ -1194,10 +1240,10 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_ComplexSubOperandSubRegRenderer: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t RendererID = MatchTable[CurrentIdx++];
- int64_t RenderOpID = MatchTable[CurrentIdx++];
- int64_t SubRegIdx = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint16_t RendererID = readU16();
+ uint64_t RenderOpID = readULEB();
+ uint16_t SubRegIdx = readU16();
MachineInstrBuilder &MI = OutMIs[InsnID];
assert(MI && "Attempted to add to undefined instruction");
State.Renderers[RendererID][RenderOpID](MI);
@@ -1211,8 +1257,8 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_CopyConstantAsSImm: {
- int64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t OldInsnID = MatchTable[CurrentIdx++];
+ uint64_t NewInsnID = readULEB();
+ uint64_t OldInsnID = readULEB();
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
assert(State.MIs[OldInsnID]->getOpcode() == TargetOpcode::G_CONSTANT &&
"Expected G_CONSTANT");
@@ -1231,8 +1277,8 @@ bool GIMatchTableExecutor::executeMatchTable(
// TODO: Needs a test case once we have a pattern that uses this.
case GIR_CopyFConstantAsFPImm: {
- int64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t OldInsnID = MatchTable[CurrentIdx++];
+ uint64_t NewInsnID = readULEB();
+ uint64_t OldInsnID = readULEB();
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
assert(State.MIs[OldInsnID]->getOpcode() == TargetOpcode::G_FCONSTANT &&
"Expected G_FCONSTANT");
@@ -1249,9 +1295,9 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_CustomRenderer: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OldInsnID = MatchTable[CurrentIdx++];
- int64_t RendererFnID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OldInsnID = readULEB();
+ uint16_t RendererFnID = readU16();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_CustomRenderer(OutMIs["
@@ -1263,7 +1309,7 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_CustomAction: {
- int64_t FnID = MatchTable[CurrentIdx++];
+ uint16_t FnID = readU16();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_CustomAction(FnID=" << FnID
<< ")\n");
@@ -1272,10 +1318,10 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_CustomOperandRenderer: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OldInsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t RendererFnID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OldInsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint16_t RendererFnID = readU16();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
DEBUG_WITH_TYPE(TgtExecutor::getName(),
@@ -1288,9 +1334,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_ConstrainOperandRC: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t OpIdx = MatchTable[CurrentIdx++];
- int64_t RCEnum = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t OpIdx = readULEB();
+ uint16_t RCEnum = readU16();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
MachineInstr &I = *OutMIs[InsnID].getInstr();
MachineFunction &MF = *I.getParent()->getParent();
@@ -1306,7 +1352,7 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_ConstrainSelectedInstOperands: {
- int64_t InsnID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
constrainSelectedInstRegOperands(*OutMIs[InsnID].getInstr(), TII, TRI,
RBI);
@@ -1318,18 +1364,18 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_MergeMemOperands: {
- int64_t InsnID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
+ uint64_t NumInsn = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_MergeMemOperands(OutMIs["
<< InsnID << "]");
- int64_t MergeInsnID = GIU_MergeMemOperands_EndOfList;
- while ((MergeInsnID = MatchTable[CurrentIdx++]) !=
- GIU_MergeMemOperands_EndOfList) {
+ for (unsigned K = 0; K < NumInsn; ++K) {
+ uint64_t NextID = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
- dbgs() << ", MIs[" << MergeInsnID << "]");
- for (const auto &MMO : State.MIs[MergeInsnID]->memoperands())
+ dbgs() << ", MIs[" << NextID << "]");
+ for (const auto &MMO : State.MIs[NextID]->memoperands())
OutMIs[InsnID].addMemOperand(MMO);
}
DEBUG_WITH_TYPE(TgtExecutor::getName(), dbgs() << ")\n");
@@ -1337,7 +1383,7 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_EraseFromParent: {
- int64_t InsnID = MatchTable[CurrentIdx++];
+ uint64_t InsnID = readULEB();
MachineInstr *MI = State.MIs[InsnID];
assert(MI && "Attempted to erase an undefined instruction");
DEBUG_WITH_TYPE(TgtExecutor::getName(),
@@ -1354,8 +1400,8 @@ bool GIMatchTableExecutor::executeMatchTable(
}
case GIR_MakeTempReg: {
- int64_t TempRegID = MatchTable[CurrentIdx++];
- int64_t TypeID = MatchTable[CurrentIdx++];
+ uint64_t TempRegID = readULEB();
+ int TypeID = readS8();
State.TempRegisters[TempRegID] =
MRI.createGenericVirtualRegister(getTypeFromIdx(TypeID));
@@ -1365,10 +1411,10 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_ReplaceReg: {
- int64_t OldInsnID = MatchTable[CurrentIdx++];
- int64_t OldOpIdx = MatchTable[CurrentIdx++];
- int64_t NewInsnID = MatchTable[CurrentIdx++];
- int64_t NewOpIdx = MatchTable[CurrentIdx++];
+ uint64_t OldInsnID = readULEB();
+ uint64_t OldOpIdx = readULEB();
+ uint64_t NewInsnID = readULEB();
+ uint64_t NewOpIdx = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_ReplaceReg(MIs["
@@ -1385,9 +1431,9 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_ReplaceRegWithTempReg: {
- int64_t OldInsnID = MatchTable[CurrentIdx++];
- int64_t OldOpIdx = MatchTable[CurrentIdx++];
- int64_t TempRegID = MatchTable[CurrentIdx++];
+ uint64_t OldInsnID = readULEB();
+ uint64_t OldOpIdx = readULEB();
+ uint64_t TempRegID = readULEB();
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_ReplaceRegWithTempReg(MIs["
@@ -1404,7 +1450,7 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
case GIR_Coverage: {
- int64_t RuleID = MatchTable[CurrentIdx++];
+ uint32_t RuleID = readU32();
assert(CoverageInfo);
CoverageInfo->setCovered(RuleID);
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
index 0b167ce9650d..e423e48fd31e 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
@@ -19,6 +19,7 @@
#include "llvm/CodeGen/LowLevelType.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include <unordered_map>
+#include <vector>
namespace llvm {
struct LegalityQuery;
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
index 3d36d06a7e9d..1387a0a37561 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
@@ -1529,6 +1529,11 @@ public:
/// Build and insert `G_FENCE Ordering, Scope`.
MachineInstrBuilder buildFence(unsigned Ordering, unsigned Scope);
+ /// Build and insert G_PREFETCH \p Addr, \p RW, \p Locality, \p CacheType
+ MachineInstrBuilder buildPrefetch(const SrcOp &Addr, unsigned RW,
+ unsigned Locality, unsigned CacheType,
+ MachineMemOperand &MMO);
+
/// Build and insert \p Dst = G_FREEZE \p Src
MachineInstrBuilder buildFreeze(const DstOp &Dst, const SrcOp &Src) {
return buildInstr(TargetOpcode::G_FREEZE, {Dst}, {Src});
diff --git a/llvm/include/llvm/CodeGen/IndirectBrExpand.h b/llvm/include/llvm/CodeGen/IndirectBrExpand.h
new file mode 100644
index 000000000000..f7d9d5df6fe2
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/IndirectBrExpand.h
@@ -0,0 +1,28 @@
+//===- llvm/CodeGen/IndirectBrExpand.h -------------------------*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_INDIRECTBREXPAND_H
+#define LLVM_CODEGEN_INDIRECTBREXPAND_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class TargetMachine;
+
+class IndirectBrExpandPass : public PassInfoMixin<IndirectBrExpandPass> {
+ const TargetMachine *TM;
+
+public:
+ IndirectBrExpandPass(const TargetMachine *TM) : TM(TM) {}
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_INDIRECTBREXPAND_H
diff --git a/llvm/include/llvm/CodeGen/IndirectThunks.h b/llvm/include/llvm/CodeGen/IndirectThunks.h
index b0a8e3043be5..9b064ab788bf 100644
--- a/llvm/include/llvm/CodeGen/IndirectThunks.h
+++ b/llvm/include/llvm/CodeGen/IndirectThunks.h
@@ -48,7 +48,7 @@ template <typename Derived, typename InsertedThunksTy>
void ThunkInserter<Derived, InsertedThunksTy>::createThunkFunction(
MachineModuleInfo &MMI, StringRef Name, bool Comdat,
StringRef TargetAttrs) {
- assert(Name.startswith(getDerived().getThunkPrefix()) &&
+ assert(Name.starts_with(getDerived().getThunkPrefix()) &&
"Created a thunk with an unexpected prefix!");
Module &M = const_cast<Module &>(*MMI.getModule());
@@ -94,7 +94,7 @@ template <typename Derived, typename InsertedThunksTy>
bool ThunkInserter<Derived, InsertedThunksTy>::run(MachineModuleInfo &MMI,
MachineFunction &MF) {
// If MF is not a thunk, check to see if we need to insert a thunk.
- if (!MF.getName().startswith(getDerived().getThunkPrefix())) {
+ if (!MF.getName().starts_with(getDerived().getThunkPrefix())) {
// Only add a thunk if one of the functions has the corresponding feature
// enabled in its subtarget, and doesn't enable external thunks. The target
// can use InsertedThunks to detect whether relevant thunks have already
diff --git a/llvm/include/llvm/CodeGen/InterleavedAccess.h b/llvm/include/llvm/CodeGen/InterleavedAccess.h
new file mode 100644
index 000000000000..31bd19a3191a
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/InterleavedAccess.h
@@ -0,0 +1,34 @@
+//===---- llvm/CodeGen/InterleavedAccess.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the InterleavedAccessPass class,
+/// its corresponding pass name is `interleaved-access`.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_INTERLEAVEDACCESS_H
+#define LLVM_CODEGEN_INTERLEAVEDACCESS_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class TargetMachine;
+
+class InterleavedAccessPass : public PassInfoMixin<InterleavedAccessPass> {
+ const TargetMachine *TM;
+
+public:
+ explicit InterleavedAccessPass(const TargetMachine *TM) : TM(TM) {}
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_INTERLEAVEDACCESS_H
diff --git a/llvm/include/llvm/CodeGen/InterleavedLoadCombine.h b/llvm/include/llvm/CodeGen/InterleavedLoadCombine.h
new file mode 100644
index 000000000000..fa99aa316c2a
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/InterleavedLoadCombine.h
@@ -0,0 +1,29 @@
+//===- llvm/CodeGen/InterleavedLoadCombine.h --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_INTERLEAVEDLOADCOMBINE_H
+#define LLVM_CODEGEN_INTERLEAVEDLOADCOMBINE_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class TargetMachine;
+
+class InterleavedLoadCombinePass
+ : public PassInfoMixin<InterleavedLoadCombinePass> {
+ const TargetMachine *TM;
+
+public:
+ explicit InterleavedLoadCombinePass(const TargetMachine *TM) : TM(TM) {}
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+};
+
+} // namespace llvm
+
+#endif // InterleavedLoadCombine
diff --git a/llvm/include/llvm/CodeGen/JMCInstrumenter.h b/llvm/include/llvm/CodeGen/JMCInstrumenter.h
new file mode 100644
index 000000000000..addac1654826
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/JMCInstrumenter.h
@@ -0,0 +1,23 @@
+//===-- llvm/CodeGen/JMCInstrumenter------------------------ ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_JMCINSTRUMENTER_H
+#define LLVM_CODEGEN_JMCINSTRUMENTER_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class JMCInstrumenterPass : public PassInfoMixin<JMCInstrumenterPass> {
+public:
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_JMCINSTRUMENTER_H
diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index bf35febb8057..bb8dbb0478ff 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -433,9 +433,9 @@ template <> struct ScalarTraits<FrameIndex> {
static StringRef input(StringRef Scalar, void *Ctx, FrameIndex &FI) {
FI.IsFixed = false;
StringRef Num;
- if (Scalar.startswith("%stack.")) {
+ if (Scalar.starts_with("%stack.")) {
Num = Scalar.substr(7);
- } else if (Scalar.startswith("%fixed-stack.")) {
+ } else if (Scalar.starts_with("%fixed-stack.")) {
Num = Scalar.substr(13);
FI.IsFixed = true;
} else {
diff --git a/llvm/include/llvm/CodeGen/MachinePassManager.h b/llvm/include/llvm/CodeGen/MachinePassManager.h
index 5dc0e2918d46..a2641a822364 100644
--- a/llvm/include/llvm/CodeGen/MachinePassManager.h
+++ b/llvm/include/llvm/CodeGen/MachinePassManager.h
@@ -37,6 +37,22 @@ class MachineFunction;
extern template class AnalysisManager<MachineFunction>;
+/// Like \c AnalysisKey, but only for machine passes.
+struct alignas(8) MachinePassKey {};
+
+/// A CRTP mix-in that provides informational APIs needed for machine passes.
+///
+/// This provides some boilerplate for types that are machine passes. It
+/// automatically mixes in \c PassInfoMixin.
+template <typename DerivedT>
+struct MachinePassInfoMixin : public PassInfoMixin<DerivedT> {
+ static MachinePassKey *ID() {
+ static_assert(std::is_base_of<MachinePassInfoMixin, DerivedT>::value,
+ "Must pass the derived type as the template argument!");
+ return &DerivedT::Key;
+ }
+};
+
/// An AnalysisManager<MachineFunction> that also exposes IR analysis results.
class MachineFunctionAnalysisManager : public AnalysisManager<MachineFunction> {
public:
diff --git a/llvm/include/llvm/CodeGen/MachinePassRegistry.def b/llvm/include/llvm/CodeGen/MachinePassRegistry.def
index 1e9e5838841b..04f2cd5ff581 100644
--- a/llvm/include/llvm/CodeGen/MachinePassRegistry.def
+++ b/llvm/include/llvm/CodeGen/MachinePassRegistry.def
@@ -16,6 +16,7 @@
#ifndef MODULE_ANALYSIS
#define MODULE_ANALYSIS(NAME, PASS_NAME, CONSTRUCTOR)
#endif
+MODULE_ANALYSIS("collector-metadata", CollectorMetadataAnalysis, ())
MODULE_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis, (PIC))
#undef MODULE_ANALYSIS
@@ -23,11 +24,13 @@ MODULE_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis, (PIC))
#define MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR)
#endif
MODULE_PASS("pre-isel-intrinsic-lowering", PreISelIntrinsicLoweringPass, ())
+MODULE_PASS("jmc-instrumenter", JMCInstrumenterPass, ())
#undef MODULE_PASS
#ifndef FUNCTION_ANALYSIS
#define FUNCTION_ANALYSIS(NAME, PASS_NAME, CONSTRUCTOR)
#endif
+FUNCTION_ANALYSIS("gc-function", GCFunctionAnalysis, ())
FUNCTION_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis, (PIC))
FUNCTION_ANALYSIS("targetir", TargetIRAnalysis,
(std::move(TM.getTargetIRAnalysis())))
@@ -37,12 +40,18 @@ FUNCTION_ANALYSIS("targetir", TargetIRAnalysis,
#define FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR)
#endif
FUNCTION_PASS("callbrprepare", CallBrPreparePass, ())
+FUNCTION_PASS("cfguard", CFGuardPass, ())
FUNCTION_PASS("consthoist", ConstantHoistingPass, ())
+FUNCTION_PASS("dwarf-eh-prepare", DwarfEHPreparePass, (TM))
FUNCTION_PASS("ee-instrument", EntryExitInstrumenterPass, (false))
-FUNCTION_PASS("expand-large-div-rem", ExpandLargeDivRemPass, ())
-FUNCTION_PASS("expand-large-fp-convert", ExpandLargeFpConvertPass, ())
+FUNCTION_PASS("expand-large-div-rem", ExpandLargeDivRemPass, (TM))
+FUNCTION_PASS("expand-large-fp-convert", ExpandLargeFpConvertPass, (TM))
+FUNCTION_PASS("expand-memcmp", ExpandMemCmpPass, (TM))
FUNCTION_PASS("expand-reductions", ExpandReductionsPass, ())
FUNCTION_PASS("expandvp", ExpandVectorPredicationPass, ())
+FUNCTION_PASS("indirectbr-expand", IndirectBrExpandPass, (TM))
+FUNCTION_PASS("interleaved-access", InterleavedAccessPass, (TM))
+FUNCTION_PASS("interleaved-load-combine", InterleavedLoadCombinePass, (TM))
FUNCTION_PASS("lower-constant-intrinsics", LowerConstantIntrinsicsPass, ())
FUNCTION_PASS("lowerinvoke", LowerInvokePass, ())
FUNCTION_PASS("mergeicmps", MergeICmpsPass, ())
@@ -51,6 +60,8 @@ FUNCTION_PASS("post-inline-ee-instrument", EntryExitInstrumenterPass, (true))
FUNCTION_PASS("replace-with-veclib", ReplaceWithVeclib, ())
FUNCTION_PASS("safe-stack", SafeStackPass, (TM))
FUNCTION_PASS("scalarize-masked-mem-intrin", ScalarizeMaskedMemIntrinPass, ())
+FUNCTION_PASS("select-optimize", SelectOptimizePass, (TM))
+FUNCTION_PASS("sjlj-eh-prepare", SjLjEHPreparePass, (TM))
FUNCTION_PASS("tlshoist", TLSVariableHoistPass, ())
FUNCTION_PASS("unreachableblockelim", UnreachableBlockElimPass, ())
FUNCTION_PASS("verify", VerifierPass, ())
@@ -119,18 +130,9 @@ MACHINE_FUNCTION_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis,
#define DUMMY_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR)
#endif
DUMMY_FUNCTION_PASS("atomic-expand", AtomicExpandPass, ())
-DUMMY_FUNCTION_PASS("cfguard-check", CFGuardCheckPass, ())
-DUMMY_FUNCTION_PASS("cfguard-dispatch", CFGuardDispatchPass, ())
DUMMY_FUNCTION_PASS("codegenprepare", CodeGenPreparePass, ())
-DUMMY_FUNCTION_PASS("dwarfehprepare", DwarfEHPass, ())
-DUMMY_FUNCTION_PASS("expandmemcmp", ExpandMemCmpPass, ())
-DUMMY_FUNCTION_PASS("gc-info-printer", GCInfoPrinterPass, ())
DUMMY_FUNCTION_PASS("gc-lowering", GCLoweringPass, ())
-DUMMY_FUNCTION_PASS("indirectbr-expand", IndirectBrExpandPass, ())
-DUMMY_FUNCTION_PASS("interleaved-access", InterleavedAccessPass, ())
-DUMMY_FUNCTION_PASS("select-optimize", SelectOptimizePass, ())
DUMMY_FUNCTION_PASS("shadow-stack-gc-lowering", ShadowStackGCLoweringPass, ())
-DUMMY_FUNCTION_PASS("sjljehprepare", SjLjEHPreparePass, ())
DUMMY_FUNCTION_PASS("stack-protector", StackProtectorPass, ())
#undef DUMMY_FUNCTION_PASS
@@ -144,17 +146,26 @@ DUMMY_MODULE_PASS("lower-emutls", LowerEmuTLSPass, ())
#define DUMMY_MACHINE_MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR)
#endif
DUMMY_MACHINE_MODULE_PASS("machine-outliner", MachineOutlinerPass, ())
+DUMMY_MACHINE_MODULE_PASS("pseudo-probe-inserter", PseudoProbeInserterPass, ())
+DUMMY_MACHINE_MODULE_PASS("mir-debugify", DebugifyMachineModule, ())
+DUMMY_MACHINE_MODULE_PASS("mir-check-debugify", CheckDebugMachineModulePass, ())
+DUMMY_MACHINE_MODULE_PASS("mir-strip-debug", StripDebugMachineModulePass,
+ (OnlyDebugified))
#undef DUMMY_MACHINE_MODULE_PASS
#ifndef DUMMY_MACHINE_FUNCTION_PASS
#define DUMMY_MACHINE_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR)
#endif
+DUMMY_MACHINE_FUNCTION_PASS("bbsections-prepare", BasicBlockSectionsPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("bbsections-profile-reader",
+ BasicBlockSectionsProfileReaderPass, (Buf))
DUMMY_MACHINE_FUNCTION_PASS("block-placement", MachineBlockPlacementPass, ())
DUMMY_MACHINE_FUNCTION_PASS("block-placement-stats",
MachineBlockPlacementStatsPass, ())
DUMMY_MACHINE_FUNCTION_PASS("branch-folder", BranchFolderPass, ())
DUMMY_MACHINE_FUNCTION_PASS("break-false-deps", BreakFalseDepsPass, ())
DUMMY_MACHINE_FUNCTION_PASS("cfguard-longjmp", CFGuardLongjmpPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("cfi-fixup", CFIFixupPass, ())
DUMMY_MACHINE_FUNCTION_PASS("cfi-instr-inserter", CFIInstrInserterPass, ())
DUMMY_MACHINE_FUNCTION_PASS("dead-mi-elimination",
DeadMachineInstructionElimPass, ())
@@ -165,12 +176,18 @@ DUMMY_MACHINE_FUNCTION_PASS("early-machinelicm", EarlyMachineLICMPass, ())
DUMMY_MACHINE_FUNCTION_PASS("early-tailduplication", EarlyTailDuplicatePass, ())
DUMMY_MACHINE_FUNCTION_PASS("fentry-insert", FEntryInserterPass, ())
DUMMY_MACHINE_FUNCTION_PASS("finalize-isel", FinalizeISelPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("fixup-statepoint-caller-saved",
+ FixupStatepointCallerSavedPass, ())
DUMMY_MACHINE_FUNCTION_PASS("free-machine-function", FreeMachineFunctionPass,
())
+DUMMY_MACHINE_FUNCTION_PASS("fs-profile-loader", MIRProfileLoaderNewPass,
+ (File, ProfileFile, P, FS))
DUMMY_MACHINE_FUNCTION_PASS("funclet-layout", FuncletLayoutPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("gc-empty-basic-blocks", GCEmptyBasicBlocksPass, ())
DUMMY_MACHINE_FUNCTION_PASS("implicit-null-checks", ImplicitNullChecksPass, ())
DUMMY_MACHINE_FUNCTION_PASS("instruction-select", InstructionSelectPass, ())
DUMMY_MACHINE_FUNCTION_PASS("irtranslator", IRTranslatorPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("kcfi", MachineKCFIPass, ())
DUMMY_MACHINE_FUNCTION_PASS("legalizer", LegalizerPass, ())
DUMMY_MACHINE_FUNCTION_PASS("livedebugvalues", LiveDebugValuesPass, ())
DUMMY_MACHINE_FUNCTION_PASS("liveintervals", LiveIntervalsPass, ())
@@ -179,6 +196,8 @@ DUMMY_MACHINE_FUNCTION_PASS("lrshrink", LiveRangeShrinkPass, ())
DUMMY_MACHINE_FUNCTION_PASS("machine-combiner", MachineCombinerPass, ())
DUMMY_MACHINE_FUNCTION_PASS("machine-cp", MachineCopyPropagationPass, ())
DUMMY_MACHINE_FUNCTION_PASS("machine-cse", MachineCSEPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("machine-function-splitter",
+ MachineFunctionSplitterPass, ())
DUMMY_MACHINE_FUNCTION_PASS("machine-latecleanup", MachineLateInstrsCleanupPass,
())
DUMMY_MACHINE_FUNCTION_PASS("machine-sanmd", MachineSanitizerBinaryMetadata, ())
@@ -186,9 +205,13 @@ DUMMY_MACHINE_FUNCTION_PASS("machine-scheduler", MachineSchedulerPass, ())
DUMMY_MACHINE_FUNCTION_PASS("machine-sink", MachineSinkingPass, ())
DUMMY_MACHINE_FUNCTION_PASS("machine-uniformity",
MachineUniformityInfoWrapperPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("machineinstr-printer", MachineFunctionPrinterPass,
+ (OS, Banner))
DUMMY_MACHINE_FUNCTION_PASS("machinelicm", MachineLICMPass, ())
-DUMMY_MACHINE_FUNCTION_PASS("machineverifier", MachineVerifierPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("machineverifier", MachineVerifierPass, (Banner))
DUMMY_MACHINE_FUNCTION_PASS("mir-printer", PrintMIRPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("mirfs-discriminators", MIRAddFSDiscriminatorsPass,
+ (P))
DUMMY_MACHINE_FUNCTION_PASS("opt-phis", OptimizePHIsPass, ())
DUMMY_MACHINE_FUNCTION_PASS("patchable-function", PatchableFunctionPass, ())
DUMMY_MACHINE_FUNCTION_PASS("peephole-opt", PeepholeOptimizerPass, ())
@@ -203,6 +226,8 @@ DUMMY_MACHINE_FUNCTION_PASS("print-machine-uniformity",
MachineUniformityInfoPrinterPass, ())
DUMMY_MACHINE_FUNCTION_PASS("processimpdefs", ProcessImplicitDefsPass, ())
DUMMY_MACHINE_FUNCTION_PASS("prologepilog", PrologEpilogInserterPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("prologepilog-code", PrologEpilogCodeInserterPass,
+ ())
DUMMY_MACHINE_FUNCTION_PASS("ra-basic", RABasicPass, ())
DUMMY_MACHINE_FUNCTION_PASS("ra-fast", RAFastPass, ())
DUMMY_MACHINE_FUNCTION_PASS("ra-greedy", RAGreedyPass, ())
@@ -212,6 +237,7 @@ DUMMY_MACHINE_FUNCTION_PASS("reg-usage-collector", RegUsageInfoCollectorPass,
DUMMY_MACHINE_FUNCTION_PASS("reg-usage-propagation",
RegUsageInfoPropagationPass, ())
DUMMY_MACHINE_FUNCTION_PASS("regalloc", RegAllocPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("regallocscoringpass", RegAllocScoringPass, ())
DUMMY_MACHINE_FUNCTION_PASS("regbankselect", RegBankSelectPass, ())
DUMMY_MACHINE_FUNCTION_PASS("removeredundantdebugvalues",
RemoveRedundantDebugValuesPass, ())
@@ -223,11 +249,21 @@ DUMMY_MACHINE_FUNCTION_PASS("shrink-wrap", ShrinkWrapPass, ())
DUMMY_MACHINE_FUNCTION_PASS("simple-register-coalescing", RegisterCoalescerPass,
())
DUMMY_MACHINE_FUNCTION_PASS("stack-coloring", StackColoringPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("stack-frame-layout", StackFrameLayoutAnalysisPass,
+ ())
DUMMY_MACHINE_FUNCTION_PASS("stack-slot-coloring", StackSlotColoringPass, ())
DUMMY_MACHINE_FUNCTION_PASS("stackmap-liveness", StackMapLivenessPass, ())
DUMMY_MACHINE_FUNCTION_PASS("tailduplication", TailDuplicatePass, ())
DUMMY_MACHINE_FUNCTION_PASS("twoaddressinstruction", TwoAddressInstructionPass,
())
+DUMMY_MACHINE_FUNCTION_PASS("unpack-mi-bundles", UnpackMachineBundlesPass,
+ (Ftor))
DUMMY_MACHINE_FUNCTION_PASS("virtregrewriter", VirtRegRewriterPass, ())
DUMMY_MACHINE_FUNCTION_PASS("xray-instrumentation", XRayInstrumentationPass, ())
#undef DUMMY_MACHINE_FUNCTION_PASS
+
+#ifndef DUMMY_MACHINE_FUNCTION_ANALYSIS
+#define DUMMY_MACHINE_FUNCTION_ANALYSIS(NAME, PASS_NAME, CONSTRUCTOR)
+#endif
+DUMMY_MACHINE_FUNCTION_ANALYSIS("gc-analysis", GCMachineCodeAnalysisPass, ())
+#undef DUMMY_MACHINE_FUNCTION_ANALYSIS
diff --git a/llvm/include/llvm/CodeGen/MacroFusion.h b/llvm/include/llvm/CodeGen/MacroFusion.h
index ea2c7a5faae3..a359fca60426 100644
--- a/llvm/include/llvm/CodeGen/MacroFusion.h
+++ b/llvm/include/llvm/CodeGen/MacroFusion.h
@@ -14,7 +14,7 @@
#ifndef LLVM_CODEGEN_MACROFUSION_H
#define LLVM_CODEGEN_MACROFUSION_H
-#include <functional>
+#include "llvm/ADT/ArrayRef.h"
#include <memory>
namespace llvm {
@@ -29,10 +29,10 @@ class SUnit;
/// Check if the instr pair, FirstMI and SecondMI, should be fused
/// together. Given SecondMI, when FirstMI is unspecified, then check if
/// SecondMI may be part of a fused pair at all.
-using ShouldSchedulePredTy = std::function<bool(const TargetInstrInfo &TII,
- const TargetSubtargetInfo &TSI,
- const MachineInstr *FirstMI,
- const MachineInstr &SecondMI)>;
+using MacroFusionPredTy = bool (*)(const TargetInstrInfo &TII,
+ const TargetSubtargetInfo &STI,
+ const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI);
/// Checks if the number of cluster edges between SU and its predecessors is
/// less than FuseLimit
@@ -48,15 +48,17 @@ bool fuseInstructionPair(ScheduleDAGInstrs &DAG, SUnit &FirstSU,
/// Create a DAG scheduling mutation to pair instructions back to back
/// for instructions that benefit according to the target-specific
-/// shouldScheduleAdjacent predicate function.
+/// predicate functions. shouldScheduleAdjacent will be true if any of the
+/// provided predicates are true.
std::unique_ptr<ScheduleDAGMutation>
-createMacroFusionDAGMutation(ShouldSchedulePredTy shouldScheduleAdjacent);
+createMacroFusionDAGMutation(ArrayRef<MacroFusionPredTy> Predicates);
/// Create a DAG scheduling mutation to pair branch instructions with one
/// of their predecessors back to back for instructions that benefit according
-/// to the target-specific shouldScheduleAdjacent predicate function.
+/// to the target-specific predicate functions. shouldScheduleAdjacent will be
+/// true if any of the provided predicates are true.
std::unique_ptr<ScheduleDAGMutation>
-createBranchMacroFusionDAGMutation(ShouldSchedulePredTy shouldScheduleAdjacent);
+createBranchMacroFusionDAGMutation(ArrayRef<MacroFusionPredTy> Predicates);
} // end namespace llvm
diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index 712048017bca..ca9fbb1def76 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -324,10 +324,6 @@ namespace llvm {
/// branch folding).
extern char &GCMachineCodeAnalysisID;
- /// Creates a pass to print GC metadata.
- ///
- FunctionPass *createGCInfoPrinter(raw_ostream &OS);
-
/// MachineCSE - This pass performs global CSE on machine instructions.
extern char &MachineCSEID;
@@ -524,7 +520,7 @@ namespace llvm {
FunctionPass *createExpandLargeFpConvertPass();
// This pass expands memcmp() to load/stores.
- FunctionPass *createExpandMemCmpPass();
+ FunctionPass *createExpandMemCmpLegacyPass();
/// Creates Break False Dependencies pass. \see BreakFalseDeps.cpp
FunctionPass *createBreakFalseDeps();
diff --git a/llvm/include/llvm/CodeGen/SchedulerRegistry.h b/llvm/include/llvm/CodeGen/SchedulerRegistry.h
index 0c356e62ae4e..cf648d1316c9 100644
--- a/llvm/include/llvm/CodeGen/SchedulerRegistry.h
+++ b/llvm/include/llvm/CodeGen/SchedulerRegistry.h
@@ -63,7 +63,7 @@ public:
ScheduleDAGSDNodes *createBURRListDAGScheduler(SelectionDAGISel *IS,
CodeGenOptLevel OptLevel);
-/// createBURRListDAGScheduler - This creates a bottom up list scheduler that
+/// createSourceListDAGScheduler - This creates a bottom up list scheduler that
/// schedules nodes in source code order when possible.
ScheduleDAGSDNodes *createSourceListDAGScheduler(SelectionDAGISel *IS,
CodeGenOptLevel OptLevel);
diff --git a/llvm/include/llvm/CodeGen/SelectOptimize.h b/llvm/include/llvm/CodeGen/SelectOptimize.h
new file mode 100644
index 000000000000..37024a154145
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/SelectOptimize.h
@@ -0,0 +1,34 @@
+//===--- llvm/CodeGen/SelectOptimize.h ---------------------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the SelectOptimizePass class,
+/// its corresponding pass name is `select-optimize`.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_SELECTOPTIMIZE_H
+#define LLVM_CODEGEN_SELECTOPTIMIZE_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class TargetMachine;
+
+class SelectOptimizePass : public PassInfoMixin<SelectOptimizePass> {
+ const TargetMachine *TM;
+
+public:
+ explicit SelectOptimizePass(const TargetMachine *TM) : TM(TM) {}
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_SELECTOPTIMIZE_H
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGISel.h b/llvm/include/llvm/CodeGen/SelectionDAGISel.h
index aa71be5d1960..c604e7eaa088 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGISel.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGISel.h
@@ -143,6 +143,15 @@ public:
OPC_MoveChild5,
OPC_MoveChild6,
OPC_MoveChild7,
+ OPC_MoveSibling,
+ OPC_MoveSibling0,
+ OPC_MoveSibling1,
+ OPC_MoveSibling2,
+ OPC_MoveSibling3,
+ OPC_MoveSibling4,
+ OPC_MoveSibling5,
+ OPC_MoveSibling6,
+ OPC_MoveSibling7,
OPC_MoveParent,
OPC_CheckSame,
OPC_CheckChild0Same,
@@ -156,6 +165,9 @@ public:
OPC_CheckOpcode,
OPC_SwitchOpcode,
OPC_CheckType,
+ // Space-optimized forms that implicitly encode VT.
+ OPC_CheckTypeI32,
+ OPC_CheckTypeI64,
OPC_CheckTypeRes,
OPC_SwitchType,
OPC_CheckChild0Type,
@@ -166,6 +178,25 @@ public:
OPC_CheckChild5Type,
OPC_CheckChild6Type,
OPC_CheckChild7Type,
+
+ OPC_CheckChild0TypeI32,
+ OPC_CheckChild1TypeI32,
+ OPC_CheckChild2TypeI32,
+ OPC_CheckChild3TypeI32,
+ OPC_CheckChild4TypeI32,
+ OPC_CheckChild5TypeI32,
+ OPC_CheckChild6TypeI32,
+ OPC_CheckChild7TypeI32,
+
+ OPC_CheckChild0TypeI64,
+ OPC_CheckChild1TypeI64,
+ OPC_CheckChild2TypeI64,
+ OPC_CheckChild3TypeI64,
+ OPC_CheckChild4TypeI64,
+ OPC_CheckChild5TypeI64,
+ OPC_CheckChild6TypeI64,
+ OPC_CheckChild7TypeI64,
+
OPC_CheckInteger,
OPC_CheckChild0Integer,
OPC_CheckChild1Integer,
@@ -194,23 +225,59 @@ public:
OPC_EmitRegister,
OPC_EmitRegister2,
OPC_EmitConvertToTarget,
+ OPC_EmitConvertToTarget0,
+ OPC_EmitConvertToTarget1,
+ OPC_EmitConvertToTarget2,
+ OPC_EmitConvertToTarget3,
+ OPC_EmitConvertToTarget4,
+ OPC_EmitConvertToTarget5,
+ OPC_EmitConvertToTarget6,
+ OPC_EmitConvertToTarget7,
OPC_EmitMergeInputChains,
OPC_EmitMergeInputChains1_0,
OPC_EmitMergeInputChains1_1,
OPC_EmitMergeInputChains1_2,
OPC_EmitCopyToReg,
+ OPC_EmitCopyToReg0,
+ OPC_EmitCopyToReg1,
OPC_EmitCopyToReg2,
+ OPC_EmitCopyToReg3,
+ OPC_EmitCopyToReg4,
+ OPC_EmitCopyToReg5,
+ OPC_EmitCopyToReg6,
+ OPC_EmitCopyToReg7,
+ OPC_EmitCopyToRegTwoByte,
OPC_EmitNodeXForm,
OPC_EmitNode,
// Space-optimized forms that implicitly encode number of result VTs.
OPC_EmitNode0,
OPC_EmitNode1,
OPC_EmitNode2,
+ // Space-optimized forms that implicitly encode EmitNodeInfo.
+ OPC_EmitNode0None,
+ OPC_EmitNode1None,
+ OPC_EmitNode2None,
+ OPC_EmitNode0Chain,
+ OPC_EmitNode1Chain,
+ OPC_EmitNode2Chain,
OPC_MorphNodeTo,
// Space-optimized forms that implicitly encode number of result VTs.
OPC_MorphNodeTo0,
OPC_MorphNodeTo1,
OPC_MorphNodeTo2,
+ // Space-optimized forms that implicitly encode EmitNodeInfo.
+ OPC_MorphNodeTo0None,
+ OPC_MorphNodeTo1None,
+ OPC_MorphNodeTo2None,
+ OPC_MorphNodeTo0Chain,
+ OPC_MorphNodeTo1Chain,
+ OPC_MorphNodeTo2Chain,
+ OPC_MorphNodeTo0GlueInput,
+ OPC_MorphNodeTo1GlueInput,
+ OPC_MorphNodeTo2GlueInput,
+ OPC_MorphNodeTo0GlueOutput,
+ OPC_MorphNodeTo1GlueOutput,
+ OPC_MorphNodeTo2GlueOutput,
OPC_CompleteMatch,
// Contains offset in table for pattern being selected
OPC_Coverage
diff --git a/llvm/include/llvm/CodeGen/SjLjEHPrepare.h b/llvm/include/llvm/CodeGen/SjLjEHPrepare.h
new file mode 100644
index 000000000000..c1fd680ff8af
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/SjLjEHPrepare.h
@@ -0,0 +1,28 @@
+//===-- llvm/CodeGen/SjLjEHPrepare.h -------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_SJLJEHPREPARE_H
+#define LLVM_CODEGEN_SJLJEHPREPARE_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class TargetMachine;
+
+class SjLjEHPreparePass : public PassInfoMixin<SjLjEHPreparePass> {
+ const TargetMachine *TM;
+
+public:
+ explicit SjLjEHPreparePass(const TargetMachine *TM) : TM(TM) {}
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_SJLJEHPREPARE_H
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index 2bbe430dc68d..a113100f04e6 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -1025,6 +1025,11 @@ protected:
return std::nullopt;
}
+ virtual std::optional<DestSourcePair>
+ isCopyLikeInstrImpl(const MachineInstr &MI) const {
+ return std::nullopt;
+ }
+
/// Return true if the given terminator MI is not expected to spill. This
/// sets the live interval as not spillable and adjusts phi node lowering to
/// not introduce copies after the terminator. Use with care, these are
@@ -1050,6 +1055,14 @@ public:
return isCopyInstrImpl(MI);
}
+ // Similar to `isCopyInstr`, but adds non-copy semantics on MIR, but
+ // ultimately generates a copy instruction.
+ std::optional<DestSourcePair> isCopyLikeInstr(const MachineInstr &MI) const {
+ if (auto IsCopyInstr = isCopyInstr(MI))
+ return IsCopyInstr;
+ return isCopyLikeInstrImpl(MI);
+ }
+
bool isFullCopyInstr(const MachineInstr &MI) const {
auto DestSrc = isCopyInstr(MI);
if (!DestSrc)
diff --git a/llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h b/llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h
index a1514d91702b..10613ec57586 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h
@@ -39,7 +39,7 @@ public:
///
/// Invalid or unimplemented markup elements are removed. Some output may be
/// deferred until future filter() or finish() call.
- void filter(StringRef Line);
+ void filter(std::string &&InputLine);
/// Records that the input stream has ended and writes any deferred output.
void finish();
@@ -142,7 +142,7 @@ private:
MarkupParser Parser;
// Current line being filtered.
- StringRef Line;
+ std::string Line;
// A module info line currently being built. This incorporates as much mmap
// information as possible before being emitted.
diff --git a/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h b/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h
index 255932d35cda..8be2c22a93a9 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h
@@ -37,7 +37,7 @@ public:
symbolizeFrame(object::SectionedAddress ModuleOffset) const = 0;
virtual std::vector<object::SectionedAddress>
- findSymbol(StringRef Symbol) const = 0;
+ findSymbol(StringRef Symbol, uint64_t Offset) const = 0;
// Return true if this is a 32-bit x86 PE COFF module.
virtual bool isWin32Module() const = 0;
diff --git a/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h b/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h
index 311fa201d900..5ef513f570b0 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h
@@ -44,7 +44,7 @@ public:
std::vector<DILocal>
symbolizeFrame(object::SectionedAddress ModuleOffset) const override;
std::vector<object::SectionedAddress>
- findSymbol(StringRef Symbol) const override;
+ findSymbol(StringRef Symbol, uint64_t Offset) const override;
// Return true if this is a 32-bit x86 PE COFF module.
bool isWin32Module() const override;
diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
index bc4aa74073a6..11a169cfc20a 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
@@ -105,12 +105,12 @@ public:
symbolizeFrame(ArrayRef<uint8_t> BuildID,
object::SectionedAddress ModuleOffset);
- Expected<std::vector<DILineInfo>> findSymbol(const ObjectFile &Obj,
- StringRef Symbol);
- Expected<std::vector<DILineInfo>> findSymbol(StringRef ModuleName,
- StringRef Symbol);
- Expected<std::vector<DILineInfo>> findSymbol(ArrayRef<uint8_t> BuildID,
- StringRef Symbol);
+ Expected<std::vector<DILineInfo>>
+ findSymbol(const ObjectFile &Obj, StringRef Symbol, uint64_t Offset);
+ Expected<std::vector<DILineInfo>>
+ findSymbol(const std::string &ModuleName, StringRef Symbol, uint64_t Offset);
+ Expected<std::vector<DILineInfo>>
+ findSymbol(ArrayRef<uint8_t> BuildID, StringRef Symbol, uint64_t Offset);
void flush();
@@ -155,8 +155,8 @@ private:
symbolizeFrameCommon(const T &ModuleSpecifier,
object::SectionedAddress ModuleOffset);
template <typename T>
- Expected<std::vector<DILineInfo>> findSymbolCommon(const T &ModuleSpecifier,
- StringRef Symbol);
+ Expected<std::vector<DILineInfo>>
+ findSymbolCommon(const T &ModuleSpecifier, StringRef Symbol, uint64_t Offset);
Expected<SymbolizableModule *> getOrCreateModuleInfo(const ObjectFile &Obj);
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 51413a46dc41..f346cfb2a931 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -195,12 +195,10 @@ struct FixupInfoThumb : public FixupInfoBase {
///
template <EdgeKind_aarch32 Kind> struct FixupInfo {};
-namespace {
struct FixupInfoArmBranch : public FixupInfoArm {
static constexpr uint32_t Opcode = 0x0a000000;
static constexpr uint32_t ImmMask = 0x00ffffff;
};
-} // namespace
template <> struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch {
static constexpr uint32_t OpcodeMask = 0x0f000000;
@@ -214,13 +212,11 @@ template <> struct FixupInfo<Arm_Call> : public FixupInfoArmBranch {
static constexpr uint32_t BitBlx = 0x10000000;
};
-namespace {
struct FixupInfoArmMov : public FixupInfoArm {
static constexpr uint32_t OpcodeMask = 0x0ff00000;
static constexpr uint32_t ImmMask = 0x000f0fff;
static constexpr uint32_t RegMask = 0x0000f000;
};
-} // namespace
template <> struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov {
static constexpr uint32_t Opcode = 0x03400000;
@@ -244,13 +240,11 @@ template <> struct FixupInfo<Thumb_Call> : public FixupInfoThumb {
static constexpr uint16_t LoBitNoBlx = 0x1000;
};
-namespace {
struct FixupInfoThumbMov : public FixupInfoThumb {
static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000};
static constexpr HalfWords ImmMask{0x040f, 0x70ff};
static constexpr HalfWords RegMask{0x0000, 0x0f00};
};
-} // namespace
template <> struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov {
static constexpr HalfWords Opcode{0xf2c0, 0x0000};
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
index 8ab8ff8a0034..923976b182d1 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
@@ -584,6 +584,19 @@ Expected<JITDylibSP> setUpGenericLLVMIRPlatform(LLJIT &J);
/// with the generic IR platform.
Expected<JITDylibSP> setUpInactivePlatform(LLJIT &J);
+/// A Platform-support class that implements initialize / deinitialize by
+/// forwarding to ORC runtime dlopen / dlclose operations.
+class ORCPlatformSupport : public LLJIT::PlatformSupport {
+public:
+ ORCPlatformSupport(orc::LLJIT &J) : J(J) {}
+ Error initialize(orc::JITDylib &JD) override;
+ Error deinitialize(orc::JITDylib &JD) override;
+
+private:
+ orc::LLJIT &J;
+ DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles;
+};
+
} // End namespace orc
} // End namespace llvm
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
index ad205de16213..d9b809ab5b11 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
@@ -47,6 +47,15 @@ public:
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Callable)
};
+ /// Used by setupJITDylib to create MachO header MaterializationUnits for
+ /// JITDylibs.
+ using MachOHeaderMUBuilder =
+ unique_function<std::unique_ptr<MaterializationUnit>(MachOPlatform &MOP)>;
+
+ /// Simple MachO header graph builder.
+ static inline std::unique_ptr<MaterializationUnit>
+ buildSimpleMachOHeaderMU(MachOPlatform &MOP);
+
/// Try to create a MachOPlatform instance, adding the ORC runtime to the
/// given JITDylib.
///
@@ -88,17 +97,23 @@ public:
static Expected<std::unique_ptr<MachOPlatform>>
Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime,
+ MachOHeaderMUBuilder BuildMachOHeaderMU = buildSimpleMachOHeaderMU,
std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
/// Construct using a path to the ORC runtime.
static Expected<std::unique_ptr<MachOPlatform>>
Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
+ MachOHeaderMUBuilder BuildMachOHeaderMU = buildSimpleMachOHeaderMU,
std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
ExecutionSession &getExecutionSession() const { return ES; }
ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
+ NonOwningSymbolStringPtr getMachOHeaderStartSymbol() const {
+ return NonOwningSymbolStringPtr(MachOHeaderStartSymbol);
+ }
+
Error setupJITDylib(JITDylib &JD) override;
Error teardownJITDylib(JITDylib &JD) override;
Error notifyAdding(ResourceTracker &RT,
@@ -243,7 +258,7 @@ private:
MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD,
std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
- Error &Err);
+ MachOHeaderMUBuilder BuildMachOHeaderMU, Error &Err);
// Associate MachOPlatform JIT-side runtime support functions with handlers.
Error associateRuntimeSupportFunctions();
@@ -271,6 +286,7 @@ private:
ExecutionSession &ES;
JITDylib &PlatformJD;
ObjectLinkingLayer &ObjLinkingLayer;
+ MachOHeaderMUBuilder BuildMachOHeaderMU;
SymbolStringPtr MachOHeaderStartSymbol = ES.intern("___dso_handle");
@@ -317,6 +333,49 @@ private:
std::atomic<BootstrapInfo *> Bootstrap;
};
+// Generates a MachO header.
+class SimpleMachOHeaderMU : public MaterializationUnit {
+public:
+ SimpleMachOHeaderMU(MachOPlatform &MOP, SymbolStringPtr HeaderStartSymbol);
+ StringRef getName() const override { return "MachOHeaderMU"; }
+ void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
+ void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override;
+
+protected:
+ virtual jitlink::Block &createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G,
+ jitlink::Section &HeaderSection);
+
+ MachOPlatform &MOP;
+
+private:
+ struct HeaderSymbol {
+ const char *Name;
+ uint64_t Offset;
+ };
+
+ static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
+ {"___mh_executable_header", 0}};
+
+ void addMachOHeader(JITDylib &JD, jitlink::LinkGraph &G,
+ const SymbolStringPtr &InitializerSymbol);
+ static MaterializationUnit::Interface
+ createHeaderInterface(MachOPlatform &MOP,
+ const SymbolStringPtr &HeaderStartSymbol);
+};
+
+/// Simple MachO header graph builder.
+inline std::unique_ptr<MaterializationUnit>
+MachOPlatform::buildSimpleMachOHeaderMU(MachOPlatform &MOP) {
+ return std::make_unique<SimpleMachOHeaderMU>(MOP, MOP.MachOHeaderStartSymbol);
+}
+
+struct MachOHeaderInfo {
+ size_t PageSize = 0;
+ uint32_t CPUType = 0;
+ uint32_t CPUSubType = 0;
+};
+MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT);
+
} // end namespace orc
} // end namespace llvm
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
index 997ddccd687a..eedecaea4e58 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
@@ -59,15 +59,16 @@ class FrontendResource {
public:
FrontendResource(MDNode *E) : Entry(E) {
- assert(Entry->getNumOperands() == 5 && "Unexpected metadata shape");
+ assert(Entry->getNumOperands() == 6 && "Unexpected metadata shape");
}
FrontendResource(GlobalVariable *GV, StringRef TypeStr, ResourceKind RK,
- uint32_t ResIndex, uint32_t Space);
+ bool IsROV, uint32_t ResIndex, uint32_t Space);
GlobalVariable *getGlobalVariable();
StringRef getSourceType();
ResourceKind getResourceKind();
+ bool getIsROV();
uint32_t getResourceIndex();
uint32_t getSpace();
MDNode *getMetadata() { return Entry; }
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index fc38e68ad273..864f87f33838 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -151,6 +151,9 @@ def NoDuplicate : EnumAttr<"noduplicate", [FnAttr]>;
/// Function does not deallocate memory.
def NoFree : EnumAttr<"nofree", [FnAttr, ParamAttr]>;
+/// Argument is dead if the call unwinds.
+def DeadOnUnwind : EnumAttr<"dead_on_unwind", [ParamAttr]>;
+
/// Disable implicit floating point insts.
def NoImplicitFloat : EnumAttr<"noimplicitfloat", [FnAttr]>;
diff --git a/llvm/include/llvm/IR/DebugInfo.h b/llvm/include/llvm/IR/DebugInfo.h
index 2a581eb5f09d..36ef77f9505b 100644
--- a/llvm/include/llvm/IR/DebugInfo.h
+++ b/llvm/include/llvm/IR/DebugInfo.h
@@ -40,7 +40,8 @@ class Module;
/// Finds dbg.declare intrinsics declaring local variables as living in the
/// memory that 'V' points to.
-TinyPtrVector<DbgDeclareInst *> FindDbgDeclareUses(Value *V);
+void findDbgDeclares(SmallVectorImpl<DbgDeclareInst *> &DbgUsers, Value *V,
+ SmallVectorImpl<DPValue *> *DPValues = nullptr);
/// Finds the llvm.dbg.value intrinsics describing a value.
void findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues,
diff --git a/llvm/include/llvm/IR/DebugProgramInstruction.h b/llvm/include/llvm/IR/DebugProgramInstruction.h
index d6b4536a2a07..8230070343e0 100644
--- a/llvm/include/llvm/IR/DebugProgramInstruction.h
+++ b/llvm/include/llvm/IR/DebugProgramInstruction.h
@@ -97,6 +97,9 @@ public:
enum class LocationType {
Declare,
Value,
+
+ End, ///< Marks the end of the concrete types.
+ Any, ///< To indicate all LocationTypes in searches.
};
/// Classification of the debug-info record that this DPValue represents.
/// Essentially, "is this a dbg.value or dbg.declare?". dbg.declares are not
@@ -113,7 +116,7 @@ public:
/// Directly construct a new DPValue representing a dbg.value intrinsic
/// assigning \p Location to the DV / Expr / DI variable.
DPValue(Metadata *Location, DILocalVariable *DV, DIExpression *Expr,
- const DILocation *DI);
+ const DILocation *DI, LocationType Type = LocationType::Value);
/// Iterator for ValueAsMetadata that internally uses direct pointer iteration
/// over either a ValueAsMetadata* or a ValueAsMetadata**, dereferencing to the
diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td
index 83fc208e7f7e..9088168b4c67 100644
--- a/llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -1401,6 +1401,13 @@ class AdvSIMD_SVE_Reduce_Intrinsic
llvm_anyvector_ty],
[IntrNoMem]>;
+class AdvSIMD_SVE_V128_Reduce_Intrinsic
+ : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
+ [LLVMScalarOrSameVectorWidth<1, llvm_i1_ty>,
+ llvm_anyvector_ty],
+ [IntrNoMem]>;
+
+
class AdvSIMD_SVE_SADDV_Reduce_Intrinsic
: DefaultAttrsIntrinsic<[llvm_i64_ty],
[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>,
@@ -1723,6 +1730,15 @@ def int_aarch64_sve_sqsub_x : AdvSIMD_2VectorArg_Intrinsic;
def int_aarch64_sve_uqadd_x : AdvSIMD_2VectorArg_Intrinsic;
def int_aarch64_sve_uqsub_x : AdvSIMD_2VectorArg_Intrinsic;
+def int_aarch64_sve_orqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_eorqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_andqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_smaxqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_umaxqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_sminqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_uminqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+
+
// Shifts
def int_aarch64_sve_asr : AdvSIMD_Pred2VectorArg_Intrinsic;
@@ -2033,6 +2049,11 @@ def int_aarch64_sve_fmaxv : AdvSIMD_SVE_Reduce_Intrinsic;
def int_aarch64_sve_fmaxnmv : AdvSIMD_SVE_Reduce_Intrinsic;
def int_aarch64_sve_fminv : AdvSIMD_SVE_Reduce_Intrinsic;
def int_aarch64_sve_fminnmv : AdvSIMD_SVE_Reduce_Intrinsic;
+def int_aarch64_sve_addqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_fmaxnmqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_fminnmqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_fmaxqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
+def int_aarch64_sve_fminqv : AdvSIMD_SVE_V128_Reduce_Intrinsic;
//
// Floating-point conversions
diff --git a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
index bc9f99783d98..51bd9b63c127 100644
--- a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
+++ b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
@@ -227,6 +227,45 @@ def int_amdgcn_s_sendmsg_rtn : Intrinsic <[llvm_anyint_ty], [llvm_i32_ty],
def int_amdgcn_s_barrier : ClangBuiltin<"__builtin_amdgcn_s_barrier">,
Intrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent, IntrWillReturn, IntrNoCallback, IntrNoFree]>;
+def int_amdgcn_s_barrier_signal : ClangBuiltin<"__builtin_amdgcn_s_barrier_signal">,
+ Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>, IntrNoMem, IntrHasSideEffects, IntrConvergent, IntrWillReturn,
+ IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_s_barrier_signal_var : ClangBuiltin<"__builtin_amdgcn_s_barrier_signal_var">,
+ Intrinsic<[], [llvm_i32_ty], [IntrNoMem, IntrHasSideEffects, IntrConvergent, IntrWillReturn,
+ IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_s_barrier_signal_isfirst : ClangBuiltin<"__builtin_amdgcn_s_barrier_signal_isfirst">,
+ Intrinsic<[llvm_i1_ty], [llvm_i32_ty], [ImmArg<ArgIndex<0>>, IntrNoMem, IntrHasSideEffects, IntrConvergent,
+ IntrWillReturn, IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_s_barrier_signal_isfirst_var : ClangBuiltin<"__builtin_amdgcn_s_barrier_signal_isfirst_var">,
+ Intrinsic<[llvm_i1_ty], [llvm_i32_ty], [IntrNoMem, IntrHasSideEffects, IntrConvergent, IntrWillReturn,
+ IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_s_barrier_init : ClangBuiltin<"__builtin_amdgcn_s_barrier_init">,
+ Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrHasSideEffects, IntrConvergent,
+ IntrWillReturn, IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_s_barrier_join : ClangBuiltin<"__builtin_amdgcn_s_barrier_join">,
+ Intrinsic<[], [llvm_i32_ty], [IntrNoMem, IntrHasSideEffects, IntrConvergent, IntrWillReturn,
+ IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_s_wakeup_barrier : ClangBuiltin<"__builtin_amdgcn_s_wakeup_barrier">,
+ Intrinsic<[], [llvm_i32_ty], [IntrNoMem, IntrHasSideEffects, IntrConvergent, IntrWillReturn,
+ IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_s_barrier_wait : ClangBuiltin<"__builtin_amdgcn_s_barrier_wait">,
+ Intrinsic<[], [llvm_i16_ty], [ImmArg<ArgIndex<0>>, IntrNoMem, IntrHasSideEffects, IntrConvergent,
+ IntrWillReturn, IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_s_barrier_leave : ClangBuiltin<"__builtin_amdgcn_s_barrier_leave">,
+ Intrinsic<[llvm_i1_ty], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent, IntrWillReturn, IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_s_get_barrier_state : ClangBuiltin<"__builtin_amdgcn_s_get_barrier_state">,
+ Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrHasSideEffects, IntrConvergent, IntrWillReturn,
+ IntrNoCallback, IntrNoFree]>;
+
def int_amdgcn_wave_barrier : ClangBuiltin<"__builtin_amdgcn_wave_barrier">,
Intrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent, IntrWillReturn, IntrNoCallback, IntrNoFree]>;
@@ -806,7 +845,9 @@ class AMDGPUImageDimIntrinsic<AMDGPUDimProfile P_,
!if(P_.IsSample, [llvm_v4i32_ty, // samp(SGPR)
llvm_i1_ty], []), // unorm(imm)
[llvm_i32_ty, // texfailctrl(imm; bit 0 = tfe, bit 1 = lwe)
- llvm_i32_ty]), // cachepolicy(imm; bit 0 = glc, bit 1 = slc, bit 2 = dlc)
+ llvm_i32_ty]), // cachepolicy(imm; bit 0 = glc, bit 1 = slc, bit 2 = dlc;
+ // gfx12+ imm: bits [0-2] = th, bits [3-4] = scope)
+ // TODO-GFX12: Update all other cachepolicy descriptions.
!listconcat(props,
!if(P_.IsAtomic, [], [ImmArg<ArgIndex<AMDGPUImageDimIntrinsicEval<P_>.DmaskArgIndex>>]),
@@ -1676,6 +1717,12 @@ def int_amdgcn_s_sleep :
IntrHasSideEffects]> {
}
+def int_amdgcn_s_sleep_var
+ : ClangBuiltin<"__builtin_amdgcn_s_sleep_var">,
+ Intrinsic<[], [llvm_i32_ty],
+ [IntrNoMem, IntrHasSideEffects, IntrWillReturn]> {
+}
+
def int_amdgcn_s_nop :
DefaultAttrsIntrinsic<[], [llvm_i16_ty], [ImmArg<ArgIndex<0>>, IntrNoMem,
IntrHasSideEffects]> {
@@ -2422,6 +2469,29 @@ def int_amdgcn_s_wait_event_export_ready :
>;
//===----------------------------------------------------------------------===//
+// GFX12 Intrinsics
+//===----------------------------------------------------------------------===//
+
+// llvm.amdgcn.permlane16.var <old> <src0> <src1> <fi> <bound_control>
+def int_amdgcn_permlane16_var : ClangBuiltin<"__builtin_amdgcn_permlane16_var">,
+ Intrinsic<[llvm_i32_ty],
+ [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i1_ty, llvm_i1_ty],
+ [IntrNoMem, IntrConvergent, IntrWillReturn,
+ ImmArg<ArgIndex<3>>, ImmArg<ArgIndex<4>>, IntrNoCallback, IntrNoFree]>;
+
+// llvm.amdgcn.permlanex16.var <old> <src0> <src1> <fi> <bound_control>
+def int_amdgcn_permlanex16_var : ClangBuiltin<"__builtin_amdgcn_permlanex16_var">,
+ Intrinsic<[llvm_i32_ty],
+ [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i1_ty, llvm_i1_ty],
+ [IntrNoMem, IntrConvergent, IntrWillReturn,
+ ImmArg<ArgIndex<3>>, ImmArg<ArgIndex<4>>, IntrNoCallback, IntrNoFree]>;
+
+def int_amdgcn_flat_atomic_fmin_num : AMDGPUGlobalAtomicRtn<llvm_anyfloat_ty>;
+def int_amdgcn_flat_atomic_fmax_num : AMDGPUGlobalAtomicRtn<llvm_anyfloat_ty>;
+def int_amdgcn_global_atomic_fmin_num : AMDGPUGlobalAtomicRtn<llvm_anyfloat_ty>;
+def int_amdgcn_global_atomic_fmax_num : AMDGPUGlobalAtomicRtn<llvm_anyfloat_ty>;
+
+//===----------------------------------------------------------------------===//
// Deep learning intrinsics.
//===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index 20c6a525a86b..fc830fca392f 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -1879,3 +1879,4 @@ let TargetPrefix = "riscv" in {
//===----------------------------------------------------------------------===//
include "llvm/IR/IntrinsicsRISCVXTHead.td"
include "llvm/IR/IntrinsicsRISCVXsf.td"
+include "llvm/IR/IntrinsicsRISCVXCV.td"
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td b/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td
new file mode 100644
index 000000000000..f1590ad66e36
--- /dev/null
+++ b/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td
@@ -0,0 +1,37 @@
+//===- IntrinsicsRISCVXCV.td - CORE-V intrinsics -----------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines all of the CORE-V vendor intrinsics for RISC-V.
+//
+//===----------------------------------------------------------------------===//
+
+class ScalarCoreVBitManipGprGprIntrinsic
+ : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty],
+ [IntrNoMem, IntrSpeculatable]>;
+
+class ScalarCoreVBitManipGprIntrinsic
+ : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty],
+ [IntrNoMem, IntrSpeculatable]>;
+
+let TargetPrefix = "riscv" in {
+ def int_riscv_cv_bitmanip_extract : ScalarCoreVBitManipGprGprIntrinsic;
+ def int_riscv_cv_bitmanip_extractu : ScalarCoreVBitManipGprGprIntrinsic;
+ def int_riscv_cv_bitmanip_bclr : ScalarCoreVBitManipGprGprIntrinsic;
+ def int_riscv_cv_bitmanip_bset : ScalarCoreVBitManipGprGprIntrinsic;
+
+ def int_riscv_cv_bitmanip_insert
+ : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
+ [IntrNoMem, IntrSpeculatable]>;
+
+ def int_riscv_cv_bitmanip_clb : ScalarCoreVBitManipGprIntrinsic;
+
+ def int_riscv_cv_bitmanip_bitrev
+ : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
+ [IntrNoMem, IntrWillReturn, IntrSpeculatable,
+ ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<2>>]>;
+} // TargetPrefix = "riscv"
diff --git a/llvm/include/llvm/IR/IntrinsicsSystemZ.td b/llvm/include/llvm/IR/IntrinsicsSystemZ.td
index a9d80ee5a5c7..9f4b905fedc7 100644
--- a/llvm/include/llvm/IR/IntrinsicsSystemZ.td
+++ b/llvm/include/llvm/IR/IntrinsicsSystemZ.td
@@ -114,7 +114,7 @@ multiclass SystemZBinaryExtBHF<string name> {
}
multiclass SystemZBinaryExtBHFG<string name> : SystemZBinaryExtBHF<name> {
- def g : SystemZBinaryConv<name#"g", llvm_v16i8_ty, llvm_v2i64_ty>;
+ def g : SystemZBinaryConv<name#"g", llvm_i128_ty, llvm_v2i64_ty>;
}
multiclass SystemZBinaryBHF<string name> {
@@ -147,7 +147,7 @@ multiclass SystemZTernaryExtBHF<string name> {
}
multiclass SystemZTernaryExtBHFG<string name> : SystemZTernaryExtBHF<name> {
- def g : SystemZTernaryConv<name#"g", llvm_v16i8_ty, llvm_v2i64_ty>;
+ def g : SystemZTernaryConv<name#"g", llvm_i128_ty, llvm_v2i64_ty>;
}
multiclass SystemZTernaryBHF<string name> {
@@ -265,10 +265,10 @@ let TargetPrefix = "s390" in {
defm int_s390_vacc : SystemZBinaryBHFG<"vacc">;
- def int_s390_vaq : SystemZBinary<"vaq", llvm_v16i8_ty>;
- def int_s390_vacq : SystemZTernary<"vacq", llvm_v16i8_ty>;
- def int_s390_vaccq : SystemZBinary<"vaccq", llvm_v16i8_ty>;
- def int_s390_vacccq : SystemZTernary<"vacccq", llvm_v16i8_ty>;
+ def int_s390_vaq : SystemZBinary<"vaq", llvm_i128_ty>;
+ def int_s390_vacq : SystemZTernary<"vacq", llvm_i128_ty>;
+ def int_s390_vaccq : SystemZBinary<"vaccq", llvm_i128_ty>;
+ def int_s390_vacccq : SystemZTernary<"vacccq", llvm_i128_ty>;
defm int_s390_vavg : SystemZBinaryBHFG<"vavg">;
defm int_s390_vavgl : SystemZBinaryBHFG<"vavgl">;
@@ -308,10 +308,10 @@ let TargetPrefix = "s390" in {
defm int_s390_vscbi : SystemZBinaryBHFG<"vscbi">;
- def int_s390_vsq : SystemZBinary<"vsq", llvm_v16i8_ty>;
- def int_s390_vsbiq : SystemZTernary<"vsbiq", llvm_v16i8_ty>;
- def int_s390_vscbiq : SystemZBinary<"vscbiq", llvm_v16i8_ty>;
- def int_s390_vsbcbiq : SystemZTernary<"vsbcbiq", llvm_v16i8_ty>;
+ def int_s390_vsq : SystemZBinary<"vsq", llvm_i128_ty>;
+ def int_s390_vsbiq : SystemZTernary<"vsbiq", llvm_i128_ty>;
+ def int_s390_vscbiq : SystemZBinary<"vscbiq", llvm_i128_ty>;
+ def int_s390_vsbcbiq : SystemZTernary<"vsbcbiq", llvm_i128_ty>;
def int_s390_vsumb : SystemZBinaryConv<"vsumb", llvm_v4i32_ty, llvm_v16i8_ty>;
def int_s390_vsumh : SystemZBinaryConv<"vsumh", llvm_v4i32_ty, llvm_v8i16_ty>;
@@ -321,9 +321,9 @@ let TargetPrefix = "s390" in {
def int_s390_vsumgf : SystemZBinaryConv<"vsumgf", llvm_v2i64_ty,
llvm_v4i32_ty>;
- def int_s390_vsumqf : SystemZBinaryConv<"vsumqf", llvm_v16i8_ty,
+ def int_s390_vsumqf : SystemZBinaryConv<"vsumqf", llvm_i128_ty,
llvm_v4i32_ty>;
- def int_s390_vsumqg : SystemZBinaryConv<"vsumqg", llvm_v16i8_ty,
+ def int_s390_vsumqg : SystemZBinaryConv<"vsumqg", llvm_i128_ty,
llvm_v2i64_ty>;
def int_s390_vtm : SystemZBinaryConv<"vtm", llvm_i32_ty, llvm_v16i8_ty>;
@@ -370,8 +370,8 @@ let TargetPrefix = "s390" in {
llvm_v16i8_ty>;
def int_s390_vmslg : ClangBuiltin<"__builtin_s390_vmslg">,
- Intrinsic<[llvm_v16i8_ty],
- [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v16i8_ty,
+ Intrinsic<[llvm_i128_ty],
+ [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i128_ty,
llvm_i32_ty], [IntrNoMem, ImmArg<ArgIndex<3>>]>;
def int_s390_vfmaxdb : Intrinsic<[llvm_v2f64_ty],
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 66177f9b9f77..46b1e95c3c15 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -103,7 +103,7 @@ void initializeEdgeBundlesPass(PassRegistry&);
void initializeEHContGuardCatchretPass(PassRegistry &);
void initializeExpandLargeFpConvertLegacyPassPass(PassRegistry&);
void initializeExpandLargeDivRemLegacyPassPass(PassRegistry&);
-void initializeExpandMemCmpPassPass(PassRegistry&);
+void initializeExpandMemCmpLegacyPassPass(PassRegistry &);
void initializeExpandPostRAPass(PassRegistry&);
void initializeExpandReductionsPass(PassRegistry&);
void initializeExpandVectorPredicationPass(PassRegistry &);
@@ -129,7 +129,7 @@ void initializeIVUsersWrapperPassPass(PassRegistry&);
void initializeIfConverterPass(PassRegistry&);
void initializeImmutableModuleSummaryIndexWrapperPassPass(PassRegistry&);
void initializeImplicitNullChecksPass(PassRegistry&);
-void initializeIndirectBrExpandPassPass(PassRegistry&);
+void initializeIndirectBrExpandLegacyPassPass(PassRegistry &);
void initializeInferAddressSpacesPass(PassRegistry&);
void initializeInstSimplifyLegacyPassPass(PassRegistry &);
void initializeInstructionCombiningPassPass(PassRegistry&);
diff --git a/llvm/include/llvm/LinkAllPasses.h b/llvm/include/llvm/LinkAllPasses.h
index bf990a1408fa..7a21876e565a 100644
--- a/llvm/include/llvm/LinkAllPasses.h
+++ b/llvm/include/llvm/LinkAllPasses.h
@@ -119,7 +119,7 @@ namespace {
(void) llvm::createPostDomTree();
(void) llvm::createMergeICmpsLegacyPass();
(void) llvm::createExpandLargeDivRemPass();
- (void) llvm::createExpandMemCmpPass();
+ (void)llvm::createExpandMemCmpLegacyPass();
(void) llvm::createExpandVectorPredicationPass();
std::string buf;
llvm::raw_string_ostream os(buf);
@@ -148,8 +148,7 @@ namespace {
llvm::AliasAnalysis AA(TLI);
llvm::BatchAAResults BAA(AA);
llvm::AliasSetTracker X(BAA);
- X.add(nullptr, llvm::LocationSize::beforeOrAfterPointer(),
- llvm::AAMDNodes()); // for -print-alias-sets
+ X.add(llvm::MemoryLocation()); // for -print-alias-sets
(void) llvm::AreStatisticsEnabled();
(void) llvm::sys::RunningOnValgrind();
}
diff --git a/llvm/include/llvm/MC/MCFragment.h b/llvm/include/llvm/MC/MCFragment.h
index c314fdd3aa69..a9b19dc56f16 100644
--- a/llvm/include/llvm/MC/MCFragment.h
+++ b/llvm/include/llvm/MC/MCFragment.h
@@ -428,7 +428,7 @@ public:
}
};
-class MCLEBFragment final : public MCEncodedFragmentWithFixups<10, 1> {
+class MCLEBFragment final : public MCEncodedFragmentWithFixups<8, 0> {
/// True if this is a sleb128, false if uleb128.
bool IsSigned;
@@ -437,7 +437,7 @@ class MCLEBFragment final : public MCEncodedFragmentWithFixups<10, 1> {
public:
MCLEBFragment(const MCExpr &Value, bool IsSigned, MCSection *Sec = nullptr)
- : MCEncodedFragmentWithFixups<10, 1>(FT_LEB, false, Sec),
+ : MCEncodedFragmentWithFixups<8, 0>(FT_LEB, false, Sec),
IsSigned(IsSigned), Value(&Value) {
getContents().push_back(0);
}
diff --git a/llvm/include/llvm/MC/MCSectionCOFF.h b/llvm/include/llvm/MC/MCSectionCOFF.h
index 373863e21ff0..2faf84f0372c 100644
--- a/llvm/include/llvm/MC/MCSectionCOFF.h
+++ b/llvm/include/llvm/MC/MCSectionCOFF.h
@@ -83,7 +83,7 @@ public:
}
static bool isImplicitlyDiscardable(StringRef Name) {
- return Name.startswith(".debug");
+ return Name.starts_with(".debug");
}
static bool classof(const MCSection *S) { return S->getVariant() == SV_COFF; }
diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h
index e7ce1e6f2c54..386c20aec184 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -214,6 +214,8 @@ struct CommonConfig {
// Cached gnu_debuglink's target CRC
uint32_t GnuDebugLinkCRC32;
std::optional<StringRef> ExtractPartition;
+ uint8_t GapFill = 0;
+ uint64_t PadTo = 0;
StringRef SplitDWO;
StringRef SymbolsPrefix;
StringRef AllocSectionsPrefix;
diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 3fca00592f73..78b6b40cbddf 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -457,8 +457,12 @@ public:
/// within the text section that the SHT_LLVM_BB_ADDR_MAP section \p Sec
/// is associated with. If the current ELFFile is relocatable, a corresponding
/// \p RelaSec must be passed in as an argument.
+ /// Optional out variable to collect all PGO Analyses. New elements are only
+ /// added if no error occurs. If not provided, the PGO Analyses are decoded
+ /// then ignored.
Expected<std::vector<BBAddrMap>>
- decodeBBAddrMap(const Elf_Shdr &Sec, const Elf_Shdr *RelaSec = nullptr) const;
+ decodeBBAddrMap(const Elf_Shdr &Sec, const Elf_Shdr *RelaSec = nullptr,
+ std::vector<PGOAnalysisMap> *PGOAnalyses = nullptr) const;
/// Returns a map from every section matching \p IsMatch to its relocation
/// section, or \p nullptr if it has no relocation section. This function
diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 8e16fc148a3c..de418a1782ac 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -110,9 +110,13 @@ public:
/// Returns a vector of all BB address maps in the object file. When
// `TextSectionIndex` is specified, only returns the BB address maps
- // corresponding to the section with that index.
+ // corresponding to the section with that index. When `PGOAnalyses`is
+ // specified, the vector is cleared then filled with extra PGO data.
+ // `PGOAnalyses` will always be the same length as the return value on
+ // success, otherwise it is empty.
Expected<std::vector<BBAddrMap>>
- readBBAddrMap(std::optional<unsigned> TextSectionIndex = std::nullopt) const;
+ readBBAddrMap(std::optional<unsigned> TextSectionIndex = std::nullopt,
+ std::vector<PGOAnalysisMap> *PGOAnalyses = nullptr) const;
};
class ELFSectionRef : public SectionRef {
@@ -742,7 +746,7 @@ Expected<uint32_t> ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const {
if (EF.getHeader().e_machine == ELF::EM_AARCH64) {
if (Expected<StringRef> NameOrErr = getSymbolName(Sym)) {
StringRef Name = *NameOrErr;
- if (Name.startswith("$d") || Name.startswith("$x"))
+ if (Name.starts_with("$d") || Name.starts_with("$x"))
Result |= SymbolRef::SF_FormatSpecific;
} else {
// TODO: Actually report errors helpfully.
@@ -752,8 +756,8 @@ Expected<uint32_t> ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const {
if (Expected<StringRef> NameOrErr = getSymbolName(Sym)) {
StringRef Name = *NameOrErr;
// TODO Investigate why empty name symbols need to be marked.
- if (Name.empty() || Name.startswith("$d") || Name.startswith("$t") ||
- Name.startswith("$a"))
+ if (Name.empty() || Name.starts_with("$d") || Name.starts_with("$t") ||
+ Name.starts_with("$a"))
Result |= SymbolRef::SF_FormatSpecific;
} else {
// TODO: Actually report errors helpfully.
@@ -764,7 +768,7 @@ Expected<uint32_t> ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const {
} else if (EF.getHeader().e_machine == ELF::EM_CSKY) {
if (Expected<StringRef> NameOrErr = getSymbolName(Sym)) {
StringRef Name = *NameOrErr;
- if (Name.startswith("$d") || Name.startswith("$t"))
+ if (Name.starts_with("$d") || Name.starts_with("$t"))
Result |= SymbolRef::SF_FormatSpecific;
} else {
// TODO: Actually report errors helpfully.
@@ -775,7 +779,7 @@ Expected<uint32_t> ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const {
StringRef Name = *NameOrErr;
// Mark empty name symbols (used for label differences) and mapping
// symbols.
- if (Name.empty() || Name.startswith("$d") || Name.startswith("$x"))
+ if (Name.empty() || Name.starts_with("$d") || Name.starts_with("$x"))
Result |= SymbolRef::SF_FormatSpecific;
} else {
// TODO: Actually report errors helpfully.
@@ -973,8 +977,8 @@ bool ELFObjectFile<ELFT>::isDebugSection(DataRefImpl Sec) const {
return false;
}
StringRef SectionName = SectionNameOrErr.get();
- return SectionName.startswith(".debug") ||
- SectionName.startswith(".zdebug") || SectionName == ".gdb_index";
+ return SectionName.starts_with(".debug") ||
+ SectionName.starts_with(".zdebug") || SectionName == ".gdb_index";
}
template <class ELFT>
diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h
index 4670abc867de..d3351a2d1650 100644
--- a/llvm/include/llvm/Object/ELFTypes.h
+++ b/llvm/include/llvm/Object/ELFTypes.h
@@ -13,6 +13,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/Error.h"
+#include "llvm/Support/BlockFrequency.h"
+#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
@@ -875,6 +877,79 @@ struct BBAddrMap {
std::vector<BBEntry> BBEntries; // Basic block entries for this function.
};
+/// A feature extension of BBAddrMap that holds information relevant to PGO.
+struct PGOAnalysisMap {
+ /// Bitfield of optional features to include in the PGO extended map.
+ struct Features {
+ bool FuncEntryCount : 1;
+ bool BBFreq : 1;
+ bool BrProb : 1;
+
+ // Encodes to minimum bit width representation.
+ uint8_t encode() const {
+ return (static_cast<uint8_t>(FuncEntryCount) << 0) |
+ (static_cast<uint8_t>(BBFreq) << 1) |
+ (static_cast<uint8_t>(BrProb) << 2);
+ }
+
+ // Decodes from minimum bit width representation and validates no
+ // unnecessary bits are used.
+ static Expected<Features> decode(uint8_t Val) {
+ Features Feat{static_cast<bool>(Val & (1 << 0)),
+ static_cast<bool>(Val & (1 << 1)),
+ static_cast<bool>(Val & (1 << 2))};
+ if (Feat.encode() != Val)
+ return createStringError(
+ std::error_code(),
+ "invalid encoding for PGOAnalysisMap::Features: 0x%x", Val);
+ return Feat;
+ }
+
+ bool operator==(const Features &Other) const {
+ return std::tie(FuncEntryCount, BBFreq, BrProb) ==
+ std::tie(Other.FuncEntryCount, Other.BBFreq, Other.BrProb);
+ }
+ };
+
+ /// Extra basic block data with fields for block frequency and branch
+ /// probability.
+ struct PGOBBEntry {
+ /// Single successor of a given basic block that contains the tag and branch
+ /// probability associated with it.
+ struct SuccessorEntry {
+ /// Unique ID of this successor basic block.
+ uint32_t ID;
+ /// Branch Probability of the edge to this successor taken from MBPI.
+ BranchProbability Prob;
+
+ bool operator==(const SuccessorEntry &Other) const {
+ return std::tie(ID, Prob) == std::tie(Other.ID, Other.Prob);
+ }
+ };
+
+ /// Block frequency taken from MBFI
+ BlockFrequency BlockFreq;
+ /// List of successors of the current block
+ llvm::SmallVector<SuccessorEntry, 2> Successors;
+
+ bool operator==(const PGOBBEntry &Other) const {
+ return std::tie(BlockFreq, Successors) ==
+ std::tie(Other.BlockFreq, Other.Successors);
+ }
+ };
+
+ uint64_t FuncEntryCount; // Prof count from IR function
+ std::vector<PGOBBEntry> BBEntries; // Extended basic block entries
+
+ // Flags to indicate if each PGO related info was enabled in this function
+ Features FeatEnable;
+
+ bool operator==(const PGOAnalysisMap &Other) const {
+ return std::tie(FuncEntryCount, BBEntries, FeatEnable) ==
+ std::tie(Other.FuncEntryCount, Other.BBEntries, Other.FeatEnable);
+ }
+};
+
} // end namespace object.
} // end namespace llvm.
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 1ba41232f552..12b47c271da2 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -170,6 +170,19 @@ struct BBAddrMapEntry {
std::optional<std::vector<BBEntry>> BBEntries;
};
+struct PGOAnalysisMapEntry {
+ struct PGOBBEntry {
+ struct SuccessorEntry {
+ uint32_t ID;
+ llvm::yaml::Hex32 BrProb;
+ };
+ std::optional<uint64_t> BBFreq;
+ std::optional<std::vector<SuccessorEntry>> Successors;
+ };
+ std::optional<uint64_t> FuncEntryCount;
+ std::optional<std::vector<PGOBBEntry>> PGOBBEntries;
+};
+
struct StackSizeEntry {
llvm::yaml::Hex64 Address;
llvm::yaml::Hex64 Size;
@@ -317,6 +330,7 @@ struct SectionHeaderTable : Chunk {
struct BBAddrMapSection : Section {
std::optional<std::vector<BBAddrMapEntry>> Entries;
+ std::optional<std::vector<PGOAnalysisMapEntry>> PGOAnalyses;
BBAddrMapSection() : Section(ChunkKind::BBAddrMap) {}
@@ -737,6 +751,10 @@ bool shouldAllocateFileSpace(ArrayRef<ProgramHeader> Phdrs,
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry::BBEntry)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::PGOAnalysisMapEntry)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::PGOAnalysisMapEntry::PGOBBEntry)
+LLVM_YAML_IS_SEQUENCE_VECTOR(
+ llvm::ELFYAML::PGOAnalysisMapEntry::PGOBBEntry::SuccessorEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::LinkerOption)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::CallGraphEntryWeight)
@@ -905,6 +923,21 @@ template <> struct MappingTraits<ELFYAML::BBAddrMapEntry::BBEntry> {
static void mapping(IO &IO, ELFYAML::BBAddrMapEntry::BBEntry &Rel);
};
+template <> struct MappingTraits<ELFYAML::PGOAnalysisMapEntry> {
+ static void mapping(IO &IO, ELFYAML::PGOAnalysisMapEntry &Rel);
+};
+
+template <> struct MappingTraits<ELFYAML::PGOAnalysisMapEntry::PGOBBEntry> {
+ static void mapping(IO &IO, ELFYAML::PGOAnalysisMapEntry::PGOBBEntry &Rel);
+};
+
+template <>
+struct MappingTraits<ELFYAML::PGOAnalysisMapEntry::PGOBBEntry::SuccessorEntry> {
+ static void
+ mapping(IO &IO,
+ ELFYAML::PGOAnalysisMapEntry::PGOBBEntry::SuccessorEntry &Rel);
+};
+
template <> struct MappingTraits<ELFYAML::GnuHashHeader> {
static void mapping(IO &IO, ELFYAML::GnuHashHeader &Rel);
};
diff --git a/llvm/include/llvm/ObjectYAML/GOFFYAML.h b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
new file mode 100644
index 000000000000..f9bf45e95bd3
--- /dev/null
+++ b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
@@ -0,0 +1,49 @@
+//===- GOFFYAML.h - GOFF YAMLIO implementation ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares classes for handling the YAML representation of GOFF.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_GOFFYAML_H
+#define LLVM_OBJECTYAML_GOFFYAML_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/ObjectYAML/YAML.h"
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+
+// The structure of the yaml files is not an exact 1:1 match to GOFF. In order
+// to use yaml::IO, we use these structures which are closer to the source.
+namespace GOFFYAML {
+
+struct FileHeader {
+ uint32_t TargetEnvironment = 0;
+ uint32_t TargetOperatingSystem = 0;
+ uint16_t CCSID = 0;
+ StringRef CharacterSetName;
+ StringRef LanguageProductIdentifier;
+ uint32_t ArchitectureLevel = 0;
+ std::optional<uint16_t> InternalCCSID;
+ std::optional<uint8_t> TargetSoftwareEnvironment;
+};
+
+struct Object {
+ FileHeader Header;
+ Object();
+};
+} // end namespace GOFFYAML
+} // end namespace llvm
+
+LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::FileHeader)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Object)
+
+#endif // LLVM_OBJECTYAML_GOFFYAML_H
diff --git a/llvm/include/llvm/ObjectYAML/ObjectYAML.h b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
index b63607e6796b..7fd15cf290f4 100644
--- a/llvm/include/llvm/ObjectYAML/ObjectYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
@@ -13,6 +13,7 @@
#include "llvm/ObjectYAML/COFFYAML.h"
#include "llvm/ObjectYAML/DXContainerYAML.h"
#include "llvm/ObjectYAML/ELFYAML.h"
+#include "llvm/ObjectYAML/GOFFYAML.h"
#include "llvm/ObjectYAML/MachOYAML.h"
#include "llvm/ObjectYAML/MinidumpYAML.h"
#include "llvm/ObjectYAML/OffloadYAML.h"
@@ -30,6 +31,7 @@ struct YamlObjectFile {
std::unique_ptr<ArchYAML::Archive> Arch;
std::unique_ptr<ELFYAML::Object> Elf;
std::unique_ptr<COFFYAML::Object> Coff;
+ std::unique_ptr<GOFFYAML::Object> Goff;
std::unique_ptr<MachOYAML::Object> MachO;
std::unique_ptr<MachOYAML::UniversalBinary> FatMachO;
std::unique_ptr<MinidumpYAML::Object> Minidump;
diff --git a/llvm/include/llvm/ObjectYAML/yaml2obj.h b/llvm/include/llvm/ObjectYAML/yaml2obj.h
index 000da077bb18..3b458c3cd890 100644
--- a/llvm/include/llvm/ObjectYAML/yaml2obj.h
+++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h
@@ -32,6 +32,10 @@ namespace ELFYAML {
struct Object;
}
+namespace GOFFYAML {
+struct Object;
+}
+
namespace MinidumpYAML {
struct Object;
}
@@ -64,6 +68,7 @@ using ErrorHandler = llvm::function_ref<void(const Twine &Msg)>;
bool yaml2archive(ArchYAML::Archive &Doc, raw_ostream &Out, ErrorHandler EH);
bool yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH);
+bool yaml2goff(GOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH);
bool yaml2elf(ELFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH,
uint64_t MaxSize);
bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH);
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 19ac90842bcb..61417431f8a8 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -720,10 +720,10 @@ template <typename AnalysisT, typename IRUnitT, typename AnalysisManagerT,
bool parseAnalysisUtilityPasses(
StringRef AnalysisName, StringRef PipelineName,
PassManager<IRUnitT, AnalysisManagerT, ExtraArgTs...> &PM) {
- if (!PipelineName.endswith(">"))
+ if (!PipelineName.ends_with(">"))
return false;
// See if this is an invalidate<> pass name
- if (PipelineName.startswith("invalidate<")) {
+ if (PipelineName.starts_with("invalidate<")) {
PipelineName = PipelineName.substr(11, PipelineName.size() - 12);
if (PipelineName != AnalysisName)
return false;
@@ -732,7 +732,7 @@ bool parseAnalysisUtilityPasses(
}
// See if this is a require<> pass name
- if (PipelineName.startswith("require<")) {
+ if (PipelineName.starts_with("require<")) {
PipelineName = PipelineName.substr(8, PipelineName.size() - 9);
if (PipelineName != AnalysisName)
return false;
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index e9fbc4631dd5..493689f6a61e 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -15,6 +15,7 @@
#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Hashing.h"
@@ -33,6 +34,7 @@
#include <cstdint>
#include <iterator>
#include <memory>
+#include <sstream>
#include <string>
#include <system_error>
#include <tuple>
@@ -237,7 +239,27 @@ struct CounterMappingRegion {
/// A BranchRegion represents leaf-level boolean expressions and is
/// associated with two counters, each representing the number of times the
/// expression evaluates to true or false.
- BranchRegion
+ BranchRegion,
+
+ /// A DecisionRegion represents a top-level boolean expression and is
+ /// associated with a variable length bitmap index and condition number.
+ MCDCDecisionRegion,
+
+ /// A Branch Region can be extended to include IDs to facilitate MC/DC.
+ MCDCBranchRegion
+ };
+
+ using MCDCConditionID = unsigned int;
+ struct MCDCParameters {
+ /// Byte Index of Bitmap Coverage Object for a Decision Region.
+ unsigned BitmapIdx = 0;
+
+ /// Number of Conditions used for a Decision Region.
+ unsigned NumConditions = 0;
+
+ /// IDs used to represent a branch region and other branch regions
+ /// evaluated based on True and False branches.
+ MCDCConditionID ID = 0, TrueID = 0, FalseID = 0;
};
/// Primary Counter that is also used for Branch Regions (TrueCount).
@@ -246,8 +268,13 @@ struct CounterMappingRegion {
/// Secondary Counter used for Branch Regions (FalseCount).
Counter FalseCount;
- unsigned FileID, ExpandedFileID;
+ /// Parameters used for Modified Condition/Decision Coverage
+ MCDCParameters MCDCParams;
+
+ unsigned FileID = 0;
+ unsigned ExpandedFileID = 0;
unsigned LineStart, ColumnStart, LineEnd, ColumnEnd;
+
RegionKind Kind;
CounterMappingRegion(Counter Count, unsigned FileID, unsigned ExpandedFileID,
@@ -257,15 +284,24 @@ struct CounterMappingRegion {
LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd),
ColumnEnd(ColumnEnd), Kind(Kind) {}
- CounterMappingRegion(Counter Count, Counter FalseCount, unsigned FileID,
+ CounterMappingRegion(Counter Count, Counter FalseCount,
+ MCDCParameters MCDCParams, unsigned FileID,
unsigned ExpandedFileID, unsigned LineStart,
unsigned ColumnStart, unsigned LineEnd,
unsigned ColumnEnd, RegionKind Kind)
- : Count(Count), FalseCount(FalseCount), FileID(FileID),
- ExpandedFileID(ExpandedFileID), LineStart(LineStart),
+ : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
+ FileID(FileID), ExpandedFileID(ExpandedFileID), LineStart(LineStart),
ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd),
Kind(Kind) {}
+ CounterMappingRegion(MCDCParameters MCDCParams, unsigned FileID,
+ unsigned ExpandedFileID, unsigned LineStart,
+ unsigned ColumnStart, unsigned LineEnd,
+ unsigned ColumnEnd, RegionKind Kind)
+ : MCDCParams(MCDCParams), ExpandedFileID(ExpandedFileID),
+ LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd),
+ ColumnEnd(ColumnEnd), Kind(Kind) {}
+
static CounterMappingRegion
makeRegion(Counter Count, unsigned FileID, unsigned LineStart,
unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
@@ -299,8 +335,27 @@ struct CounterMappingRegion {
makeBranchRegion(Counter Count, Counter FalseCount, unsigned FileID,
unsigned LineStart, unsigned ColumnStart, unsigned LineEnd,
unsigned ColumnEnd) {
- return CounterMappingRegion(Count, FalseCount, FileID, 0, LineStart,
- ColumnStart, LineEnd, ColumnEnd, BranchRegion);
+ return CounterMappingRegion(Count, FalseCount, MCDCParameters(), FileID, 0,
+ LineStart, ColumnStart, LineEnd, ColumnEnd,
+ BranchRegion);
+ }
+
+ static CounterMappingRegion
+ makeBranchRegion(Counter Count, Counter FalseCount, MCDCParameters MCDCParams,
+ unsigned FileID, unsigned LineStart, unsigned ColumnStart,
+ unsigned LineEnd, unsigned ColumnEnd) {
+ return CounterMappingRegion(Count, FalseCount, MCDCParams, FileID, 0,
+ LineStart, ColumnStart, LineEnd, ColumnEnd,
+ MCDCParams.ID == 0 ? BranchRegion
+ : MCDCBranchRegion);
+ }
+
+ static CounterMappingRegion
+ makeDecisionRegion(MCDCParameters MCDCParams, unsigned FileID,
+ unsigned LineStart, unsigned ColumnStart, unsigned LineEnd,
+ unsigned ColumnEnd) {
+ return CounterMappingRegion(MCDCParams, FileID, 0, LineStart, ColumnStart,
+ LineEnd, ColumnEnd, MCDCDecisionRegion);
}
inline LineColPair startLoc() const {
@@ -326,11 +381,189 @@ struct CountedRegion : public CounterMappingRegion {
FalseExecutionCount(FalseExecutionCount), Folded(false) {}
};
+/// MCDC Record grouping all information together.
+struct MCDCRecord {
+ /// CondState represents the evaluation of a condition in an executed test
+ /// vector, which can be True or False. A DontCare is used to mask an
+ /// unevaluatable condition resulting from short-circuit behavior of logical
+ /// operators in languages like C/C++. When comparing the evaluation of a
+ /// condition across executed test vectors, comparisons against a DontCare
+ /// are effectively ignored.
+ enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 };
+
+ using TestVector = llvm::SmallVector<CondState>;
+ using TestVectors = llvm::SmallVector<TestVector>;
+ using BoolVector = llvm::SmallVector<bool>;
+ using TVRowPair = std::pair<unsigned, unsigned>;
+ using TVPairMap = llvm::DenseMap<unsigned, TVRowPair>;
+ using CondIDMap = llvm::DenseMap<unsigned, unsigned>;
+ using LineColPairMap = llvm::DenseMap<unsigned, LineColPair>;
+
+private:
+ CounterMappingRegion Region;
+ TestVectors TV;
+ TVPairMap IndependencePairs;
+ BoolVector Folded;
+ CondIDMap PosToID;
+ LineColPairMap CondLoc;
+
+public:
+ MCDCRecord(CounterMappingRegion Region, TestVectors TV,
+ TVPairMap IndependencePairs, BoolVector Folded, CondIDMap PosToID,
+ LineColPairMap CondLoc)
+ : Region(Region), TV(TV), IndependencePairs(IndependencePairs),
+ Folded(Folded), PosToID(PosToID), CondLoc(CondLoc){};
+
+ CounterMappingRegion getDecisionRegion() const { return Region; }
+ unsigned getNumConditions() const {
+ assert(Region.MCDCParams.NumConditions != 0 &&
+ "In MC/DC, NumConditions should never be zero!");
+ return Region.MCDCParams.NumConditions;
+ }
+ unsigned getNumTestVectors() const { return TV.size(); }
+ bool isCondFolded(unsigned Condition) const { return Folded[Condition]; }
+
+ /// Return the evaluation of a condition (indicated by Condition) in an
+ /// executed test vector (indicated by TestVectorIndex), which will be True,
+ /// False, or DontCare if the condition is unevaluatable. Because condition
+ /// IDs are not associated based on their position in the expression,
+ /// accessing conditions in the TestVectors requires a translation from a
+ /// ordinal position to actual condition ID. This is done via PosToID[].
+ CondState getTVCondition(unsigned TestVectorIndex, unsigned Condition) {
+ return TV[TestVectorIndex][PosToID[Condition]];
+ }
+
+ /// Return the Result evaluation for an executed test vector.
+ /// See MCDCRecordProcessor::RecordTestVector().
+ CondState getTVResult(unsigned TestVectorIndex) {
+ return TV[TestVectorIndex][getNumConditions()];
+ }
+
+ /// Determine whether a given condition (indicated by Condition) is covered
+ /// by an Independence Pair. Because condition IDs are not associated based
+ /// on their position in the expression, accessing conditions in the
+ /// TestVectors requires a translation from a ordinal position to actual
+ /// condition ID. This is done via PosToID[].
+ bool isConditionIndependencePairCovered(unsigned Condition) const {
+ auto It = PosToID.find(Condition);
+ if (It != PosToID.end())
+ return (IndependencePairs.find(It->second) != IndependencePairs.end());
+ llvm_unreachable("Condition ID without an Ordinal mapping");
+ }
+
+ /// Return the Independence Pair that covers the given condition. Because
+ /// condition IDs are not associated based on their position in the
+ /// expression, accessing conditions in the TestVectors requires a
+ /// translation from a ordinal position to actual condition ID. This is done
+ /// via PosToID[].
+ TVRowPair getConditionIndependencePair(unsigned Condition) {
+ assert(isConditionIndependencePairCovered(Condition));
+ return IndependencePairs[PosToID[Condition]];
+ }
+
+ float getPercentCovered() const {
+ unsigned Folded = 0;
+ unsigned Covered = 0;
+ for (unsigned C = 0; C < getNumConditions(); C++) {
+ if (isCondFolded(C))
+ Folded++;
+ else if (isConditionIndependencePairCovered(C))
+ Covered++;
+ }
+
+ unsigned Total = getNumConditions() - Folded;
+ if (Total == 0)
+ return 0.0;
+ return (static_cast<double>(Covered) / static_cast<double>(Total)) * 100.0;
+ }
+
+ std::string getConditionHeaderString(unsigned Condition) {
+ std::ostringstream OS;
+ OS << "Condition C" << Condition + 1 << " --> (";
+ OS << CondLoc[Condition].first << ":" << CondLoc[Condition].second;
+ OS << ")\n";
+ return OS.str();
+ }
+
+ std::string getTestVectorHeaderString() const {
+ std::ostringstream OS;
+ if (getNumTestVectors() == 0) {
+ OS << "None.\n";
+ return OS.str();
+ }
+ const auto NumConditions = getNumConditions();
+ for (unsigned I = 0; I < NumConditions; I++) {
+ OS << "C" << I + 1;
+ if (I != NumConditions - 1)
+ OS << ", ";
+ }
+ OS << " Result\n";
+ return OS.str();
+ }
+
+ std::string getTestVectorString(unsigned TestVectorIndex) {
+ assert(TestVectorIndex < getNumTestVectors() &&
+ "TestVector index out of bounds!");
+ std::ostringstream OS;
+ const auto NumConditions = getNumConditions();
+ // Add individual condition values to the string.
+ OS << " " << TestVectorIndex + 1 << " { ";
+ for (unsigned Condition = 0; Condition < NumConditions; Condition++) {
+ if (isCondFolded(Condition))
+ OS << "C";
+ else {
+ switch (getTVCondition(TestVectorIndex, Condition)) {
+ case MCDCRecord::MCDC_DontCare:
+ OS << "-";
+ break;
+ case MCDCRecord::MCDC_True:
+ OS << "T";
+ break;
+ case MCDCRecord::MCDC_False:
+ OS << "F";
+ break;
+ }
+ }
+ if (Condition != NumConditions - 1)
+ OS << ", ";
+ }
+
+ // Add result value to the string.
+ OS << " = ";
+ if (getTVResult(TestVectorIndex) == MCDC_True)
+ OS << "T";
+ else
+ OS << "F";
+ OS << " }\n";
+
+ return OS.str();
+ }
+
+ std::string getConditionCoverageString(unsigned Condition) {
+ assert(Condition < getNumConditions() &&
+ "Condition index is out of bounds!");
+ std::ostringstream OS;
+
+ OS << " C" << Condition + 1 << "-Pair: ";
+ if (isCondFolded(Condition)) {
+ OS << "constant folded\n";
+ } else if (isConditionIndependencePairCovered(Condition)) {
+ TVRowPair rows = getConditionIndependencePair(Condition);
+ OS << "covered: (" << rows.first << ",";
+ OS << rows.second << ")\n";
+ } else
+ OS << "not covered\n";
+
+ return OS.str();
+ }
+};
+
/// A Counter mapping context is used to connect the counters, expressions
/// and the obtained counter values.
class CounterMappingContext {
ArrayRef<CounterExpression> Expressions;
ArrayRef<uint64_t> CounterValues;
+ ArrayRef<uint8_t> BitmapBytes;
public:
CounterMappingContext(ArrayRef<CounterExpression> Expressions,
@@ -338,6 +571,7 @@ public:
: Expressions(Expressions), CounterValues(CounterValues) {}
void setCounts(ArrayRef<uint64_t> Counts) { CounterValues = Counts; }
+ void setBitmapBytes(ArrayRef<uint8_t> Bytes) { BitmapBytes = Bytes; }
void dump(const Counter &C, raw_ostream &OS) const;
void dump(const Counter &C) const { dump(C, dbgs()); }
@@ -346,6 +580,17 @@ public:
/// counter was executed.
Expected<int64_t> evaluate(const Counter &C) const;
+ /// Return the number of times that a region of code associated with this
+ /// counter was executed.
+ Expected<BitVector>
+ evaluateBitmap(const CounterMappingRegion *MCDCDecision) const;
+
+ /// Return an MCDC record that indicates executed test vectors and condition
+ /// pairs.
+ Expected<MCDCRecord>
+ evaluateMCDCRegion(CounterMappingRegion Region, BitVector Bitmap,
+ ArrayRef<CounterMappingRegion> Branches);
+
unsigned getMaxCounterID(const Counter &C) const;
};
@@ -364,6 +609,8 @@ struct FunctionRecord {
std::vector<CountedRegion> CountedRegions;
/// Branch Regions in the function along with their counts.
std::vector<CountedRegion> CountedBranchRegions;
+ /// MCDC Records record a DecisionRegion and associated BranchRegions.
+ std::vector<MCDCRecord> MCDCRecords;
/// The number of times this function was executed.
uint64_t ExecutionCount = 0;
@@ -373,9 +620,12 @@ struct FunctionRecord {
FunctionRecord(FunctionRecord &&FR) = default;
FunctionRecord &operator=(FunctionRecord &&) = default;
+ void pushMCDCRecord(MCDCRecord Record) { MCDCRecords.push_back(Record); }
+
void pushRegion(CounterMappingRegion Region, uint64_t Count,
uint64_t FalseCount) {
- if (Region.Kind == CounterMappingRegion::BranchRegion) {
+ if (Region.Kind == CounterMappingRegion::BranchRegion ||
+ Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
CountedBranchRegions.emplace_back(Region, Count, FalseCount);
// If both counters are hard-coded to zero, then this region represents a
// constant-folded branch.
@@ -546,6 +796,7 @@ class CoverageData {
std::vector<CoverageSegment> Segments;
std::vector<ExpansionRecord> Expansions;
std::vector<CountedRegion> BranchRegions;
+ std::vector<MCDCRecord> MCDCRecords;
public:
CoverageData() = default;
@@ -572,6 +823,9 @@ public:
/// Branches that can be further processed.
ArrayRef<CountedRegion> getBranches() const { return BranchRegions; }
+
+ /// MCDC Records that can be further processed.
+ ArrayRef<MCDCRecord> getMCDCRecords() const { return MCDCRecords; }
};
/// The mapping of profile information to coverage data.
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 3bc677d5b6d8..288dc71d756a 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -328,8 +328,8 @@ enum class instrprof_error {
too_large,
truncated,
malformed,
- missing_debug_info_for_correlation,
- unexpected_debug_info_for_correlation,
+ missing_correlation_info,
+ unexpected_correlation_info,
unable_to_correlate_profile,
unknown_function,
invalid_prof,
diff --git a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
index a3a0805a294a..c07c67d287e2 100644
--- a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
+++ b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
@@ -5,8 +5,8 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-// This file defines InstrProfCorrelator used to generate PGO profiles from
-// raw profile data and debug info.
+// This file defines InstrProfCorrelator used to generate PGO/coverage profiles
+// from raw profile data and debug info/binary file.
//===----------------------------------------------------------------------===//
#ifndef LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
@@ -31,8 +31,9 @@ class ObjectFile;
/// to their functions.
class InstrProfCorrelator {
public:
- /// Indicate which kind correlator to use.
- enum ProfCorrelatorKind { NONE, DEBUG_INFO };
+ /// Indicate if we should use the debug info or profile metadata sections to
+ /// correlate.
+ enum ProfCorrelatorKind { NONE, DEBUG_INFO, BINARY };
static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
get(StringRef Filename, ProfCorrelatorKind FileKind);
@@ -71,11 +72,18 @@ public:
protected:
struct Context {
static llvm::Expected<std::unique_ptr<Context>>
- get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj);
+ get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj,
+ ProfCorrelatorKind FileKind);
std::unique_ptr<MemoryBuffer> Buffer;
/// The address range of the __llvm_prf_cnts section.
uint64_t CountersSectionStart;
uint64_t CountersSectionEnd;
+ /// The pointer points to start/end of profile data/name sections if
+ /// FileKind is Binary.
+ const char *DataStart;
+ const char *DataEnd;
+ const char *NameStart;
+ size_t NameSize;
/// True if target and host have different endian orders.
bool ShouldSwapBytes;
};
@@ -145,19 +153,20 @@ protected:
Error dumpYaml(int MaxWarnings, raw_ostream &OS) override;
- void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset,
- IntPtrT FunctionPtr, uint32_t NumCounters);
+ void addDataProbe(uint64_t FunctionName, uint64_t CFGHash,
+ IntPtrT CounterOffset, IntPtrT FunctionPtr,
+ uint32_t NumCounters);
+
+ // Byte-swap the value if necessary.
+ template <class T> T maybeSwap(T Value) const {
+ return Ctx->ShouldSwapBytes ? llvm::byteswap(Value) : Value;
+ }
private:
InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind,
std::unique_ptr<InstrProfCorrelator::Context> Ctx)
: InstrProfCorrelator(Kind, std::move(Ctx)){};
llvm::DenseSet<IntPtrT> CounterOffsets;
-
- // Byte-swap the value if necessary.
- template <class T> T maybeSwap(T Value) const {
- return Ctx->ShouldSwapBytes ? llvm::byteswap(Value) : Value;
- }
};
/// DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes
@@ -214,6 +223,28 @@ private:
Error correlateProfileNameImpl() override;
};
+/// BinaryInstrProfCorrelator - A child of InstrProfCorrelatorImpl that
+/// takes an object file as input to correlate profiles.
+template <class IntPtrT>
+class BinaryInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
+public:
+ BinaryInstrProfCorrelator(std::unique_ptr<InstrProfCorrelator::Context> Ctx)
+ : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)) {}
+
+ /// Return a pointer to the names string that this class constructs.
+ const char *getNamesPointer() const { return this->Ctx.NameStart; }
+
+ /// Return the number of bytes in the names string.
+ size_t getNamesSize() const { return this->Ctx.NameSize; }
+
+private:
+ void correlateProfileDataImpl(
+ int MaxWarnings,
+ InstrProfCorrelator::CorrelationData *Data = nullptr) override;
+
+ Error correlateProfileNameImpl() override;
+};
+
} // end namespace llvm
#endif // LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc
index 44a449800923..f5de23ff4b94 100644
--- a/llvm/include/llvm/ProfileData/InstrProfData.inc
+++ b/llvm/include/llvm/ProfileData/InstrProfData.inc
@@ -295,6 +295,12 @@ INSTR_PROF_SECT_ENTRY(IPSK_covfun, \
INSTR_PROF_SECT_ENTRY(IPSK_orderfile, \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON), \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COFF), "__DATA,")
+INSTR_PROF_SECT_ENTRY(IPSK_covdata, \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVDATA_COMMON), \
+ INSTR_PROF_COVDATA_COFF, "__LLVM_COV,")
+INSTR_PROF_SECT_ENTRY(IPSK_covname, \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON), \
+ INSTR_PROF_COVNAME_COFF, "__LLVM_COV,")
#undef INSTR_PROF_SECT_ENTRY
#endif
@@ -701,6 +707,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds
#define INSTR_PROF_COVMAP_COMMON __llvm_covmap
#define INSTR_PROF_COVFUN_COMMON __llvm_covfun
+#define INSTR_PROF_COVDATA_COMMON __llvm_covdata
+#define INSTR_PROF_COVNAME_COMMON __llvm_covnames
#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile
/* Windows section names. Because these section names contain dollar characters,
* they must be quoted.
@@ -713,6 +721,11 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_COFF ".lprfnd$M"
#define INSTR_PROF_COVMAP_COFF ".lcovmap$M"
#define INSTR_PROF_COVFUN_COFF ".lcovfun$M"
+/* Since cov data and cov names sections are not allocated, we don't need to
+ * access them at runtime.
+ */
+#define INSTR_PROF_COVDATA_COFF ".lcovd"
+#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"
#ifdef _WIN32
@@ -729,6 +742,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COFF
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF
#define INSTR_PROF_COVFUN_SECT_NAME INSTR_PROF_COVFUN_COFF
+#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_COVDATA_COFF
+#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_COVNAME_COFF
#define INSTR_PROF_ORDERFILE_SECT_NAME INSTR_PROF_ORDERFILE_COFF
#else
/* Runtime section names and name strings. */
@@ -744,6 +759,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON)
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON)
#define INSTR_PROF_COVFUN_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVFUN_COMMON)
+#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVDATA_COMMON)
+#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON)
/* Order file instrumentation. */
#define INSTR_PROF_ORDERFILE_SECT_NAME \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON)
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index 952cc0d0dc80..ff50dfde0e79 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -123,9 +123,6 @@ public:
virtual bool instrEntryBBEnabled() const = 0;
- /// Return true if we must provide debug info to create PGO profiles.
- virtual bool useDebugInfoCorrelate() const { return false; }
-
/// Return true if the profile has single byte counters representing coverage.
virtual bool hasSingleByteCoverage() const = 0;
@@ -378,12 +375,6 @@ public:
return (Version & VARIANT_MASK_INSTR_ENTRY) != 0;
}
- bool useDebugInfoCorrelate() const override {
- return (Version & VARIANT_MASK_DBG_CORRELATE) != 0;
- }
-
- bool useCorrelate() const { return useDebugInfoCorrelate(); }
-
bool hasSingleByteCoverage() const override {
return (Version & VARIANT_MASK_BYTE_COVERAGE) != 0;
}
diff --git a/llvm/include/llvm/ProfileData/MemProf.h b/llvm/include/llvm/ProfileData/MemProf.h
index 6557481870d8..37c19094bc2a 100644
--- a/llvm/include/llvm/ProfileData/MemProf.h
+++ b/llvm/include/llvm/ProfileData/MemProf.h
@@ -538,6 +538,11 @@ public:
offset_type /*Unused*/) {
assert(Schema != nullptr && "MemProf schema is not initialized!");
V.serialize(*Schema, Out);
+ // Clear the IndexedMemProfRecord which results in clearing/freeing its
+ // vectors of allocs and callsites. This is owned by the associated on-disk
+ // hash table, but unused after this point. See also the comment added to
+ // the client which constructs the on-disk hash table for this trait.
+ V.clear();
}
};
diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h
index f001f5ee9d39..d995cc69af89 100644
--- a/llvm/include/llvm/ProfileData/SampleProf.h
+++ b/llvm/include/llvm/ProfileData/SampleProf.h
@@ -548,7 +548,7 @@ public:
assert(!ContextStr.empty());
// Note that `[]` wrapped input indicates a full context string, otherwise
// it's treated as context-less function name only.
- bool HasContext = ContextStr.startswith("[");
+ bool HasContext = ContextStr.starts_with("[");
if (!HasContext) {
State = UnknownContext;
Func = FunctionId(ContextStr);
diff --git a/llvm/include/llvm/Support/AMDGPUAddrSpace.h b/llvm/include/llvm/Support/AMDGPUAddrSpace.h
new file mode 100644
index 000000000000..c9d9bdd2f2fa
--- /dev/null
+++ b/llvm/include/llvm/Support/AMDGPUAddrSpace.h
@@ -0,0 +1,86 @@
+//===---------------- AMDGPUAddrSpace.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// AMDGPU address space definition
+///
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_AMDGPUADDRSPACE_H
+#define LLVM_SUPPORT_AMDGPUADDRSPACE_H
+
+namespace llvm {
+/// OpenCL uses address spaces to differentiate between
+/// various memory regions on the hardware. On the CPU
+/// all of the address spaces point to the same memory,
+/// however on the GPU, each address space points to
+/// a separate piece of memory that is unique from other
+/// memory locations.
+namespace AMDGPUAS {
+enum : unsigned {
+ // The maximum value for flat, generic, local, private, constant and region.
+ MAX_AMDGPU_ADDRESS = 9,
+
+ FLAT_ADDRESS = 0, ///< Address space for flat memory.
+ GLOBAL_ADDRESS = 1, ///< Address space for global memory (RAT0, VTX0).
+ REGION_ADDRESS = 2, ///< Address space for region memory. (GDS)
+
+ CONSTANT_ADDRESS = 4, ///< Address space for constant memory (VTX2).
+ LOCAL_ADDRESS = 3, ///< Address space for local memory.
+ PRIVATE_ADDRESS = 5, ///< Address space for private memory.
+
+ CONSTANT_ADDRESS_32BIT = 6, ///< Address space for 32-bit constant memory.
+
+ BUFFER_FAT_POINTER = 7, ///< Address space for 160-bit buffer fat pointers.
+ ///< Not used in backend.
+
+ BUFFER_RESOURCE = 8, ///< Address space for 128-bit buffer resources.
+
+ BUFFER_STRIDED_POINTER = 9, ///< Address space for 192-bit fat buffer
+ ///< pointers with an additional index.
+
+ /// Internal address spaces. Can be freely renumbered.
+ STREAMOUT_REGISTER = 128, ///< Address space for GS NGG Streamout registers.
+ /// end Internal address spaces.
+
+ /// Address space for direct addressable parameter memory (CONST0).
+ PARAM_D_ADDRESS = 6,
+ /// Address space for indirect addressable parameter memory (VTX1).
+ PARAM_I_ADDRESS = 7,
+
+ // Do not re-order the CONSTANT_BUFFER_* enums. Several places depend on
+ // this order to be able to dynamically index a constant buffer, for
+ // example:
+ //
+ // ConstantBufferAS = CONSTANT_BUFFER_0 + CBIdx
+
+ CONSTANT_BUFFER_0 = 8,
+ CONSTANT_BUFFER_1 = 9,
+ CONSTANT_BUFFER_2 = 10,
+ CONSTANT_BUFFER_3 = 11,
+ CONSTANT_BUFFER_4 = 12,
+ CONSTANT_BUFFER_5 = 13,
+ CONSTANT_BUFFER_6 = 14,
+ CONSTANT_BUFFER_7 = 15,
+ CONSTANT_BUFFER_8 = 16,
+ CONSTANT_BUFFER_9 = 17,
+ CONSTANT_BUFFER_10 = 18,
+ CONSTANT_BUFFER_11 = 19,
+ CONSTANT_BUFFER_12 = 20,
+ CONSTANT_BUFFER_13 = 21,
+ CONSTANT_BUFFER_14 = 22,
+ CONSTANT_BUFFER_15 = 23,
+
+ // Some places use this if the address space can't be determined.
+ UNKNOWN_ADDRESS_SPACE = ~0u,
+};
+} // end namespace AMDGPUAS
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_AMDGPUADDRSPACE_H
diff --git a/llvm/include/llvm/Support/AMDHSAKernelDescriptor.h b/llvm/include/llvm/Support/AMDHSAKernelDescriptor.h
index 0574f96e6e15..2de2cf4185d8 100644
--- a/llvm/include/llvm/Support/AMDHSAKernelDescriptor.h
+++ b/llvm/include/llvm/Support/AMDHSAKernelDescriptor.h
@@ -88,12 +88,18 @@ enum : uint8_t {
// [GFX6-GFX9].
#define COMPUTE_PGM_RSRC1_GFX6_GFX9(NAME, SHIFT, WIDTH) \
AMDHSA_BITS_ENUM_ENTRY(COMPUTE_PGM_RSRC1_GFX6_GFX9_ ## NAME, SHIFT, WIDTH)
+// [GFX6-GFX11].
+#define COMPUTE_PGM_RSRC1_GFX6_GFX11(NAME, SHIFT, WIDTH) \
+ AMDHSA_BITS_ENUM_ENTRY(COMPUTE_PGM_RSRC1_GFX6_GFX11_##NAME, SHIFT, WIDTH)
// GFX9+.
#define COMPUTE_PGM_RSRC1_GFX9_PLUS(NAME, SHIFT, WIDTH) \
AMDHSA_BITS_ENUM_ENTRY(COMPUTE_PGM_RSRC1_GFX9_PLUS_ ## NAME, SHIFT, WIDTH)
// GFX10+.
#define COMPUTE_PGM_RSRC1_GFX10_PLUS(NAME, SHIFT, WIDTH) \
AMDHSA_BITS_ENUM_ENTRY(COMPUTE_PGM_RSRC1_GFX10_PLUS_ ## NAME, SHIFT, WIDTH)
+// GFX12+.
+#define COMPUTE_PGM_RSRC1_GFX12_PLUS(NAME, SHIFT, WIDTH) \
+ AMDHSA_BITS_ENUM_ENTRY(COMPUTE_PGM_RSRC1_GFX12_PLUS_##NAME, SHIFT, WIDTH)
enum : int32_t {
COMPUTE_PGM_RSRC1(GRANULATED_WORKITEM_VGPR_COUNT, 0, 6),
COMPUTE_PGM_RSRC1(GRANULATED_WAVEFRONT_SGPR_COUNT, 6, 4),
@@ -103,9 +109,11 @@ enum : int32_t {
COMPUTE_PGM_RSRC1(FLOAT_DENORM_MODE_32, 16, 2),
COMPUTE_PGM_RSRC1(FLOAT_DENORM_MODE_16_64, 18, 2),
COMPUTE_PGM_RSRC1(PRIV, 20, 1),
- COMPUTE_PGM_RSRC1(ENABLE_DX10_CLAMP, 21, 1),
+ COMPUTE_PGM_RSRC1_GFX6_GFX11(ENABLE_DX10_CLAMP, 21, 1),
+ COMPUTE_PGM_RSRC1_GFX12_PLUS(ENABLE_WG_RR_EN, 21, 1),
COMPUTE_PGM_RSRC1(DEBUG_MODE, 22, 1),
- COMPUTE_PGM_RSRC1(ENABLE_IEEE_MODE, 23, 1),
+ COMPUTE_PGM_RSRC1_GFX6_GFX11(ENABLE_IEEE_MODE, 23, 1),
+ COMPUTE_PGM_RSRC1_GFX12_PLUS(DISABLE_PERF, 23, 1),
COMPUTE_PGM_RSRC1(BULKY, 24, 1),
COMPUTE_PGM_RSRC1(CDBG_USER, 25, 1),
COMPUTE_PGM_RSRC1_GFX6_GFX8(RESERVED0, 26, 1),
diff --git a/llvm/include/llvm/Support/AutoConvert.h b/llvm/include/llvm/Support/AutoConvert.h
index bcf7473feac8..79566189d819 100644
--- a/llvm/include/llvm/Support/AutoConvert.h
+++ b/llvm/include/llvm/Support/AutoConvert.h
@@ -15,10 +15,26 @@
#define LLVM_SUPPORT_AUTOCONVERT_H
#ifdef __MVS__
-#define CCSID_IBM_1047 1047
-#define CCSID_UTF_8 1208
+#include <_Ccsid.h>
+#ifdef __cplusplus
#include <system_error>
+#endif // __cplusplus
+#define CCSID_IBM_1047 1047
+#define CCSID_UTF_8 1208
+#define CCSID_ISO8859_1 819
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+int enableAutoConversion(int FD);
+int disableAutoConversion(int FD);
+int restoreStdHandleAutoConversion(int FD);
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#ifdef __cplusplus
namespace llvm {
/// \brief Disable the z/OS enhanced ASCII auto-conversion for the file
@@ -30,10 +46,14 @@ std::error_code disableAutoConversion(int FD);
/// codepage.
std::error_code enableAutoConversion(int FD);
+/// Restore the z/OS enhanced ASCII auto-conversion for the std handle.
+std::error_code restoreStdHandleAutoConversion(int FD);
+
/// \brief Set the tag information for a file descriptor.
std::error_code setFileTag(int FD, int CCSID, bool Text);
} // namespace llvm
+#endif // __cplusplus
#endif // __MVS__
diff --git a/llvm/include/llvm/Support/LLVMDriver.h b/llvm/include/llvm/Support/LLVMDriver.h
index 1c68f5070777..0b2e265d50b4 100644
--- a/llvm/include/llvm/Support/LLVMDriver.h
+++ b/llvm/include/llvm/Support/LLVMDriver.h
@@ -9,8 +9,6 @@
#ifndef LLVM_SUPPORT_LLVMDRIVER_H
#define LLVM_SUPPORT_LLVMDRIVER_H
-#include "llvm/ADT/SmallVector.h"
-
namespace llvm {
struct ToolContext {
diff --git a/llvm/include/llvm/Support/SystemZ/zOSSupport.h b/llvm/include/llvm/Support/SystemZ/zOSSupport.h
new file mode 100644
index 000000000000..f9a61f887d5d
--- /dev/null
+++ b/llvm/include/llvm/Support/SystemZ/zOSSupport.h
@@ -0,0 +1,47 @@
+//===- zOSSupport.h - Common z/OS Include File ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines z/OS implementations for common functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ZOSSUPPORT_H
+#define LLVM_SUPPORT_ZOSSUPPORT_H
+
+#ifdef __MVS__
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+// z/OS Unix System Services does not have strsignal() support, so the
+// strsignal() function is implemented here.
+inline char *strsignal(int sig) {
+ static char msg[256];
+ sprintf(msg, "%d", sig);
+ return msg;
+}
+
+// z/OS Unix System Services does not have wait4() support, so the wait4
+// function is implemented here.
+inline pid_t wait4(pid_t pid, int *wstatus, int options,
+ struct rusage *rusage) {
+ pid_t Result = waitpid(pid, wstatus, options);
+ int GetrusageRC = getrusage(RUSAGE_CHILDREN, rusage);
+ assert(!GetrusageRC && "Must have valid measure of the resources!");
+ return Result;
+}
+
+// z/OS Unix System Services does not have strnlen() support, so the strnlen()
+// function is implemented here.
+inline std::size_t strnlen(const char *S, std::size_t MaxLen) {
+ const char *PtrToNullChar =
+ static_cast<const char *>(std::memchr(S, '\0', MaxLen));
+ return PtrToNullChar ? PtrToNullChar - S : MaxLen;
+}
+
+#endif
+#endif
diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def
index 16a747d23e73..3824b1c66951 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -415,6 +415,9 @@ HANDLE_TARGET_OPCODE_MARKER(GENERIC_ATOMICRMW_OP_END, G_ATOMICRMW_UDEC_WRAP)
// Generic atomic fence
HANDLE_TARGET_OPCODE(G_FENCE)
+/// Generic prefetch
+HANDLE_TARGET_OPCODE(G_PREFETCH)
+
/// Generic conditional branch instruction.
HANDLE_TARGET_OPCODE(G_BRCOND)
diff --git a/llvm/include/llvm/Support/TypeSize.h b/llvm/include/llvm/Support/TypeSize.h
index 4d9d4f400e92..b00ebf9e8c45 100644
--- a/llvm/include/llvm/Support/TypeSize.h
+++ b/llvm/include/llvm/Support/TypeSize.h
@@ -15,7 +15,6 @@
#ifndef LLVM_SUPPORT_TYPESIZE_H
#define LLVM_SUPPORT_TYPESIZE_H
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
index b3d8580e5e56..b0683ac2e32c 100644
--- a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
+++ b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
@@ -140,6 +140,8 @@ enum attributeBits {
ENUM_ENTRY(IC_EVEX_XS, 2, "requires EVEX and the XS prefix") \
ENUM_ENTRY(IC_EVEX_XD, 2, "requires EVEX and the XD prefix") \
ENUM_ENTRY(IC_EVEX_OPSIZE, 2, "requires EVEX and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_ADSIZE, 3, \
+ "requires EVEX, OPSIZE and the ADSIZE prefix") \
ENUM_ENTRY(IC_EVEX_W, 3, "requires EVEX and the W prefix") \
ENUM_ENTRY(IC_EVEX_W_XS, 4, "requires EVEX, W, and XS prefix") \
ENUM_ENTRY(IC_EVEX_W_XD, 4, "requires EVEX, W, and XD prefix") \
diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h
index 1e01eb9ea19c..7c8d264afeff 100644
--- a/llvm/include/llvm/Support/raw_ostream.h
+++ b/llvm/include/llvm/Support/raw_ostream.h
@@ -16,6 +16,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Threading.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -615,6 +616,8 @@ public:
/// immediately destroyed.
raw_fd_stream(StringRef Filename, std::error_code &EC);
+ raw_fd_stream(int fd, bool shouldClose);
+
/// This reads the \p Size bytes into a buffer pointed by \p Ptr.
///
/// \param Ptr The start of the buffer to hold data to be read.
@@ -631,6 +634,54 @@ public:
};
//===----------------------------------------------------------------------===//
+// Socket Streams
+//===----------------------------------------------------------------------===//
+
+/// A raw stream for sockets reading/writing
+
+class raw_socket_stream;
+
+// Make sure that calls to WSAStartup and WSACleanup are balanced.
+#ifdef _WIN32
+class WSABalancer {
+public:
+ WSABalancer();
+ ~WSABalancer();
+};
+#endif // _WIN32
+
+class ListeningSocket {
+ int FD;
+ std::string SocketPath;
+ ListeningSocket(int SocketFD, StringRef SocketPath);
+#ifdef _WIN32
+ WSABalancer _;
+#endif // _WIN32
+
+public:
+ static Expected<ListeningSocket> createUnix(
+ StringRef SocketPath,
+ int MaxBacklog = llvm::hardware_concurrency().compute_thread_count());
+ Expected<std::unique_ptr<raw_socket_stream>> accept();
+ ListeningSocket(ListeningSocket &&LS);
+ ~ListeningSocket();
+};
+class raw_socket_stream : public raw_fd_stream {
+ uint64_t current_pos() const override { return 0; }
+#ifdef _WIN32
+ WSABalancer _;
+#endif // _WIN32
+
+public:
+ raw_socket_stream(int SocketFD);
+ /// Create a \p raw_socket_stream connected to the Unix domain socket at \p
+ /// SocketPath.
+ static Expected<std::unique_ptr<raw_socket_stream>>
+ createConnectedUnix(StringRef SocketPath);
+ ~raw_socket_stream();
+};
+
+//===----------------------------------------------------------------------===//
// Output Stream Adaptors
//===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/Target/CGPassBuilderOption.h b/llvm/include/llvm/Target/CGPassBuilderOption.h
index 85abddbb2292..6b5c023a9b6a 100644
--- a/llvm/include/llvm/Target/CGPassBuilderOption.h
+++ b/llvm/include/llvm/Target/CGPassBuilderOption.h
@@ -31,8 +31,10 @@ struct CGPassBuilderOption {
bool DisableVerify = false;
bool EnableImplicitNullChecks = false;
bool EnableBlockPlacementStats = false;
+ bool EnableMachineFunctionSplitter = false;
bool MISchedPostRA = false;
bool EarlyLiveIntervals = false;
+ bool GCEmptyBlocks = false;
bool DisableLSR = false;
bool DisableCGP = false;
@@ -41,17 +43,25 @@ struct CGPassBuilderOption {
bool DisablePartialLibcallInlining = false;
bool DisableConstantHoisting = false;
bool DisableSelectOptimize = true;
+ bool DisableAtExitBasedGlobalDtorLowering = false;
+ bool DisableExpandReductions = false;
+ bool DisableRAFSProfileLoader = false;
+ bool DisableCFIFixup = false;
+ bool PrintAfterISel = false;
bool PrintISelInput = false;
- bool PrintGCInfo = false;
bool RequiresCodeGenSCCOrder = false;
RunOutliner EnableMachineOutliner = RunOutliner::TargetDefault;
RegAllocType RegAlloc = RegAllocType::Default;
std::optional<GlobalISelAbortMode> EnableGlobalISelAbort;
+ std::string FSProfileFile;
+ std::string FSRemappingFile;
std::optional<bool> VerifyMachineCode;
std::optional<bool> EnableFastISelOption;
std::optional<bool> EnableGlobalISelOption;
+ std::optional<bool> DebugifyAndStripAll;
+ std::optional<bool> DebugifyCheckAndStripAll;
};
CGPassBuilderOption getCGPassBuilderOption();
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td
index 9a9c09d3c20d..73e38b15bf67 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -1209,6 +1209,15 @@ def G_FENCE : GenericInstruction {
let hasSideEffects = true;
}
+// Generic opcode equivalent to the llvm.prefetch intrinsic.
+def G_PREFETCH : GenericInstruction {
+ let OutOperandList = (outs);
+ let InOperandList = (ins ptype0:$address, i32imm:$rw, i32imm:$locality, i32imm:$cachetype);
+ let hasSideEffects = true;
+ let mayLoad = true;
+ let mayStore = true;
+}
+
//------------------------------------------------------------------------------
// Variadic ops
//------------------------------------------------------------------------------
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index 4830ecbe1cd6..4c29f25bedf4 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -239,7 +239,7 @@ public:
void setCodeModel(CodeModel::Model CM) { CMModel = CM; }
void setLargeDataThreshold(uint64_t LDT) { LargeDataThreshold = LDT; }
- bool isLargeGlobalObject(const GlobalObject *GO) const;
+ bool isLargeGlobalValue(const GlobalValue *GV) const;
bool isPositionIndependent() const;
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 798e6a1d9525..d4fc9d8a96db 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -1063,6 +1063,10 @@ def extloadi32 : PatFrag<(ops node:$ptr), (extload node:$ptr)> {
let IsLoad = true;
let MemoryVT = i32;
}
+def extloadi64 : PatFrag<(ops node:$ptr), (extload node:$ptr)> {
+ let IsLoad = true;
+ let MemoryVT = i64;
+}
def extloadf16 : PatFrag<(ops node:$ptr), (extload node:$ptr)> {
let IsLoad = true;
let MemoryVT = f16;
@@ -1092,6 +1096,10 @@ def sextloadi32 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> {
let IsLoad = true;
let MemoryVT = i32;
}
+def sextloadi64 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> {
+ let IsLoad = true;
+ let MemoryVT = i64;
+}
def zextloadi1 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> {
let IsLoad = true;
@@ -1109,6 +1117,10 @@ def zextloadi32 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> {
let IsLoad = true;
let MemoryVT = i32;
}
+def zextloadi64 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> {
+ let IsLoad = true;
+ let MemoryVT = i64;
+}
def extloadvi1 : PatFrag<(ops node:$ptr), (extload node:$ptr)> {
let IsLoad = true;
@@ -1209,6 +1221,12 @@ def truncstorei32 : PatFrag<(ops node:$val, node:$ptr),
let MemoryVT = i32;
let IsTruncStore = true;
}
+def truncstorei64 : PatFrag<(ops node:$val, node:$ptr),
+ (truncstore node:$val, node:$ptr)> {
+ let IsStore = true;
+ let MemoryVT = i64;
+ let IsTruncStore = true;
+}
def truncstoref16 : PatFrag<(ops node:$val, node:$ptr),
(truncstore node:$val, node:$ptr)> {
let IsStore = true;
diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index 17cafd146b0e..56c32fae712c 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -536,10 +536,9 @@ inline constexpr CpuInfo CpuInfos[] = {
{AArch64::AEK_AES, AArch64::AEK_SHA2, AArch64::AEK_DOTPROD,
AArch64::AEK_FP16, AArch64::AEK_PROFILE, AArch64::AEK_RCPC,
AArch64::AEK_SSBS}))},
- {"neoverse-n2", ARMV8_5A,
+ {"neoverse-n2", ARMV9A,
(AArch64::ExtensionBitset(
- {AArch64::AEK_AES, AArch64::AEK_SHA2, AArch64::AEK_SHA3,
- AArch64::AEK_SM4, AArch64::AEK_BF16, AArch64::AEK_DOTPROD,
+ {AArch64::AEK_BF16, AArch64::AEK_DOTPROD,
AArch64::AEK_FP16, AArch64::AEK_I8MM, AArch64::AEK_MTE,
AArch64::AEK_SB, AArch64::AEK_SSBS, AArch64::AEK_SVE,
AArch64::AEK_SVE2, AArch64::AEK_SVE2BITPERM}))},
diff --git a/llvm/include/llvm/TargetParser/ARMTargetParser.def b/llvm/include/llvm/TargetParser/ARMTargetParser.def
index 558b6f127de3..c520ab898cb9 100644
--- a/llvm/include/llvm/TargetParser/ARMTargetParser.def
+++ b/llvm/include/llvm/TargetParser/ARMTargetParser.def
@@ -340,7 +340,7 @@ ARM_CPU_NAME("cortex-x1c", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
(ARM::AEK_FP16 | ARM::AEK_DOTPROD))
ARM_CPU_NAME("neoverse-n1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
(ARM::AEK_FP16 | ARM::AEK_DOTPROD))
-ARM_CPU_NAME("neoverse-n2", ARMV8_5A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ARM_CPU_NAME("neoverse-n2", ARMV9A, FK_NEON_FP_ARMV8, false,
(ARM::AEK_BF16 | ARM::AEK_DOTPROD | ARM::AEK_I8MM | ARM::AEK_RAS |
ARM::AEK_SB))
ARM_CPU_NAME("neoverse-v1", ARMV8_4A, FK_CRYPTO_NEON_FP_ARMV8, false,
diff --git a/llvm/include/llvm/Transforms/CFGuard.h b/llvm/include/llvm/Transforms/CFGuard.h
index 86fcbc3c13e8..caf822a2ec9f 100644
--- a/llvm/include/llvm/Transforms/CFGuard.h
+++ b/llvm/include/llvm/Transforms/CFGuard.h
@@ -11,10 +11,23 @@
#ifndef LLVM_TRANSFORMS_CFGUARD_H
#define LLVM_TRANSFORMS_CFGUARD_H
+#include "llvm/IR/PassManager.h"
+
namespace llvm {
class FunctionPass;
+class CFGuardPass : public PassInfoMixin<CFGuardPass> {
+public:
+ enum class Mechanism { Check, Dispatch };
+
+ CFGuardPass(Mechanism M = Mechanism::Check) : GuardMechanism(M) {}
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+
+private:
+ Mechanism GuardMechanism;
+};
+
/// Insert Control FLow Guard checks on indirect function calls.
FunctionPass *createCFGuardCheckPass();
diff --git a/llvm/include/llvm/Transforms/HipStdPar/HipStdPar.h b/llvm/include/llvm/Transforms/HipStdPar/HipStdPar.h
index 9df093d8d5d5..5ff38bdf0481 100644
--- a/llvm/include/llvm/Transforms/HipStdPar/HipStdPar.h
+++ b/llvm/include/llvm/Transforms/HipStdPar/HipStdPar.h
@@ -23,7 +23,6 @@
namespace llvm {
class Module;
-class ModuleAnaysisManager;
class HipStdParAcceleratorCodeSelectionPass
: public PassInfoMixin<HipStdParAcceleratorCodeSelectionPass> {
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 97b18e51beee..50167708163e 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -2161,7 +2161,7 @@ public:
Function *F = I->getFunction();
auto &ORE = Configuration.OREGetter(F);
- if (RemarkName.startswith("OMP"))
+ if (RemarkName.starts_with("OMP"))
ORE.emit([&]() {
return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, I))
<< " [" << RemarkName << "]";
@@ -2181,7 +2181,7 @@ public:
auto &ORE = Configuration.OREGetter(F);
- if (RemarkName.startswith("OMP"))
+ if (RemarkName.starts_with("OMP"))
ORE.emit([&]() {
return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, F))
<< " [" << RemarkName << "]";
diff --git a/llvm/include/llvm/Transforms/IPO/BlockExtractor.h b/llvm/include/llvm/Transforms/IPO/BlockExtractor.h
index 6211027bd672..cf6b1666b4fc 100644
--- a/llvm/include/llvm/Transforms/IPO/BlockExtractor.h
+++ b/llvm/include/llvm/Transforms/IPO/BlockExtractor.h
@@ -16,7 +16,6 @@
#include <vector>
-#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/PassManager.h"
namespace llvm {
diff --git a/llvm/include/llvm/Transforms/IPO/EmbedBitcodePass.h b/llvm/include/llvm/Transforms/IPO/EmbedBitcodePass.h
index c35048c91aba..2bb7d5f1fcf1 100644
--- a/llvm/include/llvm/Transforms/IPO/EmbedBitcodePass.h
+++ b/llvm/include/llvm/Transforms/IPO/EmbedBitcodePass.h
@@ -22,7 +22,6 @@
namespace llvm {
class Module;
-class ModulePass;
class Pass;
/// Pass embeds a copy of the module optimized with the provided pass pipeline
diff --git a/llvm/include/llvm/Transforms/Instrumentation.h b/llvm/include/llvm/Transforms/Instrumentation.h
index bb1a0d446aa2..ea97ab2562a5 100644
--- a/llvm/include/llvm/Transforms/Instrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation.h
@@ -52,7 +52,8 @@ Comdat *getOrCreateFunctionComdat(Function &F, Triple &T);
// Place global in a large section for x86-64 ELF binaries to mitigate
// relocation overflow pressure. This can be be used for metadata globals that
// aren't directly accessed by code, which has no performance impact.
-void setGlobalVariableLargeSection(Triple &TargetTriple, GlobalVariable &GV);
+void setGlobalVariableLargeSection(const Triple &TargetTriple,
+ GlobalVariable &GV);
// Insert GCOV profiling instrumentation
struct GCOVOptions {
diff --git a/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h b/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h
index c106e1651e80..0dd37c9ca58b 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h
@@ -13,173 +13,28 @@
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_INSTRPROFILING_H
#define LLVM_TRANSFORMS_INSTRUMENTATION_INSTRPROFILING_H
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/PassManager.h"
-#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Transforms/Instrumentation.h"
-#include <cstdint>
-#include <cstring>
-#include <vector>
namespace llvm {
class TargetLibraryInfo;
-using LoadStorePair = std::pair<Instruction *, Instruction *>;
-
/// Instrumentation based profiling lowering pass. This pass lowers
/// the profile instrumented code generated by FE or the IR based
/// instrumentation pass.
-class InstrProfiling : public PassInfoMixin<InstrProfiling> {
+class InstrProfilingLoweringPass
+ : public PassInfoMixin<InstrProfilingLoweringPass> {
+ const InstrProfOptions Options = {};
+ // Is this lowering for the context-sensitive instrumentation.
+ const bool IsCS = false;
+
public:
- InstrProfiling() : IsCS(false) {}
- InstrProfiling(const InstrProfOptions &Options, bool IsCS = false)
+ InstrProfilingLoweringPass() = default;
+ InstrProfilingLoweringPass(const InstrProfOptions &Options, bool IsCS = false)
: Options(Options), IsCS(IsCS) {}
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
- bool run(Module &M,
- std::function<const TargetLibraryInfo &(Function &F)> GetTLI);
-
-private:
- InstrProfOptions Options;
- Module *M;
- Triple TT;
- std::function<const TargetLibraryInfo &(Function &F)> GetTLI;
- struct PerFunctionProfileData {
- uint32_t NumValueSites[IPVK_Last + 1];
- GlobalVariable *RegionCounters = nullptr;
- GlobalVariable *DataVar = nullptr;
- GlobalVariable *RegionBitmaps = nullptr;
- uint32_t NumBitmapBytes = 0;
-
- PerFunctionProfileData() {
- memset(NumValueSites, 0, sizeof(uint32_t) * (IPVK_Last + 1));
- }
- };
- DenseMap<GlobalVariable *, PerFunctionProfileData> ProfileDataMap;
- /// If runtime relocation is enabled, this maps functions to the load
- /// instruction that produces the profile relocation bias.
- DenseMap<const Function *, LoadInst *> FunctionToProfileBiasMap;
- std::vector<GlobalValue *> CompilerUsedVars;
- std::vector<GlobalValue *> UsedVars;
- std::vector<GlobalVariable *> ReferencedNames;
- GlobalVariable *NamesVar;
- size_t NamesSize;
-
- // Is this lowering for the context-sensitive instrumentation.
- bool IsCS;
-
- // vector of counter load/store pairs to be register promoted.
- std::vector<LoadStorePair> PromotionCandidates;
-
- int64_t TotalCountersPromoted = 0;
-
- /// Lower instrumentation intrinsics in the function. Returns true if there
- /// any lowering.
- bool lowerIntrinsics(Function *F);
-
- /// Register-promote counter loads and stores in loops.
- void promoteCounterLoadStores(Function *F);
-
- /// Returns true if relocating counters at runtime is enabled.
- bool isRuntimeCounterRelocationEnabled() const;
-
- /// Returns true if profile counter update register promotion is enabled.
- bool isCounterPromotionEnabled() const;
-
- /// Count the number of instrumented value sites for the function.
- void computeNumValueSiteCounts(InstrProfValueProfileInst *Ins);
-
- /// Replace instrprof.value.profile with a call to runtime library.
- void lowerValueProfileInst(InstrProfValueProfileInst *Ins);
-
- /// Replace instrprof.cover with a store instruction to the coverage byte.
- void lowerCover(InstrProfCoverInst *Inc);
-
- /// Replace instrprof.timestamp with a call to
- /// INSTR_PROF_PROFILE_SET_TIMESTAMP.
- void lowerTimestamp(InstrProfTimestampInst *TimestampInstruction);
-
- /// Replace instrprof.increment with an increment of the appropriate value.
- void lowerIncrement(InstrProfIncrementInst *Inc);
-
- /// Force emitting of name vars for unused functions.
- void lowerCoverageData(GlobalVariable *CoverageNamesVar);
-
- /// Replace instrprof.mcdc.tvbitmask.update with a shift and or instruction
- /// using the index represented by the a temp value into a bitmap.
- void lowerMCDCTestVectorBitmapUpdate(InstrProfMCDCTVBitmapUpdate *Ins);
-
- /// Replace instrprof.mcdc.temp.update with a shift and or instruction using
- /// the corresponding condition ID.
- void lowerMCDCCondBitmapUpdate(InstrProfMCDCCondBitmapUpdate *Ins);
-
- /// Compute the address of the counter value that this profiling instruction
- /// acts on.
- Value *getCounterAddress(InstrProfCntrInstBase *I);
-
- /// Get the region counters for an increment, creating them if necessary.
- ///
- /// If the counter array doesn't yet exist, the profile data variables
- /// referring to them will also be created.
- GlobalVariable *getOrCreateRegionCounters(InstrProfCntrInstBase *Inc);
-
- /// Create the region counters.
- GlobalVariable *createRegionCounters(InstrProfCntrInstBase *Inc,
- StringRef Name,
- GlobalValue::LinkageTypes Linkage);
-
- /// Compute the address of the test vector bitmap that this profiling
- /// instruction acts on.
- Value *getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I);
-
- /// Get the region bitmaps for an increment, creating them if necessary.
- ///
- /// If the bitmap array doesn't yet exist, the profile data variables
- /// referring to them will also be created.
- GlobalVariable *getOrCreateRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc);
-
- /// Create the MC/DC bitmap as a byte-aligned array of bytes associated with
- /// an MC/DC Decision region. The number of bytes required is indicated by
- /// the intrinsic used (type InstrProfMCDCBitmapInstBase). This is called
- /// as part of setupProfileSection() and is conceptually very similar to
- /// what is done for profile data counters in createRegionCounters().
- GlobalVariable *createRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc,
- StringRef Name,
- GlobalValue::LinkageTypes Linkage);
-
- /// Set Comdat property of GV, if required.
- void maybeSetComdat(GlobalVariable *GV, Function *Fn, StringRef VarName);
-
- /// Setup the sections into which counters and bitmaps are allocated.
- GlobalVariable *setupProfileSection(InstrProfInstBase *Inc,
- InstrProfSectKind IPSK);
-
- /// Create INSTR_PROF_DATA variable for counters and bitmaps.
- void createDataVariable(InstrProfCntrInstBase *Inc);
-
- /// Emit the section with compressed function names.
- void emitNameData();
-
- /// Emit value nodes section for value profiling.
- void emitVNodes();
-
- /// Emit runtime registration functions for each profile data variable.
- void emitRegistration();
-
- /// Emit the necessary plumbing to pull in the runtime initialization.
- /// Returns true if a change was made.
- bool emitRuntimeHook();
-
- /// Add uses of our data variables and runtime hook.
- void emitUses();
-
- /// Create a static initializer for our data, on platforms that need it,
- /// and for any profile output file that was specified.
- void emitInitialization();
};
-
} // end namespace llvm
#endif // LLVM_TRANSFORMS_INSTRUMENTATION_INSTRPROFILING_H
diff --git a/llvm/include/llvm/Transforms/Instrumentation/MemProfiler.h b/llvm/include/llvm/Transforms/Instrumentation/MemProfiler.h
index 293133b29cd9..f92c6b4775a2 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/MemProfiler.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/MemProfiler.h
@@ -17,9 +17,7 @@
namespace llvm {
class Function;
-class FunctionPass;
class Module;
-class ModulePass;
namespace vfs {
class FileSystem;
diff --git a/llvm/include/llvm/Transforms/Scalar/Scalarizer.h b/llvm/include/llvm/Transforms/Scalar/Scalarizer.h
index c2d9151b4971..45e25cbf2821 100644
--- a/llvm/include/llvm/Transforms/Scalar/Scalarizer.h
+++ b/llvm/include/llvm/Transforms/Scalar/Scalarizer.h
@@ -24,7 +24,6 @@
namespace llvm {
class Function;
-class FunctionPass;
struct ScalarizerPassOptions {
// These options correspond 1:1 to cl::opt options defined in
diff --git a/llvm/include/llvm/Transforms/Scalar/SimpleLoopUnswitch.h b/llvm/include/llvm/Transforms/Scalar/SimpleLoopUnswitch.h
index 417e9668527b..b97ee23fc0e6 100644
--- a/llvm/include/llvm/Transforms/Scalar/SimpleLoopUnswitch.h
+++ b/llvm/include/llvm/Transforms/Scalar/SimpleLoopUnswitch.h
@@ -17,7 +17,6 @@ namespace llvm {
class LPMUpdater;
class Loop;
-class Pass;
class StringRef;
class raw_ostream;
diff --git a/llvm/include/llvm/Transforms/Utils/ValueMapper.h b/llvm/include/llvm/Transforms/Utils/ValueMapper.h
index eedd25f898c0..e1f2796d97ce 100644
--- a/llvm/include/llvm/Transforms/Utils/ValueMapper.h
+++ b/llvm/include/llvm/Transforms/Utils/ValueMapper.h
@@ -22,7 +22,6 @@
namespace llvm {
class Constant;
-class DIBuilder;
class DPValue;
class Function;
class GlobalVariable;
diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index b8a22184d960..da18279ae9b9 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -896,7 +896,7 @@ bool llvm::isNotVisibleOnUnwind(const Value *Object,
// Byval goes out of scope on unwind.
if (auto *A = dyn_cast<Argument>(Object))
- return A->hasByValAttr();
+ return A->hasByValAttr() || A->hasAttribute(Attribute::DeadOnUnwind);
// A noalias return is not accessible from any other code. If the pointer
// does not escape prior to the unwind, then the caller cannot access the
diff --git a/llvm/lib/Analysis/AliasSetTracker.cpp b/llvm/lib/Analysis/AliasSetTracker.cpp
index debdd328ce53..99d20c7bef3b 100644
--- a/llvm/lib/Analysis/AliasSetTracker.cpp
+++ b/llvm/lib/Analysis/AliasSetTracker.cpp
@@ -375,9 +375,8 @@ AliasSet &AliasSetTracker::getAliasSetFor(const MemoryLocation &MemLoc) {
return AliasSets.back();
}
-void AliasSetTracker::add(Value *Ptr, LocationSize Size,
- const AAMDNodes &AAInfo) {
- addPointer(MemoryLocation(Ptr, Size, AAInfo), AliasSet::NoAccess);
+void AliasSetTracker::add(const MemoryLocation &Loc) {
+ addPointer(Loc, AliasSet::NoAccess);
}
void AliasSetTracker::add(LoadInst *LI) {
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index b708ee04c0dd..910f6b72afef 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -453,6 +453,8 @@ public:
BasicBlock *ToBB,
Instruction *CxtI = nullptr);
+ ValueLatticeElement getValueAtUse(const Use &U);
+
/// Complete flush all previously computed values
void clear() {
TheCache.clear();
@@ -754,7 +756,8 @@ LazyValueInfoImpl::solveBlockValuePHINode(PHINode *PN, BasicBlock *BB) {
}
static ValueLatticeElement getValueFromCondition(Value *Val, Value *Cond,
- bool isTrueDest = true);
+ bool isTrueDest = true,
+ unsigned Depth = 0);
// If we can determine a constraint on the value given conditions assumed by
// the program, intersect those constraints with BBLV
@@ -800,11 +803,15 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
}
}
-static ConstantRange getConstantRangeOrFull(const ValueLatticeElement &Val,
- Type *Ty, const DataLayout &DL) {
- if (Val.isConstantRange(/*UndefAllowed*/ false))
+static ConstantRange toConstantRange(const ValueLatticeElement &Val,
+ Type *Ty, bool UndefAllowed = false) {
+ assert(Ty->isIntOrIntVectorTy() && "Must be integer type");
+ if (Val.isConstantRange(UndefAllowed))
return Val.getConstantRange();
- return ConstantRange::getFull(DL.getTypeSizeInBits(Ty));
+ unsigned BW = Ty->getScalarSizeInBits();
+ if (Val.isUnknown())
+ return ConstantRange::getEmpty(BW);
+ return ConstantRange::getFull(BW);
}
std::optional<ValueLatticeElement>
@@ -823,10 +830,8 @@ LazyValueInfoImpl::solveBlockValueSelect(SelectInst *SI, BasicBlock *BB) {
ValueLatticeElement &FalseVal = *OptFalseVal;
if (TrueVal.isConstantRange() || FalseVal.isConstantRange()) {
- const ConstantRange &TrueCR =
- getConstantRangeOrFull(TrueVal, SI->getType(), DL);
- const ConstantRange &FalseCR =
- getConstantRangeOrFull(FalseVal, SI->getType(), DL);
+ const ConstantRange &TrueCR = toConstantRange(TrueVal, SI->getType());
+ const ConstantRange &FalseCR = toConstantRange(FalseVal, SI->getType());
Value *LHS = nullptr;
Value *RHS = nullptr;
SelectPatternResult SPR = matchSelectPattern(SI, LHS, RHS);
@@ -897,16 +902,11 @@ LazyValueInfoImpl::getRangeFor(Value *V, Instruction *CxtI, BasicBlock *BB) {
std::optional<ValueLatticeElement> OptVal = getBlockValue(V, BB, CxtI);
if (!OptVal)
return std::nullopt;
- return getConstantRangeOrFull(*OptVal, V->getType(), DL);
+ return toConstantRange(*OptVal, V->getType());
}
std::optional<ValueLatticeElement>
LazyValueInfoImpl::solveBlockValueCast(CastInst *CI, BasicBlock *BB) {
- // Without knowing how wide the input is, we can't analyze it in any useful
- // way.
- if (!CI->getOperand(0)->getType()->isSized())
- return ValueLatticeElement::getOverdefined();
-
// Filter out casts we don't know how to reason about before attempting to
// recurse on our operand. This can cut a long search short if we know we're
// not going to be able to get any useful information anways.
@@ -914,7 +914,6 @@ LazyValueInfoImpl::solveBlockValueCast(CastInst *CI, BasicBlock *BB) {
case Instruction::Trunc:
case Instruction::SExt:
case Instruction::ZExt:
- case Instruction::BitCast:
break;
default:
// Unhandled instructions are overdefined.
@@ -1213,36 +1212,22 @@ static ValueLatticeElement getValueFromOverflowCondition(
return ValueLatticeElement::getRange(NWR);
}
-// Tracks a Value * condition and whether we're interested in it or its inverse
-typedef PointerIntPair<Value *, 1, bool> CondValue;
-
-static std::optional<ValueLatticeElement> getValueFromConditionImpl(
- Value *Val, CondValue CondVal, bool isRevisit,
- SmallDenseMap<CondValue, ValueLatticeElement> &Visited,
- SmallVectorImpl<CondValue> &Worklist) {
+static ValueLatticeElement getValueFromCondition(
+ Value *Val, Value *Cond, bool IsTrueDest, unsigned Depth) {
+ if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond))
+ return getValueFromICmpCondition(Val, ICI, IsTrueDest);
- Value *Cond = CondVal.getPointer();
- bool isTrueDest = CondVal.getInt();
- if (!isRevisit) {
- if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond))
- return getValueFromICmpCondition(Val, ICI, isTrueDest);
+ if (auto *EVI = dyn_cast<ExtractValueInst>(Cond))
+ if (auto *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand()))
+ if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1)
+ return getValueFromOverflowCondition(Val, WO, IsTrueDest);
- if (auto *EVI = dyn_cast<ExtractValueInst>(Cond))
- if (auto *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand()))
- if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1)
- return getValueFromOverflowCondition(Val, WO, isTrueDest);
- }
+ if (++Depth == MaxAnalysisRecursionDepth)
+ return ValueLatticeElement::getOverdefined();
Value *N;
- if (match(Cond, m_Not(m_Value(N)))) {
- CondValue NKey(N, !isTrueDest);
- auto NV = Visited.find(NKey);
- if (NV == Visited.end()) {
- Worklist.push_back(NKey);
- return std::nullopt;
- }
- return NV->second;
- }
+ if (match(Cond, m_Not(m_Value(N))))
+ return getValueFromCondition(Val, N, !IsTrueDest, Depth);
Value *L, *R;
bool IsAnd;
@@ -1253,64 +1238,19 @@ static std::optional<ValueLatticeElement> getValueFromConditionImpl(
else
return ValueLatticeElement::getOverdefined();
- auto LV = Visited.find(CondValue(L, isTrueDest));
- auto RV = Visited.find(CondValue(R, isTrueDest));
+ ValueLatticeElement LV = getValueFromCondition(Val, L, IsTrueDest, Depth);
+ ValueLatticeElement RV = getValueFromCondition(Val, R, IsTrueDest, Depth);
// if (L && R) -> intersect L and R
// if (!(L || R)) -> intersect !L and !R
// if (L || R) -> union L and R
// if (!(L && R)) -> union !L and !R
- if ((isTrueDest ^ IsAnd) && (LV != Visited.end())) {
- ValueLatticeElement V = LV->second;
- if (V.isOverdefined())
- return V;
- if (RV != Visited.end()) {
- V.mergeIn(RV->second);
- return V;
- }
- }
-
- if (LV == Visited.end() || RV == Visited.end()) {
- assert(!isRevisit);
- if (LV == Visited.end())
- Worklist.push_back(CondValue(L, isTrueDest));
- if (RV == Visited.end())
- Worklist.push_back(CondValue(R, isTrueDest));
- return std::nullopt;
+ if (IsTrueDest ^ IsAnd) {
+ LV.mergeIn(RV);
+ return LV;
}
- return intersect(LV->second, RV->second);
-}
-
-ValueLatticeElement getValueFromCondition(Value *Val, Value *Cond,
- bool isTrueDest) {
- assert(Cond && "precondition");
- SmallDenseMap<CondValue, ValueLatticeElement> Visited;
- SmallVector<CondValue> Worklist;
-
- CondValue CondKey(Cond, isTrueDest);
- Worklist.push_back(CondKey);
- do {
- CondValue CurrentCond = Worklist.back();
- // Insert an Overdefined placeholder into the set to prevent
- // infinite recursion if there exists IRs that use not
- // dominated by its def as in this example:
- // "%tmp3 = or i1 undef, %tmp4"
- // "%tmp4 = or i1 undef, %tmp3"
- auto Iter =
- Visited.try_emplace(CurrentCond, ValueLatticeElement::getOverdefined());
- bool isRevisit = !Iter.second;
- std::optional<ValueLatticeElement> Result = getValueFromConditionImpl(
- Val, CurrentCond, isRevisit, Visited, Worklist);
- if (Result) {
- Visited[CurrentCond] = *Result;
- Worklist.pop_back();
- }
- } while (!Worklist.empty());
-
- auto Result = Visited.find(CondKey);
- assert(Result != Visited.end());
- return Result->second;
+ return intersect(LV, RV);
}
// Return true if Usr has Op as an operand, otherwise false.
@@ -1361,12 +1301,9 @@ static ValueLatticeElement constantFoldUser(User *Usr, Value *Op,
return ValueLatticeElement::getOverdefined();
}
-/// Compute the value of Val on the edge BBFrom -> BBTo. Returns false if
-/// Val is not constrained on the edge. Result is unspecified if return value
-/// is false.
-static std::optional<ValueLatticeElement> getEdgeValueLocal(Value *Val,
- BasicBlock *BBFrom,
- BasicBlock *BBTo) {
+/// Compute the value of Val on the edge BBFrom -> BBTo.
+static ValueLatticeElement getEdgeValueLocal(Value *Val, BasicBlock *BBFrom,
+ BasicBlock *BBTo) {
// TODO: Handle more complex conditionals. If (v == 0 || v2 < 1) is false, we
// know that v != 0.
if (BranchInst *BI = dyn_cast<BranchInst>(BBFrom->getTerminator())) {
@@ -1440,7 +1377,7 @@ static std::optional<ValueLatticeElement> getEdgeValueLocal(Value *Val,
if (SwitchInst *SI = dyn_cast<SwitchInst>(BBFrom->getTerminator())) {
Value *Condition = SI->getCondition();
if (!isa<IntegerType>(Val->getType()))
- return std::nullopt;
+ return ValueLatticeElement::getOverdefined();
bool ValUsesConditionAndMayBeFoldable = false;
if (Condition != Val) {
// Check if Val has Condition as an operand.
@@ -1448,7 +1385,7 @@ static std::optional<ValueLatticeElement> getEdgeValueLocal(Value *Val,
ValUsesConditionAndMayBeFoldable = isOperationFoldable(Usr) &&
usesOperand(Usr, Condition);
if (!ValUsesConditionAndMayBeFoldable)
- return std::nullopt;
+ return ValueLatticeElement::getOverdefined();
}
assert((Condition == Val || ValUsesConditionAndMayBeFoldable) &&
"Condition != Val nor Val doesn't use Condition");
@@ -1466,7 +1403,7 @@ static std::optional<ValueLatticeElement> getEdgeValueLocal(Value *Val,
ValueLatticeElement EdgeLatticeVal =
constantFoldUser(Usr, Condition, CaseValue, DL);
if (EdgeLatticeVal.isOverdefined())
- return std::nullopt;
+ return ValueLatticeElement::getOverdefined();
EdgeVal = EdgeLatticeVal.getConstantRange();
}
if (DefaultCase) {
@@ -1483,7 +1420,7 @@ static std::optional<ValueLatticeElement> getEdgeValueLocal(Value *Val,
}
return ValueLatticeElement::getRange(std::move(EdgesVals));
}
- return std::nullopt;
+ return ValueLatticeElement::getOverdefined();
}
/// Compute the value of Val on the edge BBFrom -> BBTo or the value at
@@ -1495,9 +1432,7 @@ LazyValueInfoImpl::getEdgeValue(Value *Val, BasicBlock *BBFrom,
if (Constant *VC = dyn_cast<Constant>(Val))
return ValueLatticeElement::get(VC);
- ValueLatticeElement LocalResult =
- getEdgeValueLocal(Val, BBFrom, BBTo)
- .value_or(ValueLatticeElement::getOverdefined());
+ ValueLatticeElement LocalResult = getEdgeValueLocal(Val, BBFrom, BBTo);
if (hasSingleValue(LocalResult))
// Can't get any more precise here
return LocalResult;
@@ -1574,6 +1509,52 @@ getValueOnEdge(Value *V, BasicBlock *FromBB, BasicBlock *ToBB,
return *Result;
}
+ValueLatticeElement LazyValueInfoImpl::getValueAtUse(const Use &U) {
+ Value *V = U.get();
+ auto *CxtI = cast<Instruction>(U.getUser());
+ ValueLatticeElement VL = getValueInBlock(V, CxtI->getParent(), CxtI);
+
+ // Check whether the only (possibly transitive) use of the value is in a
+ // position where V can be constrained by a select or branch condition.
+ const Use *CurrU = &U;
+ // TODO: Increase limit?
+ const unsigned MaxUsesToInspect = 3;
+ for (unsigned I = 0; I < MaxUsesToInspect; ++I) {
+ std::optional<ValueLatticeElement> CondVal;
+ auto *CurrI = cast<Instruction>(CurrU->getUser());
+ if (auto *SI = dyn_cast<SelectInst>(CurrI)) {
+ // If the value is undef, a different value may be chosen in
+ // the select condition and at use.
+ if (!isGuaranteedNotToBeUndef(SI->getCondition(), AC))
+ break;
+ if (CurrU->getOperandNo() == 1)
+ CondVal = getValueFromCondition(V, SI->getCondition(), true);
+ else if (CurrU->getOperandNo() == 2)
+ CondVal = getValueFromCondition(V, SI->getCondition(), false);
+ } else if (auto *PHI = dyn_cast<PHINode>(CurrI)) {
+ // TODO: Use non-local query?
+ CondVal =
+ getEdgeValueLocal(V, PHI->getIncomingBlock(*CurrU), PHI->getParent());
+ }
+ if (CondVal)
+ VL = intersect(VL, *CondVal);
+
+ // Only follow one-use chain, to allow direct intersection of conditions.
+ // If there are multiple uses, we would have to intersect with the union of
+ // all conditions at different uses.
+ // Stop walking if we hit a non-speculatable instruction. Even if the
+ // result is only used under a specific condition, executing the
+ // instruction itself may cause side effects or UB already.
+ // This also disallows looking through phi nodes: If the phi node is part
+ // of a cycle, we might end up reasoning about values from different cycle
+ // iterations (PR60629).
+ if (!CurrI->hasOneUse() || !isSafeToSpeculativelyExecute(CurrI))
+ break;
+ CurrU = &*CurrI->use_begin();
+ }
+ return VL;
+}
+
void LazyValueInfoImpl::threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc,
BasicBlock *NewSucc) {
TheCache.threadEdgeImpl(OldSucc, NewSucc);
@@ -1687,66 +1668,18 @@ Constant *LazyValueInfo::getConstant(Value *V, Instruction *CxtI) {
ConstantRange LazyValueInfo::getConstantRange(Value *V, Instruction *CxtI,
bool UndefAllowed) {
assert(V->getType()->isIntegerTy());
- unsigned Width = V->getType()->getIntegerBitWidth();
BasicBlock *BB = CxtI->getParent();
ValueLatticeElement Result =
getOrCreateImpl(BB->getModule()).getValueInBlock(V, BB, CxtI);
- if (Result.isUnknown())
- return ConstantRange::getEmpty(Width);
- if (Result.isConstantRange(UndefAllowed))
- return Result.getConstantRange(UndefAllowed);
- // We represent ConstantInt constants as constant ranges but other kinds
- // of integer constants, i.e. ConstantExpr will be tagged as constants
- assert(!(Result.isConstant() && isa<ConstantInt>(Result.getConstant())) &&
- "ConstantInt value must be represented as constantrange");
- return ConstantRange::getFull(Width);
+ return toConstantRange(Result, V->getType(), UndefAllowed);
}
ConstantRange LazyValueInfo::getConstantRangeAtUse(const Use &U,
bool UndefAllowed) {
- Value *V = U.get();
- ConstantRange CR =
- getConstantRange(V, cast<Instruction>(U.getUser()), UndefAllowed);
-
- // Check whether the only (possibly transitive) use of the value is in a
- // position where V can be constrained by a select or branch condition.
- const Use *CurrU = &U;
- // TODO: Increase limit?
- const unsigned MaxUsesToInspect = 3;
- for (unsigned I = 0; I < MaxUsesToInspect; ++I) {
- std::optional<ValueLatticeElement> CondVal;
- auto *CurrI = cast<Instruction>(CurrU->getUser());
- if (auto *SI = dyn_cast<SelectInst>(CurrI)) {
- // If the value is undef, a different value may be chosen in
- // the select condition and at use.
- if (!isGuaranteedNotToBeUndef(SI->getCondition(), AC))
- break;
- if (CurrU->getOperandNo() == 1)
- CondVal = getValueFromCondition(V, SI->getCondition(), true);
- else if (CurrU->getOperandNo() == 2)
- CondVal = getValueFromCondition(V, SI->getCondition(), false);
- } else if (auto *PHI = dyn_cast<PHINode>(CurrI)) {
- // TODO: Use non-local query?
- CondVal =
- getEdgeValueLocal(V, PHI->getIncomingBlock(*CurrU), PHI->getParent());
- }
- if (CondVal && CondVal->isConstantRange())
- CR = CR.intersectWith(CondVal->getConstantRange());
-
- // Only follow one-use chain, to allow direct intersection of conditions.
- // If there are multiple uses, we would have to intersect with the union of
- // all conditions at different uses.
- // Stop walking if we hit a non-speculatable instruction. Even if the
- // result is only used under a specific condition, executing the
- // instruction itself may cause side effects or UB already.
- // This also disallows looking through phi nodes: If the phi node is part
- // of a cycle, we might end up reasoning about values from different cycle
- // iterations (PR60629).
- if (!CurrI->hasOneUse() || !isSafeToSpeculativelyExecute(CurrI))
- break;
- CurrU = &*CurrI->use_begin();
- }
- return CR;
+ auto *Inst = cast<Instruction>(U.getUser());
+ ValueLatticeElement Result =
+ getOrCreateImpl(Inst->getModule()).getValueAtUse(U);
+ return toConstantRange(Result, U->getType(), UndefAllowed);
}
/// Determine whether the specified value is known to be a
@@ -1772,20 +1705,11 @@ ConstantRange LazyValueInfo::getConstantRangeOnEdge(Value *V,
BasicBlock *FromBB,
BasicBlock *ToBB,
Instruction *CxtI) {
- unsigned Width = V->getType()->getIntegerBitWidth();
Module *M = FromBB->getModule();
ValueLatticeElement Result =
getOrCreateImpl(M).getValueOnEdge(V, FromBB, ToBB, CxtI);
-
- if (Result.isUnknown())
- return ConstantRange::getEmpty(Width);
- if (Result.isConstantRange())
- return Result.getConstantRange();
- // We represent ConstantInt constants as constant ranges but other kinds
- // of integer constants, i.e. ConstantExpr will be tagged as constants
- assert(!(Result.isConstant() && isa<ConstantInt>(Result.getConstant())) &&
- "ConstantInt value must be represented as constantrange");
- return ConstantRange::getFull(Width);
+ // TODO: Should undef be allowed here?
+ return toConstantRange(Result, V->getType(), /*UndefAllowed*/ true);
}
static LazyValueInfo::Tristate
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index a8dbb66c4a9f..0894560fd078 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -347,7 +347,12 @@ void RuntimePointerChecking::tryToCreateDiffCheck(
auto *SinkStartAR = cast<SCEVAddRecExpr>(SinkStartInt);
const Loop *StartARLoop = SrcStartAR->getLoop();
if (StartARLoop == SinkStartAR->getLoop() &&
- StartARLoop == InnerLoop->getParentLoop()) {
+ StartARLoop == InnerLoop->getParentLoop() &&
+ // If the diff check would already be loop invariant (due to the
+ // recurrences being the same), then we prefer to keep the diff checks
+ // because they are cheaper.
+ SrcStartAR->getStepRecurrence(*SE) !=
+ SinkStartAR->getStepRecurrence(*SE)) {
LLVM_DEBUG(dbgs() << "LAA: Not creating diff runtime check, since these "
"cannot be hoisted out of the outer loop\n");
CanUseDiffCheck = false;
@@ -661,7 +666,7 @@ public:
/// Register a load and whether it is only read from.
void addLoad(MemoryLocation &Loc, Type *AccessTy, bool IsReadOnly) {
Value *Ptr = const_cast<Value*>(Loc.Ptr);
- AST.add(Ptr, LocationSize::beforeOrAfterPointer(), Loc.AATags);
+ AST.add(Loc.getWithNewSize(LocationSize::beforeOrAfterPointer()));
Accesses[MemAccessInfo(Ptr, false)].insert(AccessTy);
if (IsReadOnly)
ReadOnlyPtr.insert(Ptr);
@@ -670,7 +675,7 @@ public:
/// Register a store.
void addStore(MemoryLocation &Loc, Type *AccessTy) {
Value *Ptr = const_cast<Value*>(Loc.Ptr);
- AST.add(Ptr, LocationSize::beforeOrAfterPointer(), Loc.AATags);
+ AST.add(Loc.getWithNewSize(LocationSize::beforeOrAfterPointer()));
Accesses[MemAccessInfo(Ptr, true)].insert(AccessTy);
}
diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp
index 7567efbedfb0..87ddfe3e92ae 100644
--- a/llvm/lib/Analysis/LoopInfo.cpp
+++ b/llvm/lib/Analysis/LoopInfo.cpp
@@ -1143,7 +1143,7 @@ MDNode *llvm::makePostTransformationMetadata(LLVMContext &Context,
if (S)
IsVectorMetadata =
llvm::any_of(RemovePrefixes, [S](StringRef Prefix) -> bool {
- return S->getString().startswith(Prefix);
+ return S->getString().starts_with(Prefix);
});
}
if (!IsVectorMetadata)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 451ae73dbd60..580fe112fcd7 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -12910,7 +12910,11 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
if (!BECount) {
auto canProveRHSGreaterThanEqualStart = [&]() {
auto CondGE = IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE;
- if (isLoopEntryGuardedByCond(L, CondGE, OrigRHS, OrigStart))
+ const SCEV *GuardedRHS = applyLoopGuards(OrigRHS, L);
+ const SCEV *GuardedStart = applyLoopGuards(OrigStart, L);
+
+ if (isLoopEntryGuardedByCond(L, CondGE, OrigRHS, OrigStart) ||
+ isKnownPredicate(CondGE, GuardedRHS, GuardedStart))
return true;
// (RHS > Start - 1) implies RHS >= Start.
diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp
index 63b1b7567c8e..3f76dfdaac31 100644
--- a/llvm/lib/Analysis/TargetTransformInfo.cpp
+++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
@@ -682,6 +682,11 @@ TargetTransformInfo::getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
return Cost;
}
+bool TargetTransformInfo::preferToKeepConstantsAttached(
+ const Instruction &Inst, const Function &Fn) const {
+ return TTIImpl->preferToKeepConstantsAttached(Inst, Fn);
+}
+
unsigned TargetTransformInfo::getNumberOfRegisters(unsigned ClassID) const {
return TTIImpl->getNumberOfRegisters(ClassID);
}
diff --git a/llvm/lib/Analysis/VFABIDemangling.cpp b/llvm/lib/Analysis/VFABIDemangling.cpp
index 92af314a41ca..ad918ef7245b 100644
--- a/llvm/lib/Analysis/VFABIDemangling.cpp
+++ b/llvm/lib/Analysis/VFABIDemangling.cpp
@@ -32,7 +32,7 @@ static ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) {
if (MangledName.empty())
return ParseRet::Error;
- if (MangledName.startswith(VFABI::_LLVM_)) {
+ if (MangledName.starts_with(VFABI::_LLVM_)) {
MangledName = MangledName.drop_front(strlen(VFABI::_LLVM_));
ISA = VFISAKind::LLVM;
} else {
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 5445746ab2a1..9ae05a4b5ccc 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3096,6 +3096,58 @@ static bool isNonEqualSelect(const Value *V1, const Value *V2, unsigned Depth,
isKnownNonEqual(SI1->getFalseValue(), V2, Depth + 1, Q);
}
+// Check to see if A is both a GEP and is the incoming value for a PHI in the
+// loop, and B is either a ptr or another GEP. If the PHI has 2 incoming values,
+// one of them being the recursive GEP A and the other a ptr at same base and at
+// the same/higher offset than B we are only incrementing the pointer further in
+// loop if offset of recursive GEP is greater than 0.
+static bool isNonEqualPointersWithRecursiveGEP(const Value *A, const Value *B,
+ const SimplifyQuery &Q) {
+ if (!A->getType()->isPointerTy() || !B->getType()->isPointerTy())
+ return false;
+
+ auto *GEPA = dyn_cast<GEPOperator>(A);
+ if (!GEPA || GEPA->getNumIndices() != 1 || !isa<Constant>(GEPA->idx_begin()))
+ return false;
+
+ // Handle 2 incoming PHI values with one being a recursive GEP.
+ auto *PN = dyn_cast<PHINode>(GEPA->getPointerOperand());
+ if (!PN || PN->getNumIncomingValues() != 2)
+ return false;
+
+ // Search for the recursive GEP as an incoming operand, and record that as
+ // Step.
+ Value *Start = nullptr;
+ Value *Step = const_cast<Value *>(A);
+ if (PN->getIncomingValue(0) == Step)
+ Start = PN->getIncomingValue(1);
+ else if (PN->getIncomingValue(1) == Step)
+ Start = PN->getIncomingValue(0);
+ else
+ return false;
+
+ // Other incoming node base should match the B base.
+ // StartOffset >= OffsetB && StepOffset > 0?
+ // StartOffset <= OffsetB && StepOffset < 0?
+ // Is non-equal if above are true.
+ // We use stripAndAccumulateInBoundsConstantOffsets to restrict the
+ // optimisation to inbounds GEPs only.
+ unsigned IndexWidth = Q.DL.getIndexTypeSizeInBits(Start->getType());
+ APInt StartOffset(IndexWidth, 0);
+ Start = Start->stripAndAccumulateInBoundsConstantOffsets(Q.DL, StartOffset);
+ APInt StepOffset(IndexWidth, 0);
+ Step = Step->stripAndAccumulateInBoundsConstantOffsets(Q.DL, StepOffset);
+
+ // Check if Base Pointer of Step matches the PHI.
+ if (Step != PN)
+ return false;
+ APInt OffsetB(IndexWidth, 0);
+ B = B->stripAndAccumulateInBoundsConstantOffsets(Q.DL, OffsetB);
+ return Start == B &&
+ ((StartOffset.sge(OffsetB) && StepOffset.isStrictlyPositive()) ||
+ (StartOffset.sle(OffsetB) && StepOffset.isNegative()));
+}
+
/// Return true if it is known that V1 != V2.
static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
const SimplifyQuery &Q) {
@@ -3149,6 +3201,10 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
if (isNonEqualSelect(V1, V2, Depth, Q) || isNonEqualSelect(V2, V1, Depth, Q))
return true;
+ if (isNonEqualPointersWithRecursiveGEP(V1, V2, Q) ||
+ isNonEqualPointersWithRecursiveGEP(V2, V1, Q))
+ return true;
+
return false;
}
@@ -8102,10 +8158,9 @@ static bool isTruePredicate(CmpInst::Predicate Pred, const Value *LHS,
}
case CmpInst::ICMP_ULE: {
- const APInt *C;
-
- // LHS u<= LHS +_{nuw} C for any C
- if (match(RHS, m_NUWAdd(m_Specific(LHS), m_APInt(C))))
+ // LHS u<= LHS +_{nuw} V for any V
+ if (match(RHS, m_c_Add(m_Specific(LHS), m_Value())) &&
+ cast<OverflowingBinaryOperator>(RHS)->hasNoUnsignedWrap())
return true;
// RHS >> V u<= RHS for any V
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 919c69fe2783..c8da3efbb68a 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -906,7 +906,7 @@ lltok::Kind LLLexer::LexIdentifier() {
#define DWKEYWORD(TYPE, TOKEN) \
do { \
- if (Keyword.startswith("DW_" #TYPE "_")) { \
+ if (Keyword.starts_with("DW_" #TYPE "_")) { \
StrVal.assign(Keyword.begin(), Keyword.end()); \
return lltok::TOKEN; \
} \
@@ -922,17 +922,17 @@ lltok::Kind LLLexer::LexIdentifier() {
#undef DWKEYWORD
- if (Keyword.startswith("DIFlag")) {
+ if (Keyword.starts_with("DIFlag")) {
StrVal.assign(Keyword.begin(), Keyword.end());
return lltok::DIFlag;
}
- if (Keyword.startswith("DISPFlag")) {
+ if (Keyword.starts_with("DISPFlag")) {
StrVal.assign(Keyword.begin(), Keyword.end());
return lltok::DISPFlag;
}
- if (Keyword.startswith("CSK_")) {
+ if (Keyword.starts_with("CSK_")) {
StrVal.assign(Keyword.begin(), Keyword.end());
return lltok::ChecksumKind;
}
diff --git a/llvm/lib/BinaryFormat/Magic.cpp b/llvm/lib/BinaryFormat/Magic.cpp
index 420224df57df..45a0b7e11452 100644
--- a/llvm/lib/BinaryFormat/Magic.cpp
+++ b/llvm/lib/BinaryFormat/Magic.cpp
@@ -26,7 +26,7 @@ using namespace llvm::sys::fs;
template <size_t N>
static bool startswith(StringRef Magic, const char (&S)[N]) {
- return Magic.startswith(StringRef(S, N - 1));
+ return Magic.starts_with(StringRef(S, N - 1));
}
/// Identify the magic in magic.
@@ -72,6 +72,14 @@ file_magic llvm::identify_magic(StringRef Magic) {
case 0x03:
if (startswith(Magic, "\x03\xF0\x00"))
return file_magic::goff_object;
+ // SPIR-V format in little-endian mode.
+ if (startswith(Magic, "\x03\x02\x23\x07"))
+ return file_magic::spirv_object;
+ break;
+
+ case 0x07: // SPIR-V format in big-endian mode.
+ if (startswith(Magic, "\x07\x23\x02\x03"))
+ return file_magic::spirv_object;
break;
case 0x10:
@@ -217,11 +225,11 @@ file_magic llvm::identify_magic(StringRef Magic) {
if (startswith(Magic, "MZ") && Magic.size() >= 0x3c + 4) {
uint32_t off = read32le(Magic.data() + 0x3c);
// PE/COFF file, either EXE or DLL.
- if (Magic.substr(off).startswith(
+ if (Magic.substr(off).starts_with(
StringRef(COFF::PEMagic, sizeof(COFF::PEMagic))))
return file_magic::pecoff_executable;
}
- if (Magic.startswith("Microsoft C/C++ MSF 7.00\r\n"))
+ if (Magic.starts_with("Microsoft C/C++ MSF 7.00\r\n"))
return file_magic::pdb;
if (startswith(Magic, "MDMP"))
return file_magic::minidump;
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 9d7e838733b5..8907f6fa4ff3 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2098,6 +2098,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::Writable;
case bitc::ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE:
return Attribute::CoroDestroyOnlyWhenComplete;
+ case bitc::ATTR_KIND_DEAD_ON_UNWIND:
+ return Attribute::DeadOnUnwind;
}
}
@@ -5248,7 +5250,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
return error(
"Invalid record: operand number exceeded available operands");
- unsigned PredVal = Record[OpNum];
+ CmpInst::Predicate PredVal = CmpInst::Predicate(Record[OpNum]);
bool IsFP = LHS->getType()->isFPOrFPVectorTy();
FastMathFlags FMF;
if (IsFP && Record.size() > OpNum+1)
@@ -5257,10 +5259,15 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
if (OpNum+1 != Record.size())
return error("Invalid record");
- if (LHS->getType()->isFPOrFPVectorTy())
- I = new FCmpInst((FCmpInst::Predicate)PredVal, LHS, RHS);
- else
- I = new ICmpInst((ICmpInst::Predicate)PredVal, LHS, RHS);
+ if (IsFP) {
+ if (!CmpInst::isFPPredicate(PredVal))
+ return error("Invalid fcmp predicate");
+ I = new FCmpInst(PredVal, LHS, RHS);
+ } else {
+ if (!CmpInst::isIntPredicate(PredVal))
+ return error("Invalid icmp predicate");
+ I = new ICmpInst(PredVal, LHS, RHS);
+ }
ResTypeID = getVirtualTypeID(I->getType()->getScalarType());
if (LHS->getType()->isVectorTy())
@@ -5363,6 +5370,8 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
Type *TokenTy = Type::getTokenTy(Context);
Value *ParentPad = getValue(Record, Idx++, NextValueNo, TokenTy,
getVirtualTypeID(TokenTy), CurBB);
+ if (!ParentPad)
+ return error("Invalid record");
unsigned NumHandlers = Record[Idx++];
@@ -5404,6 +5413,8 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
Type *TokenTy = Type::getTokenTy(Context);
Value *ParentPad = getValue(Record, Idx++, NextValueNo, TokenTy,
getVirtualTypeID(TokenTy), CurBB);
+ if (!ParentPad)
+ return error("Invald record");
unsigned NumArgOperands = Record[Idx++];
@@ -5958,6 +5969,9 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
if (!Align)
Align = DL.getPrefTypeAlign(Ty);
+ if (!Size->getType()->isIntegerTy())
+ return error("alloca element count must have integer type");
+
AllocaInst *AI = new AllocaInst(Ty, AS, Size, *Align);
AI->setUsedWithInAlloca(InAlloca);
AI->setSwiftError(SwiftError);
diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
index 1a4b55ea3818..910e97489dbb 100644
--- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
+++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
@@ -1633,7 +1633,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
// DICompositeType flag specifying whether template parameters are
// required on declarations of this type.
StringRef NameStr = Name->getString();
- if (!NameStr.contains('<') || NameStr.startswith("_STN|"))
+ if (!NameStr.contains('<') || NameStr.starts_with("_STN|"))
TemplateParams = getMDOrNull(Record[14]);
}
} else {
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 4e0379f5f407..8fca569a391b 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -827,6 +827,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_WRITABLE;
case Attribute::CoroDestroyOnlyWhenComplete:
return bitc::ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE;
+ case Attribute::DeadOnUnwind:
+ return bitc::ATTR_KIND_DEAD_ON_UNWIND;
case Attribute::EndAttrKinds:
llvm_unreachable("Can not encode end-attribute kinds marker.");
case Attribute::None:
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 3a679f1576b7..61309c51336e 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -59,6 +59,7 @@
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Config/config.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Comdat.h"
@@ -2147,24 +2148,80 @@ void AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
assert(!TM.getTargetTriple().isOSBinFormatXCOFF() &&
"IFunc is not supported on AIX.");
- MCSymbol *Name = getSymbol(&GI);
+ auto EmitLinkage = [&](MCSymbol *Sym) {
+ if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
+ OutStreamer->emitSymbolAttribute(Sym, MCSA_Global);
+ else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
+ OutStreamer->emitSymbolAttribute(Sym, MCSA_WeakReference);
+ else
+ assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+ };
- if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
- OutStreamer->emitSymbolAttribute(Name, MCSA_Global);
- else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
- OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference);
- else
- assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+ if (TM.getTargetTriple().isOSBinFormatELF()) {
+ MCSymbol *Name = getSymbol(&GI);
+ EmitLinkage(Name);
+ OutStreamer->emitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction);
+ emitVisibility(Name, GI.getVisibility());
+
+ // Emit the directives as assignments aka .set:
+ const MCExpr *Expr = lowerConstant(GI.getResolver());
+ OutStreamer->emitAssignment(Name, Expr);
+ MCSymbol *LocalAlias = getSymbolPreferLocal(GI);
+ if (LocalAlias != Name)
+ OutStreamer->emitAssignment(LocalAlias, Expr);
+
+ return;
+ }
- OutStreamer->emitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction);
- emitVisibility(Name, GI.getVisibility());
+ if (!TM.getTargetTriple().isOSBinFormatMachO() || !getIFuncMCSubtargetInfo())
+ llvm::report_fatal_error("IFuncs are not supported on this platform");
- // Emit the directives as assignments aka .set:
- const MCExpr *Expr = lowerConstant(GI.getResolver());
- OutStreamer->emitAssignment(Name, Expr);
- MCSymbol *LocalAlias = getSymbolPreferLocal(GI);
- if (LocalAlias != Name)
- OutStreamer->emitAssignment(LocalAlias, Expr);
+ // On Darwin platforms, emit a manually-constructed .symbol_resolver that
+ // implements the symbol resolution duties of the IFunc.
+ //
+ // Normally, this would be handled by linker magic, but unfortunately there
+ // are a few limitations in ld64 and ld-prime's implementation of
+ // .symbol_resolver that mean we can't always use them:
+ //
+ // * resolvers cannot be the target of an alias
+ // * resolvers cannot have private linkage
+ // * resolvers cannot have linkonce linkage
+ // * resolvers cannot appear in executables
+ // * resolvers cannot appear in bundles
+ //
+ // This works around that by emitting a close approximation of what the
+ // linker would have done.
+
+ MCSymbol *LazyPointer =
+ GetExternalSymbolSymbol(GI.getName() + ".lazy_pointer");
+ MCSymbol *StubHelper = GetExternalSymbolSymbol(GI.getName() + ".stub_helper");
+
+ OutStreamer->switchSection(OutContext.getObjectFileInfo()->getDataSection());
+
+ const DataLayout &DL = M.getDataLayout();
+ emitAlignment(Align(DL.getPointerSize()));
+ OutStreamer->emitLabel(LazyPointer);
+ emitVisibility(LazyPointer, GI.getVisibility());
+ OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8);
+
+ OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
+
+ const TargetSubtargetInfo *STI =
+ TM.getSubtargetImpl(*GI.getResolverFunction());
+ const TargetLowering *TLI = STI->getTargetLowering();
+ Align TextAlign(TLI->getMinFunctionAlignment());
+
+ MCSymbol *Stub = getSymbol(&GI);
+ EmitLinkage(Stub);
+ OutStreamer->emitCodeAlignment(TextAlign, getIFuncMCSubtargetInfo());
+ OutStreamer->emitLabel(Stub);
+ emitVisibility(Stub, GI.getVisibility());
+ emitMachOIFuncStubBody(M, GI, LazyPointer);
+
+ OutStreamer->emitCodeAlignment(TextAlign, getIFuncMCSubtargetInfo());
+ OutStreamer->emitLabel(StubHelper);
+ emitVisibility(StubHelper, GI.getVisibility());
+ emitMachOIFuncStubHelperBody(M, GI, LazyPointer);
}
void AsmPrinter::emitRemarksSection(remarks::RemarkStreamer &RS) {
@@ -2311,6 +2368,32 @@ bool AsmPrinter::doFinalization(Module &M) {
// through user plugins.
emitStackMaps();
+ // Print aliases in topological order, that is, for each alias a = b,
+ // b must be printed before a.
+ // This is because on some targets (e.g. PowerPC) linker expects aliases in
+ // such an order to generate correct TOC information.
+ SmallVector<const GlobalAlias *, 16> AliasStack;
+ SmallPtrSet<const GlobalAlias *, 16> AliasVisited;
+ for (const auto &Alias : M.aliases()) {
+ if (Alias.hasAvailableExternallyLinkage())
+ continue;
+ for (const GlobalAlias *Cur = &Alias; Cur;
+ Cur = dyn_cast<GlobalAlias>(Cur->getAliasee())) {
+ if (!AliasVisited.insert(Cur).second)
+ break;
+ AliasStack.push_back(Cur);
+ }
+ for (const GlobalAlias *AncestorAlias : llvm::reverse(AliasStack))
+ emitGlobalAlias(M, *AncestorAlias);
+ AliasStack.clear();
+ }
+
+ // IFuncs must come before deubginfo in case the backend decides to emit them
+ // as actual functions, since on Mach-O targets, we cannot create regular
+ // sections after DWARF.
+ for (const auto &IFunc : M.ifuncs())
+ emitGlobalIFunc(M, IFunc);
+
// Finalize debug and EH information.
for (const HandlerInfo &HI : Handlers) {
NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName,
@@ -2350,28 +2433,6 @@ bool AsmPrinter::doFinalization(Module &M) {
}
}
- // Print aliases in topological order, that is, for each alias a = b,
- // b must be printed before a.
- // This is because on some targets (e.g. PowerPC) linker expects aliases in
- // such an order to generate correct TOC information.
- SmallVector<const GlobalAlias *, 16> AliasStack;
- SmallPtrSet<const GlobalAlias *, 16> AliasVisited;
- for (const auto &Alias : M.aliases()) {
- if (Alias.hasAvailableExternallyLinkage())
- continue;
- for (const GlobalAlias *Cur = &Alias; Cur;
- Cur = dyn_cast<GlobalAlias>(Cur->getAliasee())) {
- if (!AliasVisited.insert(Cur).second)
- break;
- AliasStack.push_back(Cur);
- }
- for (const GlobalAlias *AncestorAlias : llvm::reverse(AliasStack))
- emitGlobalAlias(M, *AncestorAlias);
- AliasStack.clear();
- }
- for (const auto &IFunc : M.ifuncs())
- emitGlobalIFunc(M, IFunc);
-
GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
assert(MI && "AsmPrinter didn't require GCModuleInfo?");
for (GCModuleInfo::iterator I = MI->end(), E = MI->begin(); I != E; )
@@ -3745,7 +3806,7 @@ MCSymbol *AsmPrinter::getSymbolWithGlobalValueBase(const GlobalValue *GV,
}
/// Return the MCSymbol for the specified ExternalSymbol.
-MCSymbol *AsmPrinter::GetExternalSymbolSymbol(StringRef Sym) const {
+MCSymbol *AsmPrinter::GetExternalSymbolSymbol(Twine Sym) const {
SmallString<60> NameStr;
Mangler::getNameWithPrefix(NameStr, Sym, getDataLayout());
return OutContext.getOrCreateSymbol(NameStr);
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 3a9d5fa3b936..dddc08b3bc01 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -1397,6 +1397,12 @@ void CodeViewDebug::calculateRanges(
if (Location->Register == 0 || Location->LoadChain.size() > 1)
continue;
+ // Codeview can only express byte-aligned offsets, ensure that we have a
+ // byte-boundaried location.
+ if (Location->FragmentInfo)
+ if (Location->FragmentInfo->OffsetInBits % 8)
+ continue;
+
LocalVarDef DR;
DR.CVRegister = TRI->getCodeViewRegNum(Location->Register);
DR.InMemory = !Location->LoadChain.empty();
diff --git a/llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h b/llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h
index c9378ace4fd1..6f553dc85c64 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h
@@ -18,7 +18,6 @@ namespace llvm {
class AsmPrinter;
class DbgVariable;
class DwarfCompileUnit;
-class MachineInstr;
class MCSymbol;
/// Byte stream of .debug_loc entries.
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index 2faa057f4607..dc772bb459c9 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -25,7 +25,6 @@
#include "llvm/CodeGen/LexicalScopes.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/Support/Casting.h"
-#include <cassert>
#include <cstdint>
#include <memory>
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index ab29020bf1d7..41afbea45614 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -3478,6 +3478,16 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU,
Ins.first->second = Signature;
if (useSplitDwarf()) {
+ // Although multiple type units can have the same signature, they are not
+ // guranteed to be bit identical. When LLDB uses .debug_names it needs to
+ // know from which CU a type unit came from. These two attrbutes help it to
+ // figure that out.
+ if (getDwarfVersion() >= 5) {
+ if (!CompilationDir.empty())
+ NewTU.addString(UnitDie, dwarf::DW_AT_comp_dir, CompilationDir);
+ NewTU.addString(UnitDie, dwarf::DW_AT_dwo_name,
+ Asm->TM.Options.MCOptions.SplitDwarfFile);
+ }
MCSection *Section =
getDwarfVersion() <= 4
? Asm->getObjFileLowering().getDwarfTypesDWOSection()
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
index e10fd2b2642a..f76858fc2f36 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
@@ -28,7 +28,6 @@ class DbgLabel;
class DINode;
class DILocalScope;
class DwarfCompileUnit;
-class DwarfTypeUnit;
class DwarfUnit;
class LexicalScope;
class MCSection;
diff --git a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
index f00528023c91..ad3ad9928987 100644
--- a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
+++ b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
@@ -2269,14 +2269,14 @@ static bool
removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB,
FunctionVarLocsBuilder &FnVarLocs) {
bool Changed = false;
- SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBits;
+ SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBytes;
// Scan over the entire block, not just over the instructions mapped by
// FnVarLocs, because wedges in FnVarLocs may only be seperated by debug
// instructions.
for (const Instruction &I : reverse(*BB)) {
if (!isa<DbgVariableIntrinsic>(I)) {
// Sequence of consecutive defs ended. Clear map for the next one.
- VariableDefinedBits.clear();
+ VariableDefinedBytes.clear();
}
// Get the location defs that start just before this instruction.
@@ -2295,9 +2295,15 @@ removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB,
DebugAggregate Aggr =
getAggregate(FnVarLocs.getVariable(RIt->VariableID));
uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);
+ uint64_t SizeInBytes = divideCeil(SizeInBits, 8);
- if (SizeInBits == 0) {
+ // Cutoff for large variables to prevent expensive bitvector operations.
+ const uint64_t MaxSizeBytes = 2048;
+
+ if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {
// If the size is unknown (0) then keep this location def to be safe.
+ // Do the same for defs of large variables, which would be expensive
+ // to represent with a BitVector.
NewDefsReversed.push_back(*RIt);
continue;
}
@@ -2305,23 +2311,24 @@ removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB,
// Only keep this location definition if it is not fully eclipsed by
// other definitions in this wedge that come after it
- // Inert the bits the location definition defines.
+ // Inert the bytes the location definition defines.
auto InsertResult =
- VariableDefinedBits.try_emplace(Aggr, BitVector(SizeInBits));
+ VariableDefinedBytes.try_emplace(Aggr, BitVector(SizeInBytes));
bool FirstDefinition = InsertResult.second;
- BitVector &DefinedBits = InsertResult.first->second;
+ BitVector &DefinedBytes = InsertResult.first->second;
DIExpression::FragmentInfo Fragment =
RIt->Expr->getFragmentInfo().value_or(
DIExpression::FragmentInfo(SizeInBits, 0));
bool InvalidFragment = Fragment.endInBits() > SizeInBits;
+ uint64_t StartInBytes = Fragment.startInBits() / 8;
+ uint64_t EndInBytes = divideCeil(Fragment.endInBits(), 8);
- // If this defines any previously undefined bits, keep it.
+ // If this defines any previously undefined bytes, keep it.
if (FirstDefinition || InvalidFragment ||
- DefinedBits.find_first_unset_in(Fragment.startInBits(),
- Fragment.endInBits()) != -1) {
+ DefinedBytes.find_first_unset_in(StartInBytes, EndInBytes) != -1) {
if (!InvalidFragment)
- DefinedBits.set(Fragment.startInBits(), Fragment.endInBits());
+ DefinedBytes.set(StartInBytes, EndInBytes);
NewDefsReversed.push_back(*RIt);
continue;
}
diff --git a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
index 96662378a869..15b6f63e8632 100644
--- a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
@@ -302,7 +302,7 @@ Error BasicBlockSectionsProfileReader::ReadV0Profile() {
// specifier starting with `M=`.
auto [AliasesStr, DIFilenameStr] = S.split(' ');
SmallString<128> DIFilename;
- if (DIFilenameStr.startswith("M=")) {
+ if (DIFilenameStr.starts_with("M=")) {
DIFilename =
sys::path::remove_leading_dotslash(DIFilenameStr.substr(2));
if (DIFilename.empty())
diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index 79a95ee0d747..7b73a7b11ddf 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -41,7 +41,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
initializeEarlyTailDuplicatePass(Registry);
initializeExpandLargeDivRemLegacyPassPass(Registry);
initializeExpandLargeFpConvertLegacyPassPass(Registry);
- initializeExpandMemCmpPassPass(Registry);
+ initializeExpandMemCmpLegacyPassPass(Registry);
initializeExpandPostRAPass(Registry);
initializeFEntryInserterPass(Registry);
initializeFinalizeISelPass(Registry);
@@ -53,7 +53,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
initializeHardwareLoopsLegacyPass(Registry);
initializeIfConverterPass(Registry);
initializeImplicitNullChecksPass(Registry);
- initializeIndirectBrExpandPassPass(Registry);
+ initializeIndirectBrExpandLegacyPassPass(Registry);
initializeInterleavedLoadCombinePass(Registry);
initializeInterleavedAccessPass(Registry);
initializeJMCInstrumenterPass(Registry);
diff --git a/llvm/lib/CodeGen/CodeGenPassBuilder.cpp b/llvm/lib/CodeGen/CodeGenPassBuilder.cpp
index 7f37f2069a3b..82945528e768 100644
--- a/llvm/lib/CodeGen/CodeGenPassBuilder.cpp
+++ b/llvm/lib/CodeGen/CodeGenPassBuilder.cpp
@@ -17,9 +17,11 @@ using namespace llvm;
namespace llvm {
#define DUMMY_MACHINE_MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR) \
- AnalysisKey PASS_NAME::Key;
+ MachinePassKey PASS_NAME::Key;
#include "llvm/CodeGen/MachinePassRegistry.def"
#define DUMMY_MACHINE_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR) \
+ MachinePassKey PASS_NAME::Key;
+#define DUMMY_MACHINE_FUNCTION_ANALYSIS(NAME, PASS_NAME, CONSTRUCTOR) \
AnalysisKey PASS_NAME::Key;
#include "llvm/CodeGen/MachinePassRegistry.def"
} // namespace llvm
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index aa5cdd2e04a9..6e99fb133e26 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -1384,7 +1384,8 @@ static bool SinkCast(CastInst *CI) {
BasicBlock::iterator InsertPt = UserBB->getFirstInsertionPt();
assert(InsertPt != UserBB->end());
InsertedCast = CastInst::Create(CI->getOpcode(), CI->getOperand(0),
- CI->getType(), "", &*InsertPt);
+ CI->getType(), "");
+ InsertedCast->insertBefore(*UserBB, InsertPt);
InsertedCast->setDebugLoc(CI->getDebugLoc());
}
@@ -2058,12 +2059,13 @@ SinkShiftAndTruncate(BinaryOperator *ShiftI, Instruction *User, ConstantInt *CI,
assert(InsertPt != TruncUserBB->end());
// Sink the shift
if (ShiftI->getOpcode() == Instruction::AShr)
- InsertedShift = BinaryOperator::CreateAShr(ShiftI->getOperand(0), CI,
- "", &*InsertPt);
+ InsertedShift =
+ BinaryOperator::CreateAShr(ShiftI->getOperand(0), CI, "");
else
- InsertedShift = BinaryOperator::CreateLShr(ShiftI->getOperand(0), CI,
- "", &*InsertPt);
+ InsertedShift =
+ BinaryOperator::CreateLShr(ShiftI->getOperand(0), CI, "");
InsertedShift->setDebugLoc(ShiftI->getDebugLoc());
+ InsertedShift->insertBefore(*TruncUserBB, InsertPt);
// Sink the trunc
BasicBlock::iterator TruncInsertPt = TruncUserBB->getFirstInsertionPt();
@@ -2162,11 +2164,12 @@ static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI,
assert(InsertPt != UserBB->end());
if (ShiftI->getOpcode() == Instruction::AShr)
- InsertedShift = BinaryOperator::CreateAShr(ShiftI->getOperand(0), CI,
- "", &*InsertPt);
+ InsertedShift =
+ BinaryOperator::CreateAShr(ShiftI->getOperand(0), CI, "");
else
- InsertedShift = BinaryOperator::CreateLShr(ShiftI->getOperand(0), CI,
- "", &*InsertPt);
+ InsertedShift =
+ BinaryOperator::CreateLShr(ShiftI->getOperand(0), CI, "");
+ InsertedShift->insertBefore(*UserBB, InsertPt);
InsertedShift->setDebugLoc(ShiftI->getDebugLoc());
MadeChange = true;
@@ -3215,10 +3218,6 @@ public:
/// Same as IRBuilder::createZExt.
Value *createZExt(Instruction *Inst, Value *Opnd, Type *Ty);
- /// Same as Instruction::moveBefore.
- void moveBefore(Instruction *Inst, Instruction *Before);
- /// @}
-
private:
/// The ordered list of actions made so far.
SmallVector<std::unique_ptr<TypePromotionAction>, 16> Actions;
@@ -3278,13 +3277,6 @@ Value *TypePromotionTransaction::createZExt(Instruction *Inst, Value *Opnd,
return Val;
}
-void TypePromotionTransaction::moveBefore(Instruction *Inst,
- Instruction *Before) {
- Actions.push_back(
- std::make_unique<TypePromotionTransaction::InstructionMoveBefore>(
- Inst, Before));
-}
-
TypePromotionTransaction::ConstRestorationPt
TypePromotionTransaction::getRestorationPoint() const {
return !Actions.empty() ? Actions.back().get() : nullptr;
@@ -6196,8 +6188,6 @@ bool CodeGenPrepare::splitLargeGEPOffsets() {
// Generate a new GEP to replace the current one.
LLVMContext &Ctx = GEP->getContext();
Type *PtrIdxTy = DL->getIndexType(GEP->getType());
- Type *I8PtrTy =
- PointerType::get(Ctx, GEP->getType()->getPointerAddressSpace());
Type *I8Ty = Type::getInt8Ty(Ctx);
if (!NewBaseGEP) {
@@ -6208,16 +6198,10 @@ bool CodeGenPrepare::splitLargeGEPOffsets() {
IRBuilder<> Builder(GEP);
Value *NewGEP = NewBaseGEP;
- if (Offset == BaseOffset) {
- if (GEP->getType() != I8PtrTy)
- NewGEP = Builder.CreatePointerCast(NewGEP, GEP->getType());
- } else {
+ if (Offset != BaseOffset) {
// Calculate the new offset for the new GEP.
Value *Index = ConstantInt::get(PtrIdxTy, Offset - BaseOffset);
NewGEP = Builder.CreateGEP(I8Ty, NewBaseGEP, Index);
-
- if (GEP->getType() != I8PtrTy)
- NewGEP = Builder.CreatePointerCast(NewGEP, GEP->getType());
}
replaceAllUsesWith(GEP, NewGEP, FreshBBs, IsHugeFunc);
LargeOffsetGEPID.erase(GEP);
@@ -6628,7 +6612,8 @@ bool CodeGenPrepare::optimizeExtUses(Instruction *I) {
if (!InsertedTrunc) {
BasicBlock::iterator InsertPt = UserBB->getFirstInsertionPt();
assert(InsertPt != UserBB->end());
- InsertedTrunc = new TruncInst(I, Src->getType(), "", &*InsertPt);
+ InsertedTrunc = new TruncInst(I, Src->getType(), "");
+ InsertedTrunc->insertBefore(*UserBB, InsertPt);
InsertedInsts.insert(InsertedTrunc);
}
diff --git a/llvm/lib/CodeGen/DwarfEHPrepare.cpp b/llvm/lib/CodeGen/DwarfEHPrepare.cpp
index a44aaf33c6a4..e7eb34d8e651 100644
--- a/llvm/lib/CodeGen/DwarfEHPrepare.cpp
+++ b/llvm/lib/CodeGen/DwarfEHPrepare.cpp
@@ -42,7 +42,7 @@
using namespace llvm;
-#define DEBUG_TYPE "dwarfehprepare"
+#define DEBUG_TYPE "dwarf-eh-prepare"
STATISTIC(NumResumesLowered, "Number of resume calls lowered");
STATISTIC(NumCleanupLandingPadsUnreachable,
diff --git a/llvm/lib/CodeGen/ExpandMemCmp.cpp b/llvm/lib/CodeGen/ExpandMemCmp.cpp
index e6ca14096249..bb84813569f4 100644
--- a/llvm/lib/CodeGen/ExpandMemCmp.cpp
+++ b/llvm/lib/CodeGen/ExpandMemCmp.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/CodeGen/ExpandMemCmp.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/DomTreeUpdater.h"
@@ -38,7 +39,7 @@ namespace llvm {
class TargetLowering;
}
-#define DEBUG_TYPE "expandmemcmp"
+#define DEBUG_TYPE "expand-memcmp"
STATISTIC(NumMemCmpCalls, "Number of memcmp calls");
STATISTIC(NumMemCmpNotConstant, "Number of memcmp calls without constant size");
@@ -886,12 +887,24 @@ static bool expandMemCmp(CallInst *CI, const TargetTransformInfo *TTI,
return true;
}
-class ExpandMemCmpPass : public FunctionPass {
+// Returns true if a change was made.
+static bool runOnBlock(BasicBlock &BB, const TargetLibraryInfo *TLI,
+ const TargetTransformInfo *TTI, const TargetLowering *TL,
+ const DataLayout &DL, ProfileSummaryInfo *PSI,
+ BlockFrequencyInfo *BFI, DomTreeUpdater *DTU);
+
+static PreservedAnalyses runImpl(Function &F, const TargetLibraryInfo *TLI,
+ const TargetTransformInfo *TTI,
+ const TargetLowering *TL,
+ ProfileSummaryInfo *PSI,
+ BlockFrequencyInfo *BFI, DominatorTree *DT);
+
+class ExpandMemCmpLegacyPass : public FunctionPass {
public:
static char ID;
- ExpandMemCmpPass() : FunctionPass(ID) {
- initializeExpandMemCmpPassPass(*PassRegistry::getPassRegistry());
+ ExpandMemCmpLegacyPass() : FunctionPass(ID) {
+ initializeExpandMemCmpLegacyPassPass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &F) override {
@@ -928,25 +941,13 @@ private:
LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
FunctionPass::getAnalysisUsage(AU);
}
-
- PreservedAnalyses runImpl(Function &F, const TargetLibraryInfo *TLI,
- const TargetTransformInfo *TTI,
- const TargetLowering *TL, ProfileSummaryInfo *PSI,
- BlockFrequencyInfo *BFI, DominatorTree *DT);
- // Returns true if a change was made.
- bool runOnBlock(BasicBlock &BB, const TargetLibraryInfo *TLI,
- const TargetTransformInfo *TTI, const TargetLowering *TL,
- const DataLayout &DL, ProfileSummaryInfo *PSI,
- BlockFrequencyInfo *BFI, DomTreeUpdater *DTU);
};
-bool ExpandMemCmpPass::runOnBlock(BasicBlock &BB, const TargetLibraryInfo *TLI,
- const TargetTransformInfo *TTI,
- const TargetLowering *TL,
- const DataLayout &DL, ProfileSummaryInfo *PSI,
- BlockFrequencyInfo *BFI,
- DomTreeUpdater *DTU) {
- for (Instruction& I : BB) {
+bool runOnBlock(BasicBlock &BB, const TargetLibraryInfo *TLI,
+ const TargetTransformInfo *TTI, const TargetLowering *TL,
+ const DataLayout &DL, ProfileSummaryInfo *PSI,
+ BlockFrequencyInfo *BFI, DomTreeUpdater *DTU) {
+ for (Instruction &I : BB) {
CallInst *CI = dyn_cast<CallInst>(&I);
if (!CI) {
continue;
@@ -961,8 +962,7 @@ bool ExpandMemCmpPass::runOnBlock(BasicBlock &BB, const TargetLibraryInfo *TLI,
return false;
}
-PreservedAnalyses
-ExpandMemCmpPass::runImpl(Function &F, const TargetLibraryInfo *TLI,
+PreservedAnalyses runImpl(Function &F, const TargetLibraryInfo *TLI,
const TargetTransformInfo *TTI,
const TargetLowering *TL, ProfileSummaryInfo *PSI,
BlockFrequencyInfo *BFI, DominatorTree *DT) {
@@ -994,17 +994,32 @@ ExpandMemCmpPass::runImpl(Function &F, const TargetLibraryInfo *TLI,
} // namespace
-char ExpandMemCmpPass::ID = 0;
-INITIALIZE_PASS_BEGIN(ExpandMemCmpPass, "expandmemcmp",
+PreservedAnalyses ExpandMemCmpPass::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ const auto *TL = TM->getSubtargetImpl(F)->getTargetLowering();
+ const auto &TLI = FAM.getResult<TargetLibraryAnalysis>(F);
+ const auto &TTI = FAM.getResult<TargetIRAnalysis>(F);
+ auto *PSI = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F)
+ .getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
+ BlockFrequencyInfo *BFI = (PSI && PSI->hasProfileSummary())
+ ? &FAM.getResult<BlockFrequencyAnalysis>(F)
+ : nullptr;
+ auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
+
+ return runImpl(F, &TLI, &TTI, TL, PSI, BFI, DT);
+}
+
+char ExpandMemCmpLegacyPass::ID = 0;
+INITIALIZE_PASS_BEGIN(ExpandMemCmpLegacyPass, DEBUG_TYPE,
"Expand memcmp() to load/stores", false, false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LazyBlockFrequencyInfoPass)
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
-INITIALIZE_PASS_END(ExpandMemCmpPass, "expandmemcmp",
+INITIALIZE_PASS_END(ExpandMemCmpLegacyPass, DEBUG_TYPE,
"Expand memcmp() to load/stores", false, false)
-FunctionPass *llvm::createExpandMemCmpPass() {
- return new ExpandMemCmpPass();
+FunctionPass *llvm::createExpandMemCmpLegacyPass() {
+ return new ExpandMemCmpLegacyPass();
}
diff --git a/llvm/lib/CodeGen/GCMetadata.cpp b/llvm/lib/CodeGen/GCMetadata.cpp
index 4d27143c5298..cad7d1f1137b 100644
--- a/llvm/lib/CodeGen/GCMetadata.cpp
+++ b/llvm/lib/CodeGen/GCMetadata.cpp
@@ -24,24 +24,49 @@
using namespace llvm;
-namespace {
-
-class Printer : public FunctionPass {
- static char ID;
-
- raw_ostream &OS;
-
-public:
- explicit Printer(raw_ostream &OS) : FunctionPass(ID), OS(OS) {}
+bool GCStrategyMap::invalidate(Module &M, const PreservedAnalyses &PA,
+ ModuleAnalysisManager::Invalidator &) {
+ for (const auto &F : M) {
+ if (F.isDeclaration() || !F.hasGC())
+ continue;
+ if (!StrategyMap.contains(F.getGC()))
+ return true;
+ }
+ return false;
+}
- StringRef getPassName() const override;
- void getAnalysisUsage(AnalysisUsage &AU) const override;
+AnalysisKey CollectorMetadataAnalysis::Key;
+
+CollectorMetadataAnalysis::Result
+CollectorMetadataAnalysis::run(Module &M, ModuleAnalysisManager &MAM) {
+ Result R;
+ auto &Map = R.StrategyMap;
+ for (auto &F : M) {
+ if (F.isDeclaration() || !F.hasGC())
+ continue;
+ if (auto GCName = F.getGC(); !Map.contains(GCName))
+ Map[GCName] = getGCStrategy(GCName);
+ }
+ return R;
+}
- bool runOnFunction(Function &F) override;
- bool doFinalization(Module &M) override;
-};
+AnalysisKey GCFunctionAnalysis::Key;
-} // end anonymous namespace
+GCFunctionAnalysis::Result
+GCFunctionAnalysis::run(Function &F, FunctionAnalysisManager &FAM) {
+ assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!");
+ assert(F.hasGC() && "Function doesn't have GC!");
+
+ auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
+ assert(
+ MAMProxy.cachedResultExists<CollectorMetadataAnalysis>(*F.getParent()) &&
+ "This pass need module analysis `collector-metadata`!");
+ auto &Map =
+ MAMProxy.getCachedResult<CollectorMetadataAnalysis>(*F.getParent())
+ ->StrategyMap;
+ GCFunctionInfo Info(F, *Map[F.getGC()]);
+ return Info;
+}
INITIALIZE_PASS(GCModuleInfo, "collector-metadata",
"Create Garbage Collector Module Metadata", false, false)
@@ -53,6 +78,12 @@ GCFunctionInfo::GCFunctionInfo(const Function &F, GCStrategy &S)
GCFunctionInfo::~GCFunctionInfo() = default;
+bool GCFunctionInfo::invalidate(Function &F, const PreservedAnalyses &PA,
+ FunctionAnalysisManager::Invalidator &) {
+ auto PAC = PA.getChecker<GCFunctionAnalysis>();
+ return !PAC.preserved() && !PAC.preservedSet<AllAnalysesOn<Function>>();
+}
+
// -----------------------------------------------------------------------------
char GCModuleInfo::ID = 0;
@@ -84,58 +115,6 @@ void GCModuleInfo::clear() {
// -----------------------------------------------------------------------------
-char Printer::ID = 0;
-
-FunctionPass *llvm::createGCInfoPrinter(raw_ostream &OS) {
- return new Printer(OS);
-}
-
-StringRef Printer::getPassName() const {
- return "Print Garbage Collector Information";
-}
-
-void Printer::getAnalysisUsage(AnalysisUsage &AU) const {
- FunctionPass::getAnalysisUsage(AU);
- AU.setPreservesAll();
- AU.addRequired<GCModuleInfo>();
-}
-
-bool Printer::runOnFunction(Function &F) {
- if (F.hasGC())
- return false;
-
- GCFunctionInfo *FD = &getAnalysis<GCModuleInfo>().getFunctionInfo(F);
-
- OS << "GC roots for " << FD->getFunction().getName() << ":\n";
- for (GCFunctionInfo::roots_iterator RI = FD->roots_begin(),
- RE = FD->roots_end();
- RI != RE; ++RI)
- OS << "\t" << RI->Num << "\t" << RI->StackOffset << "[sp]\n";
-
- OS << "GC safe points for " << FD->getFunction().getName() << ":\n";
- for (GCFunctionInfo::iterator PI = FD->begin(), PE = FD->end(); PI != PE;
- ++PI) {
-
- OS << "\t" << PI->Label->getName() << ": " << "post-call"
- << ", live = {";
-
- ListSeparator LS(",");
- for (const GCRoot &R : make_range(FD->live_begin(PI), FD->live_end(PI)))
- OS << LS << " " << R.Num;
-
- OS << " }\n";
- }
-
- return false;
-}
-
-bool Printer::doFinalization(Module &M) {
- GCModuleInfo *GMI = getAnalysisIfAvailable<GCModuleInfo>();
- assert(GMI && "Printer didn't require GCModuleInfo?!");
- GMI->clear();
- return false;
-}
-
GCStrategy *GCModuleInfo::getGCStrategy(const StringRef Name) {
// TODO: Arguably, just doing a linear search would be faster for small N
auto NMI = GCStrategyMap.find(Name);
diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
index 2527b1431289..6858e030c2c7 100644
--- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
@@ -146,7 +146,12 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB,
const Value *CalleeV = CB.getCalledOperand()->stripPointerCasts();
if (const Function *F = dyn_cast<Function>(CalleeV))
Info.Callee = MachineOperand::CreateGA(F, 0);
- else
+ else if (isa<GlobalIFunc>(CalleeV) || isa<GlobalAlias>(CalleeV)) {
+ // IR IFuncs and Aliases can't be forward declared (only defined), so the
+ // callee must be in the same TU and therefore we can direct-call it without
+ // worrying about it being out of range.
+ Info.Callee = MachineOperand::CreateGA(cast<GlobalValue>(CalleeV), 0);
+ } else
Info.Callee = MachineOperand::CreateReg(GetCalleeReg(), false);
Register ReturnHintAlignReg;
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 14a4e72152e7..bea29642cd00 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -1550,8 +1550,10 @@ bool IRTranslator::translateGetElementPtr(const User &U,
// If this is a scalar constant or a splat vector of constants,
// handle it quickly.
if (const auto *CI = dyn_cast<ConstantInt>(Idx)) {
- Offset += ElementSize * CI->getSExtValue();
- continue;
+ if (std::optional<int64_t> Val = CI->getValue().trySExtValue()) {
+ Offset += ElementSize * *Val;
+ continue;
+ }
}
if (Offset != 0) {
@@ -2435,6 +2437,21 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
MIRBuilder.buildInstr(TargetOpcode::G_RESET_FPMODE, {}, {});
return true;
}
+ case Intrinsic::prefetch: {
+ Value *Addr = CI.getOperand(0);
+ unsigned RW = cast<ConstantInt>(CI.getOperand(1))->getZExtValue();
+ unsigned Locality = cast<ConstantInt>(CI.getOperand(2))->getZExtValue();
+ unsigned CacheType = cast<ConstantInt>(CI.getOperand(3))->getZExtValue();
+
+ auto Flags = RW ? MachineMemOperand::MOStore : MachineMemOperand::MOLoad;
+ auto &MMO = *MF->getMachineMemOperand(MachinePointerInfo(Addr), Flags,
+ LLT(), Align());
+
+ MIRBuilder.buildPrefetch(getOrCreateVReg(*Addr), RW, Locality, CacheType,
+ MMO);
+
+ return true;
+ }
#define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \
case Intrinsic::INTRINSIC:
#include "llvm/IR/ConstrainedOps.def"
diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
index 80e9c08e850b..a5827c26c04f 100644
--- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
@@ -314,7 +314,10 @@ MachineInstrBuilder MachineIRBuilder::buildConstant(const DstOp &Res,
assert(EltTy.getScalarSizeInBits() == Val.getBitWidth() &&
"creating constant with the wrong size");
- if (Ty.isVector()) {
+ assert(!Ty.isScalableVector() &&
+ "unexpected scalable vector in buildConstant");
+
+ if (Ty.isFixedVector()) {
auto Const = buildInstr(TargetOpcode::G_CONSTANT)
.addDef(getMRI()->createGenericVirtualRegister(EltTy))
.addCImm(&Val);
@@ -347,7 +350,10 @@ MachineInstrBuilder MachineIRBuilder::buildFConstant(const DstOp &Res,
assert(!Ty.isPointer() && "invalid operand type");
- if (Ty.isVector()) {
+ assert(!Ty.isScalableVector() &&
+ "unexpected scalable vector in buildFConstant");
+
+ if (Ty.isFixedVector()) {
auto Const = buildInstr(TargetOpcode::G_FCONSTANT)
.addDef(getMRI()->createGenericVirtualRegister(EltTy))
.addFPImm(&Val);
@@ -1051,6 +1057,18 @@ MachineIRBuilder::buildFence(unsigned Ordering, unsigned Scope) {
.addImm(Scope);
}
+MachineInstrBuilder MachineIRBuilder::buildPrefetch(const SrcOp &Addr,
+ unsigned RW,
+ unsigned Locality,
+ unsigned CacheType,
+ MachineMemOperand &MMO) {
+ auto MIB = buildInstr(TargetOpcode::G_PREFETCH);
+ Addr.addSrcToMIB(MIB);
+ MIB.addImm(RW).addImm(Locality).addImm(CacheType);
+ MIB.addMemOperand(&MMO);
+ return MIB;
+}
+
MachineInstrBuilder
MachineIRBuilder::buildBlockAddress(Register Res, const BlockAddress *BA) {
#ifndef NDEBUG
diff --git a/llvm/lib/CodeGen/GlobalMerge.cpp b/llvm/lib/CodeGen/GlobalMerge.cpp
index 339019923c00..22b6d31d0634 100644
--- a/llvm/lib/CodeGen/GlobalMerge.cpp
+++ b/llvm/lib/CodeGen/GlobalMerge.cpp
@@ -643,8 +643,7 @@ bool GlobalMerge::doInitialization(Module &M) {
StringRef Section = GV.getSection();
// Ignore all 'special' globals.
- if (GV.getName().startswith("llvm.") ||
- GV.getName().startswith(".llvm."))
+ if (GV.getName().starts_with("llvm.") || GV.getName().starts_with(".llvm."))
continue;
// Ignore all "required" globals:
diff --git a/llvm/lib/CodeGen/IndirectBrExpandPass.cpp b/llvm/lib/CodeGen/IndirectBrExpandPass.cpp
index 012892166ae7..f7b931a3bdac 100644
--- a/llvm/lib/CodeGen/IndirectBrExpandPass.cpp
+++ b/llvm/lib/CodeGen/IndirectBrExpandPass.cpp
@@ -29,6 +29,7 @@
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/DomTreeUpdater.h"
+#include "llvm/CodeGen/IndirectBrExpand.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/BasicBlock.h"
@@ -48,14 +49,12 @@ using namespace llvm;
namespace {
-class IndirectBrExpandPass : public FunctionPass {
- const TargetLowering *TLI = nullptr;
-
+class IndirectBrExpandLegacyPass : public FunctionPass {
public:
static char ID; // Pass identification, replacement for typeid
- IndirectBrExpandPass() : FunctionPass(ID) {
- initializeIndirectBrExpandPassPass(*PassRegistry::getPassRegistry());
+ IndirectBrExpandLegacyPass() : FunctionPass(ID) {
+ initializeIndirectBrExpandLegacyPassPass(*PassRegistry::getPassRegistry());
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -67,33 +66,41 @@ public:
} // end anonymous namespace
-char IndirectBrExpandPass::ID = 0;
+static bool runImpl(Function &F, const TargetLowering *TLI,
+ DomTreeUpdater *DTU);
+
+PreservedAnalyses IndirectBrExpandPass::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ auto *STI = TM->getSubtargetImpl(F);
+ if (!STI->enableIndirectBrExpand())
+ return PreservedAnalyses::all();
+
+ auto *TLI = STI->getTargetLowering();
+ auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
+ DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
+
+ bool Changed = runImpl(F, TLI, DT ? &DTU : nullptr);
+ if (!Changed)
+ return PreservedAnalyses::all();
+ PreservedAnalyses PA;
+ PA.preserve<DominatorTreeAnalysis>();
+ return PA;
+}
+
+char IndirectBrExpandLegacyPass::ID = 0;
-INITIALIZE_PASS_BEGIN(IndirectBrExpandPass, DEBUG_TYPE,
+INITIALIZE_PASS_BEGIN(IndirectBrExpandLegacyPass, DEBUG_TYPE,
"Expand indirectbr instructions", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
-INITIALIZE_PASS_END(IndirectBrExpandPass, DEBUG_TYPE,
+INITIALIZE_PASS_END(IndirectBrExpandLegacyPass, DEBUG_TYPE,
"Expand indirectbr instructions", false, false)
FunctionPass *llvm::createIndirectBrExpandPass() {
- return new IndirectBrExpandPass();
+ return new IndirectBrExpandLegacyPass();
}
-bool IndirectBrExpandPass::runOnFunction(Function &F) {
+bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
auto &DL = F.getParent()->getDataLayout();
- auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
- if (!TPC)
- return false;
-
- auto &TM = TPC->getTM<TargetMachine>();
- auto &STI = *TM.getSubtargetImpl(F);
- if (!STI.enableIndirectBrExpand())
- return false;
- TLI = STI.getTargetLowering();
-
- std::optional<DomTreeUpdater> DTU;
- if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
- DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
SmallVector<IndirectBrInst *, 1> IndirectBrs;
@@ -268,3 +275,21 @@ bool IndirectBrExpandPass::runOnFunction(Function &F) {
return true;
}
+
+bool IndirectBrExpandLegacyPass::runOnFunction(Function &F) {
+ auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
+ if (!TPC)
+ return false;
+
+ auto &TM = TPC->getTM<TargetMachine>();
+ auto &STI = *TM.getSubtargetImpl(F);
+ if (!STI.enableIndirectBrExpand())
+ return false;
+ auto *TLI = STI.getTargetLowering();
+
+ std::optional<DomTreeUpdater> DTU;
+ if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
+ DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
+
+ return runImpl(F, TLI, DTU ? &*DTU : nullptr);
+}
diff --git a/llvm/lib/CodeGen/InterleavedAccessPass.cpp b/llvm/lib/CodeGen/InterleavedAccessPass.cpp
index 65a6859a006a..2a0daf404c97 100644
--- a/llvm/lib/CodeGen/InterleavedAccessPass.cpp
+++ b/llvm/lib/CodeGen/InterleavedAccessPass.cpp
@@ -48,6 +48,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/InterleavedAccess.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
@@ -82,22 +83,14 @@ static cl::opt<bool> LowerInterleavedAccesses(
namespace {
-class InterleavedAccess : public FunctionPass {
-public:
- static char ID;
-
- InterleavedAccess() : FunctionPass(ID) {
- initializeInterleavedAccessPass(*PassRegistry::getPassRegistry());
- }
+class InterleavedAccessImpl {
+ friend class InterleavedAccess;
- StringRef getPassName() const override { return "Interleaved Access Pass"; }
-
- bool runOnFunction(Function &F) override;
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addRequired<DominatorTreeWrapperPass>();
- AU.setPreservesCFG();
- }
+public:
+ InterleavedAccessImpl() = default;
+ InterleavedAccessImpl(DominatorTree *DT, const TargetLowering *TLI)
+ : DT(DT), TLI(TLI), MaxFactor(TLI->getMaxSupportedInterleaveFactor()) {}
+ bool runOnFunction(Function &F);
private:
DominatorTree *DT = nullptr;
@@ -141,10 +134,60 @@ private:
LoadInst *LI);
};
+class InterleavedAccess : public FunctionPass {
+ InterleavedAccessImpl Impl;
+
+public:
+ static char ID;
+
+ InterleavedAccess() : FunctionPass(ID) {
+ initializeInterleavedAccessPass(*PassRegistry::getPassRegistry());
+ }
+
+ StringRef getPassName() const override { return "Interleaved Access Pass"; }
+
+ bool runOnFunction(Function &F) override;
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addRequired<DominatorTreeWrapperPass>();
+ AU.setPreservesCFG();
+ }
+};
+
} // end anonymous namespace.
+PreservedAnalyses InterleavedAccessPass::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ auto *DT = &FAM.getResult<DominatorTreeAnalysis>(F);
+ auto *TLI = TM->getSubtargetImpl(F)->getTargetLowering();
+ InterleavedAccessImpl Impl(DT, TLI);
+ bool Changed = Impl.runOnFunction(F);
+
+ if (!Changed)
+ return PreservedAnalyses::all();
+
+ PreservedAnalyses PA;
+ PA.preserveSet<CFGAnalyses>();
+ return PA;
+}
+
char InterleavedAccess::ID = 0;
+bool InterleavedAccess::runOnFunction(Function &F) {
+ auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
+ if (!TPC || !LowerInterleavedAccesses)
+ return false;
+
+ LLVM_DEBUG(dbgs() << "*** " << getPassName() << ": " << F.getName() << "\n");
+
+ Impl.DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+ auto &TM = TPC->getTM<TargetMachine>();
+ Impl.TLI = TM.getSubtargetImpl(F)->getTargetLowering();
+ Impl.MaxFactor = Impl.TLI->getMaxSupportedInterleaveFactor();
+
+ return Impl.runOnFunction(F);
+}
+
INITIALIZE_PASS_BEGIN(InterleavedAccess, DEBUG_TYPE,
"Lower interleaved memory accesses to target specific intrinsics", false,
false)
@@ -228,7 +271,7 @@ static bool isReInterleaveMask(ShuffleVectorInst *SVI, unsigned &Factor,
return false;
}
-bool InterleavedAccess::lowerInterleavedLoad(
+bool InterleavedAccessImpl::lowerInterleavedLoad(
LoadInst *LI, SmallVector<Instruction *, 32> &DeadInsts) {
if (!LI->isSimple() || isa<ScalableVectorType>(LI->getType()))
return false;
@@ -334,7 +377,7 @@ bool InterleavedAccess::lowerInterleavedLoad(
return true;
}
-bool InterleavedAccess::replaceBinOpShuffles(
+bool InterleavedAccessImpl::replaceBinOpShuffles(
ArrayRef<ShuffleVectorInst *> BinOpShuffles,
SmallVectorImpl<ShuffleVectorInst *> &Shuffles, LoadInst *LI) {
for (auto *SVI : BinOpShuffles) {
@@ -367,7 +410,7 @@ bool InterleavedAccess::replaceBinOpShuffles(
return !BinOpShuffles.empty();
}
-bool InterleavedAccess::tryReplaceExtracts(
+bool InterleavedAccessImpl::tryReplaceExtracts(
ArrayRef<ExtractElementInst *> Extracts,
ArrayRef<ShuffleVectorInst *> Shuffles) {
// If there aren't any extractelement instructions to modify, there's nothing
@@ -431,7 +474,7 @@ bool InterleavedAccess::tryReplaceExtracts(
return true;
}
-bool InterleavedAccess::lowerInterleavedStore(
+bool InterleavedAccessImpl::lowerInterleavedStore(
StoreInst *SI, SmallVector<Instruction *, 32> &DeadInsts) {
if (!SI->isSimple())
return false;
@@ -457,7 +500,7 @@ bool InterleavedAccess::lowerInterleavedStore(
return true;
}
-bool InterleavedAccess::lowerDeinterleaveIntrinsic(
+bool InterleavedAccessImpl::lowerDeinterleaveIntrinsic(
IntrinsicInst *DI, SmallVector<Instruction *, 32> &DeadInsts) {
LoadInst *LI = dyn_cast<LoadInst>(DI->getOperand(0));
@@ -476,7 +519,7 @@ bool InterleavedAccess::lowerDeinterleaveIntrinsic(
return true;
}
-bool InterleavedAccess::lowerInterleaveIntrinsic(
+bool InterleavedAccessImpl::lowerInterleaveIntrinsic(
IntrinsicInst *II, SmallVector<Instruction *, 32> &DeadInsts) {
if (!II->hasOneUse())
return false;
@@ -498,18 +541,7 @@ bool InterleavedAccess::lowerInterleaveIntrinsic(
return true;
}
-bool InterleavedAccess::runOnFunction(Function &F) {
- auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
- if (!TPC || !LowerInterleavedAccesses)
- return false;
-
- LLVM_DEBUG(dbgs() << "*** " << getPassName() << ": " << F.getName() << "\n");
-
- DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
- auto &TM = TPC->getTM<TargetMachine>();
- TLI = TM.getSubtargetImpl(F)->getTargetLowering();
- MaxFactor = TLI->getMaxSupportedInterleaveFactor();
-
+bool InterleavedAccessImpl::runOnFunction(Function &F) {
// Holds dead instructions that will be erased later.
SmallVector<Instruction *, 32> DeadInsts;
bool Changed = false;
diff --git a/llvm/lib/CodeGen/InterleavedLoadCombinePass.cpp b/llvm/lib/CodeGen/InterleavedLoadCombinePass.cpp
index 3b1d26cfed79..f2d5c3c867c2 100644
--- a/llvm/lib/CodeGen/InterleavedLoadCombinePass.cpp
+++ b/llvm/lib/CodeGen/InterleavedLoadCombinePass.cpp
@@ -23,6 +23,7 @@
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/CodeGen/InterleavedLoadCombine.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetPassConfig.h"
@@ -63,7 +64,7 @@ struct VectorInfo;
struct InterleavedLoadCombineImpl {
public:
InterleavedLoadCombineImpl(Function &F, DominatorTree &DT, MemorySSA &MSSA,
- TargetMachine &TM)
+ const TargetMachine &TM)
: F(F), DT(DT), MSSA(MSSA),
TLI(*TM.getSubtargetImpl(F)->getTargetLowering()),
TTI(TM.getTargetTransformInfo(F)) {}
@@ -1339,6 +1340,15 @@ private:
};
} // anonymous namespace
+PreservedAnalyses
+InterleavedLoadCombinePass::run(Function &F, FunctionAnalysisManager &FAM) {
+
+ auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
+ auto &MemSSA = FAM.getResult<MemorySSAAnalysis>(F).getMSSA();
+ bool Changed = InterleavedLoadCombineImpl(F, DT, MemSSA, *TM).run();
+ return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
+}
+
char InterleavedLoadCombine::ID = 0;
INITIALIZE_PASS_BEGIN(
diff --git a/llvm/lib/CodeGen/JMCInstrumenter.cpp b/llvm/lib/CodeGen/JMCInstrumenter.cpp
index a1f0a5040664..62a381918875 100644
--- a/llvm/lib/CodeGen/JMCInstrumenter.cpp
+++ b/llvm/lib/CodeGen/JMCInstrumenter.cpp
@@ -20,6 +20,7 @@
// weak symbol.
//===----------------------------------------------------------------------===//
+#include "llvm/CodeGen/JMCInstrumenter.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CodeGen/Passes.h"
@@ -39,19 +40,25 @@
using namespace llvm;
-#define DEBUG_TYPE "jmc-instrument"
+#define DEBUG_TYPE "jmc-instrumenter"
+static bool runImpl(Module &M);
namespace {
struct JMCInstrumenter : public ModulePass {
static char ID;
JMCInstrumenter() : ModulePass(ID) {
initializeJMCInstrumenterPass(*PassRegistry::getPassRegistry());
}
- bool runOnModule(Module &M) override;
+ bool runOnModule(Module &M) override { return runImpl(M); }
};
char JMCInstrumenter::ID = 0;
} // namespace
+PreservedAnalyses JMCInstrumenterPass::run(Module &M, ModuleAnalysisManager &) {
+ bool Changed = runImpl(M);
+ return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
+}
+
INITIALIZE_PASS(
JMCInstrumenter, DEBUG_TYPE,
"Instrument function entry with call to __CheckForDebuggerJustMyCode",
@@ -143,7 +150,7 @@ Function *createDefaultCheckFunction(Module &M, bool UseX86FastCall) {
}
} // namespace
-bool JMCInstrumenter::runOnModule(Module &M) {
+bool runImpl(Module &M) {
bool Changed = false;
LLVMContext &Ctx = M.getContext();
Triple ModuleTriple(M.getTargetTriple());
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
index b2c2b40139ed..87a0ba58b14c 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
@@ -1429,7 +1429,7 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) {
std::optional<ValueIDNum> InstrRefBasedLDV::getValueForInstrRef(
unsigned InstNo, unsigned OpNo, MachineInstr &MI,
- const ValueTable *MLiveOuts, const ValueTable *MLiveIns) {
+ const FuncValueTable *MLiveOuts, const FuncValueTable *MLiveIns) {
// Various optimizations may have happened to the value during codegen,
// recorded in the value substitution table. Apply any substitutions to
// the instruction / operand number in this DBG_INSTR_REF, and collect
@@ -1495,7 +1495,8 @@ std::optional<ValueIDNum> InstrRefBasedLDV::getValueForInstrRef(
} else if (PHIIt != DebugPHINumToValue.end() && PHIIt->InstrNum == InstNo) {
// It's actually a PHI value. Which value it is might not be obvious, use
// the resolver helper to find out.
- NewID = resolveDbgPHIs(*MI.getParent()->getParent(), MLiveOuts, MLiveIns,
+ assert(MLiveOuts && MLiveIns);
+ NewID = resolveDbgPHIs(*MI.getParent()->getParent(), *MLiveOuts, *MLiveIns,
MI, InstNo);
}
@@ -1574,8 +1575,8 @@ std::optional<ValueIDNum> InstrRefBasedLDV::getValueForInstrRef(
}
bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
- const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns) {
+ const FuncValueTable *MLiveOuts,
+ const FuncValueTable *MLiveIns) {
if (!MI.isDebugRef())
return false;
@@ -2116,7 +2117,7 @@ bool InstrRefBasedLDV::transferSpillOrRestoreInst(MachineInstr &MI) {
}
bool InstrRefBasedLDV::transferRegisterCopy(MachineInstr &MI) {
- auto DestSrc = TII->isCopyInstr(MI);
+ auto DestSrc = TII->isCopyLikeInstr(MI);
if (!DestSrc)
return false;
@@ -2245,8 +2246,9 @@ void InstrRefBasedLDV::accumulateFragmentMap(MachineInstr &MI) {
AllSeenFragments.insert(ThisFragment);
}
-void InstrRefBasedLDV::process(MachineInstr &MI, const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns) {
+void InstrRefBasedLDV::process(MachineInstr &MI,
+ const FuncValueTable *MLiveOuts,
+ const FuncValueTable *MLiveIns) {
// Try to interpret an MI as a debug or transfer instruction. Only if it's
// none of these should we interpret it's register defs as new value
// definitions.
@@ -3503,7 +3505,10 @@ bool InstrRefBasedLDV::depthFirstVLocAndEmit(
// Helper lambda for ejecting a block -- if nothing is going to use the block,
// we can translate the variable location information into DBG_VALUEs and then
// free all of InstrRefBasedLDV's data structures.
+ SmallPtrSet<const MachineBasicBlock *, 8> EjectedBBs;
auto EjectBlock = [&](MachineBasicBlock &MBB) -> void {
+ if (EjectedBBs.insert(&MBB).second == false)
+ return;
unsigned BBNum = MBB.getNumber();
AllTheVLocs[BBNum].clear();
@@ -3517,14 +3522,14 @@ bool InstrRefBasedLDV::depthFirstVLocAndEmit(
CurBB = BBNum;
CurInst = 1;
for (auto &MI : MBB) {
- process(MI, MOutLocs.get(), MInLocs.get());
+ process(MI, &MOutLocs, &MInLocs);
TTracker->checkInstForNewValues(CurInst, MI.getIterator());
++CurInst;
}
// Free machine-location tables for this block.
- MInLocs[BBNum].reset();
- MOutLocs[BBNum].reset();
+ MInLocs[BBNum] = ValueTable();
+ MOutLocs[BBNum] = ValueTable();
// We don't need live-in variable values for this block either.
Output[BBNum].clear();
AllTheVLocs[BBNum].clear();
@@ -3589,8 +3594,7 @@ bool InstrRefBasedLDV::depthFirstVLocAndEmit(
// anything for such out-of-scope blocks, but for the sake of being similar
// to VarLocBasedLDV, eject these too.
for (auto *MBB : ArtificialBlocks)
- if (MOutLocs[MBB->getNumber()])
- EjectBlock(*MBB);
+ EjectBlock(*MBB);
return emitTransfers(AllVarsNumbering);
}
@@ -3688,14 +3692,9 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF,
// Allocate and initialize two array-of-arrays for the live-in and live-out
// machine values. The outer dimension is the block number; while the inner
// dimension is a LocIdx from MLocTracker.
- FuncValueTable MOutLocs = std::make_unique<ValueTable[]>(MaxNumBlocks);
- FuncValueTable MInLocs = std::make_unique<ValueTable[]>(MaxNumBlocks);
unsigned NumLocs = MTracker->getNumLocs();
- for (int i = 0; i < MaxNumBlocks; ++i) {
- // These all auto-initialize to ValueIDNum::EmptyValue
- MOutLocs[i] = std::make_unique<ValueIDNum[]>(NumLocs);
- MInLocs[i] = std::make_unique<ValueIDNum[]>(NumLocs);
- }
+ FuncValueTable MOutLocs(MaxNumBlocks, ValueTable(NumLocs));
+ FuncValueTable MInLocs(MaxNumBlocks, ValueTable(NumLocs));
// Solve the machine value dataflow problem using the MLocTransfer function,
// storing the computed live-ins / live-outs into the array-of-arrays. We use
@@ -3736,7 +3735,7 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF,
MTracker->loadFromArray(MInLocs[CurBB], CurBB);
CurInst = 1;
for (auto &MI : MBB) {
- process(MI, MOutLocs.get(), MInLocs.get());
+ process(MI, &MOutLocs, &MInLocs);
++CurInst;
}
MTracker->reset();
@@ -3917,9 +3916,9 @@ public:
/// Machine location where any PHI must occur.
LocIdx Loc;
/// Table of live-in machine value numbers for blocks / locations.
- const ValueTable *MLiveIns;
+ const FuncValueTable &MLiveIns;
- LDVSSAUpdater(LocIdx L, const ValueTable *MLiveIns)
+ LDVSSAUpdater(LocIdx L, const FuncValueTable &MLiveIns)
: Loc(L), MLiveIns(MLiveIns) {}
void reset() {
@@ -4075,12 +4074,8 @@ public:
} // end namespace llvm
std::optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(
- MachineFunction &MF, const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns, MachineInstr &Here, uint64_t InstrNum) {
- assert(MLiveOuts && MLiveIns &&
- "Tried to resolve DBG_PHI before location "
- "tables allocated?");
-
+ MachineFunction &MF, const FuncValueTable &MLiveOuts,
+ const FuncValueTable &MLiveIns, MachineInstr &Here, uint64_t InstrNum) {
// This function will be called twice per DBG_INSTR_REF, and might end up
// computing lots of SSA information: memoize it.
auto SeenDbgPHIIt = SeenDbgPHIs.find(std::make_pair(&Here, InstrNum));
@@ -4094,8 +4089,8 @@ std::optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(
}
std::optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIsImpl(
- MachineFunction &MF, const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns, MachineInstr &Here, uint64_t InstrNum) {
+ MachineFunction &MF, const FuncValueTable &MLiveOuts,
+ const FuncValueTable &MLiveIns, MachineInstr &Here, uint64_t InstrNum) {
// Pick out records of DBG_PHI instructions that have been observed. If there
// are none, then we cannot compute a value number.
auto RangePair = std::equal_range(DebugPHINumToValue.begin(),
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
index 5e94962f9d7e..d6dbb1feda3e 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
@@ -205,11 +205,11 @@ namespace LiveDebugValues {
using namespace llvm;
/// Type for a table of values in a block.
-using ValueTable = std::unique_ptr<ValueIDNum[]>;
+using ValueTable = SmallVector<ValueIDNum, 0>;
/// Type for a table-of-table-of-values, i.e., the collection of either
/// live-in or live-out values for each block in the function.
-using FuncValueTable = std::unique_ptr<ValueTable[]>;
+using FuncValueTable = SmallVector<ValueTable, 0>;
/// Thin wrapper around an integer -- designed to give more type safety to
/// spill location numbers.
@@ -1200,12 +1200,12 @@ private:
/// exists, otherwise returns std::nullopt.
std::optional<ValueIDNum> getValueForInstrRef(unsigned InstNo, unsigned OpNo,
MachineInstr &MI,
- const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns);
+ const FuncValueTable *MLiveOuts,
+ const FuncValueTable *MLiveIns);
/// Observe a single instruction while stepping through a block.
- void process(MachineInstr &MI, const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns);
+ void process(MachineInstr &MI, const FuncValueTable *MLiveOuts,
+ const FuncValueTable *MLiveIns);
/// Examines whether \p MI is a DBG_VALUE and notifies trackers.
/// \returns true if MI was recognized and processed.
@@ -1213,8 +1213,8 @@ private:
/// Examines whether \p MI is a DBG_INSTR_REF and notifies trackers.
/// \returns true if MI was recognized and processed.
- bool transferDebugInstrRef(MachineInstr &MI, const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns);
+ bool transferDebugInstrRef(MachineInstr &MI, const FuncValueTable *MLiveOuts,
+ const FuncValueTable *MLiveIns);
/// Stores value-information about where this PHI occurred, and what
/// instruction number is associated with it.
@@ -1246,14 +1246,14 @@ private:
/// \p InstrNum Debug instruction number defined by DBG_PHI instructions.
/// \returns The machine value number at position Here, or std::nullopt.
std::optional<ValueIDNum> resolveDbgPHIs(MachineFunction &MF,
- const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns,
+ const FuncValueTable &MLiveOuts,
+ const FuncValueTable &MLiveIns,
MachineInstr &Here,
uint64_t InstrNum);
std::optional<ValueIDNum> resolveDbgPHIsImpl(MachineFunction &MF,
- const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns,
+ const FuncValueTable &MLiveOuts,
+ const FuncValueTable &MLiveIns,
MachineInstr &Here,
uint64_t InstrNum);
diff --git a/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp
index 116c6b7e2d19..bf730be00a9a 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp
+++ b/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp
@@ -1364,7 +1364,7 @@ void VarLocBasedLDV::removeEntryValue(const MachineInstr &MI,
// TODO: Try to keep tracking of an entry value if we encounter a propagated
// DBG_VALUE describing the copy of the entry value. (Propagated entry value
// does not indicate the parameter modification.)
- auto DestSrc = TII->isCopyInstr(*TransferInst);
+ auto DestSrc = TII->isCopyLikeInstr(*TransferInst);
if (DestSrc) {
const MachineOperand *SrcRegOp, *DestRegOp;
SrcRegOp = DestSrc->Source;
@@ -1840,7 +1840,7 @@ void VarLocBasedLDV::transferRegisterCopy(MachineInstr &MI,
OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs,
TransferMap &Transfers) {
- auto DestSrc = TII->isCopyInstr(MI);
+ auto DestSrc = TII->isCopyLikeInstr(MI);
if (!DestSrc)
return;
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index 0a0e386cde61..870611248466 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -300,8 +300,8 @@ static Cursor maybeLexIdentifier(Cursor C, MIToken &Token) {
static Cursor maybeLexMachineBasicBlock(Cursor C, MIToken &Token,
ErrorCallbackType ErrorCallback) {
- bool IsReference = C.remaining().startswith("%bb.");
- if (!IsReference && !C.remaining().startswith("bb."))
+ bool IsReference = C.remaining().starts_with("%bb.");
+ if (!IsReference && !C.remaining().starts_with("bb."))
return std::nullopt;
auto Range = C;
unsigned PrefixLength = IsReference ? 4 : 3;
@@ -335,7 +335,7 @@ static Cursor maybeLexMachineBasicBlock(Cursor C, MIToken &Token,
static Cursor maybeLexIndex(Cursor C, MIToken &Token, StringRef Rule,
MIToken::TokenKind Kind) {
- if (!C.remaining().startswith(Rule) || !isdigit(C.peek(Rule.size())))
+ if (!C.remaining().starts_with(Rule) || !isdigit(C.peek(Rule.size())))
return std::nullopt;
auto Range = C;
C.advance(Rule.size());
@@ -348,7 +348,7 @@ static Cursor maybeLexIndex(Cursor C, MIToken &Token, StringRef Rule,
static Cursor maybeLexIndexAndName(Cursor C, MIToken &Token, StringRef Rule,
MIToken::TokenKind Kind) {
- if (!C.remaining().startswith(Rule) || !isdigit(C.peek(Rule.size())))
+ if (!C.remaining().starts_with(Rule) || !isdigit(C.peek(Rule.size())))
return std::nullopt;
auto Range = C;
C.advance(Rule.size());
@@ -388,7 +388,7 @@ static Cursor maybeLexConstantPoolItem(Cursor C, MIToken &Token) {
static Cursor maybeLexSubRegisterIndex(Cursor C, MIToken &Token,
ErrorCallbackType ErrorCallback) {
const StringRef Rule = "%subreg.";
- if (!C.remaining().startswith(Rule))
+ if (!C.remaining().starts_with(Rule))
return std::nullopt;
return lexName(C, Token, MIToken::SubRegisterIndex, Rule.size(),
ErrorCallback);
@@ -397,7 +397,7 @@ static Cursor maybeLexSubRegisterIndex(Cursor C, MIToken &Token,
static Cursor maybeLexIRBlock(Cursor C, MIToken &Token,
ErrorCallbackType ErrorCallback) {
const StringRef Rule = "%ir-block.";
- if (!C.remaining().startswith(Rule))
+ if (!C.remaining().starts_with(Rule))
return std::nullopt;
if (isdigit(C.peek(Rule.size())))
return maybeLexIndex(C, Token, Rule, MIToken::IRBlock);
@@ -407,7 +407,7 @@ static Cursor maybeLexIRBlock(Cursor C, MIToken &Token,
static Cursor maybeLexIRValue(Cursor C, MIToken &Token,
ErrorCallbackType ErrorCallback) {
const StringRef Rule = "%ir.";
- if (!C.remaining().startswith(Rule))
+ if (!C.remaining().starts_with(Rule))
return std::nullopt;
if (isdigit(C.peek(Rule.size())))
return maybeLexIndex(C, Token, Rule, MIToken::IRValue);
@@ -501,7 +501,7 @@ static Cursor maybeLexExternalSymbol(Cursor C, MIToken &Token,
static Cursor maybeLexMCSymbol(Cursor C, MIToken &Token,
ErrorCallbackType ErrorCallback) {
const StringRef Rule = "<mcsymbol ";
- if (!C.remaining().startswith(Rule))
+ if (!C.remaining().starts_with(Rule))
return std::nullopt;
auto Start = C;
C.advance(Rule.size());
diff --git a/llvm/lib/CodeGen/MachinePassManager.cpp b/llvm/lib/CodeGen/MachinePassManager.cpp
index a13f820e4577..914e6b19fde9 100644
--- a/llvm/lib/CodeGen/MachinePassManager.cpp
+++ b/llvm/lib/CodeGen/MachinePassManager.cpp
@@ -33,10 +33,11 @@ Error MachineFunctionPassManager::run(Module &M,
(void)RequireCodeGenSCCOrder;
assert(!RequireCodeGenSCCOrder && "not implemented");
+ // M is unused here
+ PassInstrumentation PI = MFAM.getResult<PassInstrumentationAnalysis>(M);
+
// Add a PIC to verify machine functions.
if (VerifyMachineFunction) {
- PassInstrumentation PI = MFAM.getResult<PassInstrumentationAnalysis>(M);
-
// No need to pop this callback later since MIR pipeline is flat which means
// current pipeline is the top-level pipeline. Callbacks are not used after
// current pipeline.
@@ -59,8 +60,11 @@ Error MachineFunctionPassManager::run(Module &M,
do {
// Run machine module passes
for (; MachineModulePasses.count(Idx) && Idx != Size; ++Idx) {
+ if (!PI.runBeforePass<Module>(*Passes[Idx], M))
+ continue;
if (auto Err = MachineModulePasses.at(Idx)(M, MFAM))
return Err;
+ PI.runAfterPass(*Passes[Idx], M, PreservedAnalyses::all());
}
// Finish running all passes.
@@ -81,7 +85,6 @@ Error MachineFunctionPassManager::run(Module &M,
continue;
MachineFunction &MF = MMI.getOrCreateMachineFunction(F);
- PassInstrumentation PI = MFAM.getResult<PassInstrumentationAnalysis>(MF);
for (unsigned I = Begin, E = Idx; I != E; ++I) {
auto *P = Passes[I].get();
diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp
index 81b7fdcc5961..8cd7f4ebe88d 100644
--- a/llvm/lib/CodeGen/MachinePipeliner.cpp
+++ b/llvm/lib/CodeGen/MachinePipeliner.cpp
@@ -2225,7 +2225,7 @@ MachineInstr *SwingSchedulerDAG::findDefInLoop(Register Reg) {
}
/// Return true for an order or output dependence that is loop carried
-/// potentially. A dependence is loop carried if the destination defines a valu
+/// potentially. A dependence is loop carried if the destination defines a value
/// that may be used or defined by the source in a subsequent iteration.
bool SwingSchedulerDAG::isLoopCarriedDep(SUnit *Source, const SDep &Dep,
bool isSucc) {
@@ -2251,10 +2251,12 @@ bool SwingSchedulerDAG::isLoopCarriedDep(SUnit *Source, const SDep &Dep,
SI->hasOrderedMemoryRef() || DI->hasOrderedMemoryRef())
return true;
- // Only chain dependences between a load and store can be loop carried.
- if (!DI->mayStore() || !SI->mayLoad())
+ if (!DI->mayLoadOrStore() || !SI->mayLoadOrStore())
return false;
+ // The conservative assumption is that a dependence between memory operations
+ // may be loop carried. The following code checks when it can be proved that
+ // there is no loop carried dependence.
unsigned DeltaS, DeltaD;
if (!computeDelta(*SI, DeltaS) || !computeDelta(*DI, DeltaD))
return true;
diff --git a/llvm/lib/CodeGen/MachineScheduler.cpp b/llvm/lib/CodeGen/MachineScheduler.cpp
index c51ef33bfe54..886137d86f87 100644
--- a/llvm/lib/CodeGen/MachineScheduler.cpp
+++ b/llvm/lib/CodeGen/MachineScheduler.cpp
@@ -747,9 +747,9 @@ void ScheduleDAGMI::finishBlock() {
ScheduleDAGInstrs::finishBlock();
}
-/// enterRegion - Called back from MachineScheduler::runOnMachineFunction after
-/// crossing a scheduling boundary. [begin, end) includes all instructions in
-/// the region, including the boundary itself and single-instruction regions
+/// enterRegion - Called back from PostMachineScheduler::runOnMachineFunction
+/// after crossing a scheduling boundary. [begin, end) includes all instructions
+/// in the region, including the boundary itself and single-instruction regions
/// that don't get scheduled.
void ScheduleDAGMI::enterRegion(MachineBasicBlock *bb,
MachineBasicBlock::iterator begin,
@@ -793,9 +793,9 @@ bool ScheduleDAGMI::checkSchedLimit() {
}
/// Per-region scheduling driver, called back from
-/// MachineScheduler::runOnMachineFunction. This is a simplified driver that
-/// does not consider liveness or register pressure. It is useful for PostRA
-/// scheduling and potentially other custom schedulers.
+/// PostMachineScheduler::runOnMachineFunction. This is a simplified driver
+/// that does not consider liveness or register pressure. It is useful for
+/// PostRA scheduling and potentially other custom schedulers.
void ScheduleDAGMI::schedule() {
LLVM_DEBUG(dbgs() << "ScheduleDAGMI::schedule starting\n");
LLVM_DEBUG(SchedImpl->dumpPolicy());
diff --git a/llvm/lib/CodeGen/MachineSink.cpp b/llvm/lib/CodeGen/MachineSink.cpp
index 83d775055dfd..e7e8f6026834 100644
--- a/llvm/lib/CodeGen/MachineSink.cpp
+++ b/llvm/lib/CodeGen/MachineSink.cpp
@@ -500,11 +500,6 @@ bool MachineSinking::PerformSinkAndFold(MachineInstr &MI,
return false;
// Now we know we can fold the instruction in all its users.
- if (UsedRegA)
- MRI->clearKillFlags(UsedRegA);
- if (UsedRegB)
- MRI->clearKillFlags(UsedRegB);
-
for (auto &[SinkDst, MaybeAM] : SinkInto) {
MachineInstr *New = nullptr;
LLVM_DEBUG(dbgs() << "Sinking copy of"; MI.dump(); dbgs() << "into";
@@ -527,9 +522,25 @@ bool MachineSinking::PerformSinkAndFold(MachineInstr &MI,
New = &*std::prev(InsertPt);
if (!New->getDebugLoc())
New->setDebugLoc(SinkDst->getDebugLoc());
+
+ // The operand registers of the "sunk" instruction have their live range
+ // extended and their kill flags may no longer be correct. Conservatively
+ // clear the kill flags.
+ if (UsedRegA)
+ MRI->clearKillFlags(UsedRegA);
+ if (UsedRegB)
+ MRI->clearKillFlags(UsedRegB);
} else {
// Fold instruction into the addressing mode of a memory instruction.
New = TII->emitLdStWithAddr(*SinkDst, MaybeAM);
+
+ // The registers of the addressing mode may have their live range extended
+ // and their kill flags may no longer be correct. Conservatively clear the
+ // kill flags.
+ if (Register R = MaybeAM.BaseReg; R.isValid() && R.isVirtual())
+ MRI->clearKillFlags(R);
+ if (Register R = MaybeAM.ScaledReg; R.isValid() && R.isVirtual())
+ MRI->clearKillFlags(R);
}
LLVM_DEBUG(dbgs() << "yielding"; New->dump());
// Clear the StoreInstrCache, since we may invalidate it by erasing.
diff --git a/llvm/lib/CodeGen/MachineStableHash.cpp b/llvm/lib/CodeGen/MachineStableHash.cpp
index debb2b3809e3..1cd90474898e 100644
--- a/llvm/lib/CodeGen/MachineStableHash.cpp
+++ b/llvm/lib/CodeGen/MachineStableHash.cpp
@@ -14,7 +14,6 @@
#include "llvm/CodeGen/MachineStableHash.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index aaf9bd740d13..a015d9bbd2d3 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -1812,6 +1812,29 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
}
break;
}
+ case TargetOpcode::G_PREFETCH: {
+ const MachineOperand &AddrOp = MI->getOperand(0);
+ if (!AddrOp.isReg() || !MRI->getType(AddrOp.getReg()).isPointer()) {
+ report("addr operand must be a pointer", &AddrOp, 0);
+ break;
+ }
+ const MachineOperand &RWOp = MI->getOperand(1);
+ if (!RWOp.isImm() || (uint64_t)RWOp.getImm() >= 2) {
+ report("rw operand must be an immediate 0-1", &RWOp, 1);
+ break;
+ }
+ const MachineOperand &LocalityOp = MI->getOperand(2);
+ if (!LocalityOp.isImm() || (uint64_t)LocalityOp.getImm() >= 4) {
+ report("locality operand must be an immediate 0-3", &LocalityOp, 2);
+ break;
+ }
+ const MachineOperand &CacheTypeOp = MI->getOperand(3);
+ if (!CacheTypeOp.isImm() || (uint64_t)CacheTypeOp.getImm() >= 2) {
+ report("cache type operand must be an immediate 0-1", &CacheTypeOp, 3);
+ break;
+ }
+ break;
+ }
case TargetOpcode::G_ASSERT_ALIGN: {
if (MI->getOperand(2).getImm() < 1)
report("alignment immediate must be >= 1", MI);
diff --git a/llvm/lib/CodeGen/MacroFusion.cpp b/llvm/lib/CodeGen/MacroFusion.cpp
index fa5df68b8abc..aff4d95781f4 100644
--- a/llvm/lib/CodeGen/MacroFusion.cpp
+++ b/llvm/lib/CodeGen/MacroFusion.cpp
@@ -137,19 +137,34 @@ namespace {
/// Post-process the DAG to create cluster edges between instrs that may
/// be fused by the processor into a single operation.
class MacroFusion : public ScheduleDAGMutation {
- ShouldSchedulePredTy shouldScheduleAdjacent;
+ std::vector<MacroFusionPredTy> Predicates;
bool FuseBlock;
bool scheduleAdjacentImpl(ScheduleDAGInstrs &DAG, SUnit &AnchorSU);
public:
- MacroFusion(ShouldSchedulePredTy shouldScheduleAdjacent, bool FuseBlock)
- : shouldScheduleAdjacent(shouldScheduleAdjacent), FuseBlock(FuseBlock) {}
+ MacroFusion(ArrayRef<MacroFusionPredTy> Predicates, bool FuseBlock)
+ : Predicates(Predicates.begin(), Predicates.end()), FuseBlock(FuseBlock) {
+ }
void apply(ScheduleDAGInstrs *DAGInstrs) override;
+
+ bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
+ const TargetSubtargetInfo &STI,
+ const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI);
};
} // end anonymous namespace
+bool MacroFusion::shouldScheduleAdjacent(const TargetInstrInfo &TII,
+ const TargetSubtargetInfo &STI,
+ const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI) {
+ return llvm::any_of(Predicates, [&](MacroFusionPredTy Predicate) {
+ return Predicate(TII, STI, FirstMI, SecondMI);
+ });
+}
+
void MacroFusion::apply(ScheduleDAGInstrs *DAG) {
if (FuseBlock)
// For each of the SUnits in the scheduling block, try to fuse the instr in
@@ -197,17 +212,15 @@ bool MacroFusion::scheduleAdjacentImpl(ScheduleDAGInstrs &DAG, SUnit &AnchorSU)
}
std::unique_ptr<ScheduleDAGMutation>
-llvm::createMacroFusionDAGMutation(
- ShouldSchedulePredTy shouldScheduleAdjacent) {
- if(EnableMacroFusion)
- return std::make_unique<MacroFusion>(shouldScheduleAdjacent, true);
+llvm::createMacroFusionDAGMutation(ArrayRef<MacroFusionPredTy> Predicates) {
+ if (EnableMacroFusion)
+ return std::make_unique<MacroFusion>(Predicates, true);
return nullptr;
}
-std::unique_ptr<ScheduleDAGMutation>
-llvm::createBranchMacroFusionDAGMutation(
- ShouldSchedulePredTy shouldScheduleAdjacent) {
- if(EnableMacroFusion)
- return std::make_unique<MacroFusion>(shouldScheduleAdjacent, false);
+std::unique_ptr<ScheduleDAGMutation> llvm::createBranchMacroFusionDAGMutation(
+ ArrayRef<MacroFusionPredTy> Predicates) {
+ if (EnableMacroFusion)
+ return std::make_unique<MacroFusion>(Predicates, false);
return nullptr;
}
diff --git a/llvm/lib/CodeGen/RegAllocFast.cpp b/llvm/lib/CodeGen/RegAllocFast.cpp
index b216d7296446..40c42cabf776 100644
--- a/llvm/lib/CodeGen/RegAllocFast.cpp
+++ b/llvm/lib/CodeGen/RegAllocFast.cpp
@@ -268,7 +268,7 @@ private:
Register VirtReg);
bool defineVirtReg(MachineInstr &MI, unsigned OpNum, Register VirtReg,
bool LookAtPhysRegUses = false);
- bool useVirtReg(MachineInstr &MI, unsigned OpNum, Register VirtReg);
+ bool useVirtReg(MachineInstr &MI, MachineOperand &MO, Register VirtReg);
MachineBasicBlock::iterator
getMBBBeginInsertionPoint(MachineBasicBlock &MBB,
@@ -984,17 +984,15 @@ bool RegAllocFast::defineVirtReg(MachineInstr &MI, unsigned OpNum,
/// Allocates a register for a VirtReg use.
/// \return true if MI's MachineOperands were re-arranged/invalidated.
-bool RegAllocFast::useVirtReg(MachineInstr &MI, unsigned OpNum,
+bool RegAllocFast::useVirtReg(MachineInstr &MI, MachineOperand &MO,
Register VirtReg) {
assert(VirtReg.isVirtual() && "Not a virtual register");
if (!shouldAllocateRegister(VirtReg))
return false;
- MachineOperand &MO = MI.getOperand(OpNum);
LiveRegMap::iterator LRI;
bool New;
std::tie(LRI, New) = LiveVirtRegs.insert(LiveReg(VirtReg));
if (New) {
- MachineOperand &MO = MI.getOperand(OpNum);
if (!MO.isKill()) {
if (mayLiveOut(VirtReg)) {
LRI->LiveOut = true;
@@ -1224,6 +1222,17 @@ void RegAllocFast::findAndSortDefOperandIndexes(const MachineInstr &MI) {
});
}
+// Returns true if MO is tied and the operand it's tied to is not Undef (not
+// Undef is not the same thing as Def).
+static bool isTiedToNotUndef(const MachineOperand &MO) {
+ if (!MO.isTied())
+ return false;
+ const MachineInstr &MI = *MO.getParent();
+ unsigned TiedIdx = MI.findTiedOperandIdx(MI.getOperandNo(&MO));
+ const MachineOperand &TiedMO = MI.getOperand(TiedIdx);
+ return !TiedMO.isUndef();
+}
+
void RegAllocFast::allocateInstruction(MachineInstr &MI) {
// The basic algorithm here is:
// 1. Mark registers of def operands as free
@@ -1241,12 +1250,6 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
RegMasks.clear();
BundleVirtRegsMap.clear();
- auto TiedOpIsUndef = [&](const MachineOperand &MO, unsigned Idx) {
- assert(MO.isTied());
- unsigned TiedIdx = MI.findTiedOperandIdx(Idx);
- const MachineOperand &TiedMO = MI.getOperand(TiedIdx);
- return TiedMO.isUndef();
- };
// Scan for special cases; Apply pre-assigned register defs to state.
bool HasPhysRegUse = false;
bool HasRegMask = false;
@@ -1254,8 +1257,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
bool HasDef = false;
bool HasEarlyClobber = false;
bool NeedToAssignLiveThroughs = false;
- for (unsigned I = 0; I < MI.getNumOperands(); ++I) {
- MachineOperand &MO = MI.getOperand(I);
+ for (MachineOperand &MO : MI.operands()) {
if (MO.isReg()) {
Register Reg = MO.getReg();
if (Reg.isVirtual()) {
@@ -1268,8 +1270,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
HasEarlyClobber = true;
NeedToAssignLiveThroughs = true;
}
- if ((MO.isTied() && !TiedOpIsUndef(MO, I)) ||
- (MO.getSubReg() != 0 && !MO.isUndef()))
+ if (isTiedToNotUndef(MO) || (MO.getSubReg() != 0 && !MO.isUndef()))
NeedToAssignLiveThroughs = true;
}
} else if (Reg.isPhysical()) {
@@ -1314,35 +1315,32 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
for (uint16_t OpIdx : DefOperandIndexes) {
MachineOperand &MO = MI.getOperand(OpIdx);
LLVM_DEBUG(dbgs() << "Allocating " << MO << '\n');
- unsigned Reg = MO.getReg();
- if (MO.isEarlyClobber() ||
- (MO.isTied() && !TiedOpIsUndef(MO, OpIdx)) ||
+ Register Reg = MO.getReg();
+ if (MO.isEarlyClobber() || isTiedToNotUndef(MO) ||
(MO.getSubReg() && !MO.isUndef())) {
ReArrangedImplicitOps = defineLiveThroughVirtReg(MI, OpIdx, Reg);
} else {
ReArrangedImplicitOps = defineVirtReg(MI, OpIdx, Reg);
}
- if (ReArrangedImplicitOps) {
- // Implicit operands of MI were re-arranged,
- // re-compute DefOperandIndexes.
+ // Implicit operands of MI were re-arranged,
+ // re-compute DefOperandIndexes.
+ if (ReArrangedImplicitOps)
break;
- }
}
}
} else {
// Assign virtual register defs.
while (ReArrangedImplicitOps) {
ReArrangedImplicitOps = false;
- for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
- MachineOperand &MO = MI.getOperand(I);
+ for (MachineOperand &MO : MI.operands()) {
if (!MO.isReg() || !MO.isDef())
continue;
Register Reg = MO.getReg();
if (Reg.isVirtual()) {
- ReArrangedImplicitOps = defineVirtReg(MI, I, Reg);
- if (ReArrangedImplicitOps) {
+ ReArrangedImplicitOps =
+ defineVirtReg(MI, MI.getOperandNo(&MO), Reg);
+ if (ReArrangedImplicitOps)
break;
- }
}
}
}
@@ -1352,8 +1350,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
// Free registers occupied by defs.
// Iterate operands in reverse order, so we see the implicit super register
// defs first (we added them earlier in case of <def,read-undef>).
- for (signed I = MI.getNumOperands() - 1; I >= 0; --I) {
- MachineOperand &MO = MI.getOperand(I);
+ for (MachineOperand &MO : reverse(MI.operands())) {
if (!MO.isReg() || !MO.isDef())
continue;
@@ -1370,7 +1367,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
"tied def assigned to clobbered register");
// Do not free tied operands and early clobbers.
- if ((MO.isTied() && !TiedOpIsUndef(MO, I)) || MO.isEarlyClobber())
+ if (isTiedToNotUndef(MO) || MO.isEarlyClobber())
continue;
if (!Reg)
continue;
@@ -1411,8 +1408,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
continue;
if (MRI->isReserved(Reg))
continue;
- bool displacedAny = usePhysReg(MI, Reg);
- if (!displacedAny)
+ if (!usePhysReg(MI, Reg))
MO.setIsKill(true);
}
}
@@ -1424,8 +1420,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
bool ReArrangedImplicitMOs = true;
while (ReArrangedImplicitMOs) {
ReArrangedImplicitMOs = false;
- for (unsigned I = 0; I < MI.getNumOperands(); ++I) {
- MachineOperand &MO = MI.getOperand(I);
+ for (MachineOperand &MO : MI.operands()) {
if (!MO.isReg() || !MO.isUse())
continue;
Register Reg = MO.getReg();
@@ -1443,7 +1438,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
assert(!MO.isInternalRead() && "Bundles not supported");
assert(MO.readsReg() && "reading use");
- ReArrangedImplicitMOs = useVirtReg(MI, I, Reg);
+ ReArrangedImplicitMOs = useVirtReg(MI, MO, Reg);
if (ReArrangedImplicitMOs)
break;
}
@@ -1465,7 +1460,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
// Free early clobbers.
if (HasEarlyClobber) {
- for (MachineOperand &MO : llvm::reverse(MI.all_defs())) {
+ for (MachineOperand &MO : reverse(MI.all_defs())) {
if (!MO.isEarlyClobber())
continue;
assert(!MO.getSubReg() && "should be already handled in def processing");
diff --git a/llvm/lib/CodeGen/RegisterCoalescer.cpp b/llvm/lib/CodeGen/RegisterCoalescer.cpp
index c067d87a9fd8..c1af37c8510f 100644
--- a/llvm/lib/CodeGen/RegisterCoalescer.cpp
+++ b/llvm/lib/CodeGen/RegisterCoalescer.cpp
@@ -1201,6 +1201,8 @@ bool RegisterCoalescer::removePartialRedundancy(const CoalescerPair &CP,
<< printMBBReference(MBB) << '\t' << CopyMI);
}
+ const bool IsUndefCopy = CopyMI.getOperand(1).isUndef();
+
// Remove CopyMI.
// Note: This is fine to remove the copy before updating the live-ranges.
// While updating the live-ranges, we only look at slot indices and
@@ -1214,6 +1216,19 @@ bool RegisterCoalescer::removePartialRedundancy(const CoalescerPair &CP,
LIS->pruneValue(*static_cast<LiveRange *>(&IntB), CopyIdx.getRegSlot(),
&EndPoints);
BValNo->markUnused();
+
+ if (IsUndefCopy) {
+ // We're introducing an undef phi def, and need to set undef on any users of
+ // the previously local def to avoid artifically extending the lifetime
+ // through the block.
+ for (MachineOperand &MO : MRI->use_nodbg_operands(IntB.reg())) {
+ const MachineInstr &MI = *MO.getParent();
+ SlotIndex UseIdx = LIS->getInstructionIndex(MI);
+ if (!IntB.liveAt(UseIdx))
+ MO.setIsUndef(true);
+ }
+ }
+
// Extend IntB to the EndPoints of its original live interval.
LIS->extendToIndices(IntB, EndPoints);
@@ -1596,8 +1611,7 @@ bool RegisterCoalescer::reMaterializeTrivialDef(const CoalescerPair &CP,
LR->createDeadDef(NewMIIdx.getRegSlot(), LIS->getVNInfoAllocator());
}
- if (NewMI.getOperand(0).getSubReg())
- NewMI.getOperand(0).setIsUndef();
+ NewMI.setRegisterDefReadUndef(NewMI.getOperand(0).getReg());
// Transfer over implicit operands to the rematerialized instruction.
for (MachineOperand &MO : ImplicitOps)
diff --git a/llvm/lib/CodeGen/SanitizerBinaryMetadata.cpp b/llvm/lib/CodeGen/SanitizerBinaryMetadata.cpp
index cc29bdce1210..9002a7076840 100644
--- a/llvm/lib/CodeGen/SanitizerBinaryMetadata.cpp
+++ b/llvm/lib/CodeGen/SanitizerBinaryMetadata.cpp
@@ -52,7 +52,7 @@ bool MachineSanitizerBinaryMetadata::runOnMachineFunction(MachineFunction &MF) {
if (!MD)
return false;
const auto &Section = *cast<MDString>(MD->getOperand(0));
- if (!Section.getString().startswith(kSanitizerBinaryMetadataCoveredSection))
+ if (!Section.getString().starts_with(kSanitizerBinaryMetadataCoveredSection))
return false;
auto &AuxMDs = *cast<MDTuple>(MD->getOperand(1));
// Assume it currently only has features.
diff --git a/llvm/lib/CodeGen/SelectOptimize.cpp b/llvm/lib/CodeGen/SelectOptimize.cpp
index 05413fb5d758..1316919e65da 100644
--- a/llvm/lib/CodeGen/SelectOptimize.cpp
+++ b/llvm/lib/CodeGen/SelectOptimize.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/CodeGen/SelectOptimize.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
@@ -96,36 +97,22 @@ static cl::opt<bool>
namespace {
-class SelectOptimize : public FunctionPass {
+class SelectOptimizeImpl {
const TargetMachine *TM = nullptr;
const TargetSubtargetInfo *TSI = nullptr;
const TargetLowering *TLI = nullptr;
const TargetTransformInfo *TTI = nullptr;
const LoopInfo *LI = nullptr;
- DominatorTree *DT = nullptr;
- std::unique_ptr<BlockFrequencyInfo> BFI;
- std::unique_ptr<BranchProbabilityInfo> BPI;
+ BlockFrequencyInfo *BFI;
ProfileSummaryInfo *PSI = nullptr;
OptimizationRemarkEmitter *ORE = nullptr;
TargetSchedModel TSchedModel;
public:
- static char ID;
-
- SelectOptimize() : FunctionPass(ID) {
- initializeSelectOptimizePass(*PassRegistry::getPassRegistry());
- }
-
- bool runOnFunction(Function &F) override;
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addRequired<ProfileSummaryInfoWrapperPass>();
- AU.addRequired<TargetPassConfig>();
- AU.addRequired<TargetTransformInfoWrapperPass>();
- AU.addRequired<DominatorTreeWrapperPass>();
- AU.addRequired<LoopInfoWrapperPass>();
- AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
- }
+ SelectOptimizeImpl() = default;
+ SelectOptimizeImpl(const TargetMachine *TM) : TM(TM){};
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+ bool runOnFunction(Function &F, Pass &P);
private:
// Select groups consist of consecutive select instructions with the same
@@ -211,29 +198,94 @@ private:
// Returns true if the target architecture supports lowering a given select.
bool isSelectKindSupported(SelectInst *SI);
};
+
+class SelectOptimize : public FunctionPass {
+ SelectOptimizeImpl Impl;
+
+public:
+ static char ID;
+
+ SelectOptimize() : FunctionPass(ID) {
+ initializeSelectOptimizePass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override {
+ return Impl.runOnFunction(F, *this);
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addRequired<ProfileSummaryInfoWrapperPass>();
+ AU.addRequired<TargetPassConfig>();
+ AU.addRequired<TargetTransformInfoWrapperPass>();
+ AU.addRequired<LoopInfoWrapperPass>();
+ AU.addRequired<BlockFrequencyInfoWrapperPass>();
+ AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+ }
+};
+
} // namespace
+PreservedAnalyses SelectOptimizePass::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ SelectOptimizeImpl Impl(TM);
+ return Impl.run(F, FAM);
+}
+
char SelectOptimize::ID = 0;
INITIALIZE_PASS_BEGIN(SelectOptimize, DEBUG_TYPE, "Optimize selects", false,
false)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
-INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass)
INITIALIZE_PASS_END(SelectOptimize, DEBUG_TYPE, "Optimize selects", false,
false)
FunctionPass *llvm::createSelectOptimizePass() { return new SelectOptimize(); }
-bool SelectOptimize::runOnFunction(Function &F) {
- TM = &getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
+PreservedAnalyses SelectOptimizeImpl::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ TSI = TM->getSubtargetImpl(F);
+ TLI = TSI->getTargetLowering();
+
+ // If none of the select types are supported then skip this pass.
+ // This is an optimization pass. Legality issues will be handled by
+ // instruction selection.
+ if (!TLI->isSelectSupported(TargetLowering::ScalarValSelect) &&
+ !TLI->isSelectSupported(TargetLowering::ScalarCondVectorVal) &&
+ !TLI->isSelectSupported(TargetLowering::VectorMaskSelect))
+ return PreservedAnalyses::all();
+
+ TTI = &FAM.getResult<TargetIRAnalysis>(F);
+ if (!TTI->enableSelectOptimize())
+ return PreservedAnalyses::all();
+
+ PSI = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F)
+ .getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
+ assert(PSI && "This pass requires module analysis pass `profile-summary`!");
+ BFI = &FAM.getResult<BlockFrequencyAnalysis>(F);
+
+ // When optimizing for size, selects are preferable over branches.
+ if (F.hasOptSize() || llvm::shouldOptimizeForSize(&F, PSI, BFI))
+ return PreservedAnalyses::all();
+
+ LI = &FAM.getResult<LoopAnalysis>(F);
+ ORE = &FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
+ TSchedModel.init(TSI);
+
+ bool Changed = optimizeSelects(F);
+ return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
+}
+
+bool SelectOptimizeImpl::runOnFunction(Function &F, Pass &P) {
+ TM = &P.getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
TSI = TM->getSubtargetImpl(F);
TLI = TSI->getTargetLowering();
- // If none of the select types is supported then skip this pass.
+ // If none of the select types are supported then skip this pass.
// This is an optimization pass. Legality issues will be handled by
// instruction selection.
if (!TLI->isSelectSupported(TargetLowering::ScalarValSelect) &&
@@ -241,27 +293,25 @@ bool SelectOptimize::runOnFunction(Function &F) {
!TLI->isSelectSupported(TargetLowering::VectorMaskSelect))
return false;
- TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
+ TTI = &P.getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
if (!TTI->enableSelectOptimize())
return false;
- DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
- LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
- BPI.reset(new BranchProbabilityInfo(F, *LI));
- BFI.reset(new BlockFrequencyInfo(F, *BPI, *LI));
- PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
- ORE = &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
+ LI = &P.getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+ BFI = &P.getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+ PSI = &P.getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
+ ORE = &P.getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
TSchedModel.init(TSI);
// When optimizing for size, selects are preferable over branches.
- if (F.hasOptSize() || llvm::shouldOptimizeForSize(&F, PSI, BFI.get()))
+ if (F.hasOptSize() || llvm::shouldOptimizeForSize(&F, PSI, BFI))
return false;
return optimizeSelects(F);
}
-bool SelectOptimize::optimizeSelects(Function &F) {
+bool SelectOptimizeImpl::optimizeSelects(Function &F) {
// Determine for which select groups it is profitable converting to branches.
SelectGroups ProfSIGroups;
// Base heuristics apply only to non-loops and outer loops.
@@ -277,8 +327,8 @@ bool SelectOptimize::optimizeSelects(Function &F) {
return !ProfSIGroups.empty();
}
-void SelectOptimize::optimizeSelectsBase(Function &F,
- SelectGroups &ProfSIGroups) {
+void SelectOptimizeImpl::optimizeSelectsBase(Function &F,
+ SelectGroups &ProfSIGroups) {
// Collect all the select groups.
SelectGroups SIGroups;
for (BasicBlock &BB : F) {
@@ -293,8 +343,8 @@ void SelectOptimize::optimizeSelectsBase(Function &F,
findProfitableSIGroupsBase(SIGroups, ProfSIGroups);
}
-void SelectOptimize::optimizeSelectsInnerLoops(Function &F,
- SelectGroups &ProfSIGroups) {
+void SelectOptimizeImpl::optimizeSelectsInnerLoops(Function &F,
+ SelectGroups &ProfSIGroups) {
SmallVector<Loop *, 4> Loops(LI->begin(), LI->end());
// Need to check size on each iteration as we accumulate child loops.
for (unsigned long i = 0; i < Loops.size(); ++i)
@@ -331,7 +381,7 @@ getTrueOrFalseValue(SelectInst *SI, bool isTrue,
return V;
}
-void SelectOptimize::convertProfitableSIGroups(SelectGroups &ProfSIGroups) {
+void SelectOptimizeImpl::convertProfitableSIGroups(SelectGroups &ProfSIGroups) {
for (SelectGroup &ASI : ProfSIGroups) {
// The code transformation here is a modified version of the sinking
// transformation in CodeGenPrepare::optimizeSelectInst with a more
@@ -531,8 +581,8 @@ static bool isSpecialSelect(SelectInst *SI) {
return false;
}
-void SelectOptimize::collectSelectGroups(BasicBlock &BB,
- SelectGroups &SIGroups) {
+void SelectOptimizeImpl::collectSelectGroups(BasicBlock &BB,
+ SelectGroups &SIGroups) {
BasicBlock::iterator BBIt = BB.begin();
while (BBIt != BB.end()) {
Instruction *I = &*BBIt++;
@@ -565,8 +615,8 @@ void SelectOptimize::collectSelectGroups(BasicBlock &BB,
}
}
-void SelectOptimize::findProfitableSIGroupsBase(SelectGroups &SIGroups,
- SelectGroups &ProfSIGroups) {
+void SelectOptimizeImpl::findProfitableSIGroupsBase(
+ SelectGroups &SIGroups, SelectGroups &ProfSIGroups) {
for (SelectGroup &ASI : SIGroups) {
++NumSelectOptAnalyzed;
if (isConvertToBranchProfitableBase(ASI))
@@ -580,14 +630,14 @@ static void EmitAndPrintRemark(OptimizationRemarkEmitter *ORE,
ORE->emit(Rem);
}
-void SelectOptimize::findProfitableSIGroupsInnerLoops(
+void SelectOptimizeImpl::findProfitableSIGroupsInnerLoops(
const Loop *L, SelectGroups &SIGroups, SelectGroups &ProfSIGroups) {
NumSelectOptAnalyzed += SIGroups.size();
// For each select group in an inner-most loop,
// a branch is more preferable than a select/conditional-move if:
// i) conversion to branches for all the select groups of the loop satisfies
// loop-level heuristics including reducing the loop's critical path by
- // some threshold (see SelectOptimize::checkLoopHeuristics); and
+ // some threshold (see SelectOptimizeImpl::checkLoopHeuristics); and
// ii) the total cost of the select group is cheaper with a branch compared
// to its predicated version. The cost is in terms of latency and the cost
// of a select group is the cost of its most expensive select instruction
@@ -627,7 +677,7 @@ void SelectOptimize::findProfitableSIGroupsInnerLoops(
}
}
-bool SelectOptimize::isConvertToBranchProfitableBase(
+bool SelectOptimizeImpl::isConvertToBranchProfitableBase(
const SmallVector<SelectInst *, 2> &ASI) {
SelectInst *SI = ASI.front();
LLVM_DEBUG(dbgs() << "Analyzing select group containing " << *SI << "\n");
@@ -635,7 +685,7 @@ bool SelectOptimize::isConvertToBranchProfitableBase(
OptimizationRemarkMissed ORmiss(DEBUG_TYPE, "SelectOpti", SI);
// Skip cold basic blocks. Better to optimize for size for cold blocks.
- if (PSI->isColdBlock(SI->getParent(), BFI.get())) {
+ if (PSI->isColdBlock(SI->getParent(), BFI)) {
++NumSelectColdBB;
ORmiss << "Not converted to branch because of cold basic block. ";
EmitAndPrintRemark(ORE, ORmiss);
@@ -678,7 +728,7 @@ static InstructionCost divideNearest(InstructionCost Numerator,
return (Numerator + (Denominator / 2)) / Denominator;
}
-bool SelectOptimize::hasExpensiveColdOperand(
+bool SelectOptimizeImpl::hasExpensiveColdOperand(
const SmallVector<SelectInst *, 2> &ASI) {
bool ColdOperand = false;
uint64_t TrueWeight, FalseWeight, TotalWeight;
@@ -752,9 +802,10 @@ static bool isSafeToSinkLoad(Instruction *LoadI, Instruction *SI) {
// (sufficiently-accurate in practice), we populate this set with the
// instructions of the backwards dependence slice that only have one-use and
// form an one-use chain that leads to the source instruction.
-void SelectOptimize::getExclBackwardsSlice(Instruction *I,
- std::stack<Instruction *> &Slice,
- Instruction *SI, bool ForSinking) {
+void SelectOptimizeImpl::getExclBackwardsSlice(Instruction *I,
+ std::stack<Instruction *> &Slice,
+ Instruction *SI,
+ bool ForSinking) {
SmallPtrSet<Instruction *, 2> Visited;
std::queue<Instruction *> Worklist;
Worklist.push(I);
@@ -798,7 +849,7 @@ void SelectOptimize::getExclBackwardsSlice(Instruction *I,
}
}
-bool SelectOptimize::isSelectHighlyPredictable(const SelectInst *SI) {
+bool SelectOptimizeImpl::isSelectHighlyPredictable(const SelectInst *SI) {
uint64_t TrueWeight, FalseWeight;
if (extractBranchWeights(*SI, TrueWeight, FalseWeight)) {
uint64_t Max = std::max(TrueWeight, FalseWeight);
@@ -812,8 +863,8 @@ bool SelectOptimize::isSelectHighlyPredictable(const SelectInst *SI) {
return false;
}
-bool SelectOptimize::checkLoopHeuristics(const Loop *L,
- const CostInfo LoopCost[2]) {
+bool SelectOptimizeImpl::checkLoopHeuristics(const Loop *L,
+ const CostInfo LoopCost[2]) {
// Loop-level checks to determine if a non-predicated version (with branches)
// of the loop is more profitable than its predicated version.
@@ -881,7 +932,7 @@ bool SelectOptimize::checkLoopHeuristics(const Loop *L,
// and non-predicated version of the given loop.
// Returns false if unable to compute these costs due to invalid cost of loop
// instruction(s).
-bool SelectOptimize::computeLoopCosts(
+bool SelectOptimizeImpl::computeLoopCosts(
const Loop *L, const SelectGroups &SIGroups,
DenseMap<const Instruction *, CostInfo> &InstCostMap, CostInfo *LoopCost) {
LLVM_DEBUG(dbgs() << "Calculating Latency / IPredCost / INonPredCost of loop "
@@ -969,7 +1020,7 @@ bool SelectOptimize::computeLoopCosts(
}
SmallPtrSet<const Instruction *, 2>
-SelectOptimize::getSIset(const SelectGroups &SIGroups) {
+SelectOptimizeImpl::getSIset(const SelectGroups &SIGroups) {
SmallPtrSet<const Instruction *, 2> SIset;
for (const SelectGroup &ASI : SIGroups)
for (const SelectInst *SI : ASI)
@@ -977,7 +1028,8 @@ SelectOptimize::getSIset(const SelectGroups &SIGroups) {
return SIset;
}
-std::optional<uint64_t> SelectOptimize::computeInstCost(const Instruction *I) {
+std::optional<uint64_t>
+SelectOptimizeImpl::computeInstCost(const Instruction *I) {
InstructionCost ICost =
TTI->getInstructionCost(I, TargetTransformInfo::TCK_Latency);
if (auto OC = ICost.getValue())
@@ -986,8 +1038,8 @@ std::optional<uint64_t> SelectOptimize::computeInstCost(const Instruction *I) {
}
ScaledNumber<uint64_t>
-SelectOptimize::getMispredictionCost(const SelectInst *SI,
- const Scaled64 CondCost) {
+SelectOptimizeImpl::getMispredictionCost(const SelectInst *SI,
+ const Scaled64 CondCost) {
uint64_t MispredictPenalty = TSchedModel.getMCSchedModel()->MispredictPenalty;
// Account for the default misprediction rate when using a branch
@@ -1012,8 +1064,8 @@ SelectOptimize::getMispredictionCost(const SelectInst *SI,
// Returns the cost of a branch when the prediction is correct.
// TrueCost * TrueProbability + FalseCost * FalseProbability.
ScaledNumber<uint64_t>
-SelectOptimize::getPredictedPathCost(Scaled64 TrueCost, Scaled64 FalseCost,
- const SelectInst *SI) {
+SelectOptimizeImpl::getPredictedPathCost(Scaled64 TrueCost, Scaled64 FalseCost,
+ const SelectInst *SI) {
Scaled64 PredPathCost;
uint64_t TrueWeight, FalseWeight;
if (extractBranchWeights(*SI, TrueWeight, FalseWeight)) {
@@ -1033,7 +1085,7 @@ SelectOptimize::getPredictedPathCost(Scaled64 TrueCost, Scaled64 FalseCost,
return PredPathCost;
}
-bool SelectOptimize::isSelectKindSupported(SelectInst *SI) {
+bool SelectOptimizeImpl::isSelectKindSupported(SelectInst *SI) {
bool VectorCond = !SI->getCondition()->getType()->isIntegerTy(1);
if (VectorCond)
return false;
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index f35f663d6ba1..c782ad117ce6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -14821,12 +14821,11 @@ SDValue DAGCombiner::visitTRUNCATE(SDNode *N) {
// Handle the case where the load remains an extending load even
// after truncation.
if (N0.hasOneUse() && ISD::isUNINDEXEDLoad(N0.getNode())) {
- LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ auto *LN0 = cast<LoadSDNode>(N0);
if (LN0->isSimple() && LN0->getMemoryVT().bitsLT(VT)) {
- SDValue NewLoad = DAG.getExtLoad(LN0->getExtensionType(), SDLoc(LN0),
- VT, LN0->getChain(), LN0->getBasePtr(),
- LN0->getMemoryVT(),
- LN0->getMemOperand());
+ SDValue NewLoad = DAG.getExtLoad(
+ LN0->getExtensionType(), SDLoc(LN0), VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getMemoryVT(), LN0->getMemOperand());
DAG.ReplaceAllUsesOfValueWith(N0.getValue(1), NewLoad.getValue(1));
return NewLoad;
}
@@ -21006,20 +21005,18 @@ SDValue DAGCombiner::replaceStoreOfInsertLoad(StoreSDNode *ST) {
&IsFast) ||
!IsFast)
return SDValue();
- EVT PtrVT = Ptr.getValueType();
- SDValue Offset =
- DAG.getNode(ISD::MUL, DL, PtrVT, DAG.getZExtOrTrunc(Idx, DL, PtrVT),
- DAG.getConstant(EltVT.getSizeInBits() / 8, DL, PtrVT));
- SDValue NewPtr = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, Offset);
MachinePointerInfo PointerInfo(ST->getAddressSpace());
// If the offset is a known constant then try to recover the pointer
// info
+ SDValue NewPtr;
if (auto *CIdx = dyn_cast<ConstantSDNode>(Idx)) {
unsigned COffset = CIdx->getSExtValue() * EltVT.getSizeInBits() / 8;
NewPtr = DAG.getMemBasePlusOffset(Ptr, TypeSize::getFixed(COffset), DL);
PointerInfo = ST->getPointerInfo().getWithOffset(COffset);
+ } else {
+ NewPtr = TLI.getVectorElementPointer(DAG, Ptr, Value.getValueType(), Idx);
}
return DAG.getStore(Chain, DL, Elt, NewPtr, PointerInfo, ST->getAlign(),
@@ -24181,6 +24178,10 @@ static SDValue narrowExtractedVectorLoad(SDNode *Extract, SelectionDAG &DAG) {
unsigned Index = Extract->getConstantOperandVal(1);
unsigned NumElts = VT.getVectorMinNumElements();
+ // A fixed length vector being extracted from a scalable vector
+ // may not be any *smaller* than the scalable one.
+ if (Index == 0 && NumElts >= Ld->getValueType(0).getVectorMinNumElements())
+ return SDValue();
// The definition of EXTRACT_SUBVECTOR states that the index must be a
// multiple of the minimum number of elements in the result type.
diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
index 1128ecfd860d..03cba892a167 100644
--- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
@@ -357,6 +357,7 @@ void FunctionLoweringInfo::clear() {
StatepointRelocationMaps.clear();
PreferredExtendType.clear();
PreprocessedDbgDeclares.clear();
+ PreprocessedDPVDeclares.clear();
}
/// CreateReg - Allocate a single virtual register for the given type.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 4fd76d012a16..12ed4a82ee91 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1148,6 +1148,60 @@ SDValue SelectionDAGBuilder::getControlRoot() {
return updateRoot(PendingExports);
}
+void SelectionDAGBuilder::handleDebugDeclare(Value *Address,
+ DILocalVariable *Variable,
+ DIExpression *Expression,
+ DebugLoc DL) {
+ assert(Variable && "Missing variable");
+
+ // Check if address has undef value.
+ if (!Address || isa<UndefValue>(Address) ||
+ (Address->use_empty() && !isa<Argument>(Address))) {
+ LLVM_DEBUG(
+ dbgs()
+ << "dbg_declare: Dropping debug info (bad/undef/unused-arg address)\n");
+ return;
+ }
+
+ bool IsParameter = Variable->isParameter() || isa<Argument>(Address);
+
+ SDValue &N = NodeMap[Address];
+ if (!N.getNode() && isa<Argument>(Address))
+ // Check unused arguments map.
+ N = UnusedArgNodeMap[Address];
+ SDDbgValue *SDV;
+ if (N.getNode()) {
+ if (const BitCastInst *BCI = dyn_cast<BitCastInst>(Address))
+ Address = BCI->getOperand(0);
+ // Parameters are handled specially.
+ auto *FINode = dyn_cast<FrameIndexSDNode>(N.getNode());
+ if (IsParameter && FINode) {
+ // Byval parameter. We have a frame index at this point.
+ SDV = DAG.getFrameIndexDbgValue(Variable, Expression, FINode->getIndex(),
+ /*IsIndirect*/ true, DL, SDNodeOrder);
+ } else if (isa<Argument>(Address)) {
+ // Address is an argument, so try to emit its dbg value using
+ // virtual register info from the FuncInfo.ValueMap.
+ EmitFuncArgumentDbgValue(Address, Variable, Expression, DL,
+ FuncArgumentDbgValueKind::Declare, N);
+ return;
+ } else {
+ SDV = DAG.getDbgValue(Variable, Expression, N.getNode(), N.getResNo(),
+ true, DL, SDNodeOrder);
+ }
+ DAG.AddDbgValue(SDV, IsParameter);
+ } else {
+ // If Address is an argument then try to emit its dbg value using
+ // virtual register info from the FuncInfo.ValueMap.
+ if (!EmitFuncArgumentDbgValue(Address, Variable, Expression, DL,
+ FuncArgumentDbgValueKind::Declare, N)) {
+ LLVM_DEBUG(dbgs() << "dbg_declare: Dropping debug info"
+ << " (could not emit func-arg dbg_value)\n");
+ }
+ }
+ return;
+}
+
void SelectionDAGBuilder::visitDbgInfo(const Instruction &I) {
// Add SDDbgValue nodes for any var locs here. Do so before updating
// SDNodeOrder, as this mapping is {Inst -> Locs BEFORE Inst}.
@@ -1182,6 +1236,16 @@ void SelectionDAGBuilder::visitDbgInfo(const Instruction &I) {
DIExpression *Expression = DPV.getExpression();
dropDanglingDebugInfo(Variable, Expression);
+ if (DPV.getType() == DPValue::LocationType::Declare) {
+ if (FuncInfo.PreprocessedDPVDeclares.contains(&DPV))
+ continue;
+ LLVM_DEBUG(dbgs() << "SelectionDAG visiting dbg_declare: " << DPV
+ << "\n");
+ handleDebugDeclare(DPV.getVariableLocationOp(0), Variable, Expression,
+ DPV.getDebugLoc());
+ continue;
+ }
+
// A DPValue with no locations is a kill location.
SmallVector<Value *, 4> Values(DPV.location_ops());
if (Values.empty()) {
@@ -6218,61 +6282,15 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
if (AssignmentTrackingEnabled ||
FuncInfo.PreprocessedDbgDeclares.count(&DI))
return;
- // Assume dbg.declare can not currently use DIArgList, i.e.
- // it is non-variadic.
- assert(!DI.hasArgList() && "Only dbg.value should currently use DIArgList");
+ LLVM_DEBUG(dbgs() << "SelectionDAG visiting dbg_declare: " << DI << "\n");
DILocalVariable *Variable = DI.getVariable();
DIExpression *Expression = DI.getExpression();
dropDanglingDebugInfo(Variable, Expression);
- assert(Variable && "Missing variable");
- LLVM_DEBUG(dbgs() << "SelectionDAG visiting debug intrinsic: " << DI
- << "\n");
- // Check if address has undef value.
- const Value *Address = DI.getVariableLocationOp(0);
- if (!Address || isa<UndefValue>(Address) ||
- (Address->use_empty() && !isa<Argument>(Address))) {
- LLVM_DEBUG(dbgs() << "Dropping debug info for " << DI
- << " (bad/undef/unused-arg address)\n");
- return;
- }
-
- bool isParameter = Variable->isParameter() || isa<Argument>(Address);
-
- SDValue &N = NodeMap[Address];
- if (!N.getNode() && isa<Argument>(Address))
- // Check unused arguments map.
- N = UnusedArgNodeMap[Address];
- SDDbgValue *SDV;
- if (N.getNode()) {
- if (const BitCastInst *BCI = dyn_cast<BitCastInst>(Address))
- Address = BCI->getOperand(0);
- // Parameters are handled specially.
- auto FINode = dyn_cast<FrameIndexSDNode>(N.getNode());
- if (isParameter && FINode) {
- // Byval parameter. We have a frame index at this point.
- SDV =
- DAG.getFrameIndexDbgValue(Variable, Expression, FINode->getIndex(),
- /*IsIndirect*/ true, dl, SDNodeOrder);
- } else if (isa<Argument>(Address)) {
- // Address is an argument, so try to emit its dbg value using
- // virtual register info from the FuncInfo.ValueMap.
- EmitFuncArgumentDbgValue(Address, Variable, Expression, dl,
- FuncArgumentDbgValueKind::Declare, N);
- return;
- } else {
- SDV = DAG.getDbgValue(Variable, Expression, N.getNode(), N.getResNo(),
- true, dl, SDNodeOrder);
- }
- DAG.AddDbgValue(SDV, isParameter);
- } else {
- // If Address is an argument then try to emit its dbg value using
- // virtual register info from the FuncInfo.ValueMap.
- if (!EmitFuncArgumentDbgValue(Address, Variable, Expression, dl,
- FuncArgumentDbgValueKind::Declare, N)) {
- LLVM_DEBUG(dbgs() << "Dropping debug info for " << DI
- << " (could not emit func-arg dbg_value)\n");
- }
- }
+ // Assume dbg.declare can not currently use DIArgList, i.e.
+ // it is non-variadic.
+ assert(!DI.hasArgList() && "Only dbg.value should currently use DIArgList");
+ handleDebugDeclare(DI.getVariableLocationOp(0), Variable, Expression,
+ DI.getDebugLoc());
return;
}
case Intrinsic::dbg_label: {
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
index 5b55c3461b0b..2e102c002c09 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -368,6 +368,9 @@ public:
void handleKillDebugValue(DILocalVariable *Var, DIExpression *Expr,
DebugLoc DbgLoc, unsigned Order);
+ void handleDebugDeclare(Value *Address, DILocalVariable *Variable,
+ DIExpression *Expression, DebugLoc DL);
+
/// Evict any dangling debug information, attempting to salvage it first.
void resolveOrClearDbgInfo();
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 2018b5f0ee29..a1cf4cbbee1b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -1461,6 +1461,14 @@ static void processDbgDeclares(FunctionLoweringInfo &FuncInfo) {
if (DI && processDbgDeclare(FuncInfo, DI->getAddress(), DI->getExpression(),
DI->getVariable(), DI->getDebugLoc()))
FuncInfo.PreprocessedDbgDeclares.insert(DI);
+
+ for (const DPValue &DPV : I.getDbgValueRange()) {
+ if (DPV.getType() == DPValue::LocationType::Declare &&
+ processDbgDeclare(FuncInfo, DPV.getVariableLocationOp(0),
+ DPV.getExpression(), DPV.getVariable(),
+ DPV.getDebugLoc()))
+ FuncInfo.PreprocessedDPVDeclares.insert(&DPV);
+ }
}
}
@@ -2711,11 +2719,10 @@ CheckOpcode(const unsigned char *MatcherTable, unsigned &MatcherIndex,
return N->getOpcode() == Opc;
}
-LLVM_ATTRIBUTE_ALWAYS_INLINE static bool
-CheckType(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N,
- const TargetLowering *TLI, const DataLayout &DL) {
- MVT::SimpleValueType VT =
- static_cast<MVT::SimpleValueType>(MatcherTable[MatcherIndex++]);
+LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckType(MVT::SimpleValueType VT,
+ SDValue N,
+ const TargetLowering *TLI,
+ const DataLayout &DL) {
if (N.getValueType() == VT)
return true;
@@ -2724,13 +2731,11 @@ CheckType(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N,
}
LLVM_ATTRIBUTE_ALWAYS_INLINE static bool
-CheckChildType(const unsigned char *MatcherTable, unsigned &MatcherIndex,
- SDValue N, const TargetLowering *TLI, const DataLayout &DL,
- unsigned ChildNo) {
+CheckChildType(MVT::SimpleValueType VT, SDValue N, const TargetLowering *TLI,
+ const DataLayout &DL, unsigned ChildNo) {
if (ChildNo >= N.getNumOperands())
- return false; // Match fails if out of range child #.
- return ::CheckType(MatcherTable, MatcherIndex, N.getOperand(ChildNo), TLI,
- DL);
+ return false; // Match fails if out of range child #.
+ return ::CheckType(VT, N.getOperand(ChildNo), TLI, DL);
}
LLVM_ATTRIBUTE_ALWAYS_INLINE static bool
@@ -2829,7 +2834,8 @@ static unsigned IsPredicateKnownToFail(const unsigned char *Table,
bool &Result,
const SelectionDAGISel &SDISel,
SmallVectorImpl<std::pair<SDValue, SDNode*>> &RecordedNodes) {
- switch (Table[Index++]) {
+ unsigned Opcode = Table[Index++];
+ switch (Opcode) {
default:
Result = false;
return Index-1; // Could not evaluate this predicate.
@@ -2856,12 +2862,27 @@ static unsigned IsPredicateKnownToFail(const unsigned char *Table,
Result = !::CheckOpcode(Table, Index, N.getNode());
return Index;
case SelectionDAGISel::OPC_CheckType:
- Result = !::CheckType(Table, Index, N, SDISel.TLI,
- SDISel.CurDAG->getDataLayout());
+ case SelectionDAGISel::OPC_CheckTypeI32:
+ case SelectionDAGISel::OPC_CheckTypeI64: {
+ MVT::SimpleValueType VT;
+ switch (Opcode) {
+ case SelectionDAGISel::OPC_CheckTypeI32:
+ VT = MVT::i32;
+ break;
+ case SelectionDAGISel::OPC_CheckTypeI64:
+ VT = MVT::i64;
+ break;
+ default:
+ VT = static_cast<MVT::SimpleValueType>(Table[Index++]);
+ break;
+ }
+ Result = !::CheckType(VT, N, SDISel.TLI, SDISel.CurDAG->getDataLayout());
return Index;
+ }
case SelectionDAGISel::OPC_CheckTypeRes: {
unsigned Res = Table[Index++];
- Result = !::CheckType(Table, Index, N.getValue(Res), SDISel.TLI,
+ Result = !::CheckType(static_cast<MVT::SimpleValueType>(Table[Index++]),
+ N.getValue(Res), SDISel.TLI,
SDISel.CurDAG->getDataLayout());
return Index;
}
@@ -2873,10 +2894,40 @@ static unsigned IsPredicateKnownToFail(const unsigned char *Table,
case SelectionDAGISel::OPC_CheckChild5Type:
case SelectionDAGISel::OPC_CheckChild6Type:
case SelectionDAGISel::OPC_CheckChild7Type:
- Result = !::CheckChildType(
- Table, Index, N, SDISel.TLI, SDISel.CurDAG->getDataLayout(),
- Table[Index - 1] - SelectionDAGISel::OPC_CheckChild0Type);
+ case SelectionDAGISel::OPC_CheckChild0TypeI32:
+ case SelectionDAGISel::OPC_CheckChild1TypeI32:
+ case SelectionDAGISel::OPC_CheckChild2TypeI32:
+ case SelectionDAGISel::OPC_CheckChild3TypeI32:
+ case SelectionDAGISel::OPC_CheckChild4TypeI32:
+ case SelectionDAGISel::OPC_CheckChild5TypeI32:
+ case SelectionDAGISel::OPC_CheckChild6TypeI32:
+ case SelectionDAGISel::OPC_CheckChild7TypeI32:
+ case SelectionDAGISel::OPC_CheckChild0TypeI64:
+ case SelectionDAGISel::OPC_CheckChild1TypeI64:
+ case SelectionDAGISel::OPC_CheckChild2TypeI64:
+ case SelectionDAGISel::OPC_CheckChild3TypeI64:
+ case SelectionDAGISel::OPC_CheckChild4TypeI64:
+ case SelectionDAGISel::OPC_CheckChild5TypeI64:
+ case SelectionDAGISel::OPC_CheckChild6TypeI64:
+ case SelectionDAGISel::OPC_CheckChild7TypeI64: {
+ MVT::SimpleValueType VT;
+ unsigned ChildNo;
+ if (Opcode >= SelectionDAGISel::OPC_CheckChild0TypeI32 &&
+ Opcode <= SelectionDAGISel::OPC_CheckChild7TypeI32) {
+ VT = MVT::i32;
+ ChildNo = Opcode - SelectionDAGISel::OPC_CheckChild0TypeI32;
+ } else if (Opcode >= SelectionDAGISel::OPC_CheckChild0TypeI64 &&
+ Opcode <= SelectionDAGISel::OPC_CheckChild7TypeI64) {
+ VT = MVT::i64;
+ ChildNo = Opcode - SelectionDAGISel::OPC_CheckChild0TypeI64;
+ } else {
+ VT = static_cast<MVT::SimpleValueType>(Table[Index++]);
+ ChildNo = Opcode - SelectionDAGISel::OPC_CheckChild0Type;
+ }
+ Result = !::CheckChildType(VT, N, SDISel.TLI,
+ SDISel.CurDAG->getDataLayout(), ChildNo);
return Index;
+ }
case SelectionDAGISel::OPC_CheckCondCode:
Result = !::CheckCondCode(Table, Index, N);
return Index;
@@ -3242,6 +3293,29 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
continue;
}
+ case OPC_MoveSibling:
+ case OPC_MoveSibling0:
+ case OPC_MoveSibling1:
+ case OPC_MoveSibling2:
+ case OPC_MoveSibling3:
+ case OPC_MoveSibling4:
+ case OPC_MoveSibling5:
+ case OPC_MoveSibling6:
+ case OPC_MoveSibling7: {
+ // Pop the current node off the NodeStack.
+ NodeStack.pop_back();
+ assert(!NodeStack.empty() && "Node stack imbalance!");
+ N = NodeStack.back();
+
+ unsigned SiblingNo = Opcode == OPC_MoveSibling
+ ? MatcherTable[MatcherIndex++]
+ : Opcode - OPC_MoveSibling0;
+ if (SiblingNo >= N.getNumOperands())
+ break; // Match fails if out of range sibling #.
+ N = N.getOperand(SiblingNo);
+ NodeStack.push_back(N);
+ continue;
+ }
case OPC_MoveParent:
// Pop the current node off the NodeStack.
NodeStack.pop_back();
@@ -3306,15 +3380,29 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
continue;
case OPC_CheckType:
- if (!::CheckType(MatcherTable, MatcherIndex, N, TLI,
- CurDAG->getDataLayout()))
+ case OPC_CheckTypeI32:
+ case OPC_CheckTypeI64:
+ MVT::SimpleValueType VT;
+ switch (Opcode) {
+ case OPC_CheckTypeI32:
+ VT = MVT::i32;
+ break;
+ case OPC_CheckTypeI64:
+ VT = MVT::i64;
+ break;
+ default:
+ VT = static_cast<MVT::SimpleValueType>(MatcherTable[MatcherIndex++]);
+ break;
+ }
+ if (!::CheckType(VT, N, TLI, CurDAG->getDataLayout()))
break;
continue;
case OPC_CheckTypeRes: {
unsigned Res = MatcherTable[MatcherIndex++];
- if (!::CheckType(MatcherTable, MatcherIndex, N.getValue(Res), TLI,
- CurDAG->getDataLayout()))
+ if (!::CheckType(
+ static_cast<MVT::SimpleValueType>(MatcherTable[MatcherIndex++]),
+ N.getValue(Res), TLI, CurDAG->getDataLayout()))
break;
continue;
}
@@ -3383,15 +3471,48 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
<< '\n');
continue;
}
- case OPC_CheckChild0Type: case OPC_CheckChild1Type:
- case OPC_CheckChild2Type: case OPC_CheckChild3Type:
- case OPC_CheckChild4Type: case OPC_CheckChild5Type:
- case OPC_CheckChild6Type: case OPC_CheckChild7Type:
- if (!::CheckChildType(MatcherTable, MatcherIndex, N, TLI,
- CurDAG->getDataLayout(),
- Opcode - OPC_CheckChild0Type))
+ case OPC_CheckChild0Type:
+ case OPC_CheckChild1Type:
+ case OPC_CheckChild2Type:
+ case OPC_CheckChild3Type:
+ case OPC_CheckChild4Type:
+ case OPC_CheckChild5Type:
+ case OPC_CheckChild6Type:
+ case OPC_CheckChild7Type:
+ case OPC_CheckChild0TypeI32:
+ case OPC_CheckChild1TypeI32:
+ case OPC_CheckChild2TypeI32:
+ case OPC_CheckChild3TypeI32:
+ case OPC_CheckChild4TypeI32:
+ case OPC_CheckChild5TypeI32:
+ case OPC_CheckChild6TypeI32:
+ case OPC_CheckChild7TypeI32:
+ case OPC_CheckChild0TypeI64:
+ case OPC_CheckChild1TypeI64:
+ case OPC_CheckChild2TypeI64:
+ case OPC_CheckChild3TypeI64:
+ case OPC_CheckChild4TypeI64:
+ case OPC_CheckChild5TypeI64:
+ case OPC_CheckChild6TypeI64:
+ case OPC_CheckChild7TypeI64: {
+ MVT::SimpleValueType VT;
+ unsigned ChildNo;
+ if (Opcode >= SelectionDAGISel::OPC_CheckChild0TypeI32 &&
+ Opcode <= SelectionDAGISel::OPC_CheckChild7TypeI32) {
+ VT = MVT::i32;
+ ChildNo = Opcode - SelectionDAGISel::OPC_CheckChild0TypeI32;
+ } else if (Opcode >= SelectionDAGISel::OPC_CheckChild0TypeI64 &&
+ Opcode <= SelectionDAGISel::OPC_CheckChild7TypeI64) {
+ VT = MVT::i64;
+ ChildNo = Opcode - SelectionDAGISel::OPC_CheckChild0TypeI64;
+ } else {
+ VT = static_cast<MVT::SimpleValueType>(MatcherTable[MatcherIndex++]);
+ ChildNo = Opcode - SelectionDAGISel::OPC_CheckChild0Type;
+ }
+ if (!::CheckChildType(VT, N, TLI, CurDAG->getDataLayout(), ChildNo))
break;
continue;
+ }
case OPC_CheckCondCode:
if (!::CheckCondCode(MatcherTable, MatcherIndex, N)) break;
continue;
@@ -3512,9 +3633,19 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
continue;
}
- case OPC_EmitConvertToTarget: {
+ case OPC_EmitConvertToTarget:
+ case OPC_EmitConvertToTarget0:
+ case OPC_EmitConvertToTarget1:
+ case OPC_EmitConvertToTarget2:
+ case OPC_EmitConvertToTarget3:
+ case OPC_EmitConvertToTarget4:
+ case OPC_EmitConvertToTarget5:
+ case OPC_EmitConvertToTarget6:
+ case OPC_EmitConvertToTarget7: {
// Convert from IMM/FPIMM to target version.
- unsigned RecNo = MatcherTable[MatcherIndex++];
+ unsigned RecNo = Opcode == OPC_EmitConvertToTarget
+ ? MatcherTable[MatcherIndex++]
+ : Opcode - OPC_EmitConvertToTarget0;
assert(RecNo < RecordedNodes.size() && "Invalid EmitConvertToTarget");
SDValue Imm = RecordedNodes[RecNo].first;
@@ -3610,11 +3741,22 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
}
case OPC_EmitCopyToReg:
- case OPC_EmitCopyToReg2: {
- unsigned RecNo = MatcherTable[MatcherIndex++];
+ case OPC_EmitCopyToReg0:
+ case OPC_EmitCopyToReg1:
+ case OPC_EmitCopyToReg2:
+ case OPC_EmitCopyToReg3:
+ case OPC_EmitCopyToReg4:
+ case OPC_EmitCopyToReg5:
+ case OPC_EmitCopyToReg6:
+ case OPC_EmitCopyToReg7:
+ case OPC_EmitCopyToRegTwoByte: {
+ unsigned RecNo =
+ Opcode >= OPC_EmitCopyToReg0 && Opcode <= OPC_EmitCopyToReg7
+ ? Opcode - OPC_EmitCopyToReg0
+ : MatcherTable[MatcherIndex++];
assert(RecNo < RecordedNodes.size() && "Invalid EmitCopyToReg");
unsigned DestPhysReg = MatcherTable[MatcherIndex++];
- if (Opcode == OPC_EmitCopyToReg2)
+ if (Opcode == OPC_EmitCopyToRegTwoByte)
DestPhysReg |= MatcherTable[MatcherIndex++] << 8;
if (!InputChain.getNode())
@@ -3646,20 +3788,77 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
continue;
}
- case OPC_EmitNode: case OPC_MorphNodeTo:
- case OPC_EmitNode0: case OPC_EmitNode1: case OPC_EmitNode2:
- case OPC_MorphNodeTo0: case OPC_MorphNodeTo1: case OPC_MorphNodeTo2: {
+ case OPC_EmitNode:
+ case OPC_EmitNode0:
+ case OPC_EmitNode1:
+ case OPC_EmitNode2:
+ case OPC_EmitNode0None:
+ case OPC_EmitNode1None:
+ case OPC_EmitNode2None:
+ case OPC_EmitNode0Chain:
+ case OPC_EmitNode1Chain:
+ case OPC_EmitNode2Chain:
+ case OPC_MorphNodeTo:
+ case OPC_MorphNodeTo0:
+ case OPC_MorphNodeTo1:
+ case OPC_MorphNodeTo2:
+ case OPC_MorphNodeTo0None:
+ case OPC_MorphNodeTo1None:
+ case OPC_MorphNodeTo2None:
+ case OPC_MorphNodeTo0Chain:
+ case OPC_MorphNodeTo1Chain:
+ case OPC_MorphNodeTo2Chain:
+ case OPC_MorphNodeTo0GlueInput:
+ case OPC_MorphNodeTo1GlueInput:
+ case OPC_MorphNodeTo2GlueInput:
+ case OPC_MorphNodeTo0GlueOutput:
+ case OPC_MorphNodeTo1GlueOutput:
+ case OPC_MorphNodeTo2GlueOutput: {
uint16_t TargetOpc = MatcherTable[MatcherIndex++];
TargetOpc |= static_cast<uint16_t>(MatcherTable[MatcherIndex++]) << 8;
- unsigned EmitNodeInfo = MatcherTable[MatcherIndex++];
+ unsigned EmitNodeInfo;
+ if (Opcode >= OPC_EmitNode0None && Opcode <= OPC_EmitNode2Chain) {
+ if (Opcode >= OPC_EmitNode0Chain && Opcode <= OPC_EmitNode2Chain)
+ EmitNodeInfo = OPFL_Chain;
+ else
+ EmitNodeInfo = OPFL_None;
+ } else if (Opcode >= OPC_MorphNodeTo0None &&
+ Opcode <= OPC_MorphNodeTo2GlueOutput) {
+ if (Opcode >= OPC_MorphNodeTo0Chain && Opcode <= OPC_MorphNodeTo2Chain)
+ EmitNodeInfo = OPFL_Chain;
+ else if (Opcode >= OPC_MorphNodeTo0GlueInput &&
+ Opcode <= OPC_MorphNodeTo2GlueInput)
+ EmitNodeInfo = OPFL_GlueInput;
+ else if (Opcode >= OPC_MorphNodeTo0GlueOutput &&
+ Opcode <= OPC_MorphNodeTo2GlueOutput)
+ EmitNodeInfo = OPFL_GlueOutput;
+ else
+ EmitNodeInfo = OPFL_None;
+ } else
+ EmitNodeInfo = MatcherTable[MatcherIndex++];
// Get the result VT list.
unsigned NumVTs;
// If this is one of the compressed forms, get the number of VTs based
// on the Opcode. Otherwise read the next byte from the table.
if (Opcode >= OPC_MorphNodeTo0 && Opcode <= OPC_MorphNodeTo2)
NumVTs = Opcode - OPC_MorphNodeTo0;
+ else if (Opcode >= OPC_MorphNodeTo0None && Opcode <= OPC_MorphNodeTo2None)
+ NumVTs = Opcode - OPC_MorphNodeTo0None;
+ else if (Opcode >= OPC_MorphNodeTo0Chain &&
+ Opcode <= OPC_MorphNodeTo2Chain)
+ NumVTs = Opcode - OPC_MorphNodeTo0Chain;
+ else if (Opcode >= OPC_MorphNodeTo0GlueInput &&
+ Opcode <= OPC_MorphNodeTo2GlueInput)
+ NumVTs = Opcode - OPC_MorphNodeTo0GlueInput;
+ else if (Opcode >= OPC_MorphNodeTo0GlueOutput &&
+ Opcode <= OPC_MorphNodeTo2GlueOutput)
+ NumVTs = Opcode - OPC_MorphNodeTo0GlueOutput;
else if (Opcode >= OPC_EmitNode0 && Opcode <= OPC_EmitNode2)
NumVTs = Opcode - OPC_EmitNode0;
+ else if (Opcode >= OPC_EmitNode0None && Opcode <= OPC_EmitNode2None)
+ NumVTs = Opcode - OPC_EmitNode0None;
+ else if (Opcode >= OPC_EmitNode0Chain && Opcode <= OPC_EmitNode2Chain)
+ NumVTs = Opcode - OPC_EmitNode0Chain;
else
NumVTs = MatcherTable[MatcherIndex++];
SmallVector<EVT, 4> VTs;
@@ -3732,8 +3931,9 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
// Create the node.
MachineSDNode *Res = nullptr;
- bool IsMorphNodeTo = Opcode == OPC_MorphNodeTo ||
- (Opcode >= OPC_MorphNodeTo0 && Opcode <= OPC_MorphNodeTo2);
+ bool IsMorphNodeTo =
+ Opcode == OPC_MorphNodeTo ||
+ (Opcode >= OPC_MorphNodeTo0 && Opcode <= OPC_MorphNodeTo2GlueOutput);
if (!IsMorphNodeTo) {
// If this is a normal EmitNode command, just create the new node and
// add the results to the RecordedNodes list.
diff --git a/llvm/lib/CodeGen/SjLjEHPrepare.cpp b/llvm/lib/CodeGen/SjLjEHPrepare.cpp
index f98c096ccf08..515b5764a094 100644
--- a/llvm/lib/CodeGen/SjLjEHPrepare.cpp
+++ b/llvm/lib/CodeGen/SjLjEHPrepare.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/CodeGen/SjLjEHPrepare.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -31,13 +32,13 @@
#include "llvm/Transforms/Utils/Local.h"
using namespace llvm;
-#define DEBUG_TYPE "sjljehprepare"
+#define DEBUG_TYPE "sjlj-eh-prepare"
STATISTIC(NumInvokes, "Number of invokes replaced");
STATISTIC(NumSpilled, "Number of registers live across unwind edges");
namespace {
-class SjLjEHPrepare : public FunctionPass {
+class SjLjEHPrepareImpl {
IntegerType *DataTy = nullptr;
Type *doubleUnderDataTy = nullptr;
Type *doubleUnderJBufTy = nullptr;
@@ -55,16 +56,9 @@ class SjLjEHPrepare : public FunctionPass {
const TargetMachine *TM = nullptr;
public:
- static char ID; // Pass identification, replacement for typeid
- explicit SjLjEHPrepare(const TargetMachine *TM = nullptr)
- : FunctionPass(ID), TM(TM) {}
- bool doInitialization(Module &M) override;
- bool runOnFunction(Function &F) override;
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {}
- StringRef getPassName() const override {
- return "SJLJ Exception Handling preparation";
- }
+ explicit SjLjEHPrepareImpl(const TargetMachine *TM = nullptr) : TM(TM) {}
+ bool doInitialization(Module &M);
+ bool runOnFunction(Function &F);
private:
bool setupEntryBlockAndCallSites(Function &F);
@@ -74,8 +68,32 @@ private:
void lowerAcrossUnwindEdges(Function &F, ArrayRef<InvokeInst *> Invokes);
void insertCallSiteStore(Instruction *I, int Number);
};
+
+class SjLjEHPrepare : public FunctionPass {
+ SjLjEHPrepareImpl Impl;
+
+public:
+ static char ID; // Pass identification, replacement for typeid
+ explicit SjLjEHPrepare(const TargetMachine *TM = nullptr)
+ : FunctionPass(ID), Impl(TM) {}
+ bool doInitialization(Module &M) override { return Impl.doInitialization(M); }
+ bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); };
+
+ StringRef getPassName() const override {
+ return "SJLJ Exception Handling preparation";
+ }
+};
+
} // end anonymous namespace
+PreservedAnalyses SjLjEHPreparePass::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ SjLjEHPrepareImpl Impl(TM);
+ Impl.doInitialization(*F.getParent());
+ bool Changed = Impl.runOnFunction(F);
+ return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
+}
+
char SjLjEHPrepare::ID = 0;
INITIALIZE_PASS(SjLjEHPrepare, DEBUG_TYPE, "Prepare SjLj exceptions",
false, false)
@@ -87,7 +105,7 @@ FunctionPass *llvm::createSjLjEHPreparePass(const TargetMachine *TM) {
// doInitialization - Set up decalarations and types needed to process
// exceptions.
-bool SjLjEHPrepare::doInitialization(Module &M) {
+bool SjLjEHPrepareImpl::doInitialization(Module &M) {
// Build the function context structure.
// builtin_setjmp uses a five word jbuf
Type *VoidPtrTy = PointerType::getUnqual(M.getContext());
@@ -104,12 +122,12 @@ bool SjLjEHPrepare::doInitialization(Module &M) {
doubleUnderJBufTy // __jbuf
);
- return true;
+ return false;
}
/// insertCallSiteStore - Insert a store of the call-site value to the
/// function context
-void SjLjEHPrepare::insertCallSiteStore(Instruction *I, int Number) {
+void SjLjEHPrepareImpl::insertCallSiteStore(Instruction *I, int Number) {
IRBuilder<> Builder(I);
// Get a reference to the call_site field.
@@ -140,8 +158,8 @@ static void MarkBlocksLiveIn(BasicBlock *BB,
/// substituteLPadValues - Substitute the values returned by the landingpad
/// instruction with those returned by the personality function.
-void SjLjEHPrepare::substituteLPadValues(LandingPadInst *LPI, Value *ExnVal,
- Value *SelVal) {
+void SjLjEHPrepareImpl::substituteLPadValues(LandingPadInst *LPI, Value *ExnVal,
+ Value *SelVal) {
SmallVector<Value *, 8> UseWorkList(LPI->users());
while (!UseWorkList.empty()) {
Value *Val = UseWorkList.pop_back_val();
@@ -175,8 +193,9 @@ void SjLjEHPrepare::substituteLPadValues(LandingPadInst *LPI, Value *ExnVal,
/// setupFunctionContext - Allocate the function context on the stack and fill
/// it with all of the data that we know at this point.
-Value *SjLjEHPrepare::setupFunctionContext(Function &F,
- ArrayRef<LandingPadInst *> LPads) {
+Value *
+SjLjEHPrepareImpl::setupFunctionContext(Function &F,
+ ArrayRef<LandingPadInst *> LPads) {
BasicBlock *EntryBB = &F.front();
// Create an alloca for the incoming jump buffer ptr and the new jump buffer
@@ -233,7 +252,7 @@ Value *SjLjEHPrepare::setupFunctionContext(Function &F,
/// specially, we lower each arg to a copy instruction in the entry block. This
/// ensures that the argument value itself cannot be live out of the entry
/// block.
-void SjLjEHPrepare::lowerIncomingArguments(Function &F) {
+void SjLjEHPrepareImpl::lowerIncomingArguments(Function &F) {
BasicBlock::iterator AfterAllocaInsPt = F.begin()->begin();
while (isa<AllocaInst>(AfterAllocaInsPt) &&
cast<AllocaInst>(AfterAllocaInsPt)->isStaticAlloca())
@@ -264,8 +283,8 @@ void SjLjEHPrepare::lowerIncomingArguments(Function &F) {
/// lowerAcrossUnwindEdges - Find all variables which are alive across an unwind
/// edge and spill them.
-void SjLjEHPrepare::lowerAcrossUnwindEdges(Function &F,
- ArrayRef<InvokeInst *> Invokes) {
+void SjLjEHPrepareImpl::lowerAcrossUnwindEdges(Function &F,
+ ArrayRef<InvokeInst *> Invokes) {
// Finally, scan the code looking for instructions with bad live ranges.
for (BasicBlock &BB : F) {
for (Instruction &Inst : BB) {
@@ -358,7 +377,7 @@ void SjLjEHPrepare::lowerAcrossUnwindEdges(Function &F,
/// setupEntryBlockAndCallSites - Setup the entry block by creating and filling
/// the function context and marking the call sites with the appropriate
/// values. These values are used by the DWARF EH emitter.
-bool SjLjEHPrepare::setupEntryBlockAndCallSites(Function &F) {
+bool SjLjEHPrepareImpl::setupEntryBlockAndCallSites(Function &F) {
SmallVector<ReturnInst *, 16> Returns;
SmallVector<InvokeInst *, 16> Invokes;
SmallSetVector<LandingPadInst *, 16> LPads;
@@ -479,7 +498,7 @@ bool SjLjEHPrepare::setupEntryBlockAndCallSites(Function &F) {
return true;
}
-bool SjLjEHPrepare::runOnFunction(Function &F) {
+bool SjLjEHPrepareImpl::runOnFunction(Function &F) {
Module &M = *F.getParent();
RegisterFn = M.getOrInsertFunction(
"_Unwind_SjLj_Register", Type::getVoidTy(M.getContext()),
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 16cc83b8881f..9a0dd92bb58e 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -472,32 +472,31 @@ static SectionKind getELFKindForNamedSection(StringRef Name, SectionKind K) {
/*AddSegmentInfo=*/false) ||
Name == getInstrProfSectionName(IPSK_covfun, Triple::ELF,
/*AddSegmentInfo=*/false) ||
+ Name == getInstrProfSectionName(IPSK_covdata, Triple::ELF,
+ /*AddSegmentInfo=*/false) ||
+ Name == getInstrProfSectionName(IPSK_covname, Triple::ELF,
+ /*AddSegmentInfo=*/false) ||
Name == ".llvmbc" || Name == ".llvmcmd")
return SectionKind::getMetadata();
if (Name.empty() || Name[0] != '.') return K;
// Default implementation based on some magic section names.
- if (Name == ".bss" ||
- Name.startswith(".bss.") ||
- Name.startswith(".gnu.linkonce.b.") ||
- Name.startswith(".llvm.linkonce.b.") ||
- Name == ".sbss" ||
- Name.startswith(".sbss.") ||
- Name.startswith(".gnu.linkonce.sb.") ||
- Name.startswith(".llvm.linkonce.sb."))
+ if (Name == ".bss" || Name.starts_with(".bss.") ||
+ Name.starts_with(".gnu.linkonce.b.") ||
+ Name.starts_with(".llvm.linkonce.b.") || Name == ".sbss" ||
+ Name.starts_with(".sbss.") || Name.starts_with(".gnu.linkonce.sb.") ||
+ Name.starts_with(".llvm.linkonce.sb."))
return SectionKind::getBSS();
- if (Name == ".tdata" ||
- Name.startswith(".tdata.") ||
- Name.startswith(".gnu.linkonce.td.") ||
- Name.startswith(".llvm.linkonce.td."))
+ if (Name == ".tdata" || Name.starts_with(".tdata.") ||
+ Name.starts_with(".gnu.linkonce.td.") ||
+ Name.starts_with(".llvm.linkonce.td."))
return SectionKind::getThreadData();
- if (Name == ".tbss" ||
- Name.startswith(".tbss.") ||
- Name.startswith(".gnu.linkonce.tb.") ||
- Name.startswith(".llvm.linkonce.tb."))
+ if (Name == ".tbss" || Name.starts_with(".tbss.") ||
+ Name.starts_with(".gnu.linkonce.tb.") ||
+ Name.starts_with(".llvm.linkonce.tb."))
return SectionKind::getThreadBSS();
return K;
@@ -512,7 +511,7 @@ static unsigned getELFSectionType(StringRef Name, SectionKind K) {
// Use SHT_NOTE for section whose name starts with ".note" to allow
// emitting ELF notes from C variable declaration.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77609
- if (Name.startswith(".note"))
+ if (Name.starts_with(".note"))
return ELF::SHT_NOTE;
if (hasPrefix(Name, ".init_array"))
@@ -650,7 +649,7 @@ getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind,
Name = ".rodata.cst";
Name += utostr(EntrySize);
} else {
- Name = getSectionPrefixForGlobal(Kind, TM.isLargeGlobalObject(GO));
+ Name = getSectionPrefixForGlobal(Kind, TM.isLargeGlobalValue(GO));
}
bool HasPrefix = false;
@@ -752,7 +751,7 @@ calcUniqueIDUpdateFlagsAndSize(const GlobalObject *GO, StringRef SectionName,
getELFSectionNameForGlobal(GO, Kind, Mang, TM, EntrySize, false);
if (SymbolMergeable &&
Ctx.isELFImplicitMergeableSectionNamePrefix(SectionName) &&
- SectionName.startswith(ImplicitSectionNameStem))
+ SectionName.starts_with(ImplicitSectionNameStem))
return MCContext::GenericSectionID;
// We have seen this section name before, but with different flags or entity
@@ -770,7 +769,7 @@ getGlobalObjectInfo(const GlobalObject *GO, const TargetMachine &TM) {
Group = C->getName();
IsComdat = C->getSelectionKind() == Comdat::Any;
}
- if (TM.isLargeGlobalObject(GO))
+ if (TM.isLargeGlobalValue(GO))
Flags |= ELF::SHF_X86_64_LARGE;
return {Group, IsComdat, Flags};
}
@@ -1036,7 +1035,7 @@ MCSection *TargetLoweringObjectFileELF::getSectionForMachineBasicBlock(
SmallString<128> Name;
StringRef FunctionSectionName = MBB.getParent()->getSection()->getName();
if (FunctionSectionName.equals(".text") ||
- FunctionSectionName.startswith(".text.")) {
+ FunctionSectionName.starts_with(".text.")) {
// Function is in a regular .text section.
StringRef FunctionName = MBB.getParent()->getName();
if (MBB.getSectionID() == MBBSectionID::ColdSectionID) {
@@ -1048,7 +1047,7 @@ MCSection *TargetLoweringObjectFileELF::getSectionForMachineBasicBlock(
} else {
Name += FunctionSectionName;
if (TM.getUniqueBasicBlockSectionNames()) {
- if (!Name.endswith("."))
+ if (!Name.ends_with("."))
Name += ".";
Name += MBB.getSymbol()->getName();
} else {
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp
index 1f7c949cd603..faa5466b69e8 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -113,10 +113,9 @@ static cl::opt<bool> DisableMergeICmps("disable-mergeicmps",
cl::init(false), cl::Hidden);
static cl::opt<bool> PrintLSR("print-lsr-output", cl::Hidden,
cl::desc("Print LLVM IR produced by the loop-reduce pass"));
-static cl::opt<bool> PrintISelInput("print-isel-input", cl::Hidden,
- cl::desc("Print LLVM IR input to isel pass"));
-static cl::opt<bool> PrintGCInfo("print-gc", cl::Hidden,
- cl::desc("Dump garbage collector data"));
+static cl::opt<bool>
+ PrintISelInput("print-isel-input", cl::Hidden,
+ cl::desc("Print LLVM IR input to isel pass"));
static cl::opt<cl::boolOrDefault>
VerifyMachineCode("verify-machineinstrs", cl::Hidden,
cl::desc("Verify generated machine code"));
@@ -475,6 +474,11 @@ CGPassBuilderOption llvm::getCGPassBuilderOption() {
SET_OPTION(EnableIPRA)
SET_OPTION(OptimizeRegAlloc)
SET_OPTION(VerifyMachineCode)
+ SET_OPTION(DisableAtExitBasedGlobalDtorLowering)
+ SET_OPTION(DisableExpandReductions)
+ SET_OPTION(PrintAfterISel)
+ SET_OPTION(FSProfileFile)
+ SET_OPTION(GCEmptyBlocks)
#define SET_BOOLEAN_OPTION(Option) Opt.Option = Option;
@@ -491,7 +495,11 @@ CGPassBuilderOption llvm::getCGPassBuilderOption() {
SET_BOOLEAN_OPTION(DisableSelectOptimize)
SET_BOOLEAN_OPTION(PrintLSR)
SET_BOOLEAN_OPTION(PrintISelInput)
- SET_BOOLEAN_OPTION(PrintGCInfo)
+ SET_BOOLEAN_OPTION(DebugifyAndStripAll)
+ SET_BOOLEAN_OPTION(DebugifyCheckAndStripAll)
+ SET_BOOLEAN_OPTION(DisableRAFSProfileLoader)
+ SET_BOOLEAN_OPTION(DisableCFIFixup)
+ SET_BOOLEAN_OPTION(EnableMachineFunctionSplitter)
return Opt;
}
@@ -870,7 +878,7 @@ void TargetPassConfig::addIRPasses() {
// target lowering hook.
if (!DisableMergeICmps)
addPass(createMergeICmpsLegacyPass());
- addPass(createExpandMemCmpPass());
+ addPass(createExpandMemCmpLegacyPass());
}
// Run GC lowering passes for builtin collectors
@@ -1211,10 +1219,7 @@ void TargetPassConfig::addMachinePasses() {
}
// GC
- if (addGCPasses()) {
- if (PrintGCInfo)
- addPass(createGCInfoPrinter(dbgs()));
- }
+ addGCPasses();
// Basic block placement.
if (getOptLevel() != CodeGenOptLevel::None)
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp
index 347bada6f69d..95976c218c2f 100644
--- a/llvm/lib/CodeGen/WinEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -120,8 +120,8 @@ PreservedAnalyses WinEHPreparePass::run(Function &F,
}
char WinEHPrepare::ID = 0;
-INITIALIZE_PASS(WinEHPrepare, "winehprepare", "Prepare Windows exceptions",
- false, false)
+INITIALIZE_PASS(WinEHPrepare, DEBUG_TYPE, "Prepare Windows exceptions", false,
+ false)
FunctionPass *llvm::createWinEHPass(bool DemoteCatchSwitchPHIOnly) {
return new WinEHPrepare(DemoteCatchSwitchPHIOnly);
@@ -324,7 +324,7 @@ void llvm::calculateSEHStateForAsynchEH(const BasicBlock *BB, int State,
const Constant *FilterOrNull = cast<Constant>(
cast<CatchPadInst>(I)->getArgOperand(0)->stripPointerCasts());
const Function *Filter = dyn_cast<Function>(FilterOrNull);
- if (!Filter || !Filter->getName().startswith("__IsLocalUnwind"))
+ if (!Filter || !Filter->getName().starts_with("__IsLocalUnwind"))
State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State
} else if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) &&
State > 0) {
diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 1a7ea47adc5c..10967123a562 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -204,18 +204,18 @@ static void analyzeImportedModule(
return;
StringRef Path = dwarf::toStringRef(DIE.find(dwarf::DW_AT_LLVM_include_path));
- if (!Path.endswith(".swiftinterface"))
+ if (!Path.ends_with(".swiftinterface"))
return;
// Don't track interfaces that are part of the SDK.
StringRef SysRoot = dwarf::toStringRef(DIE.find(dwarf::DW_AT_LLVM_sysroot));
if (SysRoot.empty())
SysRoot = CU.getSysRoot();
- if (!SysRoot.empty() && Path.startswith(SysRoot))
+ if (!SysRoot.empty() && Path.starts_with(SysRoot))
return;
// Don't track interfaces that are part of the toolchain.
// For example: Swift, _Concurrency, ...
SmallString<128> Toolchain = guessToolchainBaseDir(SysRoot);
- if (!Toolchain.empty() && Path.startswith(Toolchain))
+ if (!Toolchain.empty() && Path.starts_with(Toolchain))
return;
std::optional<const char *> Name =
dwarf::toString(DIE.find(dwarf::DW_AT_name));
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
index 48e7cb1fd7e2..3f0e75690272 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
@@ -271,19 +271,19 @@ void CompileUnit::analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry) {
StringRef Path =
dwarf::toStringRef(find(DieEntry, dwarf::DW_AT_LLVM_include_path));
- if (!Path.endswith(".swiftinterface"))
+ if (!Path.ends_with(".swiftinterface"))
return;
// Don't track interfaces that are part of the SDK.
StringRef SysRoot =
dwarf::toStringRef(find(DieEntry, dwarf::DW_AT_LLVM_sysroot));
if (SysRoot.empty())
SysRoot = getSysRoot();
- if (!SysRoot.empty() && Path.startswith(SysRoot))
+ if (!SysRoot.empty() && Path.starts_with(SysRoot))
return;
// Don't track interfaces that are part of the toolchain.
// For example: Swift, _Concurrency, ...
SmallString<128> Toolchain = guessToolchainBaseDir(SysRoot);
- if (!Toolchain.empty() && Path.startswith(Toolchain))
+ if (!Toolchain.empty() && Path.starts_with(Toolchain))
return;
if (std::optional<DWARFFormValue> Val = find(DieEntry, dwarf::DW_AT_name)) {
Expected<const char *> Name = Val->getAsCString();
diff --git a/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
index e0900f7a8e3d..a9b4478e33c4 100644
--- a/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
+++ b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
@@ -333,7 +333,7 @@ Error SyntheticTypeNameBuilder::addTypeName(UnitEntryPairTy InputUnitEntryPair,
HasShortName = true;
HasTemplatesInShortName =
- Name.endswith(">") && Name.count("<") != 0 && !Name.endswith("<=>");
+ Name.ends_with(">") && Name.count("<") != 0 && !Name.ends_with("<=>");
} else {
// Finally check for declaration attributes.
addDieNameFromDeclFileAndDeclLine(InputUnitEntryPair, HasDeclFileName);
diff --git a/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp b/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
index f7503ef49693..01d49709f9b2 100644
--- a/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
@@ -41,8 +41,8 @@ MarkupFilter::MarkupFilter(raw_ostream &OS, LLVMSymbolizer &Symbolizer,
ColorsEnabled(
ColorsEnabled.value_or(WithColor::defaultAutoDetectFunction()(OS))) {}
-void MarkupFilter::filter(StringRef Line) {
- this->Line = Line;
+void MarkupFilter::filter(std::string &&InputLine) {
+ Line = std::move(InputLine);
resetColor();
Parser.parseLine(Line);
@@ -695,7 +695,9 @@ void MarkupFilter::reportTypeError(StringRef Str, StringRef TypeName) const {
// passed to beginLine().
void MarkupFilter::reportLocation(StringRef::iterator Loc) const {
errs() << Line;
- WithColor(errs().indent(Loc - Line.begin()), HighlightColor::String) << '^';
+ WithColor(errs().indent(Loc - StringRef(Line).begin()),
+ HighlightColor::String)
+ << '^';
errs() << '\n';
}
@@ -741,7 +743,7 @@ uint64_t MarkupFilter::adjustAddr(uint64_t Addr, PCType Type) const {
}
StringRef MarkupFilter::lineEnding() const {
- return Line.ends_with("\r\n") ? "\r\n" : "\n";
+ return StringRef(Line).ends_with("\r\n") ? "\r\n" : "\n";
}
bool MarkupFilter::MMap::contains(uint64_t Addr) const {
diff --git a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
index 697303038507..0c404327c693 100644
--- a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
@@ -352,12 +352,14 @@ std::vector<DILocal> SymbolizableObjectFile::symbolizeFrame(
}
std::vector<object::SectionedAddress>
-SymbolizableObjectFile::findSymbol(StringRef Symbol) const {
+SymbolizableObjectFile::findSymbol(StringRef Symbol, uint64_t Offset) const {
std::vector<object::SectionedAddress> Result;
for (const SymbolDesc &Sym : Symbols) {
if (Sym.Name.equals(Symbol)) {
- object::SectionedAddress A{Sym.Addr,
- getModuleSectionIndexForAddress(Sym.Addr)};
+ uint64_t Addr = Sym.Addr;
+ if (Offset < Sym.Size)
+ Addr += Offset;
+ object::SectionedAddress A{Addr, getModuleSectionIndexForAddress(Addr)};
Result.push_back(A);
}
}
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index 15f2a6ece8b8..43e5c9e9329e 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -233,7 +233,8 @@ LLVMSymbolizer::symbolizeFrame(ArrayRef<uint8_t> BuildID,
template <typename T>
Expected<std::vector<DILineInfo>>
-LLVMSymbolizer::findSymbolCommon(const T &ModuleSpecifier, StringRef Symbol) {
+LLVMSymbolizer::findSymbolCommon(const T &ModuleSpecifier, StringRef Symbol,
+ uint64_t Offset) {
auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
if (!InfoOrErr)
return InfoOrErr.takeError();
@@ -246,7 +247,7 @@ LLVMSymbolizer::findSymbolCommon(const T &ModuleSpecifier, StringRef Symbol) {
if (!Info)
return Result;
- for (object::SectionedAddress A : Info->findSymbol(Symbol)) {
+ for (object::SectionedAddress A : Info->findSymbol(Symbol, Offset)) {
DILineInfo LineInfo = Info->symbolizeCode(
A, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
Opts.UseSymbolTable);
@@ -261,18 +262,21 @@ LLVMSymbolizer::findSymbolCommon(const T &ModuleSpecifier, StringRef Symbol) {
}
Expected<std::vector<DILineInfo>>
-LLVMSymbolizer::findSymbol(const ObjectFile &Obj, StringRef Symbol) {
- return findSymbolCommon(Obj, Symbol);
+LLVMSymbolizer::findSymbol(const ObjectFile &Obj, StringRef Symbol,
+ uint64_t Offset) {
+ return findSymbolCommon(Obj, Symbol, Offset);
}
Expected<std::vector<DILineInfo>>
-LLVMSymbolizer::findSymbol(StringRef ModuleName, StringRef Symbol) {
- return findSymbolCommon(ModuleName.str(), Symbol);
+LLVMSymbolizer::findSymbol(const std::string &ModuleName, StringRef Symbol,
+ uint64_t Offset) {
+ return findSymbolCommon(ModuleName, Symbol, Offset);
}
Expected<std::vector<DILineInfo>>
-LLVMSymbolizer::findSymbol(ArrayRef<uint8_t> BuildID, StringRef Symbol) {
- return findSymbolCommon(BuildID, Symbol);
+LLVMSymbolizer::findSymbol(ArrayRef<uint8_t> BuildID, StringRef Symbol,
+ uint64_t Offset) {
+ return findSymbolCommon(BuildID, Symbol, Offset);
}
void LLVMSymbolizer::flush() {
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
index 46f8064bb168..a1fe9c5fcd73 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
@@ -349,11 +349,11 @@ identifyELFSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) {
constexpr StringRef EndSymbolPrefix = "__end";
auto SymName = Sym.getName();
- if (SymName.startswith(StartSymbolPrefix)) {
+ if (SymName.starts_with(StartSymbolPrefix)) {
if (auto *Sec =
G.findSectionByName(SymName.drop_front(StartSymbolPrefix.size())))
return {*Sec, true};
- } else if (SymName.startswith(EndSymbolPrefix)) {
+ } else if (SymName.starts_with(EndSymbolPrefix)) {
if (auto *Sec =
G.findSectionByName(SymName.drop_front(EndSymbolPrefix.size())))
return {*Sec, false};
diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
index bcbc429cae12..bb21f633d982 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
@@ -73,7 +73,7 @@ Linkage MachOLinkGraphBuilder::getLinkage(uint16_t Desc) {
Scope MachOLinkGraphBuilder::getScope(StringRef Name, uint8_t Type) {
if (Type & MachO::N_EXT) {
- if ((Type & MachO::N_PEXT) || Name.startswith("l"))
+ if ((Type & MachO::N_PEXT) || Name.starts_with("l"))
return Scope::Hidden;
else
return Scope::Default;
diff --git a/llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp
index b541db3672f4..f65ec27ff875 100644
--- a/llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp
@@ -105,7 +105,7 @@ llvm::orc::createDWARFContext(LinkGraph &G) {
auto SecData = getSectionData(Sec);
auto Name = Sec.getName();
// DWARFContext expects the section name to not start with a dot
- if (Name.startswith("."))
+ if (Name.starts_with("."))
Name = Name.drop_front();
LLVM_DEBUG(dbgs() << "Creating DWARFContext section " << Name
<< " with size " << SecData.size() << "\n");
diff --git a/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp
index 9ba6dd90f50d..1668473c0eb4 100644
--- a/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp
@@ -39,7 +39,7 @@ Error enableDebuggerSupport(LLJIT &J) {
if (!Registrar)
return Registrar.takeError();
ObjLinkingLayer->addPlugin(std::make_unique<DebugObjectManagerPlugin>(
- ES, std::move(*Registrar), true, true));
+ ES, std::move(*Registrar), false, true));
return Error::success();
}
case Triple::MachO: {
diff --git a/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.cpp
index c6ffd9f7c2e3..e387b06ee934 100644
--- a/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.cpp
@@ -34,7 +34,7 @@ class MachODebugObjectSynthesizerBase
: public GDBJITDebugInfoRegistrationPlugin::DebugSectionSynthesizer {
public:
static bool isDebugSection(Section &Sec) {
- return Sec.getName().startswith("__DWARF,");
+ return Sec.getName().starts_with("__DWARF,");
}
MachODebugObjectSynthesizerBase(LinkGraph &G, ExecutorAddr RegisterActionAddr)
diff --git a/llvm/lib/ExecutionEngine/Orc/Debugging/LLJITUtilsCBindings.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/LLJITUtilsCBindings.cpp
new file mode 100644
index 000000000000..2df5aef733fb
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/LLJITUtilsCBindings.cpp
@@ -0,0 +1,22 @@
+//===--------- LLJITUtilsCBindings.cpp - Advanced LLJIT features ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c/LLJIT.h"
+#include "llvm-c/LLJITUtils.h"
+
+#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+
+using namespace llvm;
+using namespace llvm::orc;
+
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJIT, LLVMOrcLLJITRef)
+
+LLVMErrorRef LLVMOrcLLJITEnableDebugSupport(LLVMOrcLLJITRef J) {
+ return wrap(llvm::orc::enableDebuggerSupport(*unwrap(J)));
+}
diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
index 7316b2dce8ab..8d5608cc4d4c 100644
--- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
@@ -103,8 +103,8 @@ bool StaticInitGVIterator::isStaticInitGlobal(GlobalValue &GV) {
// FIXME: These section checks are too strict: We should match first and
// second word split by comma.
if (GV.hasSection() &&
- (GV.getSection().startswith("__DATA,__objc_classlist") ||
- GV.getSection().startswith("__DATA,__objc_selrefs")))
+ (GV.getSection().starts_with("__DATA,__objc_classlist") ||
+ GV.getSection().starts_with("__DATA,__objc_selrefs")))
return true;
}
@@ -503,7 +503,7 @@ Error DLLImportDefinitionGenerator::tryToGenerate(
DenseMap<StringRef, SymbolLookupFlags> ToLookUpSymbols;
for (auto &KV : Symbols) {
StringRef Deinterned = *KV.first;
- if (Deinterned.startswith(getImpPrefix()))
+ if (Deinterned.starts_with(getImpPrefix()))
Deinterned = Deinterned.drop_front(StringRef(getImpPrefix()).size());
// Don't degrade the required state
if (ToLookUpSymbols.count(Deinterned) &&
diff --git a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp
index adf38659de3d..f9efff148df9 100644
--- a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp
@@ -285,7 +285,7 @@ std::vector<GlobalValue *> SymbolLinkagePromoter::operator()(Module &M) {
// Rename if necessary.
if (!GV.hasName())
GV.setName("__orc_anon." + Twine(NextId++));
- else if (GV.getName().startswith("\01L"))
+ else if (GV.getName().starts_with("\01L"))
GV.setName("__" + GV.getName().substr(1) + "." + Twine(NextId++));
else if (GV.hasLocalLinkage())
GV.setName("__orc_lcl." + GV.getName() + "." + Twine(NextId++));
diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
index 90123b3f0a96..a19e17029810 100644
--- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
@@ -84,65 +84,6 @@ Function *addHelperAndWrapper(Module &M, StringRef WrapperName,
return WrapperFn;
}
-class ORCPlatformSupport : public LLJIT::PlatformSupport {
-public:
- ORCPlatformSupport(orc::LLJIT &J) : J(J) {}
-
- Error initialize(orc::JITDylib &JD) override {
- using llvm::orc::shared::SPSExecutorAddr;
- using llvm::orc::shared::SPSString;
- using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t);
- enum dlopen_mode : int32_t {
- ORC_RT_RTLD_LAZY = 0x1,
- ORC_RT_RTLD_NOW = 0x2,
- ORC_RT_RTLD_LOCAL = 0x4,
- ORC_RT_RTLD_GLOBAL = 0x8
- };
-
- auto &ES = J.getExecutionSession();
- auto MainSearchOrder = J.getMainJITDylib().withLinkOrderDo(
- [](const JITDylibSearchOrder &SO) { return SO; });
-
- if (auto WrapperAddr =
- ES.lookup(MainSearchOrder,
- J.mangleAndIntern("__orc_rt_jit_dlopen_wrapper"))) {
- return ES.callSPSWrapper<SPSDLOpenSig>(WrapperAddr->getAddress(),
- DSOHandles[&JD], JD.getName(),
- int32_t(ORC_RT_RTLD_LAZY));
- } else
- return WrapperAddr.takeError();
- }
-
- Error deinitialize(orc::JITDylib &JD) override {
- using llvm::orc::shared::SPSExecutorAddr;
- using SPSDLCloseSig = int32_t(SPSExecutorAddr);
-
- auto &ES = J.getExecutionSession();
- auto MainSearchOrder = J.getMainJITDylib().withLinkOrderDo(
- [](const JITDylibSearchOrder &SO) { return SO; });
-
- if (auto WrapperAddr =
- ES.lookup(MainSearchOrder,
- J.mangleAndIntern("__orc_rt_jit_dlclose_wrapper"))) {
- int32_t result;
- auto E = J.getExecutionSession().callSPSWrapper<SPSDLCloseSig>(
- WrapperAddr->getAddress(), result, DSOHandles[&JD]);
- if (E)
- return E;
- else if (result)
- return make_error<StringError>("dlclose failed",
- inconvertibleErrorCode());
- DSOHandles.erase(&JD);
- } else
- return WrapperAddr.takeError();
- return Error::success();
- }
-
-private:
- orc::LLJIT &J;
- DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles;
-};
-
class GenericLLVMIRPlatformSupport;
/// orc::Platform component of Generic LLVM IR Platform support.
@@ -272,11 +213,11 @@ public:
// will trigger a lookup to materialize the module) and the InitFunctions
// map (which holds the names of the symbols to execute).
for (auto &KV : MU.getSymbols())
- if ((*KV.first).startswith(InitFunctionPrefix)) {
+ if ((*KV.first).starts_with(InitFunctionPrefix)) {
InitSymbols[&JD].add(KV.first,
SymbolLookupFlags::WeaklyReferencedSymbol);
InitFunctions[&JD].add(KV.first);
- } else if ((*KV.first).startswith(DeInitFunctionPrefix)) {
+ } else if ((*KV.first).starts_with(DeInitFunctionPrefix)) {
DeInitFunctions[&JD].add(KV.first);
}
}
@@ -656,6 +597,54 @@ public:
namespace llvm {
namespace orc {
+Error ORCPlatformSupport::initialize(orc::JITDylib &JD) {
+ using llvm::orc::shared::SPSExecutorAddr;
+ using llvm::orc::shared::SPSString;
+ using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t);
+ enum dlopen_mode : int32_t {
+ ORC_RT_RTLD_LAZY = 0x1,
+ ORC_RT_RTLD_NOW = 0x2,
+ ORC_RT_RTLD_LOCAL = 0x4,
+ ORC_RT_RTLD_GLOBAL = 0x8
+ };
+
+ auto &ES = J.getExecutionSession();
+ auto MainSearchOrder = J.getMainJITDylib().withLinkOrderDo(
+ [](const JITDylibSearchOrder &SO) { return SO; });
+
+ if (auto WrapperAddr = ES.lookup(
+ MainSearchOrder, J.mangleAndIntern("__orc_rt_jit_dlopen_wrapper"))) {
+ return ES.callSPSWrapper<SPSDLOpenSig>(WrapperAddr->getAddress(),
+ DSOHandles[&JD], JD.getName(),
+ int32_t(ORC_RT_RTLD_LAZY));
+ } else
+ return WrapperAddr.takeError();
+}
+
+Error ORCPlatformSupport::deinitialize(orc::JITDylib &JD) {
+ using llvm::orc::shared::SPSExecutorAddr;
+ using SPSDLCloseSig = int32_t(SPSExecutorAddr);
+
+ auto &ES = J.getExecutionSession();
+ auto MainSearchOrder = J.getMainJITDylib().withLinkOrderDo(
+ [](const JITDylibSearchOrder &SO) { return SO; });
+
+ if (auto WrapperAddr = ES.lookup(
+ MainSearchOrder, J.mangleAndIntern("__orc_rt_jit_dlclose_wrapper"))) {
+ int32_t result;
+ auto E = J.getExecutionSession().callSPSWrapper<SPSDLCloseSig>(
+ WrapperAddr->getAddress(), result, DSOHandles[&JD]);
+ if (E)
+ return E;
+ else if (result)
+ return make_error<StringError>("dlclose failed",
+ inconvertibleErrorCode());
+ DSOHandles.erase(&JD);
+ } else
+ return WrapperAddr.takeError();
+ return Error::success();
+}
+
void LLJIT::PlatformSupport::setInitTransform(
LLJIT &J, IRTransformLayer::TransformFunction T) {
J.InitHelperTransformLayer->setTransform(std::move(T));
diff --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
index a155b39ae263..9057300bf043 100644
--- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
@@ -15,6 +15,7 @@
#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
+#include "llvm/ExecutionEngine/Orc/MachOBuilder.h"
#include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Debug.h"
@@ -115,100 +116,6 @@ std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
jitlink::getGenericEdgeKindName);
}
-// Generates a MachO header.
-class MachOHeaderMaterializationUnit : public MaterializationUnit {
-public:
- MachOHeaderMaterializationUnit(MachOPlatform &MOP,
- const SymbolStringPtr &HeaderStartSymbol)
- : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)),
- MOP(MOP) {}
-
- StringRef getName() const override { return "MachOHeaderMU"; }
-
- void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
- auto G = createPlatformGraph(MOP, "<MachOHeaderMU>");
- addMachOHeader(*G, MOP, R->getInitializerSymbol());
- MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
- }
-
- void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
-
- static void addMachOHeader(jitlink::LinkGraph &G, MachOPlatform &MOP,
- const SymbolStringPtr &InitializerSymbol) {
- auto &HeaderSection = G.createSection("__header", MemProt::Read);
- auto &HeaderBlock = createHeaderBlock(G, HeaderSection);
-
- // Init symbol is header-start symbol.
- G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol,
- HeaderBlock.getSize(), jitlink::Linkage::Strong,
- jitlink::Scope::Default, false, true);
- for (auto &HS : AdditionalHeaderSymbols)
- G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(),
- jitlink::Linkage::Strong, jitlink::Scope::Default,
- false, true);
- }
-
-private:
- struct HeaderSymbol {
- const char *Name;
- uint64_t Offset;
- };
-
- static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
- {"___mh_executable_header", 0}};
-
- static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
- jitlink::Section &HeaderSection) {
- MachO::mach_header_64 Hdr;
- Hdr.magic = MachO::MH_MAGIC_64;
- switch (G.getTargetTriple().getArch()) {
- case Triple::aarch64:
- Hdr.cputype = MachO::CPU_TYPE_ARM64;
- Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
- break;
- case Triple::x86_64:
- Hdr.cputype = MachO::CPU_TYPE_X86_64;
- Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
- break;
- default:
- llvm_unreachable("Unrecognized architecture");
- }
- Hdr.filetype = MachO::MH_DYLIB; // Custom file type?
- Hdr.ncmds = 0;
- Hdr.sizeofcmds = 0;
- Hdr.flags = 0;
- Hdr.reserved = 0;
-
- if (G.getEndianness() != llvm::endianness::native)
- MachO::swapStruct(Hdr);
-
- auto HeaderContent = G.allocateContent(
- ArrayRef<char>(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
-
- return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
- 0);
- }
-
- static MaterializationUnit::Interface
- createHeaderInterface(MachOPlatform &MOP,
- const SymbolStringPtr &HeaderStartSymbol) {
- SymbolFlagsMap HeaderSymbolFlags;
-
- HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
- for (auto &HS : AdditionalHeaderSymbols)
- HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
- JITSymbolFlags::Exported;
-
- return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
- HeaderStartSymbol);
- }
-
- MachOPlatform &MOP;
-};
-
-constexpr MachOHeaderMaterializationUnit::HeaderSymbol
- MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
-
// Creates a Bootstrap-Complete LinkGraph to run deferred actions.
class MachOPlatformCompleteBootstrapMaterializationUnit
: public MaterializationUnit {
@@ -352,6 +259,7 @@ Expected<std::unique_ptr<MachOPlatform>>
MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD,
std::unique_ptr<DefinitionGenerator> OrcRuntime,
+ MachOHeaderMUBuilder BuildMachOHeaderMU,
std::optional<SymbolAliasMap> RuntimeAliases) {
// If the target is not supported then bail out immediately.
@@ -382,8 +290,9 @@ MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
// Create the instance.
Error Err = Error::success();
- auto P = std::unique_ptr<MachOPlatform>(new MachOPlatform(
- ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err));
+ auto P = std::unique_ptr<MachOPlatform>(
+ new MachOPlatform(ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime),
+ std::move(BuildMachOHeaderMU), Err));
if (Err)
return std::move(Err);
return std::move(P);
@@ -392,6 +301,7 @@ MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
Expected<std::unique_ptr<MachOPlatform>>
MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
+ MachOHeaderMUBuilder BuildMachOHeaderMU,
std::optional<SymbolAliasMap> RuntimeAliases) {
// Create a generator for the ORC runtime archive.
@@ -402,12 +312,11 @@ MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
return Create(ES, ObjLinkingLayer, PlatformJD,
std::move(*OrcRuntimeArchiveGenerator),
- std::move(RuntimeAliases));
+ std::move(BuildMachOHeaderMU), std::move(RuntimeAliases));
}
Error MachOPlatform::setupJITDylib(JITDylib &JD) {
- if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
- *this, MachOHeaderStartSymbol)))
+ if (auto Err = JD.define(BuildMachOHeaderMU(*this)))
return Err;
return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();
@@ -522,8 +431,10 @@ MachOPlatform::flagsForSymbol(jitlink::Symbol &Sym) {
MachOPlatform::MachOPlatform(
ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD,
- std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
- : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer) {
+ std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
+ MachOHeaderMUBuilder BuildMachOHeaderMU, Error &Err)
+ : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer),
+ BuildMachOHeaderMU(std::move(BuildMachOHeaderMU)) {
ErrorAsOutParameter _(&Err);
ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
@@ -586,8 +497,7 @@ MachOPlatform::MachOPlatform(
// the support methods callable. The bootstrap is now complete.
// Step (1) Add header materialization unit and request.
- if ((Err = PlatformJD.define(std::make_unique<MachOHeaderMaterializationUnit>(
- *this, MachOHeaderStartSymbol))))
+ if ((Err = PlatformJD.define(this->BuildMachOHeaderMU(*this))))
return;
if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError()))
return;
@@ -1755,5 +1665,97 @@ Error MachOPlatform::MachOPlatformPlugin::addSymbolTableRegistration(
return Error::success();
}
+
+template <typename MachOTraits>
+jitlink::Block &createTrivialHeaderBlock(MachOPlatform &MOP,
+ jitlink::LinkGraph &G,
+ jitlink::Section &HeaderSection) {
+ auto HdrInfo =
+ getMachOHeaderInfoFromTriple(MOP.getExecutionSession().getTargetTriple());
+ MachOBuilder<MachOTraits> B(HdrInfo.PageSize);
+
+ B.Header.filetype = MachO::MH_DYLIB;
+ B.Header.cputype = HdrInfo.CPUType;
+ B.Header.cpusubtype = HdrInfo.CPUSubType;
+
+ auto HeaderContent = G.allocateBuffer(B.layout());
+ B.write(HeaderContent);
+
+ return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
+ 0);
+}
+
+SimpleMachOHeaderMU::SimpleMachOHeaderMU(MachOPlatform &MOP,
+ SymbolStringPtr HeaderStartSymbol)
+ : MaterializationUnit(
+ createHeaderInterface(MOP, std::move(HeaderStartSymbol))),
+ MOP(MOP) {}
+
+void SimpleMachOHeaderMU::materialize(
+ std::unique_ptr<MaterializationResponsibility> R) {
+ auto G = createPlatformGraph(MOP, "<MachOHeaderMU>");
+ addMachOHeader(R->getTargetJITDylib(), *G, R->getInitializerSymbol());
+ MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
+}
+
+void SimpleMachOHeaderMU::discard(const JITDylib &JD,
+ const SymbolStringPtr &Sym) {}
+
+void SimpleMachOHeaderMU::addMachOHeader(
+ JITDylib &JD, jitlink::LinkGraph &G,
+ const SymbolStringPtr &InitializerSymbol) {
+ auto &HeaderSection = G.createSection("__header", MemProt::Read);
+ auto &HeaderBlock = createHeaderBlock(JD, G, HeaderSection);
+
+ // Init symbol is header-start symbol.
+ G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol, HeaderBlock.getSize(),
+ jitlink::Linkage::Strong, jitlink::Scope::Default, false,
+ true);
+ for (auto &HS : AdditionalHeaderSymbols)
+ G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(),
+ jitlink::Linkage::Strong, jitlink::Scope::Default, false,
+ true);
+}
+
+jitlink::Block &
+SimpleMachOHeaderMU::createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G,
+ jitlink::Section &HeaderSection) {
+ switch (MOP.getExecutionSession().getTargetTriple().getArch()) {
+ case Triple::aarch64:
+ case Triple::x86_64:
+ return createTrivialHeaderBlock<MachO64LE>(MOP, G, HeaderSection);
+ default:
+ llvm_unreachable("Unsupported architecture");
+ }
+}
+
+MaterializationUnit::Interface SimpleMachOHeaderMU::createHeaderInterface(
+ MachOPlatform &MOP, const SymbolStringPtr &HeaderStartSymbol) {
+ SymbolFlagsMap HeaderSymbolFlags;
+
+ HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
+ for (auto &HS : AdditionalHeaderSymbols)
+ HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
+ JITSymbolFlags::Exported;
+
+ return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
+ HeaderStartSymbol);
+}
+
+MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT) {
+ switch (TT.getArch()) {
+ case Triple::aarch64:
+ return {/* PageSize = */ 16 * 1024,
+ /* CPUType = */ MachO::CPU_TYPE_ARM64,
+ /* CPUSubType = */ MachO::CPU_SUBTYPE_ARM64_ALL};
+ case Triple::x86_64:
+ return {/* PageSize = */ 4 * 1024,
+ /* CPUType = */ MachO::CPU_TYPE_X86_64,
+ /* CPUSubType = */ MachO::CPU_SUBTYPE_X86_64_ALL};
+ default:
+ llvm_unreachable("Unrecognized architecture");
+ }
+}
+
} // End namespace orc.
} // End namespace llvm.
diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp
index 7c8fa63477d0..0286b0c93197 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp
@@ -72,7 +72,7 @@ getMachOObjectFileSymbolInfo(ExecutionSession &ES,
return SymFlags.takeError();
// Strip the 'exported' flag from MachO linker-private symbols.
- if (Name->startswith("l"))
+ if (Name->starts_with("l"))
*SymFlags &= ~JITSymbolFlags::Exported;
I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags);
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/ObjectFormats.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/ObjectFormats.cpp
index 1d9d23e64158..a407fcab6ae3 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/ObjectFormats.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/ObjectFormats.cpp
@@ -102,7 +102,7 @@ bool isELFInitializerSection(StringRef SecName) {
}
bool isCOFFInitializerSection(StringRef SecName) {
- return SecName.startswith(".CRT");
+ return SecName.starts_with(".CRT");
}
} // namespace orc
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp
index 210fbf6e43e3..c153b4464568 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp
@@ -42,7 +42,7 @@ JITSymbolFlags llvm::JITSymbolFlags::fromGlobalValue(const GlobalValue &GV) {
const auto &DL = M->getDataLayout();
StringRef LPGP = DL.getLinkerPrivateGlobalPrefix();
if (!LPGP.empty() && GV.getName().front() == '\01' &&
- GV.getName().substr(1).startswith(LPGP))
+ GV.getName().substr(1).starts_with(LPGP))
Flags &= ~JITSymbolFlags::Exported;
}
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp
index 9255311f992d..25a2d8780fb5 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp
@@ -83,7 +83,8 @@ uint64_t RuntimeDyldCOFF::getDLLImportOffset(unsigned SectionID, StubMap &Stubs,
StringRef Name,
bool SetSectionIDMinus1) {
LLVM_DEBUG(dbgs() << "Getting DLLImport entry for " << Name << "... ");
- assert(Name.startswith(getImportSymbolPrefix()) && "Not a DLLImport symbol?");
+ assert(Name.starts_with(getImportSymbolPrefix()) &&
+ "Not a DLLImport symbol?");
RelocationValueRef Reloc;
Reloc.SymbolName = Name.data();
auto I = Stubs.find(Reloc);
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
index 68497305f06b..7fadbdd6a1ff 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
@@ -142,7 +142,7 @@ private:
std::tie(Token, Remaining) = parseNumberString(Expr);
else {
unsigned TokLen = 1;
- if (Expr.startswith("<<") || Expr.startswith(">>"))
+ if (Expr.starts_with("<<") || Expr.starts_with(">>"))
TokLen = 2;
Token = Expr.substr(0, TokLen);
}
@@ -177,9 +177,9 @@ private:
return std::make_pair(BinOpToken::Invalid, "");
// Handle the two 2-character tokens.
- if (Expr.startswith("<<"))
+ if (Expr.starts_with("<<"))
return std::make_pair(BinOpToken::ShiftLeft, Expr.substr(2).ltrim());
- if (Expr.startswith(">>"))
+ if (Expr.starts_with(">>"))
return std::make_pair(BinOpToken::ShiftRight, Expr.substr(2).ltrim());
// Handle one-character tokens.
@@ -242,7 +242,7 @@ private:
// On success, returns a pair containing the value of the operand, plus
// the expression remaining to be evaluated.
std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const {
- if (!Expr.startswith("("))
+ if (!Expr.starts_with("("))
return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
StringRef RemainingExpr = Expr.substr(1).ltrim();
StringRef Symbol;
@@ -273,7 +273,7 @@ private:
"");
}
- if (!RemainingExpr.startswith(","))
+ if (!RemainingExpr.starts_with(","))
return std::make_pair(
unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -283,7 +283,7 @@ private:
if (OpIdxExpr.hasError())
return std::make_pair(OpIdxExpr, "");
- if (!RemainingExpr.startswith(")"))
+ if (!RemainingExpr.starts_with(")"))
return std::make_pair(
unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -343,7 +343,7 @@ private:
// expression remaining to be evaluated.
std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr,
ParseContext PCtx) const {
- if (!Expr.startswith("("))
+ if (!Expr.starts_with("("))
return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
StringRef RemainingExpr = Expr.substr(1).ltrim();
StringRef Symbol;
@@ -354,7 +354,7 @@ private:
EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
"");
- if (!RemainingExpr.startswith(")"))
+ if (!RemainingExpr.starts_with(")"))
return std::make_pair(
unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -381,7 +381,7 @@ private:
// remaining to be evaluated.
std::pair<EvalResult, StringRef>
evalStubOrGOTAddr(StringRef Expr, ParseContext PCtx, bool IsStubAddr) const {
- if (!Expr.startswith("("))
+ if (!Expr.starts_with("("))
return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
StringRef RemainingExpr = Expr.substr(1).ltrim();
@@ -392,7 +392,7 @@ private:
StubContainerName = RemainingExpr.substr(0, ComaIdx).rtrim();
RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();
- if (!RemainingExpr.startswith(","))
+ if (!RemainingExpr.starts_with(","))
return std::make_pair(
unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -400,7 +400,7 @@ private:
StringRef Symbol;
std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
- if (!RemainingExpr.startswith(")"))
+ if (!RemainingExpr.starts_with(")"))
return std::make_pair(
unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -418,7 +418,7 @@ private:
std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr,
ParseContext PCtx) const {
- if (!Expr.startswith("("))
+ if (!Expr.starts_with("("))
return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
StringRef RemainingExpr = Expr.substr(1).ltrim();
@@ -429,7 +429,7 @@ private:
FileName = RemainingExpr.substr(0, ComaIdx).rtrim();
RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();
- if (!RemainingExpr.startswith(","))
+ if (!RemainingExpr.starts_with(","))
return std::make_pair(
unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -439,7 +439,7 @@ private:
SectionName = RemainingExpr.substr(0, CloseParensIdx).rtrim();
RemainingExpr = RemainingExpr.substr(CloseParensIdx).ltrim();
- if (!RemainingExpr.startswith(")"))
+ if (!RemainingExpr.starts_with(")"))
return std::make_pair(
unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -480,7 +480,7 @@ private:
std::string ErrMsg("No known address for symbol '");
ErrMsg += Symbol;
ErrMsg += "'";
- if (Symbol.startswith("L"))
+ if (Symbol.starts_with("L"))
ErrMsg += " (this appears to be an assembler local label - "
" perhaps drop the 'L'?)";
@@ -501,7 +501,7 @@ private:
// pair representing the number and the expression remaining to be parsed.
std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const {
size_t FirstNonDigit = StringRef::npos;
- if (Expr.startswith("0x")) {
+ if (Expr.starts_with("0x")) {
FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2);
if (FirstNonDigit == StringRef::npos)
FirstNonDigit = Expr.size();
@@ -535,14 +535,14 @@ private:
// remaining to be parsed.
std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr,
ParseContext PCtx) const {
- assert(Expr.startswith("(") && "Not a parenthesized expression");
+ assert(Expr.starts_with("(") && "Not a parenthesized expression");
EvalResult SubExprResult;
StringRef RemainingExpr;
std::tie(SubExprResult, RemainingExpr) =
evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx);
if (SubExprResult.hasError())
return std::make_pair(SubExprResult, "");
- if (!RemainingExpr.startswith(")"))
+ if (!RemainingExpr.starts_with(")"))
return std::make_pair(
unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -554,11 +554,11 @@ private:
// Return a pair containing the result, plus the expression remaining to be
// parsed.
std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const {
- assert(Expr.startswith("*") && "Not a load expression");
+ assert(Expr.starts_with("*") && "Not a load expression");
StringRef RemainingExpr = Expr.substr(1).ltrim();
// Parse read size.
- if (!RemainingExpr.startswith("{"))
+ if (!RemainingExpr.starts_with("{"))
return std::make_pair(EvalResult("Expected '{' following '*'."), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
EvalResult ReadSizeExpr;
@@ -568,7 +568,7 @@ private:
uint64_t ReadSize = ReadSizeExpr.getValue();
if (ReadSize < 1 || ReadSize > 8)
return std::make_pair(EvalResult("Invalid size for dereference."), "");
- if (!RemainingExpr.startswith("}"))
+ if (!RemainingExpr.starts_with("}"))
return std::make_pair(EvalResult("Missing '}' for dereference."), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -625,7 +625,7 @@ private:
return std::make_pair(SubExprResult, RemainingExpr);
// Evaluate bit-slice if present.
- if (RemainingExpr.startswith("["))
+ if (RemainingExpr.starts_with("["))
std::tie(SubExprResult, RemainingExpr) =
evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr));
@@ -645,7 +645,7 @@ private:
StringRef RemainingExpr;
std::tie(SubExprResult, RemainingExpr) = Ctx;
- assert(RemainingExpr.startswith("[") && "Not a slice expr.");
+ assert(RemainingExpr.starts_with("[") && "Not a slice expr.");
RemainingExpr = RemainingExpr.substr(1).ltrim();
EvalResult HighBitExpr;
@@ -654,7 +654,7 @@ private:
if (HighBitExpr.hasError())
return std::make_pair(HighBitExpr, RemainingExpr);
- if (!RemainingExpr.startswith(":"))
+ if (!RemainingExpr.starts_with(":"))
return std::make_pair(
unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -665,7 +665,7 @@ private:
if (LowBitExpr.hasError())
return std::make_pair(LowBitExpr, RemainingExpr);
- if (!RemainingExpr.startswith("]"))
+ if (!RemainingExpr.starts_with("]"))
return std::make_pair(
unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), "");
RemainingExpr = RemainingExpr.substr(1).ltrim();
@@ -846,7 +846,7 @@ bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix,
++LineEnd;
StringRef Line(LineStart, LineEnd - LineStart);
- if (Line.startswith(RulePrefix))
+ if (Line.starts_with(RulePrefix))
CheckExpr += Line.substr(RulePrefix.size()).str();
// If there's a check expr string...
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFAArch64.h b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFAArch64.h
index a1151b81d141..66c9753a72fd 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFAArch64.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFAArch64.h
@@ -174,7 +174,7 @@ public:
unsigned TargetSectionID = -1;
uint64_t TargetOffset = -1;
- if (TargetName.startswith(getImportSymbolPrefix())) {
+ if (TargetName.starts_with(getImportSymbolPrefix())) {
TargetSectionID = SectionID;
TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName);
TargetName = StringRef();
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h
index 2a54728fd0bf..0d5afc289b8c 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h
@@ -60,7 +60,7 @@ public:
unsigned TargetSectionID = -1;
uint64_t TargetOffset = -1;
- if (TargetName.startswith(getImportSymbolPrefix())) {
+ if (TargetName.starts_with(getImportSymbolPrefix())) {
TargetSectionID = SectionID;
TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
TargetName = StringRef();
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h
index a3e66c6bc0ec..c079d8896c1d 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h
@@ -129,7 +129,7 @@ public:
unsigned TargetSectionID = -1;
uint64_t TargetOffset = -1;
- if (TargetName.startswith(getImportSymbolPrefix())) {
+ if (TargetName.starts_with(getImportSymbolPrefix())) {
TargetSectionID = SectionID;
TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
TargetName = StringRef();
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
index 43ce64af8685..984a8d765c84 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
@@ -226,7 +226,7 @@ public:
unsigned TargetSectionID = 0;
uint64_t TargetOffset = 0;
- if (TargetName.startswith(getImportSymbolPrefix())) {
+ if (TargetName.starts_with(getImportSymbolPrefix())) {
assert(IsExtern && "DLLImport not marked extern?");
TargetSectionID = SectionID;
TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName);
diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp
index ac8f52d586bc..b728c14d288a 100644
--- a/llvm/lib/FileCheck/FileCheck.cpp
+++ b/llvm/lib/FileCheck/FileCheck.cpp
@@ -404,7 +404,7 @@ Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand(
StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint,
std::optional<size_t> LineNumber, FileCheckPatternContext *Context,
const SourceMgr &SM) {
- if (Expr.startswith("(")) {
+ if (Expr.starts_with("(")) {
if (AO != AllowedOperand::Any)
return ErrorDiagnostic::get(
SM, Expr, "parenthesized expression not permitted here");
@@ -417,7 +417,7 @@ Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand(
parseVariable(Expr, SM);
if (ParseVarResult) {
// Try to parse a function call.
- if (Expr.ltrim(SpaceChars).startswith("(")) {
+ if (Expr.ltrim(SpaceChars).starts_with("(")) {
if (AO != AllowedOperand::Any)
return ErrorDiagnostic::get(SM, ParseVarResult->Name,
"unexpected function call");
@@ -458,7 +458,7 @@ Expected<std::unique_ptr<ExpressionAST>>
Pattern::parseParenExpr(StringRef &Expr, std::optional<size_t> LineNumber,
FileCheckPatternContext *Context, const SourceMgr &SM) {
Expr = Expr.ltrim(SpaceChars);
- assert(Expr.startswith("("));
+ assert(Expr.starts_with("("));
// Parse right operand.
Expr.consume_front("(");
@@ -471,7 +471,7 @@ Pattern::parseParenExpr(StringRef &Expr, std::optional<size_t> LineNumber,
Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber,
Context, SM);
Expr = Expr.ltrim(SpaceChars);
- while (SubExprResult && !Expr.empty() && !Expr.startswith(")")) {
+ while (SubExprResult && !Expr.empty() && !Expr.starts_with(")")) {
StringRef OrigExpr = Expr;
SubExprResult = parseBinop(OrigExpr, Expr, std::move(*SubExprResult), false,
LineNumber, Context, SM);
@@ -537,7 +537,7 @@ Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName,
std::optional<size_t> LineNumber,
FileCheckPatternContext *Context, const SourceMgr &SM) {
Expr = Expr.ltrim(SpaceChars);
- assert(Expr.startswith("("));
+ assert(Expr.starts_with("("));
auto OptFunc = StringSwitch<binop_eval_t>(FuncName)
.Case("add", exprAdd)
@@ -557,8 +557,8 @@ Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName,
// Parse call arguments, which are comma separated.
SmallVector<std::unique_ptr<ExpressionAST>, 4> Args;
- while (!Expr.empty() && !Expr.startswith(")")) {
- if (Expr.startswith(","))
+ while (!Expr.empty() && !Expr.starts_with(")")) {
+ if (Expr.starts_with(","))
return ErrorDiagnostic::get(SM, Expr, "missing argument");
// Parse the argument, which is an arbitary expression.
@@ -569,7 +569,7 @@ Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName,
while (Arg && !Expr.empty()) {
Expr = Expr.ltrim(SpaceChars);
// Have we reached an argument terminator?
- if (Expr.startswith(",") || Expr.startswith(")"))
+ if (Expr.starts_with(",") || Expr.starts_with(")"))
break;
// Arg = Arg <op> <expr>
@@ -588,7 +588,7 @@ Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName,
break;
Expr = Expr.ltrim(SpaceChars);
- if (Expr.startswith(")"))
+ if (Expr.starts_with(")"))
return ErrorDiagnostic::get(SM, Expr, "missing argument");
}
@@ -818,7 +818,7 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix,
// by escaping scary characters in fixed strings, building up one big regex.
while (!PatternStr.empty()) {
// RegEx matches.
- if (PatternStr.startswith("{{")) {
+ if (PatternStr.starts_with("{{")) {
// This is the start of a regex match. Scan for the }}.
size_t End = PatternStr.find("}}");
if (End == StringRef::npos) {
@@ -857,7 +857,7 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix,
// names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be
// valid, as this helps catch some common errors. If there are extra '['s
// before the "[[", treat them literally.
- if (PatternStr.startswith("[[") && !PatternStr.startswith("[[[")) {
+ if (PatternStr.starts_with("[[") && !PatternStr.starts_with("[[[")) {
StringRef UnparsedPatternStr = PatternStr.substr(2);
// Find the closing bracket pair ending the match. End is going to be an
// offset relative to the beginning of the match string.
@@ -1392,7 +1392,7 @@ size_t Pattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) {
size_t BracketDepth = 0;
while (!Str.empty()) {
- if (Str.startswith("]]") && BracketDepth == 0)
+ if (Str.starts_with("]]") && BracketDepth == 0)
return Offset;
if (Str[0] == '\\') {
// Backslash escapes the next char within regexes, so skip them both.
@@ -1591,10 +1591,10 @@ FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix,
}
// You can't combine -NOT with another suffix.
- if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||
- Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||
- Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") ||
- Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))
+ if (Rest.starts_with("DAG-NOT:") || Rest.starts_with("NOT-DAG:") ||
+ Rest.starts_with("NEXT-NOT:") || Rest.starts_with("NOT-NEXT:") ||
+ Rest.starts_with("SAME-NOT:") || Rest.starts_with("NOT-SAME:") ||
+ Rest.starts_with("EMPTY-NOT:") || Rest.starts_with("NOT-EMPTY:"))
return {Check::CheckBadNot, Rest};
if (Rest.consume_front("NEXT"))
diff --git a/llvm/lib/Frontend/HLSL/HLSLResource.cpp b/llvm/lib/Frontend/HLSL/HLSLResource.cpp
index a3a7d0b8696c..709fe3212623 100644
--- a/llvm/lib/Frontend/HLSL/HLSLResource.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLResource.cpp
@@ -33,25 +33,31 @@ ResourceKind FrontendResource::getResourceKind() {
cast<ConstantAsMetadata>(Entry->getOperand(2))->getValue())
->getLimitedValue());
}
-uint32_t FrontendResource::getResourceIndex() {
+bool FrontendResource::getIsROV() {
return cast<ConstantInt>(
cast<ConstantAsMetadata>(Entry->getOperand(3))->getValue())
->getLimitedValue();
}
-uint32_t FrontendResource::getSpace() {
+uint32_t FrontendResource::getResourceIndex() {
return cast<ConstantInt>(
cast<ConstantAsMetadata>(Entry->getOperand(4))->getValue())
->getLimitedValue();
}
+uint32_t FrontendResource::getSpace() {
+ return cast<ConstantInt>(
+ cast<ConstantAsMetadata>(Entry->getOperand(5))->getValue())
+ ->getLimitedValue();
+}
FrontendResource::FrontendResource(GlobalVariable *GV, StringRef TypeStr,
- ResourceKind RK, uint32_t ResIndex,
- uint32_t Space) {
+ ResourceKind RK, bool IsROV,
+ uint32_t ResIndex, uint32_t Space) {
auto &Ctx = GV->getContext();
IRBuilder<> B(Ctx);
Entry = MDNode::get(
Ctx, {ValueAsMetadata::get(GV), MDString::get(Ctx, TypeStr),
ConstantAsMetadata::get(B.getInt32(static_cast<int>(RK))),
+ ConstantAsMetadata::get(B.getInt1(IsROV)),
ConstantAsMetadata::get(B.getInt32(ResIndex)),
ConstantAsMetadata::get(B.getInt32(Space))});
}
diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index be9a44885f66..ce428f78dc84 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -5213,10 +5213,13 @@ OpenMPIRBuilder::getOrCreateInternalVariable(Type *Ty, const StringRef &Name,
// variable for possibly changing that to internal or private, or maybe
// create different versions of the function for different OMP internal
// variables.
- auto *GV = new GlobalVariable(
- M, Ty, /*IsConstant=*/false, GlobalValue::CommonLinkage,
- Constant::getNullValue(Ty), Elem.first(),
- /*InsertBefore=*/nullptr, GlobalValue::NotThreadLocal, AddressSpace);
+ auto Linkage = this->M.getTargetTriple().rfind("wasm32") == 0
+ ? GlobalValue::ExternalLinkage
+ : GlobalValue::CommonLinkage;
+ auto *GV = new GlobalVariable(M, Ty, /*IsConstant=*/false, Linkage,
+ Constant::getNullValue(Ty), Elem.first(),
+ /*InsertBefore=*/nullptr,
+ GlobalValue::NotThreadLocal, AddressSpace);
const DataLayout &DL = M.getDataLayout();
const llvm::Align TypeAlign = DL.getABITypeAlign(Ty);
const llvm::Align PtrAlign = DL.getPointerABIAlignment(AddressSpace);
diff --git a/llvm/lib/FuzzMutate/FuzzerCLI.cpp b/llvm/lib/FuzzMutate/FuzzerCLI.cpp
index 0e47e3cc3af2..c64e9c04e199 100644
--- a/llvm/lib/FuzzMutate/FuzzerCLI.cpp
+++ b/llvm/lib/FuzzMutate/FuzzerCLI.cpp
@@ -43,7 +43,7 @@ void llvm::handleExecNameEncodedBEOpts(StringRef ExecName) {
Args.push_back("-global-isel");
// For now we default GlobalISel to -O0
Args.push_back("-O0");
- } else if (Opt.startswith("O")) {
+ } else if (Opt.starts_with("O")) {
Args.push_back("-" + Opt.str());
} else if (Triple(Opt).getArch()) {
Args.push_back("-mtriple=" + Opt.str());
@@ -140,7 +140,7 @@ int llvm::runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne,
for (int I = 1; I < ArgC; ++I) {
StringRef Arg(ArgV[I]);
- if (Arg.startswith("-")) {
+ if (Arg.starts_with("-")) {
if (Arg.equals("-ignore_remaining_args=1"))
break;
continue;
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 10a74ed68a39..fd5160209506 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -1962,7 +1962,8 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,
.addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::Dereferenceable)
.addAttribute(Attribute::DereferenceableOrNull)
- .addAttribute(Attribute::Writable);
+ .addAttribute(Attribute::Writable)
+ .addAttribute(Attribute::DeadOnUnwind);
if (ASK & ASK_UNSAFE_TO_DROP)
Incompatible.addAttribute(Attribute::Nest)
.addAttribute(Attribute::SwiftError)
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 645691f44179..6b54047020a0 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -582,7 +582,7 @@ static bool UpgradeX86IntrinsicFunction(Function *F, StringRef Name,
if (Name.consume_front("xop.")) {
Intrinsic::ID ID = Intrinsic::not_intrinsic;
- if (Name.startswith("vpermil2")) { // Added in 3.9
+ if (Name.starts_with("vpermil2")) { // Added in 3.9
// Upgrade any XOP PERMIL2 index operand still using a float/double
// vector.
auto Idx = F->getFunctionType()->getParamType(2);
@@ -5207,10 +5207,12 @@ std::string llvm::UpgradeDataLayoutString(StringRef DL, StringRef TT) {
// This goes before adding new address spaces to prevent incoherent string
// values.
if (!DL.contains("-ni") && !DL.starts_with("ni"))
- Res.append("-ni:7:8");
- // Update ni:7 to ni:7:8.
+ Res.append("-ni:7:8:9");
+ // Update ni:7 to ni:7:8:9.
if (DL.ends_with("ni:7"))
- Res.append(":8");
+ Res.append(":8:9");
+ if (DL.ends_with("ni:7:8"))
+ Res.append(":9");
// Add sizing for address spaces 7 and 8 (fat raw buffers and buffer
// resources) An empty data layout has already been upgraded to G1 by now.
@@ -5218,6 +5220,8 @@ std::string llvm::UpgradeDataLayoutString(StringRef DL, StringRef TT) {
Res.append("-p7:160:256:256:32");
if (!DL.contains("-p8") && !DL.starts_with("p8"))
Res.append("-p8:128:128");
+ if (!DL.contains("-p9") && !DL.starts_with("p9"))
+ Res.append("-p9:192:256:256:32");
return Res;
}
diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index f364c56a42c5..03b74b0480f0 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -73,7 +73,10 @@ void BasicBlock::convertToNewDbgValues() {
SmallVector<DPValue *, 4> DPVals;
for (Instruction &I : make_early_inc_range(InstList)) {
assert(!I.DbgMarker && "DbgMarker already set on old-format instrs?");
- if (DbgValueInst *DVI = dyn_cast<DbgValueInst>(&I)) {
+ if (DbgVariableIntrinsic *DVI = dyn_cast<DbgVariableIntrinsic>(&I)) {
+ if (isa<DbgAssignIntrinsic>(DVI))
+ continue;
+
// Convert this dbg.value to a DPValue.
DPValue *Value = new DPValue(DVI);
DPVals.push_back(Value);
@@ -1088,6 +1091,8 @@ void BasicBlock::insertDPValueBefore(DPValue *DPV,
// shouldn't be generated at times when there's no terminator.
assert(Where != end());
assert(Where->getParent() == this);
+ if (!Where->DbgMarker)
+ createMarker(Where);
bool InsertAtHead = Where.getHeadBit();
Where->DbgMarker->insertDPValue(DPV, InsertAtHead);
}
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 7832028bf367..fb30fbce0ba2 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -43,6 +43,8 @@
using namespace llvm;
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OperandBundleDef, LLVMOperandBundleRef)
+
#define DEBUG_TYPE "ir"
void llvm::initializeCore(PassRegistry &Registry) {
@@ -2567,6 +2569,34 @@ void LLVMRemoveGlobalIFunc(LLVMValueRef IFunc) {
unwrap<GlobalIFunc>(IFunc)->removeFromParent();
}
+/*--.. Operations on operand bundles........................................--*/
+
+LLVMOperandBundleRef LLVMCreateOperandBundle(const char *Tag, size_t TagLen,
+ LLVMValueRef *Args,
+ unsigned NumArgs) {
+ return wrap(new OperandBundleDef(std::string(Tag, TagLen),
+ ArrayRef(unwrap(Args), NumArgs)));
+}
+
+void LLVMDisposeOperandBundle(LLVMOperandBundleRef Bundle) {
+ delete unwrap(Bundle);
+}
+
+const char *LLVMGetOperandBundleTag(LLVMOperandBundleRef Bundle, size_t *Len) {
+ StringRef Str = unwrap(Bundle)->getTag();
+ *Len = Str.size();
+ return Str.data();
+}
+
+unsigned LLVMGetNumOperandBundleArgs(LLVMOperandBundleRef Bundle) {
+ return unwrap(Bundle)->inputs().size();
+}
+
+LLVMValueRef LLVMGetOperandBundleArgAtIndex(LLVMOperandBundleRef Bundle,
+ unsigned Index) {
+ return wrap(unwrap(Bundle)->inputs()[Index]);
+}
+
/*--.. Operations on basic blocks ..........................................--*/
LLVMValueRef LLVMBasicBlockAsValue(LLVMBasicBlockRef BB) {
@@ -2858,6 +2888,16 @@ LLVMTypeRef LLVMGetCalledFunctionType(LLVMValueRef Instr) {
return wrap(unwrap<CallBase>(Instr)->getFunctionType());
}
+unsigned LLVMGetNumOperandBundles(LLVMValueRef C) {
+ return unwrap<CallBase>(C)->getNumOperandBundles();
+}
+
+LLVMOperandBundleRef LLVMGetOperandBundleAtIndex(LLVMValueRef C,
+ unsigned Index) {
+ return wrap(
+ new OperandBundleDef(unwrap<CallBase>(C)->getOperandBundleAt(Index)));
+}
+
/*--.. Operations on call instructions (only) ..............................--*/
LLVMBool LLVMIsTailCall(LLVMValueRef Call) {
@@ -3140,6 +3180,20 @@ LLVMValueRef LLVMBuildInvoke2(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
ArrayRef(unwrap(Args), NumArgs), Name));
}
+LLVMValueRef LLVMBuildInvokeWithOperandBundles(
+ LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args,
+ unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
+ LLVMOperandBundleRef *Bundles, unsigned NumBundles, const char *Name) {
+ SmallVector<OperandBundleDef, 8> OBs;
+ for (auto *Bundle : ArrayRef(Bundles, NumBundles)) {
+ OperandBundleDef *OB = unwrap(Bundle);
+ OBs.push_back(*OB);
+ }
+ return wrap(unwrap(B)->CreateInvoke(
+ unwrap<FunctionType>(Ty), unwrap(Fn), unwrap(Then), unwrap(Catch),
+ ArrayRef(unwrap(Args), NumArgs), OBs, Name));
+}
+
LLVMValueRef LLVMBuildLandingPad(LLVMBuilderRef B, LLVMTypeRef Ty,
LLVMValueRef PersFn, unsigned NumClauses,
const char *Name) {
@@ -3265,6 +3319,39 @@ void LLVMSetArgOperand(LLVMValueRef Funclet, unsigned i, LLVMValueRef value) {
/*--.. Arithmetic ..........................................................--*/
+static FastMathFlags mapFromLLVMFastMathFlags(LLVMFastMathFlags FMF) {
+ FastMathFlags NewFMF;
+ NewFMF.setAllowReassoc((FMF & LLVMFastMathAllowReassoc) != 0);
+ NewFMF.setNoNaNs((FMF & LLVMFastMathNoNaNs) != 0);
+ NewFMF.setNoInfs((FMF & LLVMFastMathNoInfs) != 0);
+ NewFMF.setNoSignedZeros((FMF & LLVMFastMathNoSignedZeros) != 0);
+ NewFMF.setAllowReciprocal((FMF & LLVMFastMathAllowReciprocal) != 0);
+ NewFMF.setAllowContract((FMF & LLVMFastMathAllowContract) != 0);
+ NewFMF.setApproxFunc((FMF & LLVMFastMathApproxFunc) != 0);
+
+ return NewFMF;
+}
+
+static LLVMFastMathFlags mapToLLVMFastMathFlags(FastMathFlags FMF) {
+ LLVMFastMathFlags NewFMF = LLVMFastMathNone;
+ if (FMF.allowReassoc())
+ NewFMF |= LLVMFastMathAllowReassoc;
+ if (FMF.noNaNs())
+ NewFMF |= LLVMFastMathNoNaNs;
+ if (FMF.noInfs())
+ NewFMF |= LLVMFastMathNoInfs;
+ if (FMF.noSignedZeros())
+ NewFMF |= LLVMFastMathNoSignedZeros;
+ if (FMF.allowReciprocal())
+ NewFMF |= LLVMFastMathAllowReciprocal;
+ if (FMF.allowContract())
+ NewFMF |= LLVMFastMathAllowContract;
+ if (FMF.approxFunc())
+ NewFMF |= LLVMFastMathApproxFunc;
+
+ return NewFMF;
+}
+
LLVMValueRef LLVMBuildAdd(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS,
const char *Name) {
return wrap(unwrap(B)->CreateAdd(unwrap(LHS), unwrap(RHS), Name));
@@ -3464,6 +3551,22 @@ void LLVMSetNNeg(LLVMValueRef NonNegInst, LLVMBool IsNonNeg) {
cast<Instruction>(P)->setNonNeg(IsNonNeg);
}
+LLVMFastMathFlags LLVMGetFastMathFlags(LLVMValueRef FPMathInst) {
+ Value *P = unwrap<Value>(FPMathInst);
+ FastMathFlags FMF = cast<Instruction>(P)->getFastMathFlags();
+ return mapToLLVMFastMathFlags(FMF);
+}
+
+void LLVMSetFastMathFlags(LLVMValueRef FPMathInst, LLVMFastMathFlags FMF) {
+ Value *P = unwrap<Value>(FPMathInst);
+ cast<Instruction>(P)->setFastMathFlags(mapFromLLVMFastMathFlags(FMF));
+}
+
+LLVMBool LLVMCanValueUseFastMathFlags(LLVMValueRef V) {
+ Value *Val = unwrap<Value>(V);
+ return isa<FPMathOperator>(Val);
+}
+
LLVMBool LLVMGetIsDisjoint(LLVMValueRef Inst) {
Value *P = unwrap<Value>(Inst);
return cast<PossiblyDisjointInst>(P)->isDisjoint();
@@ -3878,6 +3981,21 @@ LLVMValueRef LLVMBuildCall2(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
ArrayRef(unwrap(Args), NumArgs), Name));
}
+LLVMValueRef
+LLVMBuildCallWithOperandBundles(LLVMBuilderRef B, LLVMTypeRef Ty,
+ LLVMValueRef Fn, LLVMValueRef *Args,
+ unsigned NumArgs, LLVMOperandBundleRef *Bundles,
+ unsigned NumBundles, const char *Name) {
+ FunctionType *FTy = unwrap<FunctionType>(Ty);
+ SmallVector<OperandBundleDef, 8> OBs;
+ for (auto *Bundle : ArrayRef(Bundles, NumBundles)) {
+ OperandBundleDef *OB = unwrap(Bundle);
+ OBs.push_back(*OB);
+ }
+ return wrap(unwrap(B)->CreateCall(
+ FTy, unwrap(Fn), ArrayRef(unwrap(Args), NumArgs), OBs, Name));
+}
+
LLVMValueRef LLVMBuildSelect(LLVMBuilderRef B, LLVMValueRef If,
LLVMValueRef Then, LLVMValueRef Else,
const char *Name) {
diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp
index 3fe940e19295..eab05eed428e 100644
--- a/llvm/lib/IR/DebugInfo.cpp
+++ b/llvm/lib/IR/DebugInfo.cpp
@@ -44,30 +44,10 @@ using namespace llvm;
using namespace llvm::at;
using namespace llvm::dwarf;
-TinyPtrVector<DbgDeclareInst *> llvm::FindDbgDeclareUses(Value *V) {
- // This function is hot. Check whether the value has any metadata to avoid a
- // DenseMap lookup.
- if (!V->isUsedByMetadata())
- return {};
- auto *L = LocalAsMetadata::getIfExists(V);
- if (!L)
- return {};
- auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L);
- if (!MDV)
- return {};
-
- TinyPtrVector<DbgDeclareInst *> Declares;
- for (User *U : MDV->users()) {
- if (auto *DDI = dyn_cast<DbgDeclareInst>(U))
- Declares.push_back(DDI);
- }
-
- return Declares;
-}
-
-template <typename IntrinsicT>
-static void findDbgIntrinsics(SmallVectorImpl<IntrinsicT *> &Result,
- Value *V, SmallVectorImpl<DPValue *> *DPValues) {
+template <typename IntrinsicT,
+ DPValue::LocationType Type = DPValue::LocationType::Any>
+static void findDbgIntrinsics(SmallVectorImpl<IntrinsicT *> &Result, Value *V,
+ SmallVectorImpl<DPValue *> *DPValues) {
// This function is hot. Check whether the value has any metadata to avoid a
// DenseMap lookup.
if (!V->isUsedByMetadata())
@@ -96,7 +76,7 @@ static void findDbgIntrinsics(SmallVectorImpl<IntrinsicT *> &Result,
// Get DPValues that use this as a single value.
if (LocalAsMetadata *L = dyn_cast<LocalAsMetadata>(MD)) {
for (DPValue *DPV : L->getAllDPValueUsers()) {
- if (DPV->getType() == DPValue::LocationType::Value)
+ if (Type == DPValue::LocationType::Any || DPV->getType() == Type)
DPValues->push_back(DPV);
}
}
@@ -110,21 +90,29 @@ static void findDbgIntrinsics(SmallVectorImpl<IntrinsicT *> &Result,
continue;
DIArgList *DI = cast<DIArgList>(AL);
for (DPValue *DPV : DI->getAllDPValueUsers())
- if (DPV->getType() == DPValue::LocationType::Value)
+ if (Type == DPValue::LocationType::Any || DPV->getType() == Type)
if (EncounteredDPValues.insert(DPV).second)
DPValues->push_back(DPV);
}
}
}
+void llvm::findDbgDeclares(SmallVectorImpl<DbgDeclareInst *> &DbgUsers,
+ Value *V, SmallVectorImpl<DPValue *> *DPValues) {
+ findDbgIntrinsics<DbgDeclareInst, DPValue::LocationType::Declare>(DbgUsers, V,
+ DPValues);
+}
+
void llvm::findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues,
Value *V, SmallVectorImpl<DPValue *> *DPValues) {
- findDbgIntrinsics<DbgValueInst>(DbgValues, V, DPValues);
+ findDbgIntrinsics<DbgValueInst, DPValue::LocationType::Value>(DbgValues, V,
+ DPValues);
}
void llvm::findDbgUsers(SmallVectorImpl<DbgVariableIntrinsic *> &DbgUsers,
Value *V, SmallVectorImpl<DPValue *> *DPValues) {
- findDbgIntrinsics<DbgVariableIntrinsic>(DbgUsers, V, DPValues);
+ findDbgIntrinsics<DbgVariableIntrinsic, DPValue::LocationType::Any>(
+ DbgUsers, V, DPValues);
}
DISubprogram *llvm::getDISubprogram(const MDNode *Scope) {
@@ -559,7 +547,7 @@ bool llvm::StripDebugInfo(Module &M) {
for (NamedMDNode &NMD : llvm::make_early_inc_range(M.named_metadata())) {
// We're stripping debug info, and without them, coverage information
// doesn't quite make sense.
- if (NMD.getName().startswith("llvm.dbg.") ||
+ if (NMD.getName().starts_with("llvm.dbg.") ||
NMD.getName() == "llvm.gcov") {
NMD.eraseFromParent();
Changed = true;
diff --git a/llvm/lib/IR/DebugProgramInstruction.cpp b/llvm/lib/IR/DebugProgramInstruction.cpp
index 6a4ee9d61010..7b709a2de033 100644
--- a/llvm/lib/IR/DebugProgramInstruction.cpp
+++ b/llvm/lib/IR/DebugProgramInstruction.cpp
@@ -35,10 +35,9 @@ DPValue::DPValue(const DPValue &DPV)
DbgLoc(DPV.getDebugLoc()), Type(DPV.getType()) {}
DPValue::DPValue(Metadata *Location, DILocalVariable *DV, DIExpression *Expr,
- const DILocation *DI)
+ const DILocation *DI, LocationType Type)
: DebugValueUser(Location), Variable(DV), Expression(Expr), DbgLoc(DI),
- Type(LocationType::Value) {
-}
+ Type(Type) {}
void DPValue::deleteInstr() { delete this; }
@@ -204,6 +203,10 @@ DPValue::createDebugIntrinsic(Module *M, Instruction *InsertBefore) const {
case DPValue::LocationType::Value:
IntrinsicFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_value);
break;
+ case DPValue::LocationType::End:
+ case DPValue::LocationType::Any:
+ llvm_unreachable("Invalid LocationType");
+ break;
}
// Create the intrinsic from this DPValue's information, optionally insert
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index c3706dc1b02f..22e2455462bf 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -439,7 +439,7 @@ Function::Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace,
if (ParentModule)
ParentModule->getFunctionList().push_back(this);
- HasLLVMReservedName = getName().startswith("llvm.");
+ HasLLVMReservedName = getName().starts_with("llvm.");
// Ensure intrinsics have the right parameter attributes.
// Note, the IntID field will have been set in Value::setName if this function
// name is a valid intrinsic ID.
@@ -876,7 +876,7 @@ bool Function::isTargetIntrinsic() const {
///
/// Returns the relevant slice of \c IntrinsicNameTable
static ArrayRef<const char *> findTargetSubtable(StringRef Name) {
- assert(Name.startswith("llvm."));
+ assert(Name.starts_with("llvm."));
ArrayRef<IntrinsicTargetInfo> Targets(TargetInfos);
// Drop "llvm." and take the first dotted component. That will be the target
@@ -915,7 +915,7 @@ Intrinsic::ID Function::lookupIntrinsicID(StringRef Name) {
void Function::updateAfterNameChange() {
LibFuncCache = UnknownLibFunc;
StringRef Name = getName();
- if (!Name.startswith("llvm.")) {
+ if (!Name.starts_with("llvm.")) {
HasLLVMReservedName = false;
IntID = Intrinsic::not_intrinsic;
return;
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index bc228a577c6a..299b4e74677d 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -2412,9 +2412,6 @@ bool ShuffleVectorInst::isInsertSubvectorMask(ArrayRef<int> Mask,
}
bool ShuffleVectorInst::isIdentityWithPadding() const {
- if (isa<UndefValue>(Op<2>()))
- return false;
-
// FIXME: Not currently possible to express a shuffle mask for a scalable
// vector for this case.
if (isa<ScalableVectorType>(getType()))
@@ -2439,9 +2436,6 @@ bool ShuffleVectorInst::isIdentityWithPadding() const {
}
bool ShuffleVectorInst::isIdentityWithExtract() const {
- if (isa<UndefValue>(Op<2>()))
- return false;
-
// FIXME: Not currently possible to express a shuffle mask for a scalable
// vector for this case.
if (isa<ScalableVectorType>(getType()))
@@ -2457,8 +2451,7 @@ bool ShuffleVectorInst::isIdentityWithExtract() const {
bool ShuffleVectorInst::isConcat() const {
// Vector concatenation is differentiated from identity with padding.
- if (isa<UndefValue>(Op<0>()) || isa<UndefValue>(Op<1>()) ||
- isa<UndefValue>(Op<2>()))
+ if (isa<UndefValue>(Op<0>()) || isa<UndefValue>(Op<1>()))
return false;
// FIXME: Not currently possible to express a shuffle mask for a scalable
diff --git a/llvm/lib/IR/Mangler.cpp b/llvm/lib/IR/Mangler.cpp
index 8d9880ecba58..3acac2c3e3db 100644
--- a/llvm/lib/IR/Mangler.cpp
+++ b/llvm/lib/IR/Mangler.cpp
@@ -149,8 +149,8 @@ void Mangler::getNameWithPrefix(raw_ostream &OS, const GlobalValue *GV,
// Don't add byte count suffixes when '\01' or '?' are in the first
// character.
- if (Name.startswith("\01") ||
- (DL.doNotMangleLeadingQuestionMark() && Name.startswith("?")))
+ if (Name.starts_with("\01") ||
+ (DL.doNotMangleLeadingQuestionMark() && Name.starts_with("?")))
MSFunc = nullptr;
CallingConv::ID CC =
diff --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp
index 017641a8dba1..cd982c7da102 100644
--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -229,8 +229,8 @@ bool GEPOperator::collectOffset(
// Insert an initial offset of 0 for V iff none exists already, then
// increment the offset by IndexedSize.
if (!IndexedSize.isZero()) {
- VariableOffsets.insert({V, APInt(BitWidth, 0)});
- VariableOffsets[V] += IndexedSize;
+ auto *It = VariableOffsets.insert({V, APInt(BitWidth, 0)}).first;
+ It->second += IndexedSize;
}
}
return true;
diff --git a/llvm/lib/IR/PassInstrumentation.cpp b/llvm/lib/IR/PassInstrumentation.cpp
index d85cefbbe6f7..6d5f3acb7a4d 100644
--- a/llvm/lib/IR/PassInstrumentation.cpp
+++ b/llvm/lib/IR/PassInstrumentation.cpp
@@ -35,7 +35,8 @@ bool isSpecialPass(StringRef PassID, const std::vector<StringRef> &Specials) {
StringRef Prefix = PassID;
if (Pos != StringRef::npos)
Prefix = PassID.substr(0, Pos);
- return any_of(Specials, [Prefix](StringRef S) { return Prefix.endswith(S); });
+ return any_of(Specials,
+ [Prefix](StringRef S) { return Prefix.ends_with(S); });
}
} // namespace llvm
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index a185ca3fb8dc..85d779c98a9b 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -834,7 +834,7 @@ struct TargetTypeInfo {
static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
LLVMContext &C = Ty->getContext();
StringRef Name = Ty->getName();
- if (Name.startswith("spirv."))
+ if (Name.starts_with("spirv."))
return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::HasZeroInit,
TargetExtType::CanBeGlobal);
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index f137f0468c3c..8aba28026306 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -958,7 +958,7 @@ void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) {
void Verifier::visitNamedMDNode(const NamedMDNode &NMD) {
// There used to be various other llvm.dbg.* nodes, but we don't support
// upgrading them and we want to reserve the namespace for future uses.
- if (NMD.getName().startswith("llvm.dbg."))
+ if (NMD.getName().starts_with("llvm.dbg."))
CheckDI(NMD.getName() == "llvm.dbg.cu",
"unrecognized named metadata node in the llvm.dbg namespace", &NMD);
for (const MDNode *MD : NMD.operands()) {
@@ -2229,13 +2229,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
}
// Check EVEX512 feature.
- if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features")) {
- Triple T(M.getTargetTriple());
- if (T.isX86()) {
- StringRef TF = Attrs.getFnAttr("target-features").getValueAsString();
- Check(!TF.contains("+avx512f") || !TF.contains("-evex512"),
- "512-bit vector arguments require 'evex512' for AVX512", V);
- }
+ if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features") &&
+ TT.isX86()) {
+ StringRef TF = Attrs.getFnAttr("target-features").getValueAsString();
+ Check(!TF.contains("+avx512f") || !TF.contains("-evex512"),
+ "512-bit vector arguments require 'evex512' for AVX512", V);
}
checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-prefix", V);
@@ -5374,7 +5372,7 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
Check(cast<ConstantInt>(Call.getArgOperand(1))->getZExtValue() < 2,
"rw argument to llvm.prefetch must be 0-1", Call);
Check(cast<ConstantInt>(Call.getArgOperand(2))->getZExtValue() < 4,
- "locality argument to llvm.prefetch must be 0-4", Call);
+ "locality argument to llvm.prefetch must be 0-3", Call);
Check(cast<ConstantInt>(Call.getArgOperand(3))->getZExtValue() < 2,
"cache type argument to llvm.prefetch must be 0-1", Call);
break;
diff --git a/llvm/lib/InterfaceStub/IFSHandler.cpp b/llvm/lib/InterfaceStub/IFSHandler.cpp
index aa5817dceed5..da46592bd381 100644
--- a/llvm/lib/InterfaceStub/IFSHandler.cpp
+++ b/llvm/lib/InterfaceStub/IFSHandler.cpp
@@ -167,7 +167,7 @@ template <> struct MappingTraits<IFSStubTriple> {
bool usesTriple(StringRef Buf) {
for (line_iterator I(MemoryBufferRef(Buf, "ELFStub")); !I.is_at_eof(); ++I) {
StringRef Line = (*I).trim();
- if (Line.startswith("Target:")) {
+ if (Line.starts_with("Target:")) {
if (Line == "Target:" || Line.contains("{")) {
return false;
}
diff --git a/llvm/lib/LTO/LTOModule.cpp b/llvm/lib/LTO/LTOModule.cpp
index 868169e78225..f839fe944e18 100644
--- a/llvm/lib/LTO/LTOModule.cpp
+++ b/llvm/lib/LTO/LTOModule.cpp
@@ -91,7 +91,7 @@ bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer,
expectedToErrorOrAndEmitErrors(Context, getBitcodeTargetTriple(*BCOrErr));
if (!TripleOrErr)
return false;
- return StringRef(*TripleOrErr).startswith(TriplePrefix);
+ return StringRef(*TripleOrErr).starts_with(TriplePrefix);
}
std::string LTOModule::getProducerString(MemoryBuffer *Buffer) {
@@ -382,17 +382,17 @@ void LTOModule::addDefinedDataSymbol(StringRef Name, const GlobalValue *v) {
// special case if this data blob is an ObjC class definition
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(v)) {
StringRef Section = GV->getSection();
- if (Section.startswith("__OBJC,__class,")) {
+ if (Section.starts_with("__OBJC,__class,")) {
addObjCClass(GV);
}
// special case if this data blob is an ObjC category definition
- else if (Section.startswith("__OBJC,__category,")) {
+ else if (Section.starts_with("__OBJC,__category,")) {
addObjCCategory(GV);
}
// special case if this data blob is the list of referenced classes
- else if (Section.startswith("__OBJC,__cls_refs,")) {
+ else if (Section.starts_with("__OBJC,__cls_refs,")) {
addObjCClassRef(GV);
}
}
diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp
index 5d8fae28bf40..1bd562d1e8ae 100644
--- a/llvm/lib/Linker/IRMover.cpp
+++ b/llvm/lib/Linker/IRMover.cpp
@@ -1569,7 +1569,7 @@ Error IRLinker::run() {
std::string ModuleId = SrcM->getModuleIdentifier();
StringRef FileName = llvm::sys::path::filename(ModuleId);
bool SrcIsLibDevice =
- FileName.startswith("libdevice") && FileName.endswith(".10.bc");
+ FileName.starts_with("libdevice") && FileName.ends_with(".10.bc");
bool SrcHasLibDeviceDL =
(SrcM->getDataLayoutStr().empty() ||
SrcM->getDataLayoutStr() == "e-i64:64-v16:16-v32:32-n16:32:64");
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
index e4d18d8a7dd5..cb8af1aa9955 100644
--- a/llvm/lib/MC/ELFObjectWriter.cpp
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -72,7 +72,7 @@ class ELFObjectWriter;
struct ELFWriter;
bool isDwoSection(const MCSectionELF &Sec) {
- return Sec.getName().endswith(".dwo");
+ return Sec.getName().ends_with(".dwo");
}
class SymbolTableWriter {
@@ -872,7 +872,7 @@ void ELFWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec,
const DebugCompressionType CompressionType = MAI->compressDebugSections();
if (CompressionType == DebugCompressionType::None ||
- !SectionName.startswith(".debug_")) {
+ !SectionName.starts_with(".debug_")) {
Asm.writeSectionData(W.OS, &Section, Layout);
return;
}
@@ -1250,7 +1250,7 @@ void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
StringRef Prefix = AliasName.substr(0, Pos);
StringRef Rest = AliasName.substr(Pos);
StringRef Tail = Rest;
- if (Rest.startswith("@@@"))
+ if (Rest.starts_with("@@@"))
Tail = Rest.substr(Symbol.isUndefined() ? 2 : 1);
auto *Alias =
@@ -1268,8 +1268,8 @@ void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
if (!Symbol.isUndefined() && S.KeepOriginalSym)
continue;
- if (Symbol.isUndefined() && Rest.startswith("@@") &&
- !Rest.startswith("@@@")) {
+ if (Symbol.isUndefined() && Rest.starts_with("@@") &&
+ !Rest.starts_with("@@@")) {
Asm.getContext().reportError(S.Loc, "default version symbol " +
AliasName + " must be defined");
continue;
@@ -1287,7 +1287,7 @@ void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
for (const MCSymbol *&Sym : AddrsigSyms) {
if (const MCSymbol *R = Renames.lookup(cast<MCSymbolELF>(Sym)))
Sym = R;
- if (Sym->isInSection() && Sym->getName().startswith(".L"))
+ if (Sym->isInSection() && Sym->getName().starts_with(".L"))
Sym = Sym->getSection().getBeginSymbol();
Sym->setUsedInReloc();
}
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 5a157fc36d8e..9e1d108ac14d 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -467,12 +467,12 @@ void MCAsmStreamer::addExplicitComment(const Twine &T) {
StringRef c = T.getSingleStringRef();
if (c.equals(StringRef(MAI->getSeparatorString())))
return;
- if (c.startswith(StringRef("//"))) {
+ if (c.starts_with(StringRef("//"))) {
ExplicitCommentToEmit.append("\t");
ExplicitCommentToEmit.append(MAI->getCommentString());
// drop //
ExplicitCommentToEmit.append(c.slice(2, c.size()).str());
- } else if (c.startswith(StringRef("/*"))) {
+ } else if (c.starts_with(StringRef("/*"))) {
size_t p = 2, len = c.size() - 2;
// emit each line in comment as separate newline.
do {
@@ -485,7 +485,7 @@ void MCAsmStreamer::addExplicitComment(const Twine &T) {
ExplicitCommentToEmit.append("\n");
p = newp + 1;
} while (p < len);
- } else if (c.startswith(StringRef(MAI->getCommentString()))) {
+ } else if (c.starts_with(StringRef(MAI->getCommentString()))) {
ExplicitCommentToEmit.append("\t");
ExplicitCommentToEmit.append(c.str());
} else if (c.front() == '#') {
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index ba4e1c3c4107..6e72b5062a1d 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -271,7 +271,7 @@ MCSymbol *MCContext::createSymbol(StringRef Name, bool AlwaysAddSuffix,
// label, if used.
bool IsTemporary = CanBeUnnamed;
if (AllowTemporaryLabels && !IsTemporary)
- IsTemporary = Name.startswith(MAI->getPrivateGlobalPrefix());
+ IsTemporary = Name.starts_with(MAI->getPrivateGlobalPrefix());
SmallString<128> NewName = Name;
bool AddSuffix = AlwaysAddSuffix;
@@ -382,8 +382,8 @@ MCContext::createXCOFFSymbolImpl(const StringMapEntry<bool> *Name,
return new (nullptr, *this) MCSymbolXCOFF(nullptr, IsTemporary);
StringRef OriginalName = Name->first();
- if (OriginalName.startswith("._Renamed..") ||
- OriginalName.startswith("_Renamed.."))
+ if (OriginalName.starts_with("._Renamed..") ||
+ OriginalName.starts_with("_Renamed.."))
reportError(SMLoc(), "invalid symbol name from source");
if (MAI->isValidUnquotedName(OriginalName))
@@ -628,8 +628,8 @@ void MCContext::recordELFMergeableSectionInfo(StringRef SectionName,
}
bool MCContext::isELFImplicitMergeableSectionNamePrefix(StringRef SectionName) {
- return SectionName.startswith(".rodata.str") ||
- SectionName.startswith(".rodata.cst");
+ return SectionName.starts_with(".rodata.str") ||
+ SectionName.starts_with(".rodata.cst");
}
bool MCContext::isELFGenericMergeableSection(StringRef SectionName) {
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index f94fc48a033d..d0face9140de 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -1211,7 +1211,7 @@ void MCGenDwarfLabelEntry::Make(MCSymbol *Symbol, MCStreamer *MCOS,
// The dwarf label's name does not have the symbol name's leading
// underbar if any.
StringRef Name = Symbol->getName();
- if (Name.startswith("_"))
+ if (Name.starts_with("_"))
Name = Name.substr(1, Name.size()-1);
// Get the dwarf file number to be used for the dwarf label.
diff --git a/llvm/lib/MC/MCParser/AsmLexer.cpp b/llvm/lib/MC/MCParser/AsmLexer.cpp
index f13549b24e2d..e08404ae0ad9 100644
--- a/llvm/lib/MC/MCParser/AsmLexer.cpp
+++ b/llvm/lib/MC/MCParser/AsmLexer.cpp
@@ -32,7 +32,7 @@
using namespace llvm;
AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI) {
- AllowAtInIdentifier = !StringRef(MAI.getCommentString()).startswith("@");
+ AllowAtInIdentifier = !StringRef(MAI.getCommentString()).starts_with("@");
LexMotorolaIntegers = MAI.shouldUseMotorolaIntegers();
}
@@ -605,7 +605,7 @@ AsmToken AsmLexer::LexSingleQuote() {
StringRef Res = StringRef(TokStart,CurPtr - TokStart);
long long Value;
- if (Res.startswith("\'\\")) {
+ if (Res.starts_with("\'\\")) {
char theChar = Res[2];
switch (theChar) {
default: Value = theChar; break;
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index 825b12e037d3..8e508dbdb1c6 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -1991,7 +1991,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
// Otherwise, we have a normal instruction or directive.
// Directives start with "."
- if (IDVal.startswith(".") && IDVal != ".") {
+ if (IDVal.starts_with(".") && IDVal != ".") {
// There are several entities interested in parsing directives:
//
// 1. The target-specific assembly parser. Some directives are target
diff --git a/llvm/lib/MC/MCParser/COFFMasmParser.cpp b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
index 34aa5bf2ae39..8adb0dcddb16 100644
--- a/llvm/lib/MC/MCParser/COFFMasmParser.cpp
+++ b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
@@ -250,7 +250,7 @@ bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive, SMLoc Loc) {
SmallVector<char, 247> SectionNameVector;
StringRef Class;
- if (SegmentName == "_TEXT" || SegmentName.startswith("_TEXT$")) {
+ if (SegmentName == "_TEXT" || SegmentName.starts_with("_TEXT$")) {
if (SegmentName.size() == 5) {
SectionName = ".text";
} else {
diff --git a/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
index dbfe0d83e1b2..93e1d2f44b8c 100644
--- a/llvm/lib/MC/MCParser/ELFAsmParser.cpp
+++ b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
@@ -531,7 +531,7 @@ static bool allowSectionTypeMismatch(const Triple &TT, StringRef SectionName,
// MIPS .debug_* sections should have SHT_MIPS_DWARF section type to
// distinguish among sections contain DWARF and ECOFF debug formats,
// but in assembly files these sections have SHT_PROGBITS type.
- return SectionName.startswith(".debug_") && Type == ELF::SHT_PROGBITS;
+ return SectionName.starts_with(".debug_") && Type == ELF::SHT_PROGBITS;
}
return false;
}
@@ -634,7 +634,7 @@ EndStmt:
unsigned Type = ELF::SHT_PROGBITS;
if (TypeName.empty()) {
- if (SectionName.startswith(".note"))
+ if (SectionName.starts_with(".note"))
Type = ELF::SHT_NOTE;
else if (hasPrefix(SectionName, ".init_array"))
Type = ELF::SHT_INIT_ARRAY;
diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp
index 8960e739365c..51563ea86a6c 100644
--- a/llvm/lib/MC/MCParser/MasmParser.cpp
+++ b/llvm/lib/MC/MCParser/MasmParser.cpp
@@ -2117,7 +2117,7 @@ bool MasmParser::parseStatement(ParseStatementInfo &Info,
// Treat ".<number>" as a valid identifier in this context.
IDVal = getTok().getString();
Lex(); // always eat a token
- if (!IDVal.startswith("."))
+ if (!IDVal.starts_with("."))
return Error(IDLoc, "unexpected token at start of statement");
} else if (parseIdentifier(IDVal, StartOfStatement)) {
if (!TheCondState.Ignore) {
@@ -7190,7 +7190,7 @@ bool MasmParser::parseDirectiveRadix(SMLoc DirectiveLoc) {
bool MasmParser::parseDirectiveEcho(SMLoc DirectiveLoc) {
std::string Message = parseStringTo(AsmToken::EndOfStatement);
llvm::outs() << Message;
- if (!StringRef(Message).endswith("\n"))
+ if (!StringRef(Message).ends_with("\n"))
llvm::outs() << '\n';
return false;
}
diff --git a/llvm/lib/MC/StringTableBuilder.cpp b/llvm/lib/MC/StringTableBuilder.cpp
index 0e4f72e13615..df316bae98ce 100644
--- a/llvm/lib/MC/StringTableBuilder.cpp
+++ b/llvm/lib/MC/StringTableBuilder.cpp
@@ -150,7 +150,7 @@ void StringTableBuilder::finalizeStringTable(bool Optimize) {
StringRef Previous;
for (StringPair *P : Strings) {
StringRef S = P->first.val();
- if (Previous.endswith(S)) {
+ if (Previous.ends_with(S)) {
size_t Pos = Size - S.size() - (K != RAW);
if (isAligned(Alignment, Pos)) {
P->second = Pos;
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index b99df3837cc2..fd48d5080ff6 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -193,7 +193,7 @@ static void patchI64(raw_pwrite_stream &Stream, uint64_t Value,
}
bool isDwoSection(const MCSection &Sec) {
- return Sec.getName().endswith(".dwo");
+ return Sec.getName().ends_with(".dwo");
}
class WasmObjectWriter : public MCObjectWriter {
@@ -529,7 +529,7 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
const auto *SymA = cast<MCSymbolWasm>(&RefA->getSymbol());
// The .init_array isn't translated as data, so don't do relocations in it.
- if (FixupSection.getName().startswith(".init_array")) {
+ if (FixupSection.getName().starts_with(".init_array")) {
SymA->setUsedInInitArray();
return;
}
@@ -1491,7 +1491,7 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
<< Section.getGroup() << "\n";);
// .init_array sections are handled specially elsewhere.
- if (SectionName.startswith(".init_array"))
+ if (SectionName.starts_with(".init_array"))
continue;
// Code is handled separately
@@ -1526,7 +1526,7 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
StringRef Name = SectionName;
// For user-defined custom sections, strip the prefix
- if (Name.startswith(".custom_section."))
+ if (Name.starts_with(".custom_section."))
Name = Name.substr(strlen(".custom_section."));
MCSymbol *Begin = Sec.getBeginSymbol();
@@ -1851,9 +1851,9 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
// Translate .init_array section contents into start functions.
for (const MCSection &S : Asm) {
const auto &WS = static_cast<const MCSectionWasm &>(S);
- if (WS.getName().startswith(".fini_array"))
+ if (WS.getName().starts_with(".fini_array"))
report_fatal_error(".fini_array sections are unsupported");
- if (!WS.getName().startswith(".init_array"))
+ if (!WS.getName().starts_with(".init_array"))
continue;
if (WS.getFragmentList().empty())
continue;
diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp
index 1f73cb9884e0..f265fafa59e7 100644
--- a/llvm/lib/MC/WinCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp
@@ -241,7 +241,7 @@ public:
} // end anonymous namespace
static bool isDwoSection(const MCSection &Sec) {
- return Sec.getName().endswith(".dwo");
+ return Sec.getName().ends_with(".dwo");
}
//------------------------------------------------------------------------------
diff --git a/llvm/lib/ObjCopy/COFF/COFFObjcopy.cpp b/llvm/lib/ObjCopy/COFF/COFFObjcopy.cpp
index 622726be8ce5..782d5b2f70c3 100644
--- a/llvm/lib/ObjCopy/COFF/COFFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/COFF/COFFObjcopy.cpp
@@ -29,7 +29,7 @@ using namespace object;
using namespace COFF;
static bool isDebugSection(const Section &Sec) {
- return Sec.Name.startswith(".debug");
+ return Sec.Name.starts_with(".debug");
}
static uint64_t getNextRVA(const Object &Obj) {
diff --git a/llvm/lib/ObjCopy/ConfigManager.cpp b/llvm/lib/ObjCopy/ConfigManager.cpp
index bccb2903e62a..10ece49028f2 100644
--- a/llvm/lib/ObjCopy/ConfigManager.cpp
+++ b/llvm/lib/ObjCopy/ConfigManager.cpp
@@ -23,7 +23,8 @@ Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {
Common.ExtractDWO || Common.PreserveDates || Common.StripDWO ||
Common.StripNonAlloc || Common.StripSections || Common.Weaken ||
Common.DecompressDebugSections ||
- Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty())
+ Common.DiscardMode == DiscardType::Locals ||
+ !Common.SymbolsToAdd.empty() || Common.GapFill != 0 || Common.PadTo != 0)
return createStringError(llvm::errc::invalid_argument,
"option is not supported for COFF");
@@ -42,7 +43,8 @@ Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
Common.PreserveDates || Common.StripAllGNU || Common.StripDWO ||
Common.StripNonAlloc || Common.StripSections ||
Common.DecompressDebugSections || Common.StripUnneeded ||
- Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty())
+ Common.DiscardMode == DiscardType::Locals ||
+ !Common.SymbolsToAdd.empty() || Common.GapFill != 0 || Common.PadTo != 0)
return createStringError(llvm::errc::invalid_argument,
"option is not supported for MachO");
@@ -60,7 +62,8 @@ Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
!Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
!Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
!Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() ||
- !Common.SymbolsToRename.empty())
+ !Common.SymbolsToRename.empty() || Common.GapFill != 0 ||
+ Common.PadTo != 0)
return createStringError(llvm::errc::invalid_argument,
"only flags for section dumping, removal, and "
"addition are supported");
@@ -86,7 +89,8 @@ Expected<const XCOFFConfig &> ConfigManager::getXCOFFConfig() const {
Common.ExtractMainPartition || Common.OnlyKeepDebug ||
Common.PreserveDates || Common.StripAllGNU || Common.StripDWO ||
Common.StripDebug || Common.StripNonAlloc || Common.StripSections ||
- Common.Weaken || Common.StripUnneeded || Common.DecompressDebugSections) {
+ Common.Weaken || Common.StripUnneeded || Common.DecompressDebugSections ||
+ Common.GapFill != 0 || Common.PadTo != 0) {
return createStringError(
llvm::errc::invalid_argument,
"no flags are supported yet, only basic copying is allowed");
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 9d02ba051a0a..daf03810fd7b 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -52,11 +52,11 @@ using namespace llvm::object;
using SectionPred = std::function<bool(const SectionBase &Sec)>;
static bool isDebugSection(const SectionBase &Sec) {
- return StringRef(Sec.Name).startswith(".debug") || Sec.Name == ".gdb_index";
+ return StringRef(Sec.Name).starts_with(".debug") || Sec.Name == ".gdb_index";
}
static bool isDWOSection(const SectionBase &Sec) {
- return StringRef(Sec.Name).endswith(".dwo");
+ return StringRef(Sec.Name).ends_with(".dwo");
}
static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
@@ -180,7 +180,7 @@ static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,
ElfType OutputElfType) {
switch (Config.OutputFormat) {
case FileFormat::Binary:
- return std::make_unique<BinaryWriter>(Obj, Out);
+ return std::make_unique<BinaryWriter>(Obj, Out, Config);
case FileFormat::IHex:
return std::make_unique<IHexWriter>(Obj, Out);
default:
@@ -214,7 +214,7 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
static bool isCompressable(const SectionBase &Sec) {
return !(Sec.Flags & ELF::SHF_COMPRESSED) &&
- StringRef(Sec.Name).startswith(".debug");
+ StringRef(Sec.Name).starts_with(".debug");
}
static Error replaceDebugSections(
@@ -248,7 +248,7 @@ static bool isAArch64MappingSymbol(const Symbol &Sym) {
StringRef Name = Sym.Name;
if (!Name.consume_front("$x") && !Name.consume_front("$d"))
return false;
- return Name.empty() || Name.startswith(".");
+ return Name.empty() || Name.starts_with(".");
}
static bool isArmMappingSymbol(const Symbol &Sym) {
@@ -259,7 +259,7 @@ static bool isArmMappingSymbol(const Symbol &Sym) {
if (!Name.consume_front("$a") && !Name.consume_front("$d") &&
!Name.consume_front("$t"))
return false;
- return Name.empty() || Name.startswith(".");
+ return Name.empty() || Name.starts_with(".");
}
// Check if the symbol should be preserved because it is required by ABI.
@@ -361,7 +361,7 @@ static Error updateAndRemoveSymbols(const CommonConfig &Config,
if ((Config.DiscardMode == DiscardType::All ||
(Config.DiscardMode == DiscardType::Locals &&
- StringRef(Sym.Name).startswith(".L"))) &&
+ StringRef(Sym.Name).starts_with(".L"))) &&
Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF &&
Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
return true;
@@ -448,7 +448,7 @@ static Error replaceAndRemoveSections(const CommonConfig &Config,
return true;
if (&Sec == Obj.SectionNames)
return false;
- if (StringRef(Sec.Name).startswith(".gnu.warning"))
+ if (StringRef(Sec.Name).starts_with(".gnu.warning"))
return false;
// We keep the .ARM.attribute section to maintain compatibility
// with Debian derived distributions. This is a bug in their
@@ -662,7 +662,7 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
OwnedDataSection &NewSection =
Obj.addSection<OwnedDataSection>(Name, Data);
- if (Name.startswith(".note") && Name != ".note.GNU-stack")
+ if (Name.starts_with(".note") && Name != ".note.GNU-stack")
NewSection.Type = SHT_NOTE;
return Error::success();
};
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 0a54d3798d8b..5352736bdcb9 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2636,9 +2636,36 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
}
Error BinaryWriter::write() {
- for (const SectionBase &Sec : Obj.allocSections())
+ SmallVector<const SectionBase *, 30> SectionsToWrite;
+ for (const SectionBase &Sec : Obj.allocSections()) {
+ if (Sec.Type != SHT_NOBITS)
+ SectionsToWrite.push_back(&Sec);
+ }
+
+ if (SectionsToWrite.empty())
+ return Error::success();
+
+ llvm::stable_sort(SectionsToWrite,
+ [](const SectionBase *LHS, const SectionBase *RHS) {
+ return LHS->Offset < RHS->Offset;
+ });
+
+ assert(SectionsToWrite.front()->Offset == 0);
+
+ for (size_t i = 0; i != SectionsToWrite.size(); ++i) {
+ const SectionBase &Sec = *SectionsToWrite[i];
if (Error Err = Sec.accept(*SecWriter))
return Err;
+ if (GapFill == 0)
+ continue;
+ uint64_t PadOffset = (i < SectionsToWrite.size() - 1)
+ ? SectionsToWrite[i + 1]->Offset
+ : Buf->getBufferSize();
+ assert(PadOffset <= Buf->getBufferSize());
+ assert(Sec.Offset + Sec.Size <= PadOffset);
+ std::fill(Buf->getBufferStart() + Sec.Offset + Sec.Size,
+ Buf->getBufferStart() + PadOffset, GapFill);
+ }
// TODO: Implement direct writing to the output stream (without intermediate
// memory buffer Buf).
@@ -2664,7 +2691,7 @@ Error BinaryWriter::finalize() {
// file size. This might not be the same as the offset returned by
// layoutSections, because we want to truncate the last segment to the end of
// its last non-empty section, to match GNU objcopy's behaviour.
- TotalSize = 0;
+ TotalSize = PadTo > MinAddr ? PadTo - MinAddr : 0;
for (SectionBase &Sec : Obj.allocSections())
if (Sec.Type != SHT_NOBITS && Sec.Size > 0) {
Sec.Offset = Sec.Addr - MinAddr;
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 89a03b3fe0ee..95bea0964eae 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -357,6 +357,8 @@ public:
class BinaryWriter : public Writer {
private:
+ const uint8_t GapFill;
+ const uint64_t PadTo;
std::unique_ptr<BinarySectionWriter> SecWriter;
uint64_t TotalSize = 0;
@@ -365,7 +367,8 @@ public:
~BinaryWriter() {}
Error finalize() override;
Error write() override;
- BinaryWriter(Object &Obj, raw_ostream &Out) : Writer(Obj, Out) {}
+ BinaryWriter(Object &Obj, raw_ostream &Out, const CommonConfig &Config)
+ : Writer(Obj, Out), GapFill(Config.GapFill), PadTo(Config.PadTo) {}
};
class IHexWriter : public Writer {
diff --git a/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp b/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp
index 067ef39d9052..a3d4ba3a94f7 100644
--- a/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp
+++ b/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp
@@ -10,6 +10,7 @@
#include "llvm/Support/Alignment.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
using namespace llvm;
using namespace llvm::objcopy::macho;
diff --git a/llvm/lib/ObjCopy/MachO/MachOObject.cpp b/llvm/lib/ObjCopy/MachO/MachOObject.cpp
index 9a4abadc8710..d593d6788e11 100644
--- a/llvm/lib/ObjCopy/MachO/MachOObject.cpp
+++ b/llvm/lib/ObjCopy/MachO/MachOObject.cpp
@@ -8,6 +8,7 @@
#include "MachOObject.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include <unordered_set>
using namespace llvm;
diff --git a/llvm/lib/ObjCopy/MachO/MachOObject.h b/llvm/lib/ObjCopy/MachO/MachOObject.h
index 1cbd2eb5f320..b3303fd291c8 100644
--- a/llvm/lib/ObjCopy/MachO/MachOObject.h
+++ b/llvm/lib/ObjCopy/MachO/MachOObject.h
@@ -119,8 +119,8 @@ struct SymbolEntry {
}
bool isSwiftSymbol() const {
- return StringRef(Name).startswith("_$s") ||
- StringRef(Name).startswith("_$S");
+ return StringRef(Name).starts_with("_$s") ||
+ StringRef(Name).starts_with("_$S");
}
std::optional<uint32_t> section() const {
diff --git a/llvm/lib/ObjCopy/MachO/MachOReader.cpp b/llvm/lib/ObjCopy/MachO/MachOReader.cpp
index 25f8c020cde9..4549977c12c3 100644
--- a/llvm/lib/ObjCopy/MachO/MachOReader.cpp
+++ b/llvm/lib/ObjCopy/MachO/MachOReader.cpp
@@ -11,6 +11,7 @@
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Errc.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include <memory>
using namespace llvm;
diff --git a/llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp b/llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp
index e5af59f93280..5bba1dea9adf 100644
--- a/llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp
+++ b/llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp
@@ -22,11 +22,11 @@ using namespace object;
using SectionPred = std::function<bool(const Section &Sec)>;
static bool isDebugSection(const Section &Sec) {
- return Sec.Name.startswith(".debug");
+ return Sec.Name.starts_with(".debug");
}
static bool isLinkerSection(const Section &Sec) {
- return Sec.Name.startswith("reloc.") || Sec.Name == "linking";
+ return Sec.Name.starts_with("reloc.") || Sec.Name == "linking";
}
static bool isNameSection(const Section &Sec) { return Sec.Name == "name"; }
diff --git a/llvm/lib/Object/Archive.cpp b/llvm/lib/Object/Archive.cpp
index fdd87824e229..4ac4d727afb6 100644
--- a/llvm/lib/Object/Archive.cpp
+++ b/llvm/lib/Object/Archive.cpp
@@ -227,7 +227,7 @@ Expected<StringRef> BigArchiveMemberHeader::getRawName() const {
StringRef NameTerminator = "`\n";
StringRef NameStringWithNameTerminator =
StringRef(ArMemHdr->Name, NameLenWithPadding + NameTerminator.size());
- if (!NameStringWithNameTerminator.endswith(NameTerminator)) {
+ if (!NameStringWithNameTerminator.ends_with(NameTerminator)) {
uint64_t Offset =
reinterpret_cast<const char *>(ArMemHdr->Name + NameLenWithPadding) -
Parent->getData().data();
@@ -315,7 +315,7 @@ Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const {
return Parent->getStringTable().begin() + StringOffset;
}
- if (Name.startswith("#1/")) {
+ if (Name.starts_with("#1/")) {
uint64_t NameLength;
if (Name.substr(3).rtrim(' ').getAsInteger(10, NameLength)) {
std::string Buf;
@@ -524,7 +524,7 @@ Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err)
// The actual start of the file is after the name and any necessary
// even-alignment padding.
StartOfFile += ((Name.size() + 1) >> 1) << 1;
- } else if (Name.startswith("#1/")) {
+ } else if (Name.starts_with("#1/")) {
uint64_t NameSize;
StringRef RawNameSize = Name.substr(3).rtrim(' ');
if (RawNameSize.getAsInteger(10, NameSize)) {
@@ -671,7 +671,7 @@ Expected<std::unique_ptr<Archive>> Archive::create(MemoryBufferRef Source) {
std::unique_ptr<Archive> Ret;
StringRef Buffer = Source.getBuffer();
- if (Buffer.startswith(BigArchiveMagic))
+ if (Buffer.starts_with(BigArchiveMagic))
Ret = std::make_unique<BigArchive>(Source, Err);
else
Ret = std::make_unique<Archive>(Source, Err);
@@ -711,11 +711,11 @@ Archive::Archive(MemoryBufferRef Source, Error &Err)
ErrorAsOutParameter ErrAsOutParam(&Err);
StringRef Buffer = Data.getBuffer();
// Check for sufficient magic.
- if (Buffer.startswith(ThinArchiveMagic)) {
+ if (Buffer.starts_with(ThinArchiveMagic)) {
IsThin = true;
- } else if (Buffer.startswith(ArchiveMagic)) {
+ } else if (Buffer.starts_with(ArchiveMagic)) {
IsThin = false;
- } else if (Buffer.startswith(BigArchiveMagic)) {
+ } else if (Buffer.starts_with(BigArchiveMagic)) {
Format = K_AIXBIG;
IsThin = false;
return;
@@ -800,7 +800,7 @@ Archive::Archive(MemoryBufferRef Source, Error &Err)
return;
}
- if (Name.startswith("#1/")) {
+ if (Name.starts_with("#1/")) {
Format = K_BSD;
// We know this is BSD, so getName will work since there is no string table.
Expected<StringRef> NameOrErr = C->getName();
diff --git a/llvm/lib/Object/Binary.cpp b/llvm/lib/Object/Binary.cpp
index 0ee9f7fac448..0b9d95485287 100644
--- a/llvm/lib/Object/Binary.cpp
+++ b/llvm/lib/Object/Binary.cpp
@@ -89,6 +89,7 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer,
case file_magic::dxcontainer_object:
case file_magic::offload_bundle:
case file_magic::offload_bundle_compressed:
+ case file_magic::spirv_object:
// Unrecognized object file format.
return errorCodeToError(object_error::invalid_file_type);
case file_magic::offload_binary:
diff --git a/llvm/lib/Object/COFFImportFile.cpp b/llvm/lib/Object/COFFImportFile.cpp
index 2cca1f728cc7..eeb13ffe9c11 100644
--- a/llvm/lib/Object/COFFImportFile.cpp
+++ b/llvm/lib/Object/COFFImportFile.cpp
@@ -91,11 +91,11 @@ static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
// stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
// See the comment in isDecorated in COFFModuleDefinition.cpp for more
// details.
- if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW)
+ if (ExtName.starts_with("_") && ExtName.contains('@') && !MinGW)
return IMPORT_NAME;
if (Sym != ExtName)
return IMPORT_NAME_UNDECORATE;
- if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
+ if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.starts_with("_"))
return IMPORT_NAME_NOPREFIX;
return IMPORT_NAME;
}
@@ -105,7 +105,7 @@ static Expected<std::string> replace(StringRef S, StringRef From,
size_t Pos = S.find(From);
// From and To may be mangled, but substrings in S may not.
- if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
+ if (Pos == StringRef::npos && From.starts_with("_") && To.starts_with("_")) {
From = From.substr(1);
To = To.substr(1);
Pos = S.find(From);
diff --git a/llvm/lib/Object/COFFModuleDefinition.cpp b/llvm/lib/Object/COFFModuleDefinition.cpp
index a33949733c8e..648f01f823d0 100644
--- a/llvm/lib/Object/COFFModuleDefinition.cpp
+++ b/llvm/lib/Object/COFFModuleDefinition.cpp
@@ -74,7 +74,7 @@ static bool isDecorated(StringRef Sym, bool MingwDef) {
// We can't check for a leading underscore here, since function names
// themselves can start with an underscore, while a second one still needs
// to be added.
- return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") ||
+ return Sym.starts_with("@") || Sym.contains("@@") || Sym.starts_with("?") ||
(!MingwDef && Sym.contains('@'));
}
@@ -97,7 +97,7 @@ public:
}
case '=':
Buf = Buf.drop_front();
- if (Buf.startswith("=")) {
+ if (Buf.starts_with("=")) {
Buf = Buf.drop_front();
return Token(EqualEqual, "==");
}
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index 574f7a7cf1f4..8700912614db 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -336,7 +336,7 @@ bool COFFObjectFile::isDebugSection(DataRefImpl Ref) const {
return false;
}
StringRef SectionName = SectionNameOrErr.get();
- return SectionName.startswith(".debug");
+ return SectionName.starts_with(".debug");
}
unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {
@@ -1203,9 +1203,9 @@ COFFObjectFile::getSectionName(const coff_section *Sec) const {
StringRef Name = StringRef(Sec->Name, COFF::NameSize).split('\0').first;
// Check for string table entry. First byte is '/'.
- if (Name.startswith("/")) {
+ if (Name.starts_with("/")) {
uint32_t Offset;
- if (Name.startswith("//")) {
+ if (Name.starts_with("//")) {
if (decodeBase64StringEntry(Name.substr(2), Offset))
return createStringError(object_error::parse_failed,
"invalid section name");
diff --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp
index 433739fdc27d..4aabe9cea3e5 100644
--- a/llvm/lib/Object/DXContainer.cpp
+++ b/llvm/lib/Object/DXContainer.cpp
@@ -301,7 +301,7 @@ Error DirectX::PSVRuntimeInfo::parse(uint16_t ShaderKind) {
// String table starts at a 4-byte offset.
Current = reinterpret_cast<const char *>(
- alignTo<4>(reinterpret_cast<const uintptr_t>(Current)));
+ alignTo<4>(reinterpret_cast<uintptr_t>(Current)));
uint32_t StringTableSize = 0;
if (Error Err = readInteger(Data, Current, StringTableSize))
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 36847d1a2a42..300639f2bfa0 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -646,11 +646,36 @@ ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const {
return base() + Offset;
}
-template <class ELFT>
-Expected<std::vector<BBAddrMap>>
-ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
- const Elf_Shdr *RelaSec) const {
- bool IsRelocatable = getHeader().e_type == ELF::ET_REL;
+// Helper to extract and decode the next ULEB128 value as unsigned int.
+// Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the unsigned
+// int limit.
+// Also returns zero if ULEBSizeErr is already in an error state.
+// ULEBSizeErr is an out variable if an error occurs.
+template <typename IntTy, std::enable_if_t<std::is_unsigned_v<IntTy>, int> = 0>
+static IntTy readULEB128As(DataExtractor &Data, DataExtractor::Cursor &Cur,
+ Error &ULEBSizeErr) {
+ // Bail out and do not extract data if ULEBSizeErr is already set.
+ if (ULEBSizeErr)
+ return 0;
+ uint64_t Offset = Cur.tell();
+ uint64_t Value = Data.getULEB128(Cur);
+ if (Value > std::numeric_limits<IntTy>::max()) {
+ ULEBSizeErr = createError("ULEB128 value at offset 0x" +
+ Twine::utohexstr(Offset) + " exceeds UINT" +
+ Twine(std::numeric_limits<IntTy>::digits) +
+ "_MAX (0x" + Twine::utohexstr(Value) + ")");
+ return 0;
+ }
+ return static_cast<IntTy>(Value);
+}
+
+template <typename ELFT>
+static Expected<std::vector<BBAddrMap>>
+decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
+ const typename ELFFile<ELFT>::Elf_Shdr &Sec,
+ const typename ELFFile<ELFT>::Elf_Shdr *RelaSec,
+ std::vector<PGOAnalysisMap> *PGOAnalyses) {
+ bool IsRelocatable = EF.getHeader().e_type == ELF::ET_REL;
// This DenseMap maps the offset of each function (the location of the
// reference to the function in the SHT_LLVM_BB_ADDR_MAP section) to the
@@ -660,44 +685,28 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
assert(RelaSec &&
"Can't read a SHT_LLVM_BB_ADDR_MAP section in a relocatable "
"object file without providing a relocation section.");
- Expected<Elf_Rela_Range> Relas = this->relas(*RelaSec);
+ Expected<typename ELFFile<ELFT>::Elf_Rela_Range> Relas = EF.relas(*RelaSec);
if (!Relas)
return createError("unable to read relocations for section " +
- describe(*this, Sec) + ": " +
+ describe(EF, Sec) + ": " +
toString(Relas.takeError()));
- for (Elf_Rela Rela : *Relas)
+ for (typename ELFFile<ELFT>::Elf_Rela Rela : *Relas)
FunctionOffsetTranslations[Rela.r_offset] = Rela.r_addend;
}
- Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
+ Expected<ArrayRef<uint8_t>> ContentsOrErr = EF.getSectionContents(Sec);
if (!ContentsOrErr)
return ContentsOrErr.takeError();
ArrayRef<uint8_t> Content = *ContentsOrErr;
- DataExtractor Data(Content, isLE(), ELFT::Is64Bits ? 8 : 4);
+ DataExtractor Data(Content, EF.isLE(), ELFT::Is64Bits ? 8 : 4);
std::vector<BBAddrMap> FunctionEntries;
DataExtractor::Cursor Cur(0);
Error ULEBSizeErr = Error::success();
Error MetadataDecodeErr = Error::success();
- // Helper to extract and decode the next ULEB128 value as uint32_t.
- // Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the uint32_t
- // limit.
- // Also returns zero if ULEBSizeErr is already in an error state.
- auto ReadULEB128AsUInt32 = [&Data, &Cur, &ULEBSizeErr]() -> uint32_t {
- // Bail out and do not extract data if ULEBSizeErr is already set.
- if (ULEBSizeErr)
- return 0;
- uint64_t Offset = Cur.tell();
- uint64_t Value = Data.getULEB128(Cur);
- if (Value > UINT32_MAX) {
- ULEBSizeErr = createError(
- "ULEB128 value at offset 0x" + Twine::utohexstr(Offset) +
- " exceeds UINT32_MAX (0x" + Twine::utohexstr(Value) + ")");
- return 0;
- }
- return static_cast<uint32_t>(Value);
- };
uint8_t Version = 0;
+ uint8_t Feature = 0;
+ PGOAnalysisMap::Features FeatEnable{};
while (!ULEBSizeErr && !MetadataDecodeErr && Cur &&
Cur.tell() < Content.size()) {
if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
@@ -707,10 +716,24 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
if (Version > 2)
return createError("unsupported SHT_LLVM_BB_ADDR_MAP version: " +
Twine(static_cast<int>(Version)));
- Data.getU8(Cur); // Feature byte
+ Feature = Data.getU8(Cur); // Feature byte
+ if (!Cur)
+ break;
+ auto FeatEnableOrErr = PGOAnalysisMap::Features::decode(Feature);
+ if (!FeatEnableOrErr)
+ return FeatEnableOrErr.takeError();
+ FeatEnable =
+ FeatEnableOrErr ? *FeatEnableOrErr : PGOAnalysisMap::Features{};
+ if (Feature != 0 && Version < 2 && Cur)
+ return createError(
+ "version should be >= 2 for SHT_LLVM_BB_ADDR_MAP when "
+ "PGO features are enabled: version = " +
+ Twine(static_cast<int>(Version)) +
+ " feature = " + Twine(static_cast<int>(Feature)));
}
uint64_t SectionOffset = Cur.tell();
- uintX_t Address = static_cast<uintX_t>(Data.getAddress(Cur));
+ auto Address =
+ static_cast<typename ELFFile<ELFT>::uintX_t>(Data.getAddress(Cur));
if (!Cur)
return Cur.takeError();
if (IsRelocatable) {
@@ -719,20 +742,23 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
if (FOTIterator == FunctionOffsetTranslations.end()) {
return createError("failed to get relocation data for offset: " +
Twine::utohexstr(SectionOffset) + " in section " +
- describe(*this, Sec));
+ describe(EF, Sec));
}
Address = FOTIterator->second;
}
- uint32_t NumBlocks = ReadULEB128AsUInt32();
+ uint32_t NumBlocks = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
+
std::vector<BBAddrMap::BBEntry> BBEntries;
uint32_t PrevBBEndOffset = 0;
for (uint32_t BlockIndex = 0;
!MetadataDecodeErr && !ULEBSizeErr && Cur && (BlockIndex < NumBlocks);
++BlockIndex) {
- uint32_t ID = Version >= 2 ? ReadULEB128AsUInt32() : BlockIndex;
- uint32_t Offset = ReadULEB128AsUInt32();
- uint32_t Size = ReadULEB128AsUInt32();
- uint32_t MD = ReadULEB128AsUInt32();
+ uint32_t ID = Version >= 2
+ ? readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr)
+ : BlockIndex;
+ uint32_t Offset = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
+ uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
+ uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
if (Version >= 1) {
// Offset is calculated relative to the end of the previous BB.
Offset += PrevBBEndOffset;
@@ -747,6 +773,44 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
BBEntries.push_back({ID, Offset, Size, *MetadataOrErr});
}
FunctionEntries.emplace_back(Address, std::move(BBEntries));
+
+ if (FeatEnable.FuncEntryCount || FeatEnable.BBFreq || FeatEnable.BrProb) {
+ // Function entry count
+ uint64_t FuncEntryCount =
+ FeatEnable.FuncEntryCount
+ ? readULEB128As<uint64_t>(Data, Cur, ULEBSizeErr)
+ : 0;
+
+ std::vector<PGOAnalysisMap::PGOBBEntry> PGOBBEntries;
+ for (uint32_t BlockIndex = 0; !MetadataDecodeErr && !ULEBSizeErr && Cur &&
+ (BlockIndex < NumBlocks);
+ ++BlockIndex) {
+ // Block frequency
+ uint64_t BBF = FeatEnable.BBFreq
+ ? readULEB128As<uint64_t>(Data, Cur, ULEBSizeErr)
+ : 0;
+
+ // Branch probability
+ llvm::SmallVector<PGOAnalysisMap::PGOBBEntry::SuccessorEntry, 2>
+ Successors;
+ if (FeatEnable.BrProb) {
+ auto SuccCount = readULEB128As<uint64_t>(Data, Cur, ULEBSizeErr);
+ for (uint64_t I = 0; I < SuccCount; ++I) {
+ uint32_t BBID = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
+ uint32_t BrProb = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
+ if (PGOAnalyses)
+ Successors.push_back({BBID, BranchProbability::getRaw(BrProb)});
+ }
+ }
+
+ if (PGOAnalyses)
+ PGOBBEntries.push_back({BlockFrequency(BBF), std::move(Successors)});
+ }
+
+ if (PGOAnalyses)
+ PGOAnalyses->push_back(
+ {FuncEntryCount, std::move(PGOBBEntries), FeatEnable});
+ }
}
// Either Cur is in the error state, or we have an error in ULEBSizeErr or
// MetadataDecodeErr (but not both), but we join all errors here to be safe.
@@ -757,6 +821,18 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
}
template <class ELFT>
+Expected<std::vector<BBAddrMap>>
+ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, const Elf_Shdr *RelaSec,
+ std::vector<PGOAnalysisMap> *PGOAnalyses) const {
+ size_t OriginalPGOSize = PGOAnalyses ? PGOAnalyses->size() : 0;
+ auto AddrMapsOrErr = decodeBBAddrMapImpl(*this, Sec, RelaSec, PGOAnalyses);
+ // remove new analyses when an error occurs
+ if (!AddrMapsOrErr && PGOAnalyses)
+ PGOAnalyses->resize(OriginalPGOSize);
+ return std::move(AddrMapsOrErr);
+}
+
+template <class ELFT>
Expected<
MapVector<const typename ELFT::Shdr *, const typename ELFT::Shdr *>>
ELFFile<ELFT>::getSectionAndRelocations(
diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp
index 25dbcbd68431..3c86b0f25dda 100644
--- a/llvm/lib/Object/ELFObjectFile.cpp
+++ b/llvm/lib/Object/ELFObjectFile.cpp
@@ -716,10 +716,13 @@ std::vector<ELFPltEntry> ELFObjectFileBase::getPltEntries() const {
template <class ELFT>
Expected<std::vector<BBAddrMap>> static readBBAddrMapImpl(
- const ELFFile<ELFT> &EF, std::optional<unsigned> TextSectionIndex) {
+ const ELFFile<ELFT> &EF, std::optional<unsigned> TextSectionIndex,
+ std::vector<PGOAnalysisMap> *PGOAnalyses) {
using Elf_Shdr = typename ELFT::Shdr;
bool IsRelocatable = EF.getHeader().e_type == ELF::ET_REL;
std::vector<BBAddrMap> BBAddrMaps;
+ if (PGOAnalyses)
+ PGOAnalyses->clear();
const auto &Sections = cantFail(EF.sections());
auto IsMatch = [&](const Elf_Shdr &Sec) -> Expected<bool> {
@@ -748,10 +751,13 @@ Expected<std::vector<BBAddrMap>> static readBBAddrMapImpl(
return createError("unable to get relocation section for " +
describe(EF, *Sec));
Expected<std::vector<BBAddrMap>> BBAddrMapOrErr =
- EF.decodeBBAddrMap(*Sec, RelocSec);
- if (!BBAddrMapOrErr)
+ EF.decodeBBAddrMap(*Sec, RelocSec, PGOAnalyses);
+ if (!BBAddrMapOrErr) {
+ if (PGOAnalyses)
+ PGOAnalyses->clear();
return createError("unable to read " + describe(EF, *Sec) + ": " +
toString(BBAddrMapOrErr.takeError()));
+ }
std::move(BBAddrMapOrErr->begin(), BBAddrMapOrErr->end(),
std::back_inserter(BBAddrMaps));
}
@@ -828,13 +834,14 @@ ELFObjectFileBase::readDynsymVersions() const {
}
Expected<std::vector<BBAddrMap>> ELFObjectFileBase::readBBAddrMap(
- std::optional<unsigned> TextSectionIndex) const {
+ std::optional<unsigned> TextSectionIndex,
+ std::vector<PGOAnalysisMap> *PGOAnalyses) const {
if (const auto *Obj = dyn_cast<ELF32LEObjectFile>(this))
- return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex);
+ return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex, PGOAnalyses);
if (const auto *Obj = dyn_cast<ELF64LEObjectFile>(this))
- return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex);
+ return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex, PGOAnalyses);
if (const auto *Obj = dyn_cast<ELF32BEObjectFile>(this))
- return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex);
+ return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex, PGOAnalyses);
return readBBAddrMapImpl(cast<ELF64BEObjectFile>(this)->getELFFile(),
- TextSectionIndex);
+ TextSectionIndex, PGOAnalyses);
}
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 5e6c6ea79427..1cfd0a069463 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -2066,9 +2066,9 @@ bool MachOObjectFile::isDebugSection(DataRefImpl Sec) const {
return false;
}
StringRef SectionName = SectionNameOrErr.get();
- return SectionName.startswith("__debug") ||
- SectionName.startswith("__zdebug") ||
- SectionName.startswith("__apple") || SectionName == "__gdb_index" ||
+ return SectionName.starts_with("__debug") ||
+ SectionName.starts_with("__zdebug") ||
+ SectionName.starts_with("__apple") || SectionName == "__gdb_index" ||
SectionName == "__swift_ast";
}
@@ -2083,7 +2083,7 @@ ArrayRef<uint8_t> getSegmentContents(const MachOObjectFile &Obj,
return {};
}
auto &Segment = SegmentOrErr.get();
- if (StringRef(Segment.segname, 16).startswith(SegmentName))
+ if (StringRef(Segment.segname, 16).starts_with(SegmentName))
return arrayRefFromStringRef(Obj.getData().slice(
Segment.fileoff, Segment.fileoff + Segment.filesize));
return {};
@@ -2469,7 +2469,7 @@ StringRef MachOObjectFile::guessLibraryShortName(StringRef Name,
if (c == Name.npos || c == 0)
goto guess_library;
V = Name.slice(c+1, Name.npos);
- if (!V.startswith("Versions/"))
+ if (!V.starts_with("Versions/"))
goto guess_library;
d = Name.rfind('/', c);
if (d == Name.npos)
diff --git a/llvm/lib/Object/ModuleSymbolTable.cpp b/llvm/lib/Object/ModuleSymbolTable.cpp
index dc73937863e6..ab073e18cb46 100644
--- a/llvm/lib/Object/ModuleSymbolTable.cpp
+++ b/llvm/lib/Object/ModuleSymbolTable.cpp
@@ -215,7 +215,7 @@ uint32_t ModuleSymbolTable::getSymbolFlags(Symbol S) const {
GV->hasExternalWeakLinkage())
Res |= BasicSymbolRef::SF_Weak;
- if (GV->getName().startswith("llvm."))
+ if (GV->getName().starts_with("llvm."))
Res |= BasicSymbolRef::SF_FormatSpecific;
else if (auto *Var = dyn_cast<GlobalVariable>(GV)) {
if (Var->getSection() == "llvm.metadata")
diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp
index 428166f58070..ca921836b7f6 100644
--- a/llvm/lib/Object/ObjectFile.cpp
+++ b/llvm/lib/Object/ObjectFile.cpp
@@ -160,6 +160,7 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type,
case file_magic::dxcontainer_object:
case file_magic::offload_bundle:
case file_magic::offload_bundle_compressed:
+ case file_magic::spirv_object:
return errorCodeToError(object_error::invalid_file_type);
case file_magic::tapi_file:
return errorCodeToError(object_error::invalid_file_type);
diff --git a/llvm/lib/Object/RecordStreamer.cpp b/llvm/lib/Object/RecordStreamer.cpp
index d01076c0bceb..891016cf7475 100644
--- a/llvm/lib/Object/RecordStreamer.cpp
+++ b/llvm/lib/Object/RecordStreamer.cpp
@@ -206,7 +206,7 @@ void RecordStreamer::flushSymverDirectives() {
for (auto AliasName : Symver.second) {
std::pair<StringRef, StringRef> Split = AliasName.split("@@@");
SmallString<128> NewName;
- if (!Split.second.empty() && !Split.second.startswith("@")) {
+ if (!Split.second.empty() && !Split.second.starts_with("@")) {
// Special processing for "@@@" according
// https://sourceware.org/binutils/docs/as/Symver.html
const char *Separator = IsDefined ? "@@" : "@";
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 0982c7e2efbb..168fb57935d6 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -1092,7 +1092,7 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
} else if (Sec.Name == "target_features") {
if (Error Err = parseTargetFeaturesSection(Ctx))
return Err;
- } else if (Sec.Name.startswith("reloc.")) {
+ } else if (Sec.Name.starts_with("reloc.")) {
if (Error Err = parseRelocSection(Sec.Name, Ctx))
return Err;
}
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 40f81f867efa..94b0529f7610 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -32,6 +32,7 @@
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
+#include <variant>
using namespace llvm;
@@ -666,7 +667,7 @@ bool ELFState<ELFT>::initImplicitHeader(ContiguousBlobAccumulator &CBA,
initSymtabSectionHeader(Header, SymtabType::Static, CBA, YAMLSec);
else if (SecName == ".dynsym")
initSymtabSectionHeader(Header, SymtabType::Dynamic, CBA, YAMLSec);
- else if (SecName.startswith(".debug_")) {
+ else if (SecName.starts_with(".debug_")) {
// If a ".debug_*" section's type is a preserved one, e.g., SHT_DYNAMIC, we
// will not treat it as a debug section.
if (YAMLSec && !isa<ELFYAML::RawContentSection>(YAMLSec))
@@ -1390,10 +1391,24 @@ template <class ELFT>
void ELFState<ELFT>::writeSectionContent(
Elf_Shdr &SHeader, const ELFYAML::BBAddrMapSection &Section,
ContiguousBlobAccumulator &CBA) {
- if (!Section.Entries)
+ if (!Section.Entries) {
+ if (Section.PGOAnalyses)
+ WithColor::warning()
+ << "PGOAnalyses should not exist in SHT_LLVM_BB_ADDR_MAP when "
+ "Entries does not exist";
return;
+ }
+
+ const std::vector<ELFYAML::PGOAnalysisMapEntry> *PGOAnalyses = nullptr;
+ if (Section.PGOAnalyses) {
+ if (Section.Entries->size() != Section.PGOAnalyses->size())
+ WithColor::warning() << "PGOAnalyses must be the same length as Entries "
+ "in SHT_LLVM_BB_ADDR_MAP";
+ else
+ PGOAnalyses = &Section.PGOAnalyses.value();
+ }
- for (const ELFYAML::BBAddrMapEntry &E : *Section.Entries) {
+ for (const auto &[Idx, E] : llvm::enumerate(*Section.Entries)) {
// Write version and feature values.
if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP) {
if (E.Version > 2)
@@ -1404,6 +1419,14 @@ void ELFState<ELFT>::writeSectionContent(
CBA.write(E.Feature);
SHeader.sh_size += 2;
}
+
+ if (Section.PGOAnalyses) {
+ if (E.Version < 2)
+ WithColor::warning()
+ << "unsupported SHT_LLVM_BB_ADDR_MAP version when using PGO: "
+ << static_cast<int>(E.Version) << "; must use version >= 2";
+ }
+
// Write the address of the function.
CBA.write<uintX_t>(E.Address, ELFT::TargetEndianness);
// Write number of BBEntries (number of basic blocks in the function). This
@@ -1412,14 +1435,43 @@ void ELFState<ELFT>::writeSectionContent(
E.NumBlocks.value_or(E.BBEntries ? E.BBEntries->size() : 0);
SHeader.sh_size += sizeof(uintX_t) + CBA.writeULEB128(NumBlocks);
// Write all BBEntries.
- if (!E.BBEntries)
+ if (E.BBEntries) {
+ for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *E.BBEntries) {
+ if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP && E.Version > 1)
+ SHeader.sh_size += CBA.writeULEB128(BBE.ID);
+ SHeader.sh_size += CBA.writeULEB128(BBE.AddressOffset) +
+ CBA.writeULEB128(BBE.Size) +
+ CBA.writeULEB128(BBE.Metadata);
+ }
+ }
+
+ if (!PGOAnalyses)
continue;
- for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *E.BBEntries) {
- if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP && E.Version > 1)
- SHeader.sh_size += CBA.writeULEB128(BBE.ID);
- SHeader.sh_size += CBA.writeULEB128(BBE.AddressOffset) +
- CBA.writeULEB128(BBE.Size) +
- CBA.writeULEB128(BBE.Metadata);
+ const ELFYAML::PGOAnalysisMapEntry &PGOEntry = PGOAnalyses->at(Idx);
+
+ if (PGOEntry.FuncEntryCount)
+ SHeader.sh_size += CBA.writeULEB128(*PGOEntry.FuncEntryCount);
+
+ if (!PGOEntry.PGOBBEntries)
+ continue;
+
+ const auto &PGOBBEntries = PGOEntry.PGOBBEntries.value();
+ if (!E.BBEntries || E.BBEntries->size() != PGOBBEntries.size()) {
+ WithColor::warning() << "PBOBBEntries must be the same length as "
+ "BBEntries in SHT_LLVM_BB_ADDR_MAP.\n"
+ << "Mismatch on function with address: "
+ << E.Address;
+ continue;
+ }
+
+ for (const auto &PGOBBE : PGOBBEntries) {
+ if (PGOBBE.BBFreq)
+ SHeader.sh_size += CBA.writeULEB128(*PGOBBE.BBFreq);
+ if (PGOBBE.Successors) {
+ SHeader.sh_size += CBA.writeULEB128(PGOBBE.Successors->size());
+ for (const auto &[ID, BrProb] : *PGOBBE.Successors)
+ SHeader.sh_size += CBA.writeULEB128(ID) + CBA.writeULEB128(BrProb);
+ }
}
}
}
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index c47d4eaa309d..6ad4a067415a 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1291,10 +1291,10 @@ StringRef ScalarTraits<ELFYAML::YAMLIntUInt>::input(StringRef Scalar, void *Ctx,
StringRef ErrMsg = "invalid number";
// We do not accept negative hex numbers because their meaning is ambiguous.
// For example, would -0xfffffffff mean 1 or INT32_MIN?
- if (Scalar.empty() || Scalar.startswith("-0x"))
+ if (Scalar.empty() || Scalar.starts_with("-0x"))
return ErrMsg;
- if (Scalar.startswith("-")) {
+ if (Scalar.starts_with("-")) {
const int64_t MinVal = Is64 ? INT64_MIN : INT32_MIN;
long long Int;
if (getAsSignedInteger(Scalar, /*Radix=*/0, Int) || (Int < MinVal))
@@ -1390,6 +1390,7 @@ static void sectionMapping(IO &IO, ELFYAML::BBAddrMapSection &Section) {
commonSectionMapping(IO, Section);
IO.mapOptional("Content", Section.Content);
IO.mapOptional("Entries", Section.Entries);
+ IO.mapOptional("PGOAnalyses", Section.PGOAnalyses);
}
static void sectionMapping(IO &IO, ELFYAML::StackSizesSection &Section) {
@@ -1559,7 +1560,7 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
// When the Type string does not have a "SHT_" prefix, we know it is not a
// description of a regular ELF output section.
TypeStr = getStringValue(IO, "Type");
- if (TypeStr.startswith("SHT_") || isInteger(TypeStr))
+ if (TypeStr.starts_with("SHT_") || isInteger(TypeStr))
IO.mapRequired("Type", Type);
}
@@ -1825,6 +1826,28 @@ void MappingTraits<ELFYAML::BBAddrMapEntry::BBEntry>::mapping(
IO.mapRequired("Metadata", E.Metadata);
}
+void MappingTraits<ELFYAML::PGOAnalysisMapEntry>::mapping(
+ IO &IO, ELFYAML::PGOAnalysisMapEntry &E) {
+ assert(IO.getContext() && "The IO context is not initialized");
+ IO.mapOptional("FuncEntryCount", E.FuncEntryCount);
+ IO.mapOptional("PGOBBEntries", E.PGOBBEntries);
+}
+
+void MappingTraits<ELFYAML::PGOAnalysisMapEntry::PGOBBEntry>::mapping(
+ IO &IO, ELFYAML::PGOAnalysisMapEntry::PGOBBEntry &E) {
+ assert(IO.getContext() && "The IO context is not initialized");
+ IO.mapOptional("BBFreq", E.BBFreq);
+ IO.mapOptional("Successors", E.Successors);
+}
+
+void MappingTraits<ELFYAML::PGOAnalysisMapEntry::PGOBBEntry::SuccessorEntry>::
+ mapping(IO &IO,
+ ELFYAML::PGOAnalysisMapEntry::PGOBBEntry::SuccessorEntry &E) {
+ assert(IO.getContext() && "The IO context is not initialized");
+ IO.mapRequired("ID", E.ID);
+ IO.mapRequired("BrProb", E.BrProb);
+}
+
void MappingTraits<ELFYAML::GnuHashHeader>::mapping(IO &IO,
ELFYAML::GnuHashHeader &E) {
assert(IO.getContext() && "The IO context is not initialized");
diff --git a/llvm/lib/ObjectYAML/GOFFEmitter.cpp b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
new file mode 100644
index 000000000000..345904407e1d
--- /dev/null
+++ b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
@@ -0,0 +1,282 @@
+//===- yaml2goff - Convert YAML to a GOFF object file ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// The GOFF component of yaml2obj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/IndexedMap.h"
+#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/ConvertEBCDIC.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace {
+
+// Common flag values on records.
+enum {
+ // Flag: This record is continued.
+ Rec_Continued = 1,
+
+ // Flag: This record is a continuation.
+ Rec_Continuation = 1 << (8 - 6 - 1),
+};
+
+template <typename ValueType> struct BinaryBeImpl {
+ ValueType Value;
+ BinaryBeImpl(ValueType V) : Value(V) {}
+};
+
+template <typename ValueType>
+raw_ostream &operator<<(raw_ostream &OS, const BinaryBeImpl<ValueType> &BBE) {
+ char Buffer[sizeof(BBE.Value)];
+ support::endian::write<ValueType, llvm::endianness::big, support::unaligned>(
+ Buffer, BBE.Value);
+ OS.write(Buffer, sizeof(BBE.Value));
+ return OS;
+}
+
+template <typename ValueType> BinaryBeImpl<ValueType> binaryBe(ValueType V) {
+ return BinaryBeImpl<ValueType>(V);
+}
+
+struct ZerosImpl {
+ size_t NumBytes;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const ZerosImpl &Z) {
+ OS.write_zeros(Z.NumBytes);
+ return OS;
+}
+
+ZerosImpl zeros(const size_t NumBytes) { return ZerosImpl{NumBytes}; }
+
+// The GOFFOstream is responsible to write the data into the fixed physical
+// records of the format. A user of this class announces the start of a new
+// logical record and the size of its payload. While writing the payload, the
+// physical records are created for the data. Possible fill bytes at the end of
+// a physical record are written automatically.
+class GOFFOstream : public raw_ostream {
+public:
+ explicit GOFFOstream(raw_ostream &OS)
+ : OS(OS), LogicalRecords(0), RemainingSize(0), NewLogicalRecord(false) {
+ SetBufferSize(GOFF::PayloadLength);
+ }
+
+ ~GOFFOstream() { finalize(); }
+
+ void makeNewRecord(GOFF::RecordType Type, size_t Size) {
+ fillRecord();
+ CurrentType = Type;
+ RemainingSize = Size;
+ if (size_t Gap = (RemainingSize % GOFF::PayloadLength))
+ RemainingSize += GOFF::PayloadLength - Gap;
+ NewLogicalRecord = true;
+ ++LogicalRecords;
+ }
+
+ void finalize() { fillRecord(); }
+
+ uint32_t logicalRecords() { return LogicalRecords; }
+
+private:
+ // The underlying raw_ostream.
+ raw_ostream &OS;
+
+ // The number of logical records emitted so far.
+ uint32_t LogicalRecords;
+
+ // The remaining size of this logical record, including fill bytes.
+ size_t RemainingSize;
+
+ // The type of the current (logical) record.
+ GOFF::RecordType CurrentType;
+
+ // Signals start of new record.
+ bool NewLogicalRecord;
+
+ // Return the number of bytes left to write until next physical record.
+ // Please note that we maintain the total number of bytes left, not the
+ // written size.
+ size_t bytesToNextPhysicalRecord() {
+ size_t Bytes = RemainingSize % GOFF::PayloadLength;
+ return Bytes ? Bytes : GOFF::PayloadLength;
+ }
+
+ // Write the record prefix of a physical record, using the current record
+ // type.
+ static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
+ size_t RemainingSize,
+ uint8_t Flags = Rec_Continuation) {
+ uint8_t TypeAndFlags = Flags | (Type << 4);
+ if (RemainingSize > GOFF::RecordLength)
+ TypeAndFlags |= Rec_Continued;
+ OS << binaryBe(static_cast<unsigned char>(GOFF::PTVPrefix))
+ << binaryBe(static_cast<unsigned char>(TypeAndFlags))
+ << binaryBe(static_cast<unsigned char>(0));
+ }
+
+ // Fill the last physical record of a logical record with zero bytes.
+ void fillRecord() {
+ assert((GetNumBytesInBuffer() <= RemainingSize) &&
+ "More bytes in buffer than expected");
+ size_t Remains = RemainingSize - GetNumBytesInBuffer();
+ if (Remains) {
+ assert((Remains < GOFF::RecordLength) &&
+ "Attempting to fill more than one physical record");
+ raw_ostream::write_zeros(Remains);
+ }
+ flush();
+ assert(RemainingSize == 0 && "Not fully flushed");
+ assert(GetNumBytesInBuffer() == 0 && "Buffer not fully empty");
+ }
+
+ // See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override {
+ assert((RemainingSize >= Size) && "Attempt to write too much data");
+ assert(RemainingSize && "Logical record overflow");
+ if (!(RemainingSize % GOFF::PayloadLength)) {
+ writeRecordPrefix(OS, CurrentType, RemainingSize,
+ NewLogicalRecord ? 0 : Rec_Continuation);
+ NewLogicalRecord = false;
+ }
+ assert(!NewLogicalRecord &&
+ "New logical record not on physical record boundary");
+
+ size_t Idx = 0;
+ while (Size > 0) {
+ size_t BytesToWrite = bytesToNextPhysicalRecord();
+ if (BytesToWrite > Size)
+ BytesToWrite = Size;
+ OS.write(Ptr + Idx, BytesToWrite);
+ Idx += BytesToWrite;
+ Size -= BytesToWrite;
+ RemainingSize -= BytesToWrite;
+ if (Size) {
+ writeRecordPrefix(OS, CurrentType, RemainingSize);
+ }
+ }
+ }
+
+ // Return the current position within the stream, not counting the bytes
+ // currently in the buffer.
+ uint64_t current_pos() const override { return OS.tell(); }
+};
+
+class GOFFState {
+ void writeHeader(GOFFYAML::FileHeader &FileHdr);
+ void writeEnd();
+
+ void reportError(const Twine &Msg) {
+ ErrHandler(Msg);
+ HasError = true;
+ }
+
+ GOFFState(raw_ostream &OS, GOFFYAML::Object &Doc,
+ yaml::ErrorHandler ErrHandler)
+ : GW(OS), Doc(Doc), ErrHandler(ErrHandler), HasError(false) {}
+
+ ~GOFFState() { GW.finalize(); }
+
+ bool writeObject();
+
+public:
+ static bool writeGOFF(raw_ostream &OS, GOFFYAML::Object &Doc,
+ yaml::ErrorHandler ErrHandler);
+
+private:
+ GOFFOstream GW;
+ GOFFYAML::Object &Doc;
+ yaml::ErrorHandler ErrHandler;
+ bool HasError;
+};
+
+void GOFFState::writeHeader(GOFFYAML::FileHeader &FileHdr) {
+ SmallString<16> CCSIDName;
+ if (std::error_code EC =
+ ConverterEBCDIC::convertToEBCDIC(FileHdr.CharacterSetName, CCSIDName))
+ reportError("Conversion error on " + FileHdr.CharacterSetName);
+ if (CCSIDName.size() > 16) {
+ reportError("CharacterSetName too long");
+ CCSIDName.resize(16);
+ }
+ SmallString<16> LangProd;
+ if (std::error_code EC = ConverterEBCDIC::convertToEBCDIC(
+ FileHdr.LanguageProductIdentifier, LangProd))
+ reportError("Conversion error on " + FileHdr.LanguageProductIdentifier);
+ if (LangProd.size() > 16) {
+ reportError("LanguageProductIdentifier too long");
+ LangProd.resize(16);
+ }
+
+ GW.makeNewRecord(GOFF::RT_HDR, GOFF::PayloadLength);
+ GW << binaryBe(FileHdr.TargetEnvironment) // TargetEnvironment
+ << binaryBe(FileHdr.TargetOperatingSystem) // TargetOperatingSystem
+ << zeros(2) // Reserved
+ << binaryBe(FileHdr.CCSID) // CCSID
+ << CCSIDName // CharacterSetName
+ << zeros(16 - CCSIDName.size()) // Fill bytes
+ << LangProd // LanguageProductIdentifier
+ << zeros(16 - LangProd.size()) // Fill bytes
+ << binaryBe(FileHdr.ArchitectureLevel); // ArchitectureLevel
+ // The module propties are optional. Figure out if we need to write them.
+ uint16_t ModPropLen = 0;
+ if (FileHdr.TargetSoftwareEnvironment)
+ ModPropLen = 3;
+ else if (FileHdr.InternalCCSID)
+ ModPropLen = 2;
+ if (ModPropLen) {
+ GW << binaryBe(ModPropLen) << zeros(6);
+ if (ModPropLen >= 2)
+ GW << binaryBe(FileHdr.InternalCCSID ? *FileHdr.InternalCCSID : 0);
+ if (ModPropLen >= 3)
+ GW << binaryBe(FileHdr.TargetSoftwareEnvironment
+ ? *FileHdr.TargetSoftwareEnvironment
+ : 0);
+ }
+}
+
+void GOFFState::writeEnd() {
+ GW.makeNewRecord(GOFF::RT_END, GOFF::PayloadLength);
+ GW << binaryBe(uint8_t(0)) // No entry point
+ << binaryBe(uint8_t(0)) // No AMODE
+ << zeros(3) // Reserved
+ << binaryBe(GW.logicalRecords());
+ // No entry point yet. Automatically fill remaining space with zero bytes.
+ GW.finalize();
+}
+
+bool GOFFState::writeObject() {
+ writeHeader(Doc.Header);
+ if (HasError)
+ return false;
+ writeEnd();
+ return true;
+}
+
+bool GOFFState::writeGOFF(raw_ostream &OS, GOFFYAML::Object &Doc,
+ yaml::ErrorHandler ErrHandler) {
+ GOFFState State(OS, Doc, ErrHandler);
+ return State.writeObject();
+}
+} // namespace
+
+namespace llvm {
+namespace yaml {
+
+bool yaml2goff(llvm::GOFFYAML::Object &Doc, raw_ostream &Out,
+ ErrorHandler ErrHandler) {
+ return GOFFState::writeGOFF(Out, Doc, ErrHandler);
+}
+
+} // namespace yaml
+} // namespace llvm
diff --git a/llvm/lib/ObjectYAML/GOFFYAML.cpp b/llvm/lib/ObjectYAML/GOFFYAML.cpp
new file mode 100644
index 000000000000..ae857980a521
--- /dev/null
+++ b/llvm/lib/ObjectYAML/GOFFYAML.cpp
@@ -0,0 +1,46 @@
+//===-- GOFFYAML.cpp - GOFF YAMLIO implementation ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines classes for handling the YAML representation of GOFF.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ObjectYAML/GOFFYAML.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include <string.h>
+
+namespace llvm {
+namespace GOFFYAML {
+
+Object::Object() {}
+
+} // namespace GOFFYAML
+
+namespace yaml {
+
+void MappingTraits<GOFFYAML::FileHeader>::mapping(
+ IO &IO, GOFFYAML::FileHeader &FileHdr) {
+ IO.mapOptional("TargetEnvironment", FileHdr.TargetEnvironment, 0);
+ IO.mapOptional("TargetOperatingSystem", FileHdr.TargetOperatingSystem, 0);
+ IO.mapOptional("CCSID", FileHdr.CCSID, 0);
+ IO.mapOptional("CharacterSetName", FileHdr.CharacterSetName, "");
+ IO.mapOptional("LanguageProductIdentifier", FileHdr.LanguageProductIdentifier,
+ "");
+ IO.mapOptional("ArchitectureLevel", FileHdr.ArchitectureLevel, 1);
+ IO.mapOptional("InternalCCSID", FileHdr.InternalCCSID);
+ IO.mapOptional("TargetSoftwareEnvironment",
+ FileHdr.TargetSoftwareEnvironment);
+}
+
+void MappingTraits<GOFFYAML::Object>::mapping(IO &IO, GOFFYAML::Object &Obj) {
+ IO.mapTag("!GOFF", true);
+ IO.mapRequired("FileHeader", Obj.Header);
+}
+
+} // namespace yaml
+} // namespace llvm
diff --git a/llvm/lib/ObjectYAML/MachOEmitter.cpp b/llvm/lib/ObjectYAML/MachOEmitter.cpp
index 6bcc2cee27ed..c08b389daea9 100644
--- a/llvm/lib/ObjectYAML/MachOEmitter.cpp
+++ b/llvm/lib/ObjectYAML/MachOEmitter.cpp
@@ -19,6 +19,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LEB128.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp
index 86342c5501c7..82b2eaecec9b 100644
--- a/llvm/lib/ObjectYAML/MachOYAML.cpp
+++ b/llvm/lib/ObjectYAML/MachOYAML.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Host.h"
diff --git a/llvm/lib/ObjectYAML/ObjectYAML.cpp b/llvm/lib/ObjectYAML/ObjectYAML.cpp
index d57e5583016b..1815eaff8e36 100644
--- a/llvm/lib/ObjectYAML/ObjectYAML.cpp
+++ b/llvm/lib/ObjectYAML/ObjectYAML.cpp
@@ -26,6 +26,8 @@ void MappingTraits<YamlObjectFile>::mapping(IO &IO,
MappingTraits<ELFYAML::Object>::mapping(IO, *ObjectFile.Elf);
if (ObjectFile.Coff)
MappingTraits<COFFYAML::Object>::mapping(IO, *ObjectFile.Coff);
+ if (ObjectFile.Goff)
+ MappingTraits<GOFFYAML::Object>::mapping(IO, *ObjectFile.Goff);
if (ObjectFile.MachO)
MappingTraits<MachOYAML::Object>::mapping(IO, *ObjectFile.MachO);
if (ObjectFile.FatMachO)
@@ -46,6 +48,9 @@ void MappingTraits<YamlObjectFile>::mapping(IO &IO,
} else if (IO.mapTag("!COFF")) {
ObjectFile.Coff.reset(new COFFYAML::Object());
MappingTraits<COFFYAML::Object>::mapping(IO, *ObjectFile.Coff);
+ } else if (IO.mapTag("!GOFF")) {
+ ObjectFile.Goff.reset(new GOFFYAML::Object());
+ MappingTraits<GOFFYAML::Object>::mapping(IO, *ObjectFile.Goff);
} else if (IO.mapTag("!mach-o")) {
ObjectFile.MachO.reset(new MachOYAML::Object());
MappingTraits<MachOYAML::Object>::mapping(IO, *ObjectFile.MachO);
diff --git a/llvm/lib/ObjectYAML/yaml2obj.cpp b/llvm/lib/ObjectYAML/yaml2obj.cpp
index 06050e246fbf..b9a9ad639709 100644
--- a/llvm/lib/ObjectYAML/yaml2obj.cpp
+++ b/llvm/lib/ObjectYAML/yaml2obj.cpp
@@ -38,6 +38,8 @@ bool convertYAML(yaml::Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler,
return yaml2elf(*Doc.Elf, Out, ErrHandler, MaxSize);
if (Doc.Coff)
return yaml2coff(*Doc.Coff, Out, ErrHandler);
+ if (Doc.Goff)
+ return yaml2goff(*Doc.Goff, Out, ErrHandler);
if (Doc.MachO || Doc.FatMachO)
return yaml2macho(Doc, Out, ErrHandler);
if (Doc.Minidump)
diff --git a/llvm/lib/Option/ArgList.cpp b/llvm/lib/Option/ArgList.cpp
index 8f764ec779f3..72003e3a5259 100644
--- a/llvm/lib/Option/ArgList.cpp
+++ b/llvm/lib/Option/ArgList.cpp
@@ -185,8 +185,8 @@ const char *ArgList::GetOrMakeJoinedArgString(unsigned Index,
StringRef LHS,
StringRef RHS) const {
StringRef Cur = getArgString(Index);
- if (Cur.size() == LHS.size() + RHS.size() &&
- Cur.startswith(LHS) && Cur.endswith(RHS))
+ if (Cur.size() == LHS.size() + RHS.size() && Cur.starts_with(LHS) &&
+ Cur.ends_with(RHS))
return Cur.data();
return MakeArgString(LHS + RHS);
diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp
index 50eebf1f954b..cf69f6173b6d 100644
--- a/llvm/lib/Option/OptTable.cpp
+++ b/llvm/lib/Option/OptTable.cpp
@@ -152,7 +152,7 @@ static bool isInput(const ArrayRef<StringLiteral> &Prefixes, StringRef Arg) {
if (Arg == "-")
return true;
for (const StringRef &Prefix : Prefixes)
- if (Arg.startswith(Prefix))
+ if (Arg.starts_with(Prefix))
return false;
return true;
}
@@ -161,10 +161,10 @@ static bool isInput(const ArrayRef<StringLiteral> &Prefixes, StringRef Arg) {
static unsigned matchOption(const OptTable::Info *I, StringRef Str,
bool IgnoreCase) {
for (auto Prefix : I->Prefixes) {
- if (Str.startswith(Prefix)) {
+ if (Str.starts_with(Prefix)) {
StringRef Rest = Str.substr(Prefix.size());
bool Matched = IgnoreCase ? Rest.starts_with_insensitive(I->getName())
- : Rest.startswith(I->getName());
+ : Rest.starts_with(I->getName());
if (Matched)
return Prefix.size() + StringRef(I->getName()).size();
}
@@ -175,7 +175,7 @@ static unsigned matchOption(const OptTable::Info *I, StringRef Str,
// Returns true if one of the Prefixes + In.Names matches Option
static bool optionMatches(const OptTable::Info &In, StringRef Option) {
for (auto Prefix : In.Prefixes)
- if (Option.endswith(In.getName()))
+ if (Option.ends_with(In.getName()))
if (Option.slice(0, Option.size() - In.getName().size()) == Prefix)
return true;
return false;
@@ -197,7 +197,7 @@ OptTable::suggestValueCompletions(StringRef Option, StringRef Arg) const {
std::vector<std::string> Result;
for (StringRef Val : Candidates)
- if (Val.startswith(Arg) && Arg.compare(Val))
+ if (Val.starts_with(Arg) && Arg.compare(Val))
Result.push_back(std::string(Val));
return Result;
}
@@ -221,7 +221,7 @@ OptTable::findByPrefix(StringRef Cur, Visibility VisibilityMask,
std::string S = (Prefix + In.getName() + "\t").str();
if (In.HelpText)
S += In.HelpText;
- if (StringRef(S).startswith(Cur) && S != std::string(Cur) + "\t")
+ if (StringRef(S).starts_with(Cur) && S != std::string(Cur) + "\t")
Ret.push_back(S);
}
}
@@ -664,15 +664,24 @@ static void PrintHelpOptionList(raw_ostream &OS, StringRef Title,
const unsigned InitialPad = 2;
for (const OptionInfo &Opt : OptionHelp) {
const std::string &Option = Opt.Name;
- int Pad = OptionFieldWidth - int(Option.size());
+ int Pad = OptionFieldWidth + InitialPad;
+ int FirstLinePad = OptionFieldWidth - int(Option.size());
OS.indent(InitialPad) << Option;
// Break on long option names.
- if (Pad < 0) {
+ if (FirstLinePad < 0) {
OS << "\n";
- Pad = OptionFieldWidth + InitialPad;
+ FirstLinePad = OptionFieldWidth + InitialPad;
+ Pad = FirstLinePad;
}
- OS.indent(Pad + 1) << Opt.HelpText << '\n';
+
+ SmallVector<StringRef> Lines;
+ Opt.HelpText.split(Lines, '\n');
+ assert(Lines.size() && "Expected at least the first line in the help text");
+ auto *LinesIt = Lines.begin();
+ OS.indent(FirstLinePad + 1) << *LinesIt << '\n';
+ while (Lines.end() != ++LinesIt)
+ OS.indent(Pad + 1) << *LinesIt << '\n';
}
}
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index a5f9b5424358..95b9fb7ad735 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -76,8 +76,16 @@
#include "llvm/CodeGen/DwarfEHPrepare.h"
#include "llvm/CodeGen/ExpandLargeDivRem.h"
#include "llvm/CodeGen/ExpandLargeFpConvert.h"
+#include "llvm/CodeGen/ExpandMemCmp.h"
+#include "llvm/CodeGen/GCMetadata.h"
#include "llvm/CodeGen/HardwareLoops.h"
+#include "llvm/CodeGen/IndirectBrExpand.h"
+#include "llvm/CodeGen/InterleavedAccess.h"
+#include "llvm/CodeGen/InterleavedLoadCombine.h"
+#include "llvm/CodeGen/JMCInstrumenter.h"
#include "llvm/CodeGen/SafeStack.h"
+#include "llvm/CodeGen/SelectOptimize.h"
+#include "llvm/CodeGen/SjLjEHPrepare.h"
#include "llvm/CodeGen/TypePromotion.h"
#include "llvm/CodeGen/WasmEHPrepare.h"
#include "llvm/CodeGen/WinEHPrepare.h"
@@ -96,6 +104,7 @@
#include "llvm/Support/Regex.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h"
+#include "llvm/Transforms/CFGuard.h"
#include "llvm/Transforms/Coroutines/CoroCleanup.h"
#include "llvm/Transforms/Coroutines/CoroConditionalWrapper.h"
#include "llvm/Transforms/Coroutines/CoroEarly.h"
@@ -562,7 +571,7 @@ static bool checkParametrizedPassName(StringRef Name, StringRef PassName) {
// normal pass name w/o parameters == default parameters
if (Name.empty())
return true;
- return Name.startswith("<") && Name.endswith(">");
+ return Name.starts_with("<") && Name.ends_with(">");
}
static std::optional<OptimizationLevel> parseOptLevel(StringRef S) {
@@ -734,6 +743,26 @@ Expected<bool> parsePostOrderFunctionAttrsPassOptions(StringRef Params) {
"PostOrderFunctionAttrs");
}
+Expected<CFGuardPass::Mechanism> parseCFGuardPassOptions(StringRef Params) {
+ if (Params.empty())
+ return CFGuardPass::Mechanism::Check;
+
+ auto [Param, RHS] = Params.split(';');
+ if (!RHS.empty())
+ return make_error<StringError>(
+ formatv("too many CFGuardPass parameters '{0}' ", Params).str(),
+ inconvertibleErrorCode());
+
+ if (Param == "check")
+ return CFGuardPass::Mechanism::Check;
+ if (Param == "dispatch")
+ return CFGuardPass::Mechanism::Dispatch;
+
+ return make_error<StringError>(
+ formatv("invalid CFGuardPass mechanism: '{0}' ", Param).str(),
+ inconvertibleErrorCode());
+}
+
Expected<bool> parseEarlyCSEPassOptions(StringRef Params) {
return parseSinglePassOption(Params, "memssa", "EarlyCSE");
}
@@ -1130,8 +1159,8 @@ Expected<bool> parseWinEHPrepareOptions(StringRef Params) {
/// Tests whether a pass name starts with a valid prefix for a default pipeline
/// alias.
static bool startsWithDefaultPipelineAliasPrefix(StringRef Name) {
- return Name.startswith("default") || Name.startswith("thinlto") ||
- Name.startswith("lto");
+ return Name.starts_with("default") || Name.starts_with("thinlto") ||
+ Name.starts_with("lto");
}
/// Tests whether registered callbacks will accept a given pass name.
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index e7f88680655c..5c6c391049a7 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -810,7 +810,7 @@ void PassBuilder::addPGOInstrPasses(ModulePassManager &MPM,
Options.DoCounterPromotion = true;
Options.UseBFIInPromotion = IsCS;
Options.Atomic = AtomicCounterUpdate;
- MPM.addPass(InstrProfiling(Options, IsCS));
+ MPM.addPass(InstrProfilingLoweringPass(Options, IsCS));
}
void PassBuilder::addPGOInstrPassesForO0(
@@ -837,7 +837,7 @@ void PassBuilder::addPGOInstrPassesForO0(
Options.DoCounterPromotion = false;
Options.UseBFIInPromotion = IsCS;
Options.Atomic = AtomicCounterUpdate;
- MPM.addPass(InstrProfiling(Options, IsCS));
+ MPM.addPass(InstrProfilingLoweringPass(Options, IsCS));
}
static InlineParams getInlineParamsFromOptLevel(OptimizationLevel Level) {
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 7462704ec2df..d8fc7cd8a231 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -19,6 +19,7 @@
#define MODULE_ANALYSIS(NAME, CREATE_PASS)
#endif
MODULE_ANALYSIS("callgraph", CallGraphAnalysis())
+MODULE_ANALYSIS("collector-metadata", CollectorMetadataAnalysis())
MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis())
MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis())
MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
@@ -77,10 +78,11 @@ MODULE_PASS("inliner-wrapper-no-mandatory-first",
ModuleInlinerWrapperPass(getInlineParams(), false))
MODULE_PASS("insert-gcov-profiling", GCOVProfilerPass())
MODULE_PASS("instrorderfile", InstrOrderFilePass())
-MODULE_PASS("instrprof", InstrProfiling())
+MODULE_PASS("instrprof", InstrProfilingLoweringPass())
MODULE_PASS("internalize", InternalizePass())
MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass())
MODULE_PASS("iroutliner", IROutlinerPass())
+MODULE_PASS("jmc-instrumenter", JMCInstrumenterPass())
MODULE_PASS("lower-global-dtors", LowerGlobalDtorsPass())
MODULE_PASS("lower-ifunc", LowerIFuncPass())
MODULE_PASS("lowertypetests", LowerTypeTestsPass())
@@ -234,6 +236,7 @@ FUNCTION_ANALYSIS("demanded-bits", DemandedBitsAnalysis())
FUNCTION_ANALYSIS("domfrontier", DominanceFrontierAnalysis())
FUNCTION_ANALYSIS("domtree", DominatorTreeAnalysis())
FUNCTION_ANALYSIS("func-properties", FunctionPropertiesAnalysis())
+FUNCTION_ANALYSIS("gc-function", GCFunctionAnalysis())
FUNCTION_ANALYSIS("inliner-size-estimator", InlineSizeEstimatorAnalysis())
FUNCTION_ANALYSIS("lazy-value-info", LazyValueAnalysis())
FUNCTION_ANALYSIS("loops", LoopAnalysis())
@@ -302,9 +305,10 @@ FUNCTION_PASS("dot-dom-only", DomOnlyPrinter())
FUNCTION_PASS("dot-post-dom", PostDomPrinter())
FUNCTION_PASS("dot-post-dom-only", PostDomOnlyPrinter())
FUNCTION_PASS("dse", DSEPass())
-FUNCTION_PASS("dwarfehprepare", DwarfEHPreparePass(TM))
+FUNCTION_PASS("dwarf-eh-prepare", DwarfEHPreparePass(TM))
FUNCTION_PASS("expand-large-div-rem", ExpandLargeDivRemPass(TM))
FUNCTION_PASS("expand-large-fp-convert", ExpandLargeFpConvertPass(TM))
+FUNCTION_PASS("expand-memcmp", ExpandMemCmpPass(TM))
FUNCTION_PASS("fix-irreducible", FixIrreduciblePass())
FUNCTION_PASS("flattencfg", FlattenCFGPass())
FUNCTION_PASS("float2int", Float2IntPass())
@@ -312,12 +316,15 @@ FUNCTION_PASS("guard-widening", GuardWideningPass())
FUNCTION_PASS("gvn-hoist", GVNHoistPass())
FUNCTION_PASS("gvn-sink", GVNSinkPass())
FUNCTION_PASS("helloworld", HelloWorldPass())
+FUNCTION_PASS("indirectbr-expand", IndirectBrExpandPass(TM))
FUNCTION_PASS("infer-address-spaces", InferAddressSpacesPass())
FUNCTION_PASS("infer-alignment", InferAlignmentPass())
FUNCTION_PASS("inject-tli-mappings", InjectTLIMappings())
FUNCTION_PASS("instcount", InstCountPass())
FUNCTION_PASS("instnamer", InstructionNamerPass())
FUNCTION_PASS("instsimplify", InstSimplifyPass())
+FUNCTION_PASS("interleaved-access", InterleavedAccessPass(TM))
+FUNCTION_PASS("interleaved-load-combine", InterleavedLoadCombinePass(TM))
FUNCTION_PASS("invalidate<all>", InvalidateAllAnalysesPass())
FUNCTION_PASS("irce", IRCEPass())
FUNCTION_PASS("jump-threading", JumpThreadingPass())
@@ -395,9 +402,11 @@ FUNCTION_PASS("safe-stack", SafeStackPass(TM))
FUNCTION_PASS("scalarize-masked-mem-intrin", ScalarizeMaskedMemIntrinPass())
FUNCTION_PASS("scalarizer", ScalarizerPass())
FUNCTION_PASS("sccp", SCCPPass())
+FUNCTION_PASS("select-optimize", SelectOptimizePass(TM))
FUNCTION_PASS("separate-const-offset-from-gep",
SeparateConstOffsetFromGEPPass())
FUNCTION_PASS("sink", SinkingPass())
+FUNCTION_PASS("sjlj-eh-prepare", SjLjEHPreparePass(TM))
FUNCTION_PASS("slp-vectorizer", SLPVectorizerPass())
FUNCTION_PASS("slsr", StraightLineStrengthReducePass())
FUNCTION_PASS("strip-gc-relocates", StripGCRelocates())
@@ -430,6 +439,10 @@ FUNCTION_PASS("wasm-eh-prepare", WasmEHPreparePass())
#define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)
#endif
FUNCTION_PASS_WITH_PARAMS(
+ "cfguard", "CFGuardPass",
+ [](CFGuardPass::Mechanism M) { return CFGuardPass(M); },
+ parseCFGuardPassOptions, "check;dispatch")
+FUNCTION_PASS_WITH_PARAMS(
"early-cse", "EarlyCSEPass",
[](bool UseMemorySSA) { return EarlyCSEPass(UseMemorySSA); },
parseEarlyCSEPassOptions, "memssa")
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index df445c2dd78b..fd1317e3eb25 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -130,6 +130,11 @@ static cl::opt<std::string> IRDumpDirectory(
"files in this directory rather than written to stderr"),
cl::Hidden, cl::value_desc("filename"));
+template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR) {
+ const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
+ return IRPtr ? *IRPtr : nullptr;
+}
+
namespace {
// An option for specifying an executable that will be called with the IR
@@ -147,18 +152,18 @@ static cl::opt<std::string>
/// Extract Module out of \p IR unit. May return nullptr if \p IR does not match
/// certain global filters. Will never return nullptr if \p Force is true.
const Module *unwrapModule(Any IR, bool Force = false) {
- if (const auto **M = llvm::any_cast<const Module *>(&IR))
- return *M;
+ if (const auto *M = unwrapIR<Module>(IR))
+ return M;
- if (const auto **F = llvm::any_cast<const Function *>(&IR)) {
- if (!Force && !isFunctionInPrintList((*F)->getName()))
+ if (const auto *F = unwrapIR<Function>(IR)) {
+ if (!Force && !isFunctionInPrintList(F->getName()))
return nullptr;
- return (*F)->getParent();
+ return F->getParent();
}
- if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR)) {
- for (const LazyCallGraph::Node &N : **C) {
+ if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
+ for (const LazyCallGraph::Node &N : *C) {
const Function &F = N.getFunction();
if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {
return F.getParent();
@@ -168,8 +173,8 @@ const Module *unwrapModule(Any IR, bool Force = false) {
return nullptr;
}
- if (const auto **L = llvm::any_cast<const Loop *>(&IR)) {
- const Function *F = (*L)->getHeader()->getParent();
+ if (const auto *L = unwrapIR<Loop>(IR)) {
+ const Function *F = L->getHeader()->getParent();
if (!Force && !isFunctionInPrintList(F->getName()))
return nullptr;
return F->getParent();
@@ -211,20 +216,20 @@ void printIR(raw_ostream &OS, const Loop *L) {
}
std::string getIRName(Any IR) {
- if (llvm::any_cast<const Module *>(&IR))
+ if (unwrapIR<Module>(IR))
return "[module]";
- if (const auto **F = llvm::any_cast<const Function *>(&IR))
- return (*F)->getName().str();
+ if (const auto *F = unwrapIR<Function>(IR))
+ return F->getName().str();
- if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR))
- return (*C)->getName();
+ if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
+ return C->getName();
- if (const auto **L = llvm::any_cast<const Loop *>(&IR))
- return (*L)->getName().str();
+ if (const auto *L = unwrapIR<Loop>(IR))
+ return L->getName().str();
- if (const auto **MF = llvm::any_cast<const MachineFunction *>(&IR))
- return (*MF)->getName().str();
+ if (const auto *MF = unwrapIR<MachineFunction>(IR))
+ return MF->getName().str();
llvm_unreachable("Unknown wrapped IR type");
}
@@ -246,17 +251,17 @@ bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {
}
bool shouldPrintIR(Any IR) {
- if (const auto **M = llvm::any_cast<const Module *>(&IR))
- return moduleContainsFilterPrintFunc(**M);
+ if (const auto *M = unwrapIR<Module>(IR))
+ return moduleContainsFilterPrintFunc(*M);
- if (const auto **F = llvm::any_cast<const Function *>(&IR))
- return isFunctionInPrintList((*F)->getName());
+ if (const auto *F = unwrapIR<Function>(IR))
+ return isFunctionInPrintList(F->getName());
- if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR))
- return sccContainsFilterPrintFunc(**C);
+ if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
+ return sccContainsFilterPrintFunc(*C);
- if (const auto **L = llvm::any_cast<const Loop *>(&IR))
- return isFunctionInPrintList((*L)->getHeader()->getParent()->getName());
+ if (const auto *L = unwrapIR<Loop>(IR))
+ return isFunctionInPrintList(L->getHeader()->getParent()->getName());
llvm_unreachable("Unknown wrapped IR type");
}
@@ -273,23 +278,23 @@ void unwrapAndPrint(raw_ostream &OS, Any IR) {
return;
}
- if (const auto **M = llvm::any_cast<const Module *>(&IR)) {
- printIR(OS, *M);
+ if (const auto *M = unwrapIR<Module>(IR)) {
+ printIR(OS, M);
return;
}
- if (const auto **F = llvm::any_cast<const Function *>(&IR)) {
- printIR(OS, *F);
+ if (const auto *F = unwrapIR<Function>(IR)) {
+ printIR(OS, F);
return;
}
- if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR)) {
- printIR(OS, *C);
+ if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
+ printIR(OS, C);
return;
}
- if (const auto **L = llvm::any_cast<const Loop *>(&IR)) {
- printIR(OS, *L);
+ if (const auto *L = unwrapIR<Loop>(IR)) {
+ printIR(OS, L);
return;
}
llvm_unreachable("Unknown wrapped IR type");
@@ -320,13 +325,10 @@ std::string makeHTMLReady(StringRef SR) {
// Return the module when that is the appropriate level of comparison for \p IR.
const Module *getModuleForComparison(Any IR) {
- if (const auto **M = llvm::any_cast<const Module *>(&IR))
- return *M;
- if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR))
- return (*C)
- ->begin()
- ->getFunction()
- .getParent();
+ if (const auto *M = unwrapIR<Module>(IR))
+ return M;
+ if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
+ return C->begin()->getFunction().getParent();
return nullptr;
}
@@ -339,8 +341,8 @@ bool isInterestingFunction(const Function &F) {
bool isInteresting(Any IR, StringRef PassID, StringRef PassName) {
if (isIgnored(PassID) || !isPassInPrintList(PassName))
return false;
- if (const auto **F = llvm::any_cast<const Function *>(&IR))
- return isInterestingFunction(**F);
+ if (const auto *F = unwrapIR<Function>(IR))
+ return isInterestingFunction(*F);
return true;
}
@@ -662,12 +664,11 @@ template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
return;
}
- const Function **FPtr = llvm::any_cast<const Function *>(&IR);
- const Function *F = FPtr ? *FPtr : nullptr;
+ const auto *F = unwrapIR<Function>(IR);
if (!F) {
- const Loop **L = llvm::any_cast<const Loop *>(&IR);
+ const auto *L = unwrapIR<Loop>(IR);
assert(L && "Unknown IR unit.");
- F = (*L)->getHeader()->getParent();
+ F = L->getHeader()->getParent();
}
assert(F && "Unknown IR unit.");
generateFunctionData(Data, *F);
@@ -706,21 +707,20 @@ static SmallString<32> getIRFileDisplayName(Any IR) {
stable_hash NameHash = stable_hash_combine_string(M->getName());
unsigned int MaxHashWidth = sizeof(stable_hash) * 8 / 4;
write_hex(ResultStream, NameHash, HexPrintStyle::Lower, MaxHashWidth);
- if (llvm::any_cast<const Module *>(&IR)) {
+ if (unwrapIR<Module>(IR)) {
ResultStream << "-module";
- } else if (const Function **F = llvm::any_cast<const Function *>(&IR)) {
+ } else if (const auto *F = unwrapIR<Function>(IR)) {
ResultStream << "-function-";
- stable_hash FunctionNameHash = stable_hash_combine_string((*F)->getName());
+ stable_hash FunctionNameHash = stable_hash_combine_string(F->getName());
write_hex(ResultStream, FunctionNameHash, HexPrintStyle::Lower,
MaxHashWidth);
- } else if (const LazyCallGraph::SCC **C =
- llvm::any_cast<const LazyCallGraph::SCC *>(&IR)) {
+ } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
ResultStream << "-scc-";
- stable_hash SCCNameHash = stable_hash_combine_string((*C)->getName());
+ stable_hash SCCNameHash = stable_hash_combine_string(C->getName());
write_hex(ResultStream, SCCNameHash, HexPrintStyle::Lower, MaxHashWidth);
- } else if (const Loop **L = llvm::any_cast<const Loop *>(&IR)) {
+ } else if (const auto *L = unwrapIR<Loop>(IR)) {
ResultStream << "-loop-";
- stable_hash LoopNameHash = stable_hash_combine_string((*L)->getName());
+ stable_hash LoopNameHash = stable_hash_combine_string(L->getName());
write_hex(ResultStream, LoopNameHash, HexPrintStyle::Lower, MaxHashWidth);
} else {
llvm_unreachable("Unknown wrapped IR type");
@@ -975,11 +975,10 @@ void OptNoneInstrumentation::registerCallbacks(
}
bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
- const Function **FPtr = llvm::any_cast<const Function *>(&IR);
- const Function *F = FPtr ? *FPtr : nullptr;
+ const auto *F = unwrapIR<Function>(IR);
if (!F) {
- if (const auto **L = llvm::any_cast<const Loop *>(&IR))
- F = (*L)->getHeader()->getParent();
+ if (const auto *L = unwrapIR<Loop>(IR))
+ F = L->getHeader()->getParent();
}
bool ShouldRun = !(F && F->hasOptNone());
if (!ShouldRun && DebugLogging) {
@@ -1054,15 +1053,14 @@ void PrintPassInstrumentation::registerCallbacks(
auto &OS = print();
OS << "Running pass: " << PassID << " on " << getIRName(IR);
- if (const auto **F = llvm::any_cast<const Function *>(&IR)) {
- unsigned Count = (*F)->getInstructionCount();
+ if (const auto *F = unwrapIR<Function>(IR)) {
+ unsigned Count = F->getInstructionCount();
OS << " (" << Count << " instruction";
if (Count != 1)
OS << 's';
OS << ')';
- } else if (const auto **C =
- llvm::any_cast<const LazyCallGraph::SCC *>(&IR)) {
- int Count = (*C)->size();
+ } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
+ int Count = C->size();
OS << " (" << Count << " node";
if (Count != 1)
OS << 's';
@@ -1277,10 +1275,10 @@ bool PreservedCFGCheckerInstrumentation::CFG::invalidate(
static SmallVector<Function *, 1> GetFunctions(Any IR) {
SmallVector<Function *, 1> Functions;
- if (const auto **MaybeF = llvm::any_cast<const Function *>(&IR)) {
- Functions.push_back(*const_cast<Function **>(MaybeF));
- } else if (const auto **MaybeM = llvm::any_cast<const Module *>(&IR)) {
- for (Function &F : **const_cast<Module **>(MaybeM))
+ if (const auto *MaybeF = unwrapIR<Function>(IR)) {
+ Functions.push_back(const_cast<Function *>(MaybeF));
+ } else if (const auto *MaybeM = unwrapIR<Module>(IR)) {
+ for (Function &F : *const_cast<Module *>(MaybeM))
Functions.push_back(&F);
}
return Functions;
@@ -1315,8 +1313,8 @@ void PreservedCFGCheckerInstrumentation::registerCallbacks(
FAM.getResult<PreservedFunctionHashAnalysis>(*F);
}
- if (auto *MaybeM = llvm::any_cast<const Module *>(&IR)) {
- Module &M = **const_cast<Module **>(MaybeM);
+ if (const auto *MPtr = unwrapIR<Module>(IR)) {
+ auto &M = *const_cast<Module *>(MPtr);
MAM.getResult<PreservedModuleHashAnalysis>(M);
}
});
@@ -1374,8 +1372,8 @@ void PreservedCFGCheckerInstrumentation::registerCallbacks(
CheckCFG(P, F->getName(), *GraphBefore,
CFG(F, /* TrackBBLifetime */ false));
}
- if (auto *MaybeM = llvm::any_cast<const Module *>(&IR)) {
- Module &M = **const_cast<Module **>(MaybeM);
+ if (const auto *MPtr = unwrapIR<Module>(IR)) {
+ auto &M = *const_cast<Module *>(MPtr);
if (auto *HashBefore =
MAM.getCachedResult<PreservedModuleHashAnalysis>(M)) {
if (HashBefore->Hash != StructuralHash(M)) {
@@ -1393,11 +1391,10 @@ void VerifyInstrumentation::registerCallbacks(
[this](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
if (isIgnored(P) || P == "VerifierPass")
return;
- const Function **FPtr = llvm::any_cast<const Function *>(&IR);
- const Function *F = FPtr ? *FPtr : nullptr;
+ const auto *F = unwrapIR<Function>(IR);
if (!F) {
- if (const auto **L = llvm::any_cast<const Loop *>(&IR))
- F = (*L)->getHeader()->getParent();
+ if (const auto *L = unwrapIR<Loop>(IR))
+ F = L->getHeader()->getParent();
}
if (F) {
@@ -1409,12 +1406,10 @@ void VerifyInstrumentation::registerCallbacks(
"\"{0}\", compilation aborted!",
P));
} else {
- const Module **MPtr = llvm::any_cast<const Module *>(&IR);
- const Module *M = MPtr ? *MPtr : nullptr;
+ const auto *M = unwrapIR<Module>(IR);
if (!M) {
- if (const auto **C =
- llvm::any_cast<const LazyCallGraph::SCC *>(&IR))
- M = (*C)->begin()->getFunction().getParent();
+ if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
+ M = C->begin()->getFunction().getParent();
}
if (M) {
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 380a3aef9b14..eece6a2cc717 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -30,6 +30,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
+#include <cmath>
#include <cstdint>
#include <iterator>
#include <map>
@@ -221,6 +222,264 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
return LastPoppedValue;
}
+Expected<BitVector> CounterMappingContext::evaluateBitmap(
+ const CounterMappingRegion *MCDCDecision) const {
+ unsigned ID = MCDCDecision->MCDCParams.BitmapIdx;
+ unsigned NC = MCDCDecision->MCDCParams.NumConditions;
+ unsigned SizeInBits = llvm::alignTo(uint64_t(1) << NC, CHAR_BIT);
+ unsigned SizeInBytes = SizeInBits / CHAR_BIT;
+
+ ArrayRef<uint8_t> Bytes(&BitmapBytes[ID], SizeInBytes);
+
+ // Mask each bitmap byte into the BitVector. Go in reverse so that the
+ // bitvector can just be shifted over by one byte on each iteration.
+ BitVector Result(SizeInBits, false);
+ for (auto Byte = std::rbegin(Bytes); Byte != std::rend(Bytes); ++Byte) {
+ uint32_t Data = *Byte;
+ Result <<= CHAR_BIT;
+ Result.setBitsInMask(&Data, 1);
+ }
+ return Result;
+}
+
+class MCDCRecordProcessor {
+ /// A bitmap representing the executed test vectors for a boolean expression.
+ /// Each index of the bitmap corresponds to a possible test vector. An index
+ /// with a bit value of '1' indicates that the corresponding Test Vector
+ /// identified by that index was executed.
+ BitVector &ExecutedTestVectorBitmap;
+
+ /// Decision Region to which the ExecutedTestVectorBitmap applies.
+ CounterMappingRegion &Region;
+
+ /// Array of branch regions corresponding each conditions in the boolean
+ /// expression.
+ ArrayRef<CounterMappingRegion> Branches;
+
+ /// Total number of conditions in the boolean expression.
+ unsigned NumConditions;
+
+ /// Mapping of a condition ID to its corresponding branch region.
+ llvm::DenseMap<unsigned, const CounterMappingRegion *> Map;
+
+ /// Vector used to track whether a condition is constant folded.
+ MCDCRecord::BoolVector Folded;
+
+ /// Mapping of calculated MC/DC Independence Pairs for each condition.
+ MCDCRecord::TVPairMap IndependencePairs;
+
+ /// Total number of possible Test Vectors for the boolean expression.
+ MCDCRecord::TestVectors TestVectors;
+
+ /// Actual executed Test Vectors for the boolean expression, based on
+ /// ExecutedTestVectorBitmap.
+ MCDCRecord::TestVectors ExecVectors;
+
+public:
+ MCDCRecordProcessor(BitVector &Bitmap, CounterMappingRegion &Region,
+ ArrayRef<CounterMappingRegion> Branches)
+ : ExecutedTestVectorBitmap(Bitmap), Region(Region), Branches(Branches),
+ NumConditions(Region.MCDCParams.NumConditions),
+ Folded(NumConditions, false), IndependencePairs(NumConditions),
+ TestVectors((size_t)1 << NumConditions) {}
+
+private:
+ void recordTestVector(MCDCRecord::TestVector &TV,
+ MCDCRecord::CondState Result) {
+ // Calculate an index that is used to identify the test vector in a vector
+ // of test vectors. This index also corresponds to the index values of an
+ // MCDC Region's bitmap (see findExecutedTestVectors()).
+ unsigned Index = 0;
+ for (auto Cond = std::rbegin(TV); Cond != std::rend(TV); ++Cond) {
+ Index <<= 1;
+ Index |= (*Cond == MCDCRecord::MCDC_True) ? 0x1 : 0x0;
+ }
+
+ // Copy the completed test vector to the vector of testvectors.
+ TestVectors[Index] = TV;
+
+ // The final value (T,F) is equal to the last non-dontcare state on the
+ // path (in a short-circuiting system).
+ TestVectors[Index].push_back(Result);
+ }
+
+ void shouldCopyOffTestVectorForTruePath(MCDCRecord::TestVector &TV,
+ unsigned ID) {
+ // Branch regions are hashed based on an ID.
+ const CounterMappingRegion *Branch = Map[ID];
+
+ TV[ID - 1] = MCDCRecord::MCDC_True;
+ if (Branch->MCDCParams.TrueID > 0)
+ buildTestVector(TV, Branch->MCDCParams.TrueID);
+ else
+ recordTestVector(TV, MCDCRecord::MCDC_True);
+ }
+
+ void shouldCopyOffTestVectorForFalsePath(MCDCRecord::TestVector &TV,
+ unsigned ID) {
+ // Branch regions are hashed based on an ID.
+ const CounterMappingRegion *Branch = Map[ID];
+
+ TV[ID - 1] = MCDCRecord::MCDC_False;
+ if (Branch->MCDCParams.FalseID > 0)
+ buildTestVector(TV, Branch->MCDCParams.FalseID);
+ else
+ recordTestVector(TV, MCDCRecord::MCDC_False);
+ }
+
+ /// Starting with the base test vector, build a comprehensive list of
+ /// possible test vectors by recursively walking the branch condition IDs
+ /// provided. Once an end node is reached, record the test vector in a vector
+ /// of test vectors that can be matched against during MC/DC analysis, and
+ /// then reset the positions to 'DontCare'.
+ void buildTestVector(MCDCRecord::TestVector &TV, unsigned ID = 1) {
+ shouldCopyOffTestVectorForTruePath(TV, ID);
+ shouldCopyOffTestVectorForFalsePath(TV, ID);
+
+ // Reset back to DontCare.
+ TV[ID - 1] = MCDCRecord::MCDC_DontCare;
+ }
+
+ /// Walk the bits in the bitmap. A bit set to '1' indicates that the test
+ /// vector at the corresponding index was executed during a test run.
+ void findExecutedTestVectors(BitVector &ExecutedTestVectorBitmap) {
+ for (unsigned Idx = 0; Idx < ExecutedTestVectorBitmap.size(); ++Idx) {
+ if (ExecutedTestVectorBitmap[Idx] == 0)
+ continue;
+ assert(!TestVectors[Idx].empty() && "Test Vector doesn't exist.");
+ ExecVectors.push_back(TestVectors[Idx]);
+ }
+ }
+
+ /// For a given condition and two executed Test Vectors, A and B, see if the
+ /// two test vectors match forming an Independence Pair for the condition.
+ /// For two test vectors to match, the following must be satisfied:
+ /// - The condition's value in each test vector must be opposite.
+ /// - The result's value in each test vector must be opposite.
+ /// - All other conditions' values must be equal or marked as "don't care".
+ bool matchTestVectors(unsigned Aidx, unsigned Bidx, unsigned ConditionIdx) {
+ const MCDCRecord::TestVector &A = ExecVectors[Aidx];
+ const MCDCRecord::TestVector &B = ExecVectors[Bidx];
+
+ // If condition values in both A and B aren't opposites, no match.
+ // Because a value can be 0 (false), 1 (true), or -1 (DontCare), a check
+ // that "XOR != 1" will ensure that the values are opposites and that
+ // neither of them is a DontCare.
+ // 1 XOR 0 == 1 | 0 XOR 0 == 0 | -1 XOR 0 == -1
+ // 1 XOR 1 == 0 | 0 XOR 1 == 1 | -1 XOR 1 == -2
+ // 1 XOR -1 == -2 | 0 XOR -1 == -1 | -1 XOR -1 == 0
+ if ((A[ConditionIdx] ^ B[ConditionIdx]) != 1)
+ return false;
+
+ // If the results of both A and B aren't opposites, no match.
+ if ((A[NumConditions] ^ B[NumConditions]) != 1)
+ return false;
+
+ for (unsigned Idx = 0; Idx < NumConditions; ++Idx) {
+ // Look for other conditions that don't match. Skip over the given
+ // Condition as well as any conditions marked as "don't care".
+ const auto ARecordTyForCond = A[Idx];
+ const auto BRecordTyForCond = B[Idx];
+ if (Idx == ConditionIdx ||
+ ARecordTyForCond == MCDCRecord::MCDC_DontCare ||
+ BRecordTyForCond == MCDCRecord::MCDC_DontCare)
+ continue;
+
+ // If there is a condition mismatch with any of the other conditions,
+ // there is no match for the test vectors.
+ if (ARecordTyForCond != BRecordTyForCond)
+ return false;
+ }
+
+ // Otherwise, match.
+ return true;
+ }
+
+ /// Find all possible Independence Pairs for a boolean expression given its
+ /// executed Test Vectors. This process involves looking at each condition
+ /// and attempting to find two Test Vectors that "match", giving us a pair.
+ void findIndependencePairs() {
+ unsigned NumTVs = ExecVectors.size();
+
+ // For each condition.
+ for (unsigned C = 0; C < NumConditions; ++C) {
+ bool PairFound = false;
+
+ // For each executed test vector.
+ for (unsigned I = 0; !PairFound && I < NumTVs; ++I) {
+ // Compared to every other executed test vector.
+ for (unsigned J = 0; !PairFound && J < NumTVs; ++J) {
+ if (I == J)
+ continue;
+
+ // If a matching pair of vectors is found, record them.
+ if ((PairFound = matchTestVectors(I, J, C)))
+ IndependencePairs[C] = std::make_pair(I + 1, J + 1);
+ }
+ }
+ }
+ }
+
+public:
+ /// Process the MC/DC Record in order to produce a result for a boolean
+ /// expression. This process includes tracking the conditions that comprise
+ /// the decision region, calculating the list of all possible test vectors,
+ /// marking the executed test vectors, and then finding an Independence Pair
+ /// out of the executed test vectors for each condition in the boolean
+ /// expression. A condition is tracked to ensure that its ID can be mapped to
+ /// its ordinal position in the boolean expression. The condition's source
+ /// location is also tracked, as well as whether it is constant folded (in
+ /// which case it is excuded from the metric).
+ MCDCRecord processMCDCRecord() {
+ unsigned I = 0;
+ MCDCRecord::CondIDMap PosToID;
+ MCDCRecord::LineColPairMap CondLoc;
+
+ // Walk the Record's BranchRegions (representing Conditions) in order to:
+ // - Hash the condition based on its corresponding ID. This will be used to
+ // calculate the test vectors.
+ // - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
+ // actual ID. This will be used to visualize the conditions in the
+ // correct order.
+ // - Keep track of the condition source location. This will be used to
+ // visualize where the condition is.
+ // - Record whether the condition is constant folded so that we exclude it
+ // from being measured.
+ for (const auto &B : Branches) {
+ Map[B.MCDCParams.ID] = &B;
+ PosToID[I] = B.MCDCParams.ID - 1;
+ CondLoc[I] = B.startLoc();
+ Folded[I++] = (B.Count.isZero() && B.FalseCount.isZero());
+ }
+
+ // Initialize a base test vector as 'DontCare'.
+ MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
+
+ // Use the base test vector to build the list of all possible test vectors.
+ buildTestVector(TV);
+
+ // Using Profile Bitmap from runtime, mark the executed test vectors.
+ findExecutedTestVectors(ExecutedTestVectorBitmap);
+
+ // Compare executed test vectors against each other to find an independence
+ // pairs for each condition. This processing takes the most time.
+ findIndependencePairs();
+
+ // Record Test vectors, executed vectors, and independence pairs.
+ MCDCRecord Res(Region, ExecVectors, IndependencePairs, Folded, PosToID,
+ CondLoc);
+ return Res;
+ }
+};
+
+Expected<MCDCRecord> CounterMappingContext::evaluateMCDCRegion(
+ CounterMappingRegion Region, BitVector ExecutedTestVectorBitmap,
+ ArrayRef<CounterMappingRegion> Branches) {
+
+ MCDCRecordProcessor MCDCProcessor(ExecutedTestVectorBitmap, Region, Branches);
+ return MCDCProcessor.processMCDCRecord();
+}
+
unsigned CounterMappingContext::getMaxCounterID(const Counter &C) const {
struct StackElem {
Counter ICounter;
@@ -303,6 +562,24 @@ static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
return MaxCounterID;
}
+static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx,
+ const CoverageMappingRecord &Record) {
+ unsigned MaxBitmapID = 0;
+ unsigned NumConditions = 0;
+ // The last DecisionRegion has the highest bitmap byte index used in the
+ // function, which when combined with its number of conditions, yields the
+ // full bitmap size.
+ for (const auto &Region : reverse(Record.MappingRegions)) {
+ if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
+ MaxBitmapID = Region.MCDCParams.BitmapIdx;
+ NumConditions = Region.MCDCParams.NumConditions;
+ break;
+ }
+ }
+ unsigned SizeInBits = llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT);
+ return MaxBitmapID + (SizeInBits / CHAR_BIT);
+}
+
Error CoverageMapping::loadFunctionRecord(
const CoverageMappingRecord &Record,
IndexedInstrProfReader &ProfileReader) {
@@ -326,12 +603,28 @@ Error CoverageMapping::loadFunctionRecord(
FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
Record.FunctionHash);
return Error::success();
- } else if (IPE != instrprof_error::unknown_function)
+ }
+ if (IPE != instrprof_error::unknown_function)
return make_error<InstrProfError>(IPE);
Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
}
Ctx.setCounts(Counts);
+ std::vector<uint8_t> BitmapBytes;
+ if (Error E = ProfileReader.getFunctionBitmapBytes(
+ Record.FunctionName, Record.FunctionHash, BitmapBytes)) {
+ instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
+ if (IPE == instrprof_error::hash_mismatch) {
+ FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
+ Record.FunctionHash);
+ return Error::success();
+ }
+ if (IPE != instrprof_error::unknown_function)
+ return make_error<InstrProfError>(IPE);
+ BitmapBytes.assign(getMaxBitmapSize(Ctx, Record) + 1, 0);
+ }
+ Ctx.setBitmapBytes(BitmapBytes);
+
assert(!Record.MappingRegions.empty() && "Function has no regions");
// This coverage record is a zero region for a function that's unused in
@@ -343,8 +636,20 @@ Error CoverageMapping::loadFunctionRecord(
Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
return Error::success();
+ unsigned NumConds = 0;
+ const CounterMappingRegion *MCDCDecision;
+ std::vector<CounterMappingRegion> MCDCBranches;
+
FunctionRecord Function(OrigFuncName, Record.Filenames);
for (const auto &Region : Record.MappingRegions) {
+ // If an MCDCDecisionRegion is seen, track the BranchRegions that follow
+ // it according to Region.NumConditions.
+ if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
+ assert(NumConds == 0);
+ MCDCDecision = &Region;
+ NumConds = Region.MCDCParams.NumConditions;
+ continue;
+ }
Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
if (auto E = ExecutionCount.takeError()) {
consumeError(std::move(E));
@@ -356,6 +661,44 @@ Error CoverageMapping::loadFunctionRecord(
return Error::success();
}
Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
+
+ // If a MCDCDecisionRegion was seen, store the BranchRegions that
+ // correspond to it in a vector, according to the number of conditions
+ // recorded for the region (tracked by NumConds).
+ if (NumConds > 0 && Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
+ MCDCBranches.push_back(Region);
+
+ // As we move through all of the MCDCBranchRegions that follow the
+ // MCDCDecisionRegion, decrement NumConds to make sure we account for
+ // them all before we calculate the bitmap of executed test vectors.
+ if (--NumConds == 0) {
+ // Evaluating the test vector bitmap for the decision region entails
+ // calculating precisely what bits are pertinent to this region alone.
+ // This is calculated based on the recorded offset into the global
+ // profile bitmap; the length is calculated based on the recorded
+ // number of conditions.
+ Expected<BitVector> ExecutedTestVectorBitmap =
+ Ctx.evaluateBitmap(MCDCDecision);
+ if (auto E = ExecutedTestVectorBitmap.takeError()) {
+ consumeError(std::move(E));
+ return Error::success();
+ }
+
+ // Since the bitmap identifies the executed test vectors for an MC/DC
+ // DecisionRegion, all of the information is now available to process.
+ // This is where the bulk of the MC/DC progressing takes place.
+ Expected<MCDCRecord> Record = Ctx.evaluateMCDCRegion(
+ *MCDCDecision, *ExecutedTestVectorBitmap, MCDCBranches);
+ if (auto E = Record.takeError()) {
+ consumeError(std::move(E));
+ return Error::success();
+ }
+
+ // Save the MC/DC Record so that it can be visualized later.
+ Function.pushMCDCRecord(*Record);
+ MCDCBranches.clear();
+ }
+ }
}
// Don't create records for (filenames, function) pairs we've already seen.
@@ -862,6 +1205,10 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
for (const auto &CR : Function.CountedBranchRegions)
if (FileIDs.test(CR.FileID) && (CR.FileID == CR.ExpandedFileID))
FileCoverage.BranchRegions.push_back(CR);
+ // Capture MCDC records specific to the function.
+ for (const auto &MR : Function.MCDCRecords)
+ if (FileIDs.test(MR.getDecisionRegion().FileID))
+ FileCoverage.MCDCRecords.push_back(MR);
}
LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
@@ -914,6 +1261,11 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
if (CR.FileID == *MainFileID)
FunctionCoverage.BranchRegions.push_back(CR);
+ // Capture MCDC records specific to the function.
+ for (const auto &MR : Function.MCDCRecords)
+ if (MR.getDecisionRegion().FileID == *MainFileID)
+ FunctionCoverage.MCDCRecords.push_back(MR);
+
LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
<< "\n");
FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index d6aade6fcd0f..ac8e6b56379f 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -244,6 +244,7 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
unsigned LineStart = 0;
for (size_t I = 0; I < NumRegions; ++I) {
Counter C, C2;
+ uint64_t BIDX = 0, NC = 0, ID = 0, TID = 0, FID = 0;
CounterMappingRegion::RegionKind Kind = CounterMappingRegion::CodeRegion;
// Read the combined counter + region kind.
@@ -294,6 +295,27 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
if (auto Err = readCounter(C2))
return Err;
break;
+ case CounterMappingRegion::MCDCBranchRegion:
+ // For a MCDC Branch Region, read two successive counters and 3 IDs.
+ Kind = CounterMappingRegion::MCDCBranchRegion;
+ if (auto Err = readCounter(C))
+ return Err;
+ if (auto Err = readCounter(C2))
+ return Err;
+ if (auto Err = readIntMax(ID, std::numeric_limits<unsigned>::max()))
+ return Err;
+ if (auto Err = readIntMax(TID, std::numeric_limits<unsigned>::max()))
+ return Err;
+ if (auto Err = readIntMax(FID, std::numeric_limits<unsigned>::max()))
+ return Err;
+ break;
+ case CounterMappingRegion::MCDCDecisionRegion:
+ Kind = CounterMappingRegion::MCDCDecisionRegion;
+ if (auto Err = readIntMax(BIDX, std::numeric_limits<unsigned>::max()))
+ return Err;
+ if (auto Err = readIntMax(NC, std::numeric_limits<unsigned>::max()))
+ return Err;
+ break;
default:
return make_error<CoverageMapError>(coveragemap_error::malformed,
"region kind is incorrect");
@@ -347,9 +369,14 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
dbgs() << "\n";
});
- auto CMR = CounterMappingRegion(C, C2, InferredFileID, ExpandedFileID,
- LineStart, ColumnStart,
- LineStart + NumLines, ColumnEnd, Kind);
+ auto CMR = CounterMappingRegion(
+ C, C2,
+ CounterMappingRegion::MCDCParameters{
+ static_cast<unsigned>(BIDX), static_cast<unsigned>(NC),
+ static_cast<unsigned>(ID), static_cast<unsigned>(TID),
+ static_cast<unsigned>(FID)},
+ InferredFileID, ExpandedFileID, LineStart, ColumnStart,
+ LineStart + NumLines, ColumnEnd, Kind);
if (CMR.startLoc() > CMR.endLoc())
return make_error<CoverageMapError>(
coveragemap_error::malformed,
@@ -466,9 +493,13 @@ Error InstrProfSymtab::create(SectionRef &Section) {
// If this is a linked PE/COFF file, then we have to skip over the null byte
// that is allocated in the .lprfn$A section in the LLVM profiling runtime.
+ // If the name section is .lprfcovnames, it doesn't have the null byte at the
+ // beginning.
const ObjectFile *Obj = Section.getObject();
if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject())
- Data = Data.drop_front(1);
+ if (Expected<StringRef> NameOrErr = Section.getName())
+ if (*NameOrErr != getInstrProfSectionName(IPSK_covname, Triple::COFF))
+ Data = Data.drop_front(1);
return Error::success();
}
@@ -997,10 +1028,13 @@ loadTestingFormat(StringRef Data, StringRef CompilationDir) {
BytesInAddress, Endian, CompilationDir);
}
-/// Find all sections that match \p Name. There may be more than one if comdats
-/// are in use, e.g. for the __llvm_covfun section on ELF.
-static Expected<std::vector<SectionRef>> lookupSections(ObjectFile &OF,
- StringRef Name) {
+/// Find all sections that match \p IPSK name. There may be more than one if
+/// comdats are in use, e.g. for the __llvm_covfun section on ELF.
+static Expected<std::vector<SectionRef>>
+lookupSections(ObjectFile &OF, InstrProfSectKind IPSK) {
+ auto ObjFormat = OF.getTripleObjectFormat();
+ auto Name =
+ getInstrProfSectionName(IPSK, ObjFormat, /*AddSegmentInfo=*/false);
// On COFF, the object file section name may end in "$M". This tells the
// linker to sort these sections between "$A" and "$Z". The linker removes the
// dollar and everything after it in the final binary. Do the same to match.
@@ -1015,8 +1049,13 @@ static Expected<std::vector<SectionRef>> lookupSections(ObjectFile &OF,
Expected<StringRef> NameOrErr = Section.getName();
if (!NameOrErr)
return NameOrErr.takeError();
- if (stripSuffix(*NameOrErr) == Name)
+ if (stripSuffix(*NameOrErr) == Name) {
+ // COFF profile name section contains two null bytes indicating the
+ // start/end of the section. If its size is 2 bytes, it's empty.
+ if (IsCOFF && IPSK == IPSK_name && Section.getSize() == 2)
+ continue;
Sections.push_back(Section);
+ }
}
if (Sections.empty())
return make_error<CoverageMapError>(coveragemap_error::no_data_found);
@@ -1052,15 +1091,27 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
OF->isLittleEndian() ? llvm::endianness::little : llvm::endianness::big;
// Look for the sections that we are interested in.
- auto ObjFormat = OF->getTripleObjectFormat();
- auto NamesSection =
- lookupSections(*OF, getInstrProfSectionName(IPSK_name, ObjFormat,
- /*AddSegmentInfo=*/false));
- if (auto E = NamesSection.takeError())
+ InstrProfSymtab ProfileNames;
+ std::vector<SectionRef> NamesSectionRefs;
+ // If IPSK_name is not found, fallback to search for IPK_covname, which is
+ // used when binary correlation is enabled.
+ auto NamesSection = lookupSections(*OF, IPSK_name);
+ if (auto E = NamesSection.takeError()) {
+ consumeError(std::move(E));
+ NamesSection = lookupSections(*OF, IPSK_covname);
+ if (auto E = NamesSection.takeError())
+ return std::move(E);
+ }
+ NamesSectionRefs = *NamesSection;
+
+ if (NamesSectionRefs.size() != 1)
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "the size of coverage mapping section is not one");
+ if (Error E = ProfileNames.create(NamesSectionRefs.back()))
return std::move(E);
- auto CoverageSection =
- lookupSections(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat,
- /*AddSegmentInfo=*/false));
+
+ auto CoverageSection = lookupSections(*OF, IPSK_covmap);
if (auto E = CoverageSection.takeError())
return std::move(E);
std::vector<SectionRef> CoverageSectionRefs = *CoverageSection;
@@ -1072,19 +1123,8 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
return CoverageMappingOrErr.takeError();
StringRef CoverageMapping = CoverageMappingOrErr.get();
- InstrProfSymtab ProfileNames;
- std::vector<SectionRef> NamesSectionRefs = *NamesSection;
- if (NamesSectionRefs.size() != 1)
- return make_error<CoverageMapError>(
- coveragemap_error::malformed,
- "the size of coverage mapping section is not one");
- if (Error E = ProfileNames.create(NamesSectionRefs.back()))
- return std::move(E);
-
// Look for the coverage records section (Version4 only).
- auto CoverageRecordsSections =
- lookupSections(*OF, getInstrProfSectionName(IPSK_covfun, ObjFormat,
- /*AddSegmentInfo=*/false));
+ auto CoverageRecordsSections = lookupSections(*OF, IPSK_covfun);
BinaryCoverageReader::FuncRecordsStorage FuncRecords;
if (auto E = CoverageRecordsSections.takeError()) {
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
index 2abfbbad16ee..1c7d8a8909c4 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
@@ -237,6 +237,23 @@ void CoverageMappingWriter::write(raw_ostream &OS) {
writeCounter(MinExpressions, Count, OS);
writeCounter(MinExpressions, FalseCount, OS);
break;
+ case CounterMappingRegion::MCDCBranchRegion:
+ encodeULEB128(unsigned(I->Kind)
+ << Counter::EncodingCounterTagAndExpansionRegionTagBits,
+ OS);
+ writeCounter(MinExpressions, Count, OS);
+ writeCounter(MinExpressions, FalseCount, OS);
+ encodeULEB128(unsigned(I->MCDCParams.ID), OS);
+ encodeULEB128(unsigned(I->MCDCParams.TrueID), OS);
+ encodeULEB128(unsigned(I->MCDCParams.FalseID), OS);
+ break;
+ case CounterMappingRegion::MCDCDecisionRegion:
+ encodeULEB128(unsigned(I->Kind)
+ << Counter::EncodingCounterTagAndExpansionRegionTagBits,
+ OS);
+ encodeULEB128(unsigned(I->MCDCParams.BitmapIdx), OS);
+ encodeULEB128(unsigned(I->MCDCParams.NumConditions), OS);
+ break;
}
assert(I->LineStart >= PrevLineStart);
encodeULEB128(I->LineStart - PrevLineStart, OS);
diff --git a/llvm/lib/ProfileData/GCOV.cpp b/llvm/lib/ProfileData/GCOV.cpp
index 5fce3dd5f7b7..f7bf42e5c4d2 100644
--- a/llvm/lib/ProfileData/GCOV.cpp
+++ b/llvm/lib/ProfileData/GCOV.cpp
@@ -337,7 +337,7 @@ StringRef GCOVFunction::getName(bool demangle) const {
return Name;
if (demangled.empty()) {
do {
- if (Name.startswith("_Z")) {
+ if (Name.starts_with("_Z")) {
// Name is guaranteed to be NUL-terminated.
if (char *res = itaniumDemangle(Name.data())) {
demangled = res;
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 236b083a1e21..649d814cfd9d 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -113,11 +113,11 @@ static std::string getInstrProfErrString(instrprof_error Err,
case instrprof_error::malformed:
OS << "malformed instrumentation profile data";
break;
- case instrprof_error::missing_debug_info_for_correlation:
- OS << "debug info for correlation is required";
+ case instrprof_error::missing_correlation_info:
+ OS << "debug info/binary for correlation is required";
break;
- case instrprof_error::unexpected_debug_info_for_correlation:
- OS << "debug info for correlation is not necessary";
+ case instrprof_error::unexpected_correlation_info:
+ OS << "debug info/binary for correlation is not necessary";
break;
case instrprof_error::unable_to_correlate_profile:
OS << "unable to correlate profile";
@@ -385,7 +385,7 @@ StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName) {
if (FileName.empty())
return PGOFuncName;
// Drop the file name including ':'. See also getPGOFuncName.
- if (PGOFuncName.startswith(FileName))
+ if (PGOFuncName.starts_with(FileName))
PGOFuncName = PGOFuncName.drop_front(FileName.size() + 1);
return PGOFuncName;
}
diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
index 24d828f69c71..cf80a58f43bd 100644
--- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp
+++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
@@ -27,14 +27,22 @@ using namespace llvm;
/// Get profile section.
Expected<object::SectionRef> getInstrProfSection(const object::ObjectFile &Obj,
InstrProfSectKind IPSK) {
+ // On COFF, the getInstrProfSectionName returns the section names may followed
+ // by "$M". The linker removes the dollar and everything after it in the final
+ // binary. Do the same to match.
Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat();
+ auto StripSuffix = [ObjFormat](StringRef N) {
+ return ObjFormat == Triple::COFF ? N.split('$').first : N;
+ };
std::string ExpectedSectionName =
getInstrProfSectionName(IPSK, ObjFormat,
/*AddSegmentInfo=*/false);
- for (auto &Section : Obj.sections())
+ ExpectedSectionName = StripSuffix(ExpectedSectionName);
+ for (auto &Section : Obj.sections()) {
if (auto SectionName = Section.getName())
- if (SectionName.get() == ExpectedSectionName)
+ if (*SectionName == ExpectedSectionName)
return Section;
+ }
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
"could not find section (" + Twine(ExpectedSectionName) + ")");
@@ -46,14 +54,38 @@ const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters";
llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>>
InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
- const object::ObjectFile &Obj) {
+ const object::ObjectFile &Obj,
+ ProfCorrelatorKind FileKind) {
+ auto C = std::make_unique<Context>();
auto CountersSection = getInstrProfSection(Obj, IPSK_cnts);
if (auto Err = CountersSection.takeError())
return std::move(Err);
- auto C = std::make_unique<Context>();
+ if (FileKind == InstrProfCorrelator::BINARY) {
+ auto DataSection = getInstrProfSection(Obj, IPSK_covdata);
+ if (auto Err = DataSection.takeError())
+ return std::move(Err);
+ auto DataOrErr = DataSection->getContents();
+ if (!DataOrErr)
+ return DataOrErr.takeError();
+ auto NameSection = getInstrProfSection(Obj, IPSK_covname);
+ if (auto Err = NameSection.takeError())
+ return std::move(Err);
+ auto NameOrErr = NameSection->getContents();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ C->DataStart = DataOrErr->data();
+ C->DataEnd = DataOrErr->data() + DataOrErr->size();
+ C->NameStart = NameOrErr->data();
+ C->NameSize = NameOrErr->size();
+ }
C->Buffer = std::move(Buffer);
C->CountersSectionStart = CountersSection->getAddress();
C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize();
+ // In COFF object file, there's a null byte at the beginning of the counter
+ // section which doesn't exist in raw profile.
+ if (Obj.getTripleObjectFormat() == Triple::COFF)
+ ++C->CountersSectionStart;
+
C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost;
return Expected<std::unique_ptr<Context>>(std::move(C));
}
@@ -80,9 +112,17 @@ InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind) {
return get(std::move(*BufferOrErr), FileKind);
}
+ if (FileKind == BINARY) {
+ auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename));
+ if (auto Err = BufferOrErr.takeError())
+ return std::move(Err);
+
+ return get(std::move(*BufferOrErr), FileKind);
+ }
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
- "unsupported correlation kind (only DWARF debug info is supported)");
+ "unsupported correlation kind (only DWARF debug info and Binary format "
+ "(ELF/COFF) are supported)");
}
llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
@@ -93,7 +133,7 @@ InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer,
return std::move(Err);
if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
- auto CtxOrErr = Context::get(std::move(Buffer), *Obj);
+ auto CtxOrErr = Context::get(std::move(Buffer), *Obj, FileKind);
if (auto Err = CtxOrErr.takeError())
return std::move(Err);
auto T = Obj->makeTriple();
@@ -155,9 +195,11 @@ InstrProfCorrelatorImpl<IntPtrT>::get(
instrprof_error::unable_to_correlate_profile,
"unsupported debug info format (only DWARF is supported)");
}
+ if (Obj.isELF() || Obj.isCOFF())
+ return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx));
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
- "unsupported correlation file type (only DWARF is supported)");
+ "unsupported binary format (only ELF and COFF are supported)");
}
template <class IntPtrT>
@@ -212,16 +254,16 @@ Error InstrProfCorrelatorImpl<IntPtrT>::dumpYaml(int MaxWarnings,
}
template <class IntPtrT>
-void InstrProfCorrelatorImpl<IntPtrT>::addProbe(StringRef FunctionName,
- uint64_t CFGHash,
- IntPtrT CounterOffset,
- IntPtrT FunctionPtr,
- uint32_t NumCounters) {
+void InstrProfCorrelatorImpl<IntPtrT>::addDataProbe(uint64_t NameRef,
+ uint64_t CFGHash,
+ IntPtrT CounterOffset,
+ IntPtrT FunctionPtr,
+ uint32_t NumCounters) {
// Check if a probe was already added for this counter offset.
if (!CounterOffsets.insert(CounterOffset).second)
return;
Data.push_back({
- maybeSwap<uint64_t>(IndexedInstrProf::ComputeHash(FunctionName)),
+ maybeSwap<uint64_t>(NameRef),
maybeSwap<uint64_t>(CFGHash),
// In this mode, CounterPtr actually stores the section relative address
// of the counter.
@@ -236,7 +278,6 @@ void InstrProfCorrelatorImpl<IntPtrT>::addProbe(StringRef FunctionName,
// TODO: MC/DC is not yet supported.
/*NumBitmapBytes=*/maybeSwap<uint32_t>(0),
});
- NamesVec.push_back(FunctionName.str());
}
template <class IntPtrT>
@@ -277,7 +318,7 @@ bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die) {
if (!Die.hasChildren())
return false;
if (const char *Name = Die.getName(DINameKind::ShortName))
- return StringRef(Name).startswith(getInstrProfCountersVarPrefix());
+ return StringRef(Name).starts_with(getInstrProfCountersVarPrefix());
return false;
}
@@ -349,6 +390,8 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
*FunctionName);
LLVM_DEBUG(Die.dump(dbgs()));
}
+ // In debug info correlation mode, the CounterPtr is an absolute address of
+ // the counter, but it's expected to be relative later when iterating Data.
IntPtrT CounterOffset = *CounterPtr - CountersStart;
if (Data) {
InstrProfCorrelator::Probe P;
@@ -366,8 +409,9 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
P.LineNumber = LineNumber;
Data->Probes.push_back(P);
} else {
- this->addProbe(*FunctionName, *CFGHash, CounterOffset,
- FunctionPtr.value_or(0), *NumCounters);
+ this->addDataProbe(IndexedInstrProf::ComputeHash(*FunctionName), *CFGHash,
+ CounterOffset, FunctionPtr.value_or(0), *NumCounters);
+ this->NamesVec.push_back(*FunctionName);
}
};
for (auto &CU : DICtx->normal_units())
@@ -394,3 +438,46 @@ Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
/*doCompression=*/false, this->Names);
return Result;
}
+
+template <class IntPtrT>
+void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
+ int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) {
+ using RawProfData = RawInstrProf::ProfileData<IntPtrT>;
+ bool UnlimitedWarnings = (MaxWarnings == 0);
+ // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
+ int NumSuppressedWarnings = -MaxWarnings;
+
+ const RawProfData *DataStart = (const RawProfData *)this->Ctx->DataStart;
+ const RawProfData *DataEnd = (const RawProfData *)this->Ctx->DataEnd;
+ // We need to use < here because the last data record may have no padding.
+ for (const RawProfData *I = DataStart; I < DataEnd; ++I) {
+ uint64_t CounterPtr = this->template maybeSwap<IntPtrT>(I->CounterPtr);
+ uint64_t CountersStart = this->Ctx->CountersSectionStart;
+ uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
+ if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
+ if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+ WithColor::warning()
+ << format("CounterPtr out of range for function: Actual=0x%x "
+ "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
+ CounterPtr, CountersStart, CountersEnd,
+ (I - DataStart) * sizeof(RawProfData));
+ }
+ }
+ // In binary correlation mode, the CounterPtr is an absolute address of the
+ // counter, but it's expected to be relative later when iterating Data.
+ IntPtrT CounterOffset = CounterPtr - CountersStart;
+ this->addDataProbe(I->NameRef, I->FuncHash, CounterOffset,
+ I->FunctionPointer, I->NumCounters);
+ }
+}
+
+template <class IntPtrT>
+Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
+ if (this->Ctx->NameSize == 0) {
+ return make_error<InstrProfError>(
+ instrprof_error::unable_to_correlate_profile,
+ "could not find any profile data metadata in object file");
+ }
+ this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
+ return Error::success();
+}
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 74f3f3270c4c..068922d421f8 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -246,7 +246,7 @@ bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
Error TextInstrProfReader::readHeader() {
Symtab.reset(new InstrProfSymtab());
- while (Line->startswith(":")) {
+ while (Line->starts_with(":")) {
StringRef Str = Line->substr(1);
if (Str.equals_insensitive("ir"))
ProfileKind |= InstrProfKind::IRInstrumentation;
@@ -386,7 +386,7 @@ TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
// Skip empty lines and comments.
- while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
+ while (!Line.is_at_end() && (Line->empty() || Line->starts_with("#")))
++Line;
// If we hit EOF while looking for a name, we're done.
if (Line.is_at_end()) {
@@ -428,7 +428,7 @@ Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
}
// Bitmap byte information is indicated with special character.
- if (Line->startswith("$")) {
+ if (Line->starts_with("$")) {
Record.BitmapBytes.clear();
// Read the number of bitmap bytes.
uint64_t NumBitmapBytes;
@@ -556,10 +556,6 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
"\nPLEASE update this tool to version in the raw profile, or "
"regenerate raw profile with expected version.")
.str());
- if (useCorrelate() && !Correlator)
- return error(instrprof_error::missing_debug_info_for_correlation);
- if (!useCorrelate() && Correlator)
- return error(instrprof_error::unexpected_debug_info_for_correlation);
uint64_t BinaryIdSize = swap(Header.BinaryIdsSize);
// Binary id start just after the header if exists.
@@ -607,8 +603,9 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
if (Correlator) {
// These sizes in the raw file are zero because we constructed them in the
// Correlator.
- assert(DataSize == 0 && NamesSize == 0);
- assert(CountersDelta == 0 && NamesDelta == 0);
+ if (!(DataSize == 0 && NamesSize == 0 && CountersDelta == 0 &&
+ NamesDelta == 0))
+ return error(instrprof_error::unexpected_correlation_info);
Data = Correlator->getDataPointer();
DataEnd = Data + Correlator->getDataSize();
NamesStart = Correlator->getNamesPointer();
@@ -1017,7 +1014,7 @@ public:
std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
while (true) {
Parts = Parts.second.split(':');
- if (Parts.first.startswith("_Z"))
+ if (Parts.first.starts_with("_Z"))
return Parts.first;
if (Parts.second.empty())
return Name;
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 595c9aa1adc1..d65f8fe50313 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -536,7 +536,12 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
// Insert the key (func hash) and value (memprof record).
RecordTableGenerator.insert(I.first, I.second);
}
+ // Release the memory of this MapVector as it is no longer needed.
+ MemProfRecordData.clear();
+ // The call to Emit invokes RecordWriterTrait::EmitData which destructs
+ // the memprof record copies owned by the RecordTableGenerator. This works
+ // because the RecordTableGenerator is not used after this point.
uint64_t RecordTableOffset =
RecordTableGenerator.Emit(OS.OS, *RecordWriter);
@@ -549,6 +554,8 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
// Insert the key (frame id) and value (frame contents).
FrameTableGenerator.insert(I.first, I.second);
}
+ // Release the memory of this MapVector as it is no longer needed.
+ MemProfFrameData.clear();
uint64_t FrameTableOffset = FrameTableGenerator.Emit(OS.OS, *FrameWriter);
diff --git a/llvm/lib/ProfileData/ItaniumManglingCanonicalizer.cpp b/llvm/lib/ProfileData/ItaniumManglingCanonicalizer.cpp
index 593677214e58..6271b1622693 100644
--- a/llvm/lib/ProfileData/ItaniumManglingCanonicalizer.cpp
+++ b/llvm/lib/ProfileData/ItaniumManglingCanonicalizer.cpp
@@ -225,7 +225,7 @@ ItaniumManglingCanonicalizer::addEquivalence(FragmentKind Kind, StringRef First,
// arguments. This mostly just falls out, as almost all template names
// are valid as <name>s, but we also want to parse <substitution>s as
// <name>s, even though they're not.
- else if (Str.startswith("S"))
+ else if (Str.starts_with("S"))
// Parse the substitution and optional following template arguments.
N = P->Demangler.parseType();
else
@@ -289,8 +289,8 @@ parseMaybeMangledName(CanonicalizingDemangler &Demangler, StringRef Mangling,
// encoding 6memcpy 7memmove
// consistent with how they are encoded as local-names inside a C++ mangling.
Node *N;
- if (Mangling.startswith("_Z") || Mangling.startswith("__Z") ||
- Mangling.startswith("___Z") || Mangling.startswith("____Z"))
+ if (Mangling.starts_with("_Z") || Mangling.starts_with("__Z") ||
+ Mangling.starts_with("___Z") || Mangling.starts_with("____Z"))
N = Demangler.parse();
else
N = Demangler.make<itanium_demangle::NameType>(
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp
index ed92713c2c62..98d0aa794529 100644
--- a/llvm/lib/ProfileData/SampleProfReader.cpp
+++ b/llvm/lib/ProfileData/SampleProfReader.cpp
@@ -180,12 +180,12 @@ static bool isOffsetLegal(unsigned L) { return (L & 0xffff) == L; }
/// Stores the FunctionHash (a.k.a. CFG Checksum) into \p FunctionHash.
static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash,
uint32_t &Attributes) {
- if (Input.startswith("!CFGChecksum:")) {
+ if (Input.starts_with("!CFGChecksum:")) {
StringRef CFGInfo = Input.substr(strlen("!CFGChecksum:")).trim();
return !CFGInfo.getAsInteger(10, FunctionHash);
}
- if (Input.startswith("!Attributes:")) {
+ if (Input.starts_with("!Attributes:")) {
StringRef Attrib = Input.substr(strlen("!Attributes:")).trim();
return !Attrib.getAsInteger(10, Attributes);
}
diff --git a/llvm/lib/ProfileData/SymbolRemappingReader.cpp b/llvm/lib/ProfileData/SymbolRemappingReader.cpp
index 78457beb3e49..805f66b68ce7 100644
--- a/llvm/lib/ProfileData/SymbolRemappingReader.cpp
+++ b/llvm/lib/ProfileData/SymbolRemappingReader.cpp
@@ -37,7 +37,7 @@ Error SymbolRemappingReader::read(MemoryBuffer &B) {
StringRef Line = *LineIt;
Line = Line.ltrim(' ');
// line_iterator only detects comments starting in column 1.
- if (Line.startswith("#") || Line.empty())
+ if (Line.starts_with("#") || Line.empty())
continue;
SmallVector<StringRef, 4> Parts;
diff --git a/llvm/lib/Remarks/YAMLRemarkParser.cpp b/llvm/lib/Remarks/YAMLRemarkParser.cpp
index 947adbba10a2..218b6691398b 100644
--- a/llvm/lib/Remarks/YAMLRemarkParser.cpp
+++ b/llvm/lib/Remarks/YAMLRemarkParser.cpp
@@ -136,7 +136,7 @@ Expected<std::unique_ptr<YAMLRemarkParser>> remarks::createYAMLParserFromMeta(
StrTab = std::move(*MaybeStrTab);
}
// If it starts with "---", there is no external file.
- if (!Buf.startswith("---")) {
+ if (!Buf.starts_with("---")) {
// At this point, we expect Buf to contain the external file path.
StringRef ExternalFilePath = Buf;
SmallString<80> FullPath;
diff --git a/llvm/lib/Support/AutoConvert.cpp b/llvm/lib/Support/AutoConvert.cpp
index 4fb7e242c348..8170e553ac6e 100644
--- a/llvm/lib/Support/AutoConvert.cpp
+++ b/llvm/lib/Support/AutoConvert.cpp
@@ -14,21 +14,36 @@
#ifdef __MVS__
#include "llvm/Support/AutoConvert.h"
+#include <cassert>
#include <fcntl.h>
#include <sys/stat.h>
+#include <unistd.h>
-std::error_code llvm::disableAutoConversion(int FD) {
+static int savedStdHandleAutoConversionMode[3] = {-1, -1, -1};
+
+int disableAutoConversion(int FD) {
static const struct f_cnvrt Convert = {
- SETCVTOFF, // cvtcmd
- 0, // pccsid
- (short)FT_BINARY, // fccsid
+ SETCVTOFF, // cvtcmd
+ 0, // pccsid
+ 0, // fccsid
};
- if (fcntl(FD, F_CONTROL_CVT, &Convert) == -1)
- return std::error_code(errno, std::generic_category());
- return std::error_code();
+
+ return fcntl(FD, F_CONTROL_CVT, &Convert);
}
-std::error_code llvm::enableAutoConversion(int FD) {
+int restoreStdHandleAutoConversion(int FD) {
+ assert(FD == STDIN_FILENO || FD == STDOUT_FILENO || FD == STDERR_FILENO);
+ if (savedStdHandleAutoConversionMode[FD] == -1)
+ return 0;
+ struct f_cnvrt Cvt = {
+ savedStdHandleAutoConversionMode[FD], // cvtcmd
+ 0, // pccsid
+ 0, // fccsid
+ };
+ return (fcntl(FD, F_CONTROL_CVT, &Cvt));
+}
+
+int enableAutoConversion(int FD) {
struct f_cnvrt Query = {
QUERYCVT, // cvtcmd
0, // pccsid
@@ -36,17 +51,53 @@ std::error_code llvm::enableAutoConversion(int FD) {
};
if (fcntl(FD, F_CONTROL_CVT, &Query) == -1)
- return std::error_code(errno, std::generic_category());
+ return -1;
+
+ // We don't need conversion for UTF-8 tagged files.
+ // TODO: Remove the assumption of ISO8859-1 = UTF-8 here when we fully resolve
+ // problems related to UTF-8 tagged source files.
+ // When the pccsid is not ISO8859-1, autoconversion is still needed.
+ if (Query.pccsid == CCSID_ISO8859_1 &&
+ (Query.fccsid == CCSID_UTF_8 || Query.fccsid == CCSID_ISO8859_1))
+ return 0;
+
+ // Save the state of std handles before we make changes to it.
+ if ((FD == STDIN_FILENO || FD == STDOUT_FILENO || FD == STDERR_FILENO) &&
+ savedStdHandleAutoConversionMode[FD] == -1)
+ savedStdHandleAutoConversionMode[FD] = Query.cvtcmd;
+
+ if (FD == STDOUT_FILENO || FD == STDERR_FILENO)
+ Query.cvtcmd = SETCVTON;
+ else
+ Query.cvtcmd = SETCVTALL;
- Query.cvtcmd = SETCVTALL;
Query.pccsid =
(FD == STDIN_FILENO || FD == STDOUT_FILENO || FD == STDERR_FILENO)
? 0
: CCSID_UTF_8;
// Assume untagged files to be IBM-1047 encoded.
Query.fccsid = (Query.fccsid == FT_UNTAGGED) ? CCSID_IBM_1047 : Query.fccsid;
- if (fcntl(FD, F_CONTROL_CVT, &Query) == -1)
+ return fcntl(FD, F_CONTROL_CVT, &Query);
+}
+
+std::error_code llvm::disableAutoConversion(int FD) {
+ if (::disableAutoConversion(FD) == -1)
+ return std::error_code(errno, std::generic_category());
+
+ return std::error_code();
+}
+
+std::error_code llvm::enableAutoConversion(int FD) {
+ if (::enableAutoConversion(FD) == -1)
return std::error_code(errno, std::generic_category());
+
+ return std::error_code();
+}
+
+std::error_code llvm::restoreStdHandleAutoConversion(int FD) {
+ if (::restoreStdHandleAutoConversion(FD) == -1)
+ return std::error_code(errno, std::generic_category());
+
return std::error_code();
}
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp
index 31f79972125d..088b4e4d755c 100644
--- a/llvm/lib/Support/CommandLine.cpp
+++ b/llvm/lib/Support/CommandLine.cpp
@@ -324,6 +324,13 @@ public:
return false;
}
+ bool hasNamedSubCommands() const {
+ for (const auto *S : RegisteredSubCommands)
+ if (!S->getName().empty())
+ return true;
+ return false;
+ }
+
SubCommand *getActiveSubCommand() { return ActiveSubCommand; }
void updateArgStr(Option *O, StringRef NewName, SubCommand *SC) {
@@ -425,7 +432,7 @@ private:
return nullptr;
return Opt;
}
- SubCommand *LookupSubCommand(StringRef Name);
+ SubCommand *LookupSubCommand(StringRef Name, std::string &NearestString);
};
} // namespace
@@ -550,9 +557,12 @@ Option *CommandLineParser::LookupOption(SubCommand &Sub, StringRef &Arg,
return I->second;
}
-SubCommand *CommandLineParser::LookupSubCommand(StringRef Name) {
+SubCommand *CommandLineParser::LookupSubCommand(StringRef Name,
+ std::string &NearestString) {
if (Name.empty())
return &SubCommand::getTopLevel();
+ // Find a subcommand with the edit distance == 1.
+ SubCommand *NearestMatch = nullptr;
for (auto *S : RegisteredSubCommands) {
if (S == &SubCommand::getAll())
continue;
@@ -561,7 +571,14 @@ SubCommand *CommandLineParser::LookupSubCommand(StringRef Name) {
if (StringRef(S->getName()) == StringRef(Name))
return S;
+
+ if (!NearestMatch && S->getName().edit_distance(Name) < 2)
+ NearestMatch = S;
}
+
+ if (NearestMatch)
+ NearestString = NearestMatch->getName();
+
return &SubCommand::getTopLevel();
}
@@ -1527,10 +1544,14 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
int FirstArg = 1;
SubCommand *ChosenSubCommand = &SubCommand::getTopLevel();
- if (argc >= 2 && argv[FirstArg][0] != '-') {
+ std::string NearestSubCommandString;
+ bool MaybeNamedSubCommand =
+ argc >= 2 && argv[FirstArg][0] != '-' && hasNamedSubCommands();
+ if (MaybeNamedSubCommand) {
// If the first argument specifies a valid subcommand, start processing
// options from the second argument.
- ChosenSubCommand = LookupSubCommand(StringRef(argv[FirstArg]));
+ ChosenSubCommand =
+ LookupSubCommand(StringRef(argv[FirstArg]), NearestSubCommandString);
if (ChosenSubCommand != &SubCommand::getTopLevel())
FirstArg = 2;
}
@@ -1602,7 +1623,6 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
bool DashDashFound = false; // Have we read '--'?
for (int i = FirstArg; i < argc; ++i) {
Option *Handler = nullptr;
- Option *NearestHandler = nullptr;
std::string NearestHandlerString;
StringRef Value;
StringRef ArgName = "";
@@ -1682,26 +1702,39 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
// Otherwise, look for the closest available option to report to the user
// in the upcoming error.
if (!Handler && SinkOpts.empty())
- NearestHandler =
- LookupNearestOption(ArgName, OptionsMap, NearestHandlerString);
+ LookupNearestOption(ArgName, OptionsMap, NearestHandlerString);
}
if (!Handler) {
- if (SinkOpts.empty()) {
- *Errs << ProgramName << ": Unknown command line argument '" << argv[i]
- << "'. Try: '" << argv[0] << " --help'\n";
-
- if (NearestHandler) {
- // If we know a near match, report it as well.
- *Errs << ProgramName << ": Did you mean '"
- << PrintArg(NearestHandlerString, 0) << "'?\n";
- }
-
- ErrorParsing = true;
- } else {
+ if (!SinkOpts.empty()) {
for (Option *SinkOpt : SinkOpts)
SinkOpt->addOccurrence(i, "", StringRef(argv[i]));
+ continue;
}
+
+ auto ReportUnknownArgument = [&](bool IsArg,
+ StringRef NearestArgumentName) {
+ *Errs << ProgramName << ": Unknown "
+ << (IsArg ? "command line argument" : "subcommand") << " '"
+ << argv[i] << "'. Try: '" << argv[0] << " --help'\n";
+
+ if (NearestArgumentName.empty())
+ return;
+
+ *Errs << ProgramName << ": Did you mean '";
+ if (IsArg)
+ *Errs << PrintArg(NearestArgumentName, 0);
+ else
+ *Errs << NearestArgumentName;
+ *Errs << "'?\n";
+ };
+
+ if (i > 1 || !MaybeNamedSubCommand)
+ ReportUnknownArgument(/*IsArg=*/true, NearestHandlerString);
+ else
+ ReportUnknownArgument(/*IsArg=*/false, NearestSubCommandString);
+
+ ErrorParsing = true;
continue;
}
diff --git a/llvm/lib/Support/InitLLVM.cpp b/llvm/lib/Support/InitLLVM.cpp
index 2b7173b28940..7f475f42f3cb 100644
--- a/llvm/lib/Support/InitLLVM.cpp
+++ b/llvm/lib/Support/InitLLVM.cpp
@@ -8,6 +8,8 @@
#include "llvm/Support/InitLLVM.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/AutoConvert.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -15,15 +17,31 @@
#include "llvm/Support/SwapByteOrder.h"
#ifdef _WIN32
-#include "llvm/Support/Error.h"
#include "llvm/Support/Windows/WindowsSupport.h"
#endif
+#ifdef __MVS__
+#include <unistd.h>
+
+void CleanupStdHandles(void *Cookie) {
+ llvm::raw_ostream *Outs = &llvm::outs(), *Errs = &llvm::errs();
+ Outs->flush();
+ Errs->flush();
+ llvm::restoreStdHandleAutoConversion(STDIN_FILENO);
+ llvm::restoreStdHandleAutoConversion(STDOUT_FILENO);
+ llvm::restoreStdHandleAutoConversion(STDERR_FILENO);
+}
+#endif
+
using namespace llvm;
using namespace llvm::sys;
InitLLVM::InitLLVM(int &Argc, const char **&Argv,
bool InstallPipeSignalExitHandler) {
+#ifdef __MVS__
+ // Bring stdin/stdout/stderr into a known state.
+ sys::AddSignalHandler(CleanupStdHandles, nullptr);
+#endif
if (InstallPipeSignalExitHandler)
// The pipe signal handler must be installed before any other handlers are
// registered. This is because the Unix \ref RegisterHandlers function does
@@ -37,6 +55,20 @@ InitLLVM::InitLLVM(int &Argc, const char **&Argv,
sys::PrintStackTraceOnErrorSignal(Argv[0]);
install_out_of_memory_new_handler();
+#ifdef __MVS__
+
+ // We use UTF-8 as the internal character encoding. On z/OS, all external
+ // output is encoded in EBCDIC. In order to be able to read all
+ // error messages, we turn conversion to EBCDIC on for stderr fd.
+ std::string Banner = std::string(Argv[0]) + ": ";
+ ExitOnError ExitOnErr(Banner);
+
+ // If turning on conversion for stderr fails then the error message
+ // may be garbled. There is no solution to this problem.
+ ExitOnErr(errorCodeToError(llvm::enableAutoConversion(STDERR_FILENO)));
+ ExitOnErr(errorCodeToError(llvm::enableAutoConversion(STDOUT_FILENO)));
+#endif
+
#ifdef _WIN32
// We use UTF-8 as the internal character encoding. On Windows,
// arguments passed to main() may not be encoded in UTF-8. In order
@@ -61,4 +93,9 @@ InitLLVM::InitLLVM(int &Argc, const char **&Argv,
#endif
}
-InitLLVM::~InitLLVM() { llvm_shutdown(); }
+InitLLVM::~InitLLVM() {
+#ifdef __MVS__
+ CleanupStdHandles(nullptr);
+#endif
+ llvm_shutdown();
+}
diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
index 632274843006..bbbaf26a7bd4 100644
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -174,7 +174,7 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
{"zfbfmin", RISCVExtensionVersion{0, 8}},
- {"zicfilp", RISCVExtensionVersion{0, 2}},
+ {"zicfilp", RISCVExtensionVersion{0, 4}},
{"zicond", RISCVExtensionVersion{1, 0}},
{"ztso", RISCVExtensionVersion{0, 1}},
@@ -1010,7 +1010,7 @@ static const char *ImpliedExtsZcmt[] = {"zca"};
static const char *ImpliedExtsZdinx[] = {"zfinx"};
static const char *ImpliedExtsZfa[] = {"f"};
static const char *ImpliedExtsZfbfmin[] = {"f"};
-static const char *ImpliedExtsZfh[] = {"f"};
+static const char *ImpliedExtsZfh[] = {"zfhmin"};
static const char *ImpliedExtsZfhmin[] = {"f"};
static const char *ImpliedExtsZfinx[] = {"zicsr"};
static const char *ImpliedExtsZhinx[] = {"zfinx"};
@@ -1292,12 +1292,16 @@ StringRef RISCVISAInfo::computeDefaultABI() const {
if (XLen == 32) {
if (hasExtension("d"))
return "ilp32d";
+ if (hasExtension("f"))
+ return "ilp32f";
if (hasExtension("e"))
return "ilp32e";
return "ilp32";
} else if (XLen == 64) {
if (hasExtension("d"))
return "lp64d";
+ if (hasExtension("f"))
+ return "lp64f";
if (hasExtension("e"))
return "lp64e";
return "lp64";
diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp
index ac8877cca8bc..7a23421eaeb8 100644
--- a/llvm/lib/Support/SpecialCaseList.cpp
+++ b/llvm/lib/Support/SpecialCaseList.cpp
@@ -150,13 +150,12 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) {
return false;
}
- // In https://reviews.llvm.org/D154014 we transitioned to using globs instead
- // of regexes to match patterns in special case lists. Since this was a
- // breaking change, we will temporarily support the original behavior using
- // regexes. If "#!special-case-list-v2" is the first line of the file, then
- // we will use the new behavior using globs. For more details, see
+ // In https://reviews.llvm.org/D154014 we added glob support and planned to
+ // remove regex support in patterns. We temporarily support the original
+ // behavior using regexes if "#!special-case-list-v1" is the first line of the
+ // file. For more details, see
// https://discourse.llvm.org/t/use-glob-instead-of-regex-for-specialcaselists/71666
- bool UseGlobs = MB->getBuffer().starts_with("#!special-case-list-v2\n");
+ bool UseGlobs = !MB->getBuffer().starts_with("#!special-case-list-v1\n");
for (line_iterator LineIt(*MB, /*SkipBlanks=*/true, /*CommentMarker=*/'#');
!LineIt.is_at_eof(); LineIt++) {
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 3b668ba82ebb..9f89d63bb0fd 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -652,7 +652,7 @@ std::error_code equivalent(const Twine &A, const Twine &B, bool &result) {
static void expandTildeExpr(SmallVectorImpl<char> &Path) {
StringRef PathStr(Path.begin(), Path.size());
- if (PathStr.empty() || !PathStr.startswith("~"))
+ if (PathStr.empty() || !PathStr.starts_with("~"))
return;
PathStr = PathStr.drop_front();
diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc
index 2babf07944bf..551f0d7f0f02 100644
--- a/llvm/lib/Support/Unix/Process.inc
+++ b/llvm/lib/Support/Unix/Process.inc
@@ -62,7 +62,9 @@ getRUsageTimes() {
::getrusage(RUSAGE_SELF, &RU);
return {toDuration(RU.ru_utime), toDuration(RU.ru_stime)};
#else
+#ifndef __MVS__ // Exclude for MVS in case -pedantic is used
#warning Cannot get usage times on this platform
+#endif
return {std::chrono::microseconds::zero(), std::chrono::microseconds::zero()};
#endif
}
@@ -117,7 +119,9 @@ size_t Process::GetMallocUsage() {
return EndOfMemory - StartOfMemory;
return 0;
#else
+#ifndef __MVS__ // Exclude for MVS in case -pedantic is used
#warning Cannot get malloc info on this platform
+#endif
return 0;
#endif
}
diff --git a/llvm/lib/Support/Unix/Program.inc b/llvm/lib/Support/Unix/Program.inc
index 9466d0f0ba85..260719b2b58d 100644
--- a/llvm/lib/Support/Unix/Program.inc
+++ b/llvm/lib/Support/Unix/Program.inc
@@ -20,11 +20,13 @@
#include "Unix.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
+#include "llvm/Support/AutoConvert.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include "llvm/Support/raw_ostream.h"
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
@@ -466,7 +468,7 @@ ProcessInfo llvm::sys::Wait(const ProcessInfo &PI,
std::chrono::microseconds UserT = toDuration(Info.ru_utime);
std::chrono::microseconds KernelT = toDuration(Info.ru_stime);
uint64_t PeakMemory = 0;
-#ifndef __HAIKU__
+#if !defined(__HAIKU__) && !defined(__MVS__)
PeakMemory = static_cast<uint64_t>(Info.ru_maxrss);
#endif
*ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory};
@@ -520,8 +522,12 @@ std::error_code llvm::sys::ChangeStdoutMode(fs::OpenFlags Flags) {
}
std::error_code llvm::sys::ChangeStdinToBinary() {
+#ifdef __MVS__
+ return disableAutoConversion(STDIN_FILENO);
+#else
// Do nothing, as Unix doesn't differentiate between text and binary.
return std::error_code();
+#endif
}
std::error_code llvm::sys::ChangeStdoutToBinary() {
diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc
index e4563fd6ed9e..168a63bb2d96 100644
--- a/llvm/lib/Support/Windows/Path.inc
+++ b/llvm/lib/Support/Windows/Path.inc
@@ -76,7 +76,7 @@ std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16,
// If the path is a long path, mangled into forward slashes, normalize
// back to backslashes here.
- if (Path8Str.startswith("//?/"))
+ if (Path8Str.starts_with("//?/"))
llvm::sys::path::native(Path8Str, path::Style::windows_backslash);
if (std::error_code EC = UTF8ToUTF16(Path8Str, Path16))
@@ -96,7 +96,7 @@ std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16,
const char *const LongPathPrefix = "\\\\?\\";
if ((Path16.size() + CurPathLen) < MaxPathLen ||
- Path8Str.startswith(LongPathPrefix))
+ Path8Str.starts_with(LongPathPrefix))
return std::error_code();
if (!IsAbsolute) {
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 8908e7b6a150..28ab85d4344c 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -13,8 +13,10 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
+#include "llvm/Support/AutoConvert.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Duration.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
@@ -23,11 +25,17 @@
#include "llvm/Support/NativeFormatting.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/Threading.h"
#include <algorithm>
#include <cerrno>
#include <cstdio>
#include <sys/stat.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif // _WIN32
+
// <fcntl.h> may provide O_BINARY.
#if defined(HAVE_FCNTL_H)
# include <fcntl.h>
@@ -58,6 +66,13 @@
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/Windows/WindowsSupport.h"
+// winsock2.h must be included before afunix.h. Briefly turn off clang-format to
+// avoid error.
+// clang-format off
+#include <winsock2.h>
+#include <afunix.h>
+// clang-format on
+#include <io.h>
#endif
using namespace llvm;
@@ -644,7 +659,7 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
// Check if this is a console device. This is not equivalent to isatty.
IsWindowsConsole =
::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
-#endif
+#endif // _WIN32
// Get the starting position.
off_t loc = ::lseek(FD, 0, SEEK_CUR);
@@ -895,6 +910,10 @@ void raw_fd_ostream::anchor() {}
raw_fd_ostream &llvm::outs() {
// Set buffer settings to model stdout behavior.
std::error_code EC;
+#ifdef __MVS__
+ EC = enableAutoConversion(STDOUT_FILENO);
+ assert(!EC);
+#endif
static raw_fd_ostream S("-", EC, sys::fs::OF_None);
assert(!EC);
return S;
@@ -902,6 +921,10 @@ raw_fd_ostream &llvm::outs() {
raw_fd_ostream &llvm::errs() {
// Set standard error to be unbuffered and tied to outs() by default.
+#ifdef __MVS__
+ std::error_code EC = enableAutoConversion(STDERR_FILENO);
+ assert(!EC);
+#endif
static raw_fd_ostream S(STDERR_FILENO, false, true);
return S;
}
@@ -928,6 +951,9 @@ raw_fd_stream::raw_fd_stream(StringRef Filename, std::error_code &EC)
EC = std::make_error_code(std::errc::invalid_argument);
}
+raw_fd_stream::raw_fd_stream(int fd, bool shouldClose)
+ : raw_fd_ostream(fd, shouldClose, false, OStreamKind::OK_FDStream) {}
+
ssize_t raw_fd_stream::read(char *Ptr, size_t Size) {
assert(get_fd() >= 0 && "File already closed.");
ssize_t Ret = ::read(get_fd(), (void *)Ptr, Size);
@@ -943,6 +969,145 @@ bool raw_fd_stream::classof(const raw_ostream *OS) {
}
//===----------------------------------------------------------------------===//
+// raw_socket_stream
+//===----------------------------------------------------------------------===//
+
+#ifdef _WIN32
+WSABalancer::WSABalancer() {
+ WSADATA WsaData;
+ ::memset(&WsaData, 0, sizeof(WsaData));
+ if (WSAStartup(MAKEWORD(2, 2), &WsaData) != 0) {
+ llvm::report_fatal_error("WSAStartup failed");
+ }
+}
+
+WSABalancer::~WSABalancer() { WSACleanup(); }
+
+#endif // _WIN32
+
+static std::error_code getLastSocketErrorCode() {
+#ifdef _WIN32
+ return std::error_code(::WSAGetLastError(), std::system_category());
+#else
+ return std::error_code(errno, std::system_category());
+#endif
+}
+
+ListeningSocket::ListeningSocket(int SocketFD, StringRef SocketPath)
+ : FD(SocketFD), SocketPath(SocketPath) {}
+
+ListeningSocket::ListeningSocket(ListeningSocket &&LS)
+ : FD(LS.FD), SocketPath(LS.SocketPath) {
+ LS.FD = -1;
+}
+
+Expected<ListeningSocket> ListeningSocket::createUnix(StringRef SocketPath,
+ int MaxBacklog) {
+
+#ifdef _WIN32
+ WSABalancer _;
+ SOCKET MaybeWinsocket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (MaybeWinsocket == INVALID_SOCKET) {
+#else
+ int MaybeWinsocket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (MaybeWinsocket == -1) {
+#endif
+ return llvm::make_error<StringError>(getLastSocketErrorCode(),
+ "socket create failed");
+ }
+
+ struct sockaddr_un Addr;
+ memset(&Addr, 0, sizeof(Addr));
+ Addr.sun_family = AF_UNIX;
+ strncpy(Addr.sun_path, SocketPath.str().c_str(), sizeof(Addr.sun_path) - 1);
+
+ if (bind(MaybeWinsocket, (struct sockaddr *)&Addr, sizeof(Addr)) == -1) {
+ std::error_code Err = getLastSocketErrorCode();
+ if (Err == std::errc::address_in_use)
+ ::close(MaybeWinsocket);
+ return llvm::make_error<StringError>(Err, "Bind error");
+ }
+ if (listen(MaybeWinsocket, MaxBacklog) == -1) {
+ return llvm::make_error<StringError>(getLastSocketErrorCode(),
+ "Listen error");
+ }
+ int UnixSocket;
+#ifdef _WIN32
+ UnixSocket = _open_osfhandle(MaybeWinsocket, 0);
+#else
+ UnixSocket = MaybeWinsocket;
+#endif // _WIN32
+ return ListeningSocket{UnixSocket, SocketPath};
+}
+
+Expected<std::unique_ptr<raw_socket_stream>> ListeningSocket::accept() {
+ int AcceptFD;
+#ifdef _WIN32
+ SOCKET WinServerSock = _get_osfhandle(FD);
+ SOCKET WinAcceptSock = ::accept(WinServerSock, NULL, NULL);
+ AcceptFD = _open_osfhandle(WinAcceptSock, 0);
+#else
+ AcceptFD = ::accept(FD, NULL, NULL);
+#endif //_WIN32
+ if (AcceptFD == -1)
+ return llvm::make_error<StringError>(getLastSocketErrorCode(),
+ "Accept failed");
+ return std::make_unique<raw_socket_stream>(AcceptFD);
+}
+
+ListeningSocket::~ListeningSocket() {
+ if (FD == -1)
+ return;
+ ::close(FD);
+ unlink(SocketPath.c_str());
+}
+
+static Expected<int> GetSocketFD(StringRef SocketPath) {
+#ifdef _WIN32
+ SOCKET MaybeWinsocket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (MaybeWinsocket == INVALID_SOCKET) {
+#else
+ int MaybeWinsocket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (MaybeWinsocket == -1) {
+#endif // _WIN32
+ return llvm::make_error<StringError>(getLastSocketErrorCode(),
+ "Create socket failed");
+ }
+
+ struct sockaddr_un Addr;
+ memset(&Addr, 0, sizeof(Addr));
+ Addr.sun_family = AF_UNIX;
+ strncpy(Addr.sun_path, SocketPath.str().c_str(), sizeof(Addr.sun_path) - 1);
+
+ int status = connect(MaybeWinsocket, (struct sockaddr *)&Addr, sizeof(Addr));
+ if (status == -1) {
+ return llvm::make_error<StringError>(getLastSocketErrorCode(),
+ "Connect socket failed");
+ }
+#ifdef _WIN32
+ return _open_osfhandle(MaybeWinsocket, 0);
+#else
+ return MaybeWinsocket;
+#endif // _WIN32
+}
+
+raw_socket_stream::raw_socket_stream(int SocketFD)
+ : raw_fd_stream(SocketFD, true) {}
+
+Expected<std::unique_ptr<raw_socket_stream>>
+raw_socket_stream::createConnectedUnix(StringRef SocketPath) {
+#ifdef _WIN32
+ WSABalancer _;
+#endif // _WIN32
+ Expected<int> FD = GetSocketFD(SocketPath);
+ if (!FD)
+ return FD.takeError();
+ return std::make_unique<raw_socket_stream>(*FD);
+}
+
+raw_socket_stream::~raw_socket_stream() {}
+
+//===----------------------------------------------------------------------===//
// raw_string_ostream
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td
index ff256c9a8ccd..c600bcaab2b3 100644
--- a/llvm/lib/Target/AArch64/AArch64.td
+++ b/llvm/lib/Target/AArch64/AArch64.td
@@ -1480,9 +1480,9 @@ def ProcessorFeatures {
FeatureFPARMv8, FeatureFullFP16, FeatureNEON,
FeatureRCPC, FeatureSPE, FeatureSSBS,
FeaturePerfMon];
- list<SubtargetFeature> NeoverseN2 = [HasV8_5aOps, FeatureBF16, FeatureETE,
+ list<SubtargetFeature> NeoverseN2 = [HasV9_0aOps, FeatureBF16, FeatureETE,
FeatureMatMulInt8, FeatureMTE, FeatureSVE2,
- FeatureSVE2BitPerm, FeatureTRBE, FeatureCrypto,
+ FeatureSVE2BitPerm, FeatureTRBE,
FeaturePerfMon];
list<SubtargetFeature> Neoverse512TVB = [HasV8_4aOps, FeatureBF16, FeatureCacheDeepPersist,
FeatureCrypto, FeatureFPARMv8, FeatureFP16FML,
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index f4d3a85f34c8..90e1ce9ddf66 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -30,6 +30,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/FaultMaps.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
@@ -47,10 +48,12 @@
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
@@ -198,6 +201,15 @@ private:
bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const override {
return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
}
+
+ const MCSubtargetInfo *getIFuncMCSubtargetInfo() const override {
+ assert(STI);
+ return STI;
+ }
+ void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) override;
+ void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) override;
};
} // end anonymous namespace
@@ -1809,6 +1821,201 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, TmpInst);
}
+void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) {
+ // _ifunc:
+ // adrp x16, lazy_pointer@GOTPAGE
+ // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
+ // ldr x16, [x16]
+ // br x16
+
+ {
+ MCInst Adrp;
+ Adrp.setOpcode(AArch64::ADRP);
+ Adrp.addOperand(MCOperand::createReg(AArch64::X16));
+ MCOperand SymPage;
+ MCInstLowering.lowerOperand(
+ MachineOperand::CreateMCSymbol(LazyPointer,
+ AArch64II::MO_GOT | AArch64II::MO_PAGE),
+ SymPage);
+ Adrp.addOperand(SymPage);
+ OutStreamer->emitInstruction(Adrp, *STI);
+ }
+
+ {
+ MCInst Ldr;
+ Ldr.setOpcode(AArch64::LDRXui);
+ Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+ Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+ MCOperand SymPageOff;
+ MCInstLowering.lowerOperand(
+ MachineOperand::CreateMCSymbol(LazyPointer, AArch64II::MO_GOT |
+ AArch64II::MO_PAGEOFF),
+ SymPageOff);
+ Ldr.addOperand(SymPageOff);
+ Ldr.addOperand(MCOperand::createImm(0));
+ OutStreamer->emitInstruction(Ldr, *STI);
+ }
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X16)
+ .addImm(0),
+ *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
+ ? AArch64::BRAAZ
+ : AArch64::BR)
+ .addReg(AArch64::X16),
+ *STI);
+}
+
+void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
+ const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) {
+ // These stub helpers are only ever called once, so here we're optimizing for
+ // minimum size by using the pre-indexed store variants, which saves a few
+ // bytes of instructions to bump & restore sp.
+
+ // _ifunc.stub_helper:
+ // stp fp, lr, [sp, #-16]!
+ // mov fp, sp
+ // stp x1, x0, [sp, #-16]!
+ // stp x3, x2, [sp, #-16]!
+ // stp x5, x4, [sp, #-16]!
+ // stp x7, x6, [sp, #-16]!
+ // stp d1, d0, [sp, #-16]!
+ // stp d3, d2, [sp, #-16]!
+ // stp d5, d4, [sp, #-16]!
+ // stp d7, d6, [sp, #-16]!
+ // bl _resolver
+ // adrp x16, lazy_pointer@GOTPAGE
+ // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
+ // str x0, [x16]
+ // mov x16, x0
+ // ldp d7, d6, [sp], #16
+ // ldp d5, d4, [sp], #16
+ // ldp d3, d2, [sp], #16
+ // ldp d1, d0, [sp], #16
+ // ldp x7, x6, [sp], #16
+ // ldp x5, x4, [sp], #16
+ // ldp x3, x2, [sp], #16
+ // ldp x1, x0, [sp], #16
+ // ldp fp, lr, [sp], #16
+ // br x16
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::FP)
+ .addReg(AArch64::LR)
+ .addReg(AArch64::SP)
+ .addImm(-2),
+ *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
+ .addReg(AArch64::FP)
+ .addReg(AArch64::SP)
+ .addImm(0)
+ .addImm(0),
+ *STI);
+
+ for (int I = 0; I != 4; ++I)
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::X1 + 2 * I)
+ .addReg(AArch64::X0 + 2 * I)
+ .addReg(AArch64::SP)
+ .addImm(-2),
+ *STI);
+
+ for (int I = 0; I != 4; ++I)
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::D1 + 2 * I)
+ .addReg(AArch64::D0 + 2 * I)
+ .addReg(AArch64::SP)
+ .addImm(-2),
+ *STI);
+
+ OutStreamer->emitInstruction(
+ MCInstBuilder(AArch64::BL)
+ .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
+ *STI);
+
+ {
+ MCInst Adrp;
+ Adrp.setOpcode(AArch64::ADRP);
+ Adrp.addOperand(MCOperand::createReg(AArch64::X16));
+ MCOperand SymPage;
+ MCInstLowering.lowerOperand(
+ MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+ AArch64II::MO_GOT | AArch64II::MO_PAGE),
+ SymPage);
+ Adrp.addOperand(SymPage);
+ OutStreamer->emitInstruction(Adrp, *STI);
+ }
+
+ {
+ MCInst Ldr;
+ Ldr.setOpcode(AArch64::LDRXui);
+ Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+ Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+ MCOperand SymPageOff;
+ MCInstLowering.lowerOperand(
+ MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+ AArch64II::MO_GOT | AArch64II::MO_PAGEOFF),
+ SymPageOff);
+ Ldr.addOperand(SymPageOff);
+ Ldr.addOperand(MCOperand::createImm(0));
+ OutStreamer->emitInstruction(Ldr, *STI);
+ }
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::STRXui)
+ .addReg(AArch64::X0)
+ .addReg(AArch64::X16)
+ .addImm(0),
+ *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X0)
+ .addImm(0)
+ .addImm(0),
+ *STI);
+
+ for (int I = 3; I != -1; --I)
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::D1 + 2 * I)
+ .addReg(AArch64::D0 + 2 * I)
+ .addReg(AArch64::SP)
+ .addImm(2),
+ *STI);
+
+ for (int I = 3; I != -1; --I)
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::X1 + 2 * I)
+ .addReg(AArch64::X0 + 2 * I)
+ .addReg(AArch64::SP)
+ .addImm(2),
+ *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::FP)
+ .addReg(AArch64::LR)
+ .addReg(AArch64::SP)
+ .addImm(2),
+ *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
+ ? AArch64::BRAAZ
+ : AArch64::BR)
+ .addReg(AArch64::X16),
+ *STI);
+}
+
// Force static initialization.
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter() {
RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget());
diff --git a/llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp b/llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp
index 88e44eb0bfbb..8ce6f94e7341 100644
--- a/llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp
+++ b/llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp
@@ -37,7 +37,7 @@ static bool shouldTagGlobal(GlobalVariable &G) {
// For now, don't instrument constant data, as it'll be in .rodata anyway. It
// may be worth instrumenting these in future to stop them from being used as
// gadgets.
- if (G.getName().startswith("llvm.") || G.isThreadLocal() || G.isConstant()) {
+ if (G.getName().starts_with("llvm.") || G.isThreadLocal() || G.isConstant()) {
Meta.Memtag = false;
G.setSanitizerMetadata(Meta);
return false;
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index d05d22a7164e..463ec41b94e9 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -435,6 +435,8 @@ public:
bool trySelectCastFixedLengthToScalableVector(SDNode *N);
bool trySelectCastScalableToFixedLengthVector(SDNode *N);
+ bool trySelectXAR(SDNode *N);
+
// Include the pieces autogenerated from the target description.
#include "AArch64GenDAGISel.inc"
@@ -4273,6 +4275,40 @@ bool AArch64DAGToDAGISel::trySelectCastScalableToFixedLengthVector(SDNode *N) {
return true;
}
+bool AArch64DAGToDAGISel::trySelectXAR(SDNode *N) {
+ assert(N->getOpcode() == ISD::OR && "Expected OR instruction");
+
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+
+ if (N0->getOpcode() != AArch64ISD::VSHL ||
+ N1->getOpcode() != AArch64ISD::VLSHR)
+ return false;
+
+ if (N0->getOperand(0) != N1->getOperand(0) ||
+ N1->getOperand(0)->getOpcode() != ISD::XOR)
+ return false;
+
+ SDValue XOR = N0.getOperand(0);
+ SDValue R1 = XOR.getOperand(0);
+ SDValue R2 = XOR.getOperand(1);
+
+ unsigned HsAmt = N0.getConstantOperandVal(1);
+ unsigned ShAmt = N1.getConstantOperandVal(1);
+
+ SDLoc DL = SDLoc(N0.getOperand(1));
+ SDValue Imm = CurDAG->getTargetConstant(
+ ShAmt, DL, N0.getOperand(1).getValueType(), false);
+
+ if (ShAmt + HsAmt != 64)
+ return false;
+
+ SDValue Ops[] = {R1, R2, Imm};
+ CurDAG->SelectNodeTo(N, AArch64::XAR, N0.getValueType(), Ops);
+
+ return true;
+}
+
void AArch64DAGToDAGISel::Select(SDNode *Node) {
// If we have a custom node, we already have selected!
if (Node->isMachineOpcode()) {
@@ -4336,6 +4372,8 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
case ISD::OR:
if (tryBitfieldInsertOp(Node))
return;
+ if (Subtarget->hasSHA3() && trySelectXAR(Node))
+ return;
break;
case ISD::EXTRACT_SUBVECTOR: {
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index bc74d44a8fbc..3882e843fb69 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -1651,6 +1651,7 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
PredictableSelectIsExpensive = Subtarget->predictableSelectIsExpensive();
IsStrictFPEnabled = true;
+ setMaxAtomicSizeInBitsSupported(128);
}
void AArch64TargetLowering::addTypeForNEON(MVT VT) {
@@ -24909,15 +24910,21 @@ AArch64TargetLowering::shouldExpandAtomicLoadInIR(LoadInst *LI) const {
: AtomicExpansionKind::LLSC;
}
-// For the real atomic operations, we have ldxr/stxr up to 128 bits,
+// The "default" for integer RMW operations is to expand to an LL/SC loop.
+// However, with the LSE instructions (or outline-atomics mode, which provides
+// library routines in place of the LSE-instructions), we can directly emit many
+// operations instead.
+//
+// Floating-point operations are always emitted to a cmpxchg loop, because they
+// may trigger a trap which aborts an LLSC sequence.
TargetLowering::AtomicExpansionKind
AArch64TargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
+ unsigned Size = AI->getType()->getPrimitiveSizeInBits();
+ assert(Size <= 128 && "AtomicExpandPass should've handled larger sizes.");
+
if (AI->isFloatingPointOperation())
return AtomicExpansionKind::CmpXChg;
- unsigned Size = AI->getType()->getPrimitiveSizeInBits();
- if (Size > 128) return AtomicExpansionKind::None;
-
bool CanUseLSE128 = Subtarget->hasLSE128() && Size == 128 &&
(AI->getOperation() == AtomicRMWInst::Xchg ||
AI->getOperation() == AtomicRMWInst::Or ||
diff --git a/llvm/lib/Target/AArch64/AArch64InstrGISel.td b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
index 1711360779bf..1c88456560d3 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrGISel.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
@@ -209,7 +209,7 @@ def G_FCMLTZ : AArch64GenericInstruction {
let hasSideEffects = 0;
}
-def G_PREFETCH : AArch64GenericInstruction {
+def G_AARCH64_PREFETCH : AArch64GenericInstruction {
let OutOperandList = (outs);
let InOperandList = (ins type0:$imm, ptype0:$src1);
let hasSideEffects = 1;
@@ -287,7 +287,7 @@ def : GINodeEquiv<G_SDOT, AArch64sdot>;
def : GINodeEquiv<G_EXTRACT_VECTOR_ELT, vector_extract>;
-def : GINodeEquiv<G_PREFETCH, AArch64Prefetch>;
+def : GINodeEquiv<G_AARCH64_PREFETCH, AArch64Prefetch>;
// These are patterns that we only use for GlobalISel via the importer.
def : Pat<(f32 (fadd (vector_extract (v2f32 FPR64:$Rn), (i64 0)),
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index 93b8295f4f3e..7d71c316bcb0 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -9185,19 +9185,32 @@ AArch64InstrInfo::isCopyInstrImpl(const MachineInstr &MI) const {
// and zero immediate operands used as an alias for mov instruction.
if (MI.getOpcode() == AArch64::ORRWrs &&
MI.getOperand(1).getReg() == AArch64::WZR &&
- MI.getOperand(3).getImm() == 0x0) {
+ MI.getOperand(3).getImm() == 0x0 &&
+ // Check that the w->w move is not a zero-extending w->x mov.
+ (!MI.getOperand(0).getReg().isVirtual() ||
+ MI.getOperand(0).getSubReg() == 0) &&
+ (!MI.getOperand(0).getReg().isPhysical() ||
+ MI.findRegisterDefOperandIdx(MI.getOperand(0).getReg() - AArch64::W0 +
+ AArch64::X0) == -1))
return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
- }
if (MI.getOpcode() == AArch64::ORRXrs &&
MI.getOperand(1).getReg() == AArch64::XZR &&
- MI.getOperand(3).getImm() == 0x0) {
+ MI.getOperand(3).getImm() == 0x0)
return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
- }
return std::nullopt;
}
+std::optional<DestSourcePair>
+AArch64InstrInfo::isCopyLikeInstrImpl(const MachineInstr &MI) const {
+ if (MI.getOpcode() == AArch64::ORRWrs &&
+ MI.getOperand(1).getReg() == AArch64::WZR &&
+ MI.getOperand(3).getImm() == 0x0)
+ return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
+ return std::nullopt;
+}
+
std::optional<RegImmPair>
AArch64InstrInfo::isAddImmediate(const MachineInstr &MI, Register Reg) const {
int Sign = 1;
@@ -9241,7 +9254,7 @@ static std::optional<ParamLoadedValue>
describeORRLoadedValue(const MachineInstr &MI, Register DescribedReg,
const TargetInstrInfo *TII,
const TargetRegisterInfo *TRI) {
- auto DestSrc = TII->isCopyInstr(MI);
+ auto DestSrc = TII->isCopyLikeInstr(MI);
if (!DestSrc)
return std::nullopt;
@@ -9532,9 +9545,9 @@ AArch64InstrInfo::probedStackAlloc(MachineBasicBlock::iterator MBBI,
.addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, 0))
.setMIFlags(Flags);
- // STR XZR, [SP]
- BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(AArch64::STRXui))
- .addReg(AArch64::XZR)
+ // LDR XZR, [SP]
+ BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(AArch64::LDRXui))
+ .addReg(AArch64::XZR, RegState::Define)
.addReg(AArch64::SP)
.addImm(0)
.setMIFlags(Flags);
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
index e97ff0a9758d..6526f6740747 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
@@ -401,6 +401,8 @@ protected:
/// registers as machine operands.
std::optional<DestSourcePair>
isCopyInstrImpl(const MachineInstr &MI) const override;
+ std::optional<DestSourcePair>
+ isCopyLikeInstrImpl(const MachineInstr &MI) const override;
private:
unsigned getInstBundleLength(const MachineInstr &MI) const;
diff --git a/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp b/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp
index 3687492c3e3e..76dd5a2d713e 100644
--- a/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp
+++ b/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp
@@ -212,7 +212,7 @@ bool SLSBLRThunkInserter::insertThunks(MachineModuleInfo &MMI,
void SLSBLRThunkInserter::populateThunk(MachineFunction &MF) {
// FIXME: How to better communicate Register number, rather than through
// name and lookup table?
- assert(MF.getName().startswith(getThunkPrefix()));
+ assert(MF.getName().starts_with(getThunkPrefix()));
auto ThunkIt = llvm::find_if(
SLSBLRThunks, [&MF](auto T) { return T.Name == MF.getName(); });
assert(ThunkIt != std::end(SLSBLRThunks));
diff --git a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
index 21cafe9b6c44..50527e08a061 100644
--- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
@@ -4063,11 +4063,11 @@ defm BFCLAMP_ZZZ : sve2p1_bfclamp<"bfclamp", int_aarch64_sve_fclamp>;
// SME2.1 or SVE2.1 instructions
//===----------------------------------------------------------------------===//
let Predicates = [HasSVE2p1_or_HasSME2p1] in {
-defm FADDQV : sve2p1_fp_reduction_q<0b000, "faddqv">;
-defm FMAXNMQV : sve2p1_fp_reduction_q<0b100, "fmaxnmqv">;
-defm FMINNMQV : sve2p1_fp_reduction_q<0b101, "fminnmqv">;
-defm FMAXQV : sve2p1_fp_reduction_q<0b110, "fmaxqv">;
-defm FMINQV : sve2p1_fp_reduction_q<0b111, "fminqv">;
+defm FADDQV : sve2p1_fp_reduction_q<0b000, "faddqv", int_aarch64_sve_addqv>;
+defm FMAXNMQV : sve2p1_fp_reduction_q<0b100, "fmaxnmqv", int_aarch64_sve_fmaxnmqv>;
+defm FMINNMQV : sve2p1_fp_reduction_q<0b101, "fminnmqv", int_aarch64_sve_fminnmqv>;
+defm FMAXQV : sve2p1_fp_reduction_q<0b110, "fmaxqv", int_aarch64_sve_fmaxqv>;
+defm FMINQV : sve2p1_fp_reduction_q<0b111, "fminqv", int_aarch64_sve_fminqv>;
defm DUPQ_ZZI : sve2p1_dupq<"dupq">;
defm EXTQ_ZZI : sve2p1_extq<"extq", int_aarch64_sve_extq_lane>;
@@ -4075,14 +4075,14 @@ defm EXTQ_ZZI : sve2p1_extq<"extq", int_aarch64_sve_extq_lane>;
defm PMOV_PZI : sve2p1_vector_to_pred<"pmov", int_aarch64_sve_pmov_to_pred_lane, int_aarch64_sve_pmov_to_pred_lane_zero>;
defm PMOV_ZIP : sve2p1_pred_to_vector<"pmov", int_aarch64_sve_pmov_to_vector_lane_merging, int_aarch64_sve_pmov_to_vector_lane_zeroing>;
-defm ORQV_VPZ : sve2p1_int_reduce_q<0b1100, "orqv">;
-defm EORQV_VPZ : sve2p1_int_reduce_q<0b1101, "eorqv">;
-defm ANDQV_VPZ : sve2p1_int_reduce_q<0b1110, "andqv">;
-defm ADDQV_VPZ : sve2p1_int_reduce_q<0b0001, "addqv">;
-defm SMAXQV_VPZ : sve2p1_int_reduce_q<0b0100, "smaxqv">;
-defm UMAXQV_VPZ : sve2p1_int_reduce_q<0b0101, "umaxqv">;
-defm SMINQV_VPZ : sve2p1_int_reduce_q<0b0110, "sminqv">;
-defm UMINQV_VPZ : sve2p1_int_reduce_q<0b0111, "uminqv">;
+defm ORQV_VPZ : sve2p1_int_reduce_q<0b1100, "orqv", int_aarch64_sve_orqv>;
+defm EORQV_VPZ : sve2p1_int_reduce_q<0b1101, "eorqv", int_aarch64_sve_eorqv>;
+defm ANDQV_VPZ : sve2p1_int_reduce_q<0b1110, "andqv", int_aarch64_sve_andqv>;
+defm ADDQV_VPZ : sve2p1_int_reduce_q<0b0001, "addqv", int_aarch64_sve_addqv>;
+defm SMAXQV_VPZ : sve2p1_int_reduce_q<0b0100, "smaxqv", int_aarch64_sve_smaxqv>;
+defm UMAXQV_VPZ : sve2p1_int_reduce_q<0b0101, "umaxqv", int_aarch64_sve_umaxqv>;
+defm SMINQV_VPZ : sve2p1_int_reduce_q<0b0110, "sminqv", int_aarch64_sve_sminqv>;
+defm UMINQV_VPZ : sve2p1_int_reduce_q<0b0111, "uminqv", int_aarch64_sve_uminqv>;
defm ZIPQ1_ZZZ : sve2p1_permute_vec_elems_q<0b000, "zipq1", int_aarch64_sve_zipq1>;
defm ZIPQ2_ZZZ : sve2p1_permute_vec_elems_q<0b001, "zipq2", int_aarch64_sve_zipq2>;
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index fbe1bf3c5238..238269cf27bd 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -3250,7 +3250,7 @@ ParseStatus AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
}
// Parse hexadecimal representation.
- if (Tok.is(AsmToken::Integer) && Tok.getString().startswith("0x")) {
+ if (Tok.is(AsmToken::Integer) && Tok.getString().starts_with("0x")) {
if (Tok.getIntVal() > 255 || isNegative)
return TokError("encoded floating point value out of range");
@@ -7524,7 +7524,7 @@ bool AArch64AsmParser::parseAuthExpr(const MCExpr *&Res, SMLoc &EndLoc) {
AsmToken Tok = Parser.getTok();
// Look for '_sym@AUTH' ...
- if (Tok.is(AsmToken::Identifier) && Tok.getIdentifier().endswith("@AUTH")) {
+ if (Tok.is(AsmToken::Identifier) && Tok.getIdentifier().ends_with("@AUTH")) {
StringRef SymName = Tok.getIdentifier().drop_back(strlen("@AUTH"));
if (SymName.contains('@'))
return TokError(
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 21a412e9360d..8b909f53c844 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -758,18 +758,18 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
all(typeInSet(0, {s8, s16, s32, s64, s128}), typeIs(2, p0)));
getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG)
+ .legalIf(all(typeInSet(0, {s32, s64}), typeIs(1, p0)))
.customIf([](const LegalityQuery &Query) {
return Query.Types[0].getSizeInBits() == 128;
})
- .clampScalar(0, s32, s64)
- .legalIf(all(typeInSet(0, {s32, s64}), typeIs(1, p0)));
+ .clampScalar(0, s32, s64);
getActionDefinitionsBuilder(
{G_ATOMICRMW_XCHG, G_ATOMICRMW_ADD, G_ATOMICRMW_SUB, G_ATOMICRMW_AND,
G_ATOMICRMW_OR, G_ATOMICRMW_XOR, G_ATOMICRMW_MIN, G_ATOMICRMW_MAX,
G_ATOMICRMW_UMIN, G_ATOMICRMW_UMAX})
- .clampScalar(0, s32, s64)
- .legalIf(all(typeInSet(0, {s32, s64}), typeIs(1, p0)));
+ .legalIf(all(typeInSet(0, {s32, s64}), typeIs(1, p0)))
+ .clampScalar(0, s32, s64);
getActionDefinitionsBuilder(G_BLOCK_ADDR).legalFor({p0});
@@ -1127,6 +1127,8 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
getActionDefinitionsBuilder(G_IS_FPCLASS).lower();
+ getActionDefinitionsBuilder(G_PREFETCH).custom();
+
getLegacyLegalizerInfo().computeTables();
verify(*ST.getInstrInfo());
}
@@ -1176,6 +1178,8 @@ bool AArch64LegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
return legalizeExtractVectorElt(MI, MRI, Helper);
case TargetOpcode::G_DYN_STACKALLOC:
return legalizeDynStackAlloc(MI, Helper);
+ case TargetOpcode::G_PREFETCH:
+ return legalizePrefetch(MI, Helper);
}
llvm_unreachable("expected switch to return");
@@ -1349,30 +1353,6 @@ bool AArch64LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
Value.setReg(ExtValueReg);
return true;
}
- case Intrinsic::prefetch: {
- MachineIRBuilder MIB(MI);
- auto &AddrVal = MI.getOperand(1);
-
- int64_t IsWrite = MI.getOperand(2).getImm();
- int64_t Locality = MI.getOperand(3).getImm();
- int64_t IsData = MI.getOperand(4).getImm();
-
- bool IsStream = Locality == 0;
- if (Locality != 0) {
- assert(Locality <= 3 && "Prefetch locality out-of-range");
- // The locality degree is the opposite of the cache speed.
- // Put the number the other way around.
- // The encoding starts at 0 for level 1
- Locality = 3 - Locality;
- }
-
- unsigned PrfOp =
- (IsWrite << 4) | (!IsData << 3) | (Locality << 1) | IsStream;
-
- MIB.buildInstr(AArch64::G_PREFETCH).addImm(PrfOp).add(AddrVal);
- MI.eraseFromParent();
- return true;
- }
case Intrinsic::aarch64_prefetch: {
MachineIRBuilder MIB(MI);
auto &AddrVal = MI.getOperand(1);
@@ -1387,7 +1367,7 @@ bool AArch64LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
(Target << 1) | // Cache level bits
(unsigned)IsStream; // Stream bit
- MIB.buildInstr(AArch64::G_PREFETCH).addImm(PrfOp).add(AddrVal);
+ MIB.buildInstr(AArch64::G_AARCH64_PREFETCH).addImm(PrfOp).add(AddrVal);
MI.eraseFromParent();
return true;
}
@@ -1986,3 +1966,28 @@ bool AArch64LegalizerInfo::legalizeDynStackAlloc(
MI.eraseFromParent();
return true;
}
+
+bool AArch64LegalizerInfo::legalizePrefetch(MachineInstr &MI,
+ LegalizerHelper &Helper) const {
+ MachineIRBuilder &MIB = Helper.MIRBuilder;
+ auto &AddrVal = MI.getOperand(0);
+
+ int64_t IsWrite = MI.getOperand(1).getImm();
+ int64_t Locality = MI.getOperand(2).getImm();
+ int64_t IsData = MI.getOperand(3).getImm();
+
+ bool IsStream = Locality == 0;
+ if (Locality != 0) {
+ assert(Locality <= 3 && "Prefetch locality out-of-range");
+ // The locality degree is the opposite of the cache speed.
+ // Put the number the other way around.
+ // The encoding starts at 0 for level 1
+ Locality = 3 - Locality;
+ }
+
+ unsigned PrfOp = (IsWrite << 4) | (!IsData << 3) | (Locality << 1) | IsStream;
+
+ MIB.buildInstr(AArch64::G_AARCH64_PREFETCH).addImm(PrfOp).add(AddrVal);
+ MI.eraseFromParent();
+ return true;
+}
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h
index 6fd859d334cd..19f77baa77f8 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h
@@ -64,6 +64,7 @@ private:
bool legalizeExtractVectorElt(MachineInstr &MI, MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const;
bool legalizeDynStackAlloc(MachineInstr &MI, LegalizerHelper &Helper) const;
+ bool legalizePrefetch(MachineInstr &MI, LegalizerHelper &Helper) const;
const AArch64Subtarget *ST;
};
} // End llvm namespace.
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp
index 3284d0f033e3..b8e5e7bbdaba 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp
@@ -621,6 +621,13 @@ bool AArch64RegisterBankInfo::isLoadFromFPType(const MachineInstr &MI) const {
Type *EltTy = nullptr;
if (const GlobalValue *GV = dyn_cast<GlobalValue>(LdVal)) {
EltTy = GV->getValueType();
+ // Look at the first element of the struct to determine the type we are
+ // loading
+ while (StructType *StructEltTy = dyn_cast<StructType>(EltTy))
+ EltTy = StructEltTy->getTypeAtIndex(0U);
+ // Look at the first element of the array to determine its type
+ if (isa<ArrayType>(EltTy))
+ EltTy = EltTy->getArrayElementType();
} else {
// FIXME: grubbing around uses is pretty ugly, but with no more
// `getPointerElementType` there's not much else we can do.
diff --git a/llvm/lib/Target/AArch64/SVEInstrFormats.td b/llvm/lib/Target/AArch64/SVEInstrFormats.td
index c0894e9c7068..9edf26052247 100644
--- a/llvm/lib/Target/AArch64/SVEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SVEInstrFormats.td
@@ -9963,10 +9963,14 @@ class sve2p1_fp_reduction_q<bits<2> sz, bits<3> opc, string mnemonic,
let mayRaiseFPException = 1;
}
-multiclass sve2p1_fp_reduction_q<bits<3> opc, string mnemonic> {
+multiclass sve2p1_fp_reduction_q<bits<3> opc, string mnemonic, SDPatternOperator op> {
def _H : sve2p1_fp_reduction_q<0b01, opc, mnemonic, ZPR16, "8h">;
def _S : sve2p1_fp_reduction_q<0b10, opc, mnemonic, ZPR32, "4s">;
def _D : sve2p1_fp_reduction_q<0b11, opc, mnemonic, ZPR64, "2d">;
+
+ def : SVE_2_Op_Pat<v8f16, op, nxv8i1, nxv8f16, !cast<Instruction>(NAME # _H)>;
+ def : SVE_2_Op_Pat<v4f32, op, nxv4i1, nxv4f32, !cast<Instruction>(NAME # _S)>;
+ def : SVE_2_Op_Pat<v2f64, op, nxv2i1, nxv2f64, !cast<Instruction>(NAME # _D)>;
}
@@ -10183,11 +10187,16 @@ class sve2p1_int_reduce_q<bits<2> sz, bits<4> opc, string mnemonic,
let hasSideEffects = 0;
}
-multiclass sve2p1_int_reduce_q<bits<4> opc, string mnemonic> {
+multiclass sve2p1_int_reduce_q<bits<4> opc, string mnemonic, SDPatternOperator op> {
def _B : sve2p1_int_reduce_q<0b00, opc, mnemonic, ZPR8, "16b">;
def _H : sve2p1_int_reduce_q<0b01, opc, mnemonic, ZPR16, "8h">;
def _S : sve2p1_int_reduce_q<0b10, opc, mnemonic, ZPR32, "4s">;
def _D : sve2p1_int_reduce_q<0b11, opc, mnemonic, ZPR64, "2d">;
+
+ def : SVE_2_Op_Pat<v16i8, op, nxv16i1, nxv16i8, !cast<Instruction>(NAME # _B)>;
+ def : SVE_2_Op_Pat<v8i16, op, nxv8i1, nxv8i16, !cast<Instruction>(NAME # _H)>;
+ def : SVE_2_Op_Pat<v4i32, op, nxv4i1, nxv4i32, !cast<Instruction>(NAME # _S)>;
+ def : SVE_2_Op_Pat<v2i64, op, nxv2i1, nxv2i64, !cast<Instruction>(NAME # _D)>;
}
diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.h b/llvm/lib/Target/AMDGPU/AMDGPU.h
index 323560a46f31..35d33cb60bc4 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.h
@@ -12,12 +12,12 @@
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
+#include "llvm/Support/AMDGPUAddrSpace.h"
#include "llvm/Support/CodeGen.h"
namespace llvm {
class AMDGPUTargetMachine;
-class GCNTargetMachine;
class TargetMachine;
// GlobalISel passes
@@ -36,6 +36,7 @@ FunctionPass *createSIAnnotateControlFlowPass();
FunctionPass *createSIFoldOperandsPass();
FunctionPass *createSIPeepholeSDWAPass();
FunctionPass *createSILowerI1CopiesPass();
+FunctionPass *createAMDGPUGlobalISelDivergenceLoweringPass();
FunctionPass *createSIShrinkInstructionsPass();
FunctionPass *createSILoadStoreOptimizerPass();
FunctionPass *createSIWholeQuadModePass();
@@ -162,6 +163,9 @@ extern char &SILowerWWMCopiesID;
void initializeSILowerI1CopiesPass(PassRegistry &);
extern char &SILowerI1CopiesID;
+void initializeAMDGPUGlobalISelDivergenceLoweringPass(PassRegistry &);
+extern char &AMDGPUGlobalISelDivergenceLoweringID;
+
void initializeSILowerSGPRSpillsPass(PassRegistry &);
extern char &SILowerSGPRSpillsID;
@@ -390,72 +394,6 @@ enum TargetIndex {
TI_SCRATCH_RSRC_DWORD2,
TI_SCRATCH_RSRC_DWORD3
};
-}
-
-/// OpenCL uses address spaces to differentiate between
-/// various memory regions on the hardware. On the CPU
-/// all of the address spaces point to the same memory,
-/// however on the GPU, each address space points to
-/// a separate piece of memory that is unique from other
-/// memory locations.
-namespace AMDGPUAS {
-enum : unsigned {
- // The maximum value for flat, generic, local, private, constant and region.
- MAX_AMDGPU_ADDRESS = 8,
-
- FLAT_ADDRESS = 0, ///< Address space for flat memory.
- GLOBAL_ADDRESS = 1, ///< Address space for global memory (RAT0, VTX0).
- REGION_ADDRESS = 2, ///< Address space for region memory. (GDS)
-
- CONSTANT_ADDRESS = 4, ///< Address space for constant memory (VTX2).
- LOCAL_ADDRESS = 3, ///< Address space for local memory.
- PRIVATE_ADDRESS = 5, ///< Address space for private memory.
-
- CONSTANT_ADDRESS_32BIT = 6, ///< Address space for 32-bit constant memory.
-
- BUFFER_FAT_POINTER = 7, ///< Address space for 160-bit buffer fat pointers.
- ///< Not used in backend.
-
- BUFFER_RESOURCE = 8, ///< Address space for 128-bit buffer resources.
-
- /// Internal address spaces. Can be freely renumbered.
- STREAMOUT_REGISTER = 128, ///< Address space for GS NGG Streamout registers.
- /// end Internal address spaces.
-
- /// Address space for direct addressable parameter memory (CONST0).
- PARAM_D_ADDRESS = 6,
- /// Address space for indirect addressable parameter memory (VTX1).
- PARAM_I_ADDRESS = 7,
-
- // Do not re-order the CONSTANT_BUFFER_* enums. Several places depend on
- // this order to be able to dynamically index a constant buffer, for
- // example:
- //
- // ConstantBufferAS = CONSTANT_BUFFER_0 + CBIdx
-
- CONSTANT_BUFFER_0 = 8,
- CONSTANT_BUFFER_1 = 9,
- CONSTANT_BUFFER_2 = 10,
- CONSTANT_BUFFER_3 = 11,
- CONSTANT_BUFFER_4 = 12,
- CONSTANT_BUFFER_5 = 13,
- CONSTANT_BUFFER_6 = 14,
- CONSTANT_BUFFER_7 = 15,
- CONSTANT_BUFFER_8 = 16,
- CONSTANT_BUFFER_9 = 17,
- CONSTANT_BUFFER_10 = 18,
- CONSTANT_BUFFER_11 = 19,
- CONSTANT_BUFFER_12 = 20,
- CONSTANT_BUFFER_13 = 21,
- CONSTANT_BUFFER_14 = 22,
- CONSTANT_BUFFER_15 = 23,
-
- // Some places use this if the address space can't be determined.
- UNKNOWN_ADDRESS_SPACE = ~0u,
-};
-}
-
-namespace AMDGPU {
// FIXME: Missing constant_32bit
inline bool isFlatGlobalAddrSpace(unsigned AS) {
@@ -472,24 +410,25 @@ inline bool isExtendedGlobalAddrSpace(unsigned AS) {
}
static inline bool addrspacesMayAlias(unsigned AS1, unsigned AS2) {
- static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 8, "Addr space out of range");
+ static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 9, "Addr space out of range");
if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS)
return true;
- // This array is indexed by address space value enum elements 0 ... to 8
+ // This array is indexed by address space value enum elements 0 ... to 9
// clang-format off
- static const bool ASAliasRules[9][9] = {
- /* Flat Global Region Group Constant Private Const32 BufFatPtr BufRsrc */
- /* Flat */ {true, true, false, true, true, true, true, true, true},
- /* Global */ {true, true, false, false, true, false, true, true, true},
- /* Region */ {false, false, true, false, false, false, false, false, false},
- /* Group */ {true, false, false, true, false, false, false, false, false},
- /* Constant */ {true, true, false, false, false, false, true, true, true},
- /* Private */ {true, false, false, false, false, true, false, false, false},
- /* Constant 32-bit */ {true, true, false, false, true, false, false, true, true},
- /* Buffer Fat Ptr */ {true, true, false, false, true, false, true, true, true},
- /* Buffer Resource */ {true, true, false, false, true, false, true, true, true},
+ static const bool ASAliasRules[10][10] = {
+ /* Flat Global Region Group Constant Private Const32 BufFatPtr BufRsrc BufStrdPtr */
+ /* Flat */ {true, true, false, true, true, true, true, true, true, true},
+ /* Global */ {true, true, false, false, true, false, true, true, true, true},
+ /* Region */ {false, false, true, false, false, false, false, false, false, false},
+ /* Group */ {true, false, false, true, false, false, false, false, false, false},
+ /* Constant */ {true, true, false, false, false, false, true, true, true, true},
+ /* Private */ {true, false, false, false, false, true, false, false, false, false},
+ /* Constant 32-bit */ {true, true, false, false, true, false, false, true, true, true},
+ /* Buffer Fat Ptr */ {true, true, false, false, true, false, true, true, true, true},
+ /* Buffer Resource */ {true, true, false, false, true, false, true, true, true, true},
+ /* Buffer Strided Ptr */ {true, true, false, false, true, false, true, true, true, true},
};
// clang-format on
diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td
index 799e102d5617..060fb66d38f7 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -411,6 +411,12 @@ def FeatureVGPRIndexMode : SubtargetFeature<"vgpr-index-mode",
"Has VGPR mode register indexing"
>;
+def FeatureScalarDwordx3Loads : SubtargetFeature<"scalar-dwordx3-loads",
+ "HasScalarDwordx3Loads",
+ "true",
+ "Has 96-bit scalar load instructions"
+>;
+
def FeatureScalarStores : SubtargetFeature<"scalar-stores",
"HasScalarStores",
"true",
@@ -816,6 +822,18 @@ def FeatureVGPRSingleUseHintInsts : SubtargetFeature<"vgpr-singleuse-hint",
"Has single-use VGPR hint instructions"
>;
+def FeaturePseudoScalarTrans : SubtargetFeature<"pseudo-scalar-trans",
+ "HasPseudoScalarTrans",
+ "true",
+ "Has Pseudo Scalar Transcendental instructions"
+>;
+
+def FeatureHasRestrictedSOffset : SubtargetFeature<"restricted-soffset",
+ "HasRestrictedSOffset",
+ "true",
+ "Has restricted SOffset (immediate not supported)."
+>;
+
//===------------------------------------------------------------===//
// Subtarget Features (options and debugging)
//===------------------------------------------------------------===//
@@ -1461,8 +1479,11 @@ def FeatureISAVersion12 : FeatureSet<
FeaturePackedTID,
FeatureVcmpxPermlaneHazard,
FeatureSALUFloatInsts,
+ FeaturePseudoScalarTrans,
+ FeatureHasRestrictedSOffset,
FeatureVGPRSingleUseHintInsts,
- FeatureMADIntraFwdBug]>;
+ FeatureMADIntraFwdBug,
+ FeatureScalarDwordx3Loads]>;
//===----------------------------------------------------------------------===//
@@ -1773,6 +1794,11 @@ def HasUnpackedD16VMem : Predicate<"Subtarget->hasUnpackedD16VMem()">,
def HasPackedD16VMem : Predicate<"!Subtarget->hasUnpackedD16VMem()">,
AssemblerPredicate<(all_of (not FeatureUnpackedD16VMem))>;
+def HasRestrictedSOffset : Predicate<"Subtarget->hasRestrictedSOffset()">,
+ AssemblerPredicate<(all_of FeatureHasRestrictedSOffset)>;
+def HasUnrestrictedSOffset : Predicate<"!Subtarget->hasRestrictedSOffset()">,
+ AssemblerPredicate<(all_of (not FeatureHasRestrictedSOffset))>;
+
def D16PreservesUnusedBits :
Predicate<"Subtarget->d16PreservesUnusedBits()">,
AssemblerPredicate<(all_of FeatureGFX9Insts, (not FeatureSRAMECC))>;
@@ -2002,6 +2028,9 @@ def HasSALUFloatInsts : Predicate<"Subtarget->hasSALUFloatInsts()">,
def HasVGPRSingleUseHintInsts : Predicate<"Subtarget->hasVGPRSingleUseHintInsts()">,
AssemblerPredicate<(all_of FeatureVGPRSingleUseHintInsts)>;
+def HasPseudoScalarTrans : Predicate<"Subtarget->hasPseudoScalarTrans()">,
+ AssemblerPredicate<(all_of FeaturePseudoScalarTrans)>;
+
def HasGDS : Predicate<"Subtarget->hasGDS()">;
def HasGWS : Predicate<"Subtarget->hasGWS()">;
@@ -2011,6 +2040,8 @@ def HasNoCvtFP8VOP1Bug : Predicate<"!Subtarget->hasCvtFP8VOP1Bug()">;
def HasAtomicCSubNoRtnInsts : Predicate<"Subtarget->hasAtomicCSubNoRtnInsts()">;
+def HasScalarDwordx3Loads : Predicate<"Subtarget->hasScalarDwordx3Loads()">;
+
// Include AMDGPU TD files
include "SISchedule.td"
include "GCNProcessors.td"
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.h b/llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.h
index ee21fe1615be..42b33c50d9f8 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.h
@@ -98,6 +98,7 @@ struct KernArgPreloadDescriptor : public ArgDescriptor {
};
struct AMDGPUFunctionArgInfo {
+ // clang-format off
enum PreloadedValue {
// SGPRS:
PRIVATE_SEGMENT_BUFFER = 0,
@@ -120,6 +121,7 @@ struct AMDGPUFunctionArgInfo {
WORKITEM_ID_Z = 19,
FIRST_VGPR_VALUE = WORKITEM_ID_X
};
+ // clang-format on
// Kernel input registers setup for the HSA ABI in allocation order.
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
index 4bf1f1357b69..d317a733d433 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
@@ -426,7 +426,7 @@ amdhsa::kernel_descriptor_t AMDGPUAsmPrinter::getAmdhsaKernelDescriptor(
memset(&KernelDescriptor, 0x0, sizeof(KernelDescriptor));
assert(isUInt<32>(PI.ScratchSize));
- assert(isUInt<32>(PI.getComputePGMRSrc1()));
+ assert(isUInt<32>(PI.getComputePGMRSrc1(STM)));
assert(isUInt<32>(PI.getComputePGMRSrc2()));
KernelDescriptor.group_segment_fixed_size = PI.LDSSize;
@@ -435,7 +435,7 @@ amdhsa::kernel_descriptor_t AMDGPUAsmPrinter::getAmdhsaKernelDescriptor(
Align MaxKernArgAlign;
KernelDescriptor.kernarg_size = STM.getKernArgSegmentSize(F, MaxKernArgAlign);
- KernelDescriptor.compute_pgm_rsrc1 = PI.getComputePGMRSrc1();
+ KernelDescriptor.compute_pgm_rsrc1 = PI.getComputePGMRSrc1(STM);
KernelDescriptor.compute_pgm_rsrc2 = PI.getComputePGMRSrc2();
KernelDescriptor.kernel_code_properties = getAmdhsaKernelCodeProperties(MF);
@@ -974,7 +974,7 @@ void AMDGPUAsmPrinter::EmitProgramInfoSI(const MachineFunction &MF,
if (AMDGPU::isCompute(MF.getFunction().getCallingConv())) {
OutStreamer->emitInt32(R_00B848_COMPUTE_PGM_RSRC1);
- OutStreamer->emitInt32(CurrentProgramInfo.getComputePGMRSrc1());
+ OutStreamer->emitInt32(CurrentProgramInfo.getComputePGMRSrc1(STM));
OutStreamer->emitInt32(R_00B84C_COMPUTE_PGM_RSRC2);
OutStreamer->emitInt32(CurrentProgramInfo.getComputePGMRSrc2());
@@ -1038,7 +1038,7 @@ void AMDGPUAsmPrinter::EmitPALMetadata(const MachineFunction &MF,
MD->setNumUsedSgprs(CC, CurrentProgramInfo.NumSGPRsForWavesPerEU);
if (MD->getPALMajorVersion() < 3) {
- MD->setRsrc1(CC, CurrentProgramInfo.getPGMRSrc1(CC));
+ MD->setRsrc1(CC, CurrentProgramInfo.getPGMRSrc1(CC, STM));
if (AMDGPU::isCompute(CC)) {
MD->setRsrc2(CC, CurrentProgramInfo.getComputePGMRSrc2());
} else {
@@ -1116,10 +1116,11 @@ void AMDGPUAsmPrinter::emitPALFunctionMetadata(const MachineFunction &MF) {
const MachineFrameInfo &MFI = MF.getFrameInfo();
StringRef FnName = MF.getFunction().getName();
MD->setFunctionScratchSize(FnName, MFI.getStackSize());
+ const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
// Set compute registers
MD->setRsrc1(CallingConv::AMDGPU_CS,
- CurrentProgramInfo.getPGMRSrc1(CallingConv::AMDGPU_CS));
+ CurrentProgramInfo.getPGMRSrc1(CallingConv::AMDGPU_CS, ST));
MD->setRsrc2(CallingConv::AMDGPU_CS, CurrentProgramInfo.getComputePGMRSrc2());
// Set optional info
@@ -1155,7 +1156,7 @@ void AMDGPUAsmPrinter::getAmdKernelCode(amd_kernel_code_t &Out,
AMDGPU::initDefaultAMDKernelCodeT(Out, &STM);
Out.compute_pgm_resource_registers =
- CurrentProgramInfo.getComputePGMRSrc1() |
+ CurrentProgramInfo.getComputePGMRSrc1(STM) |
(CurrentProgramInfo.getComputePGMRSrc2() << 32);
Out.code_properties |= AMD_CODE_PROPERTY_IS_PTR64;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
index 4caa9cd9225b..87b1957c799e 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
@@ -2199,7 +2199,7 @@ bool AMDGPUCodeGenPrepare::runOnFunction(Function &F) {
auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>();
Impl.DT = DTWP ? &DTWP->getDomTree() : nullptr;
Impl.HasUnsafeFPMath = hasUnsafeFPMath(F);
- SIModeRegisterDefaults Mode(F);
+ SIModeRegisterDefaults Mode(F, *Impl.ST);
Impl.HasFP32DenormalFlush =
Mode.FP32Denormals == DenormalMode::getPreserveSign();
return Impl.run(F);
@@ -2216,7 +2216,7 @@ PreservedAnalyses AMDGPUCodeGenPreparePass::run(Function &F,
Impl.UA = &FAM.getResult<UniformityInfoAnalysis>(F);
Impl.DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
Impl.HasUnsafeFPMath = hasUnsafeFPMath(F);
- SIModeRegisterDefaults Mode(F);
+ SIModeRegisterDefaults Mode(F, *Impl.ST);
Impl.HasFP32DenormalFlush =
Mode.FP32Denormals == DenormalMode::getPreserveSign();
PreservedAnalyses PA = PreservedAnalyses::none();
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp b/llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp
index d48916670112..69dc78d33c83 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp
@@ -29,6 +29,8 @@ static bool fnegFoldsIntoMI(const MachineInstr &MI) {
case AMDGPU::G_FMAXNUM:
case AMDGPU::G_FMINNUM_IEEE:
case AMDGPU::G_FMAXNUM_IEEE:
+ case AMDGPU::G_FMINIMUM:
+ case AMDGPU::G_FMAXIMUM:
case AMDGPU::G_FSIN:
case AMDGPU::G_FPEXT:
case AMDGPU::G_INTRINSIC_TRUNC:
@@ -174,6 +176,10 @@ static unsigned inverseMinMax(unsigned Opc) {
return AMDGPU::G_FMINNUM_IEEE;
case AMDGPU::G_FMINNUM_IEEE:
return AMDGPU::G_FMAXNUM_IEEE;
+ case AMDGPU::G_FMAXIMUM:
+ return AMDGPU::G_FMINIMUM;
+ case AMDGPU::G_FMINIMUM:
+ return AMDGPU::G_FMAXIMUM;
case AMDGPU::G_AMDGPU_FMAX_LEGACY:
return AMDGPU::G_AMDGPU_FMIN_LEGACY;
case AMDGPU::G_AMDGPU_FMIN_LEGACY:
@@ -207,6 +213,8 @@ bool AMDGPUCombinerHelper::matchFoldableFneg(MachineInstr &MI,
case AMDGPU::G_FMAXNUM:
case AMDGPU::G_FMINNUM_IEEE:
case AMDGPU::G_FMAXNUM_IEEE:
+ case AMDGPU::G_FMINIMUM:
+ case AMDGPU::G_FMAXIMUM:
case AMDGPU::G_AMDGPU_FMIN_LEGACY:
case AMDGPU::G_AMDGPU_FMAX_LEGACY:
// 0 doesn't have a negated inline immediate.
@@ -304,6 +312,8 @@ void AMDGPUCombinerHelper::applyFoldableFneg(MachineInstr &MI,
case AMDGPU::G_FMAXNUM:
case AMDGPU::G_FMINNUM_IEEE:
case AMDGPU::G_FMAXNUM_IEEE:
+ case AMDGPU::G_FMINIMUM:
+ case AMDGPU::G_FMAXIMUM:
case AMDGPU::G_AMDGPU_FMIN_LEGACY:
case AMDGPU::G_AMDGPU_FMAX_LEGACY: {
NegateOperand(MatchInfo->getOperand(1));
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUGISel.td b/llvm/lib/Target/AMDGPU/AMDGPUGISel.td
index c61aab4a45c6..2b85024a9b40 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUGISel.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUGISel.td
@@ -105,6 +105,11 @@ def gi_global_saddr :
def gi_mubuf_scratch_offset :
GIComplexOperandMatcher<s32, "selectMUBUFScratchOffset">,
GIComplexPatternEquiv<MUBUFScratchOffset>;
+
+def gi_buf_soffset :
+ GIComplexOperandMatcher<s32, "selectBUFSOffset">,
+ GIComplexPatternEquiv<BUFSOffset>;
+
def gi_mubuf_scratch_offen :
GIComplexOperandMatcher<s32, "selectMUBUFScratchOffen">,
GIComplexPatternEquiv<MUBUFScratchOffen>;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUGlobalISelDivergenceLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUGlobalISelDivergenceLowering.cpp
new file mode 100644
index 000000000000..4cd8b1ec1051
--- /dev/null
+++ b/llvm/lib/Target/AMDGPU/AMDGPUGlobalISelDivergenceLowering.cpp
@@ -0,0 +1,68 @@
+//===-- AMDGPUGlobalISelDivergenceLowering.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// GlobalISel pass that selects divergent i1 phis as lane mask phis.
+/// Lane mask merging uses same algorithm as SDAG in SILowerI1Copies.
+/// Handles all cases of temporal divergence.
+/// For divergent non-phi i1 and uniform i1 uses outside of the cycle this pass
+/// currently depends on LCSSA to insert phis with one incoming.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPU.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+
+#define DEBUG_TYPE "amdgpu-global-isel-divergence-lowering"
+
+using namespace llvm;
+
+namespace {
+
+class AMDGPUGlobalISelDivergenceLowering : public MachineFunctionPass {
+public:
+ static char ID;
+
+public:
+ AMDGPUGlobalISelDivergenceLowering() : MachineFunctionPass(ID) {
+ initializeAMDGPUGlobalISelDivergenceLoweringPass(
+ *PassRegistry::getPassRegistry());
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ StringRef getPassName() const override {
+ return "AMDGPU GlobalISel divergence lowering";
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+};
+
+} // End anonymous namespace.
+
+INITIALIZE_PASS_BEGIN(AMDGPUGlobalISelDivergenceLowering, DEBUG_TYPE,
+ "AMDGPU GlobalISel divergence lowering", false, false)
+INITIALIZE_PASS_END(AMDGPUGlobalISelDivergenceLowering, DEBUG_TYPE,
+ "AMDGPU GlobalISel divergence lowering", false, false)
+
+char AMDGPUGlobalISelDivergenceLowering::ID = 0;
+
+char &llvm::AMDGPUGlobalISelDivergenceLoweringID =
+ AMDGPUGlobalISelDivergenceLowering::ID;
+
+FunctionPass *llvm::createAMDGPUGlobalISelDivergenceLoweringPass() {
+ return new AMDGPUGlobalISelDivergenceLowering();
+}
+
+bool AMDGPUGlobalISelDivergenceLowering::runOnMachineFunction(
+ MachineFunction &MF) {
+ return false;
+}
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUHSAMetadataStreamer.h b/llvm/lib/Target/AMDGPU/AMDGPUHSAMetadataStreamer.h
index 18a7b5d7a963..6d6bd86711b1 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUHSAMetadataStreamer.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUHSAMetadataStreamer.h
@@ -30,7 +30,6 @@ class MDNode;
class Module;
struct SIProgramInfo;
class Type;
-class GCNSubtarget;
namespace AMDGPU {
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp
index a6d1da94b890..b0eac567ec9f 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp
@@ -132,7 +132,7 @@ bool AMDGPUDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
}
#endif
Subtarget = &MF.getSubtarget<GCNSubtarget>();
- Mode = SIModeRegisterDefaults(MF.getFunction());
+ Mode = SIModeRegisterDefaults(MF.getFunction(), *Subtarget);
return SelectionDAGISel::runOnMachineFunction(MF);
}
@@ -1166,6 +1166,11 @@ bool AMDGPUDAGToDAGISel::isFlatScratchBaseLegal(SDValue Addr) const {
if (isNoUnsignedWrap(Addr))
return true;
+ // Starting with GFX12, VADDR and SADDR fields in VSCRATCH can use negative
+ // values.
+ if (AMDGPU::isGFX12Plus(*Subtarget))
+ return true;
+
auto LHS = Addr.getOperand(0);
auto RHS = Addr.getOperand(1);
@@ -1319,7 +1324,9 @@ bool AMDGPUDAGToDAGISel::SelectMUBUF(SDValue Addr, SDValue &Ptr, SDValue &VAddr,
Idxen = CurDAG->getTargetConstant(0, DL, MVT::i1);
Offen = CurDAG->getTargetConstant(0, DL, MVT::i1);
Addr64 = CurDAG->getTargetConstant(0, DL, MVT::i1);
- SOffset = CurDAG->getTargetConstant(0, DL, MVT::i32);
+ SOffset = Subtarget->hasRestrictedSOffset()
+ ? CurDAG->getRegister(AMDGPU::SGPR_NULL, MVT::i32)
+ : CurDAG->getTargetConstant(0, DL, MVT::i32);
ConstantSDNode *C1 = nullptr;
SDValue N0 = Addr;
@@ -1374,7 +1381,8 @@ bool AMDGPUDAGToDAGISel::SelectMUBUF(SDValue Addr, SDValue &Ptr, SDValue &VAddr,
return true;
}
- if (SIInstrInfo::isLegalMUBUFImmOffset(C1->getZExtValue())) {
+ const SIInstrInfo *TII = Subtarget->getInstrInfo();
+ if (TII->isLegalMUBUFImmOffset(C1->getZExtValue())) {
// Legal offset for instruction.
Offset = CurDAG->getTargetConstant(C1->getZExtValue(), DL, MVT::i32);
return true;
@@ -1448,7 +1456,7 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFScratchOffen(SDNode *Parent,
AMDGPUTargetMachine::getNullPointerValue(AMDGPUAS::PRIVATE_ADDRESS);
// Don't fold null pointer.
if (Imm != NullPtr) {
- const uint32_t MaxOffset = SIInstrInfo::getMaxMUBUFImmOffset();
+ const uint32_t MaxOffset = SIInstrInfo::getMaxMUBUFImmOffset(*Subtarget);
SDValue HighBits =
CurDAG->getTargetConstant(Imm & ~MaxOffset, DL, MVT::i32);
MachineSDNode *MovHighBits = CurDAG->getMachineNode(
@@ -1482,8 +1490,9 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFScratchOffen(SDNode *Parent,
// Therefore it should be safe to fold any VGPR offset on gfx9 into the
// MUBUF vaddr, but not on older subtargets which can only do this if the
// sign bit is known 0.
+ const SIInstrInfo *TII = Subtarget->getInstrInfo();
ConstantSDNode *C1 = cast<ConstantSDNode>(N1);
- if (SIInstrInfo::isLegalMUBUFImmOffset(C1->getZExtValue()) &&
+ if (TII->isLegalMUBUFImmOffset(C1->getZExtValue()) &&
(!Subtarget->privateMemoryResourceIsRangeChecked() ||
CurDAG->SignBitIsZero(N0))) {
std::tie(VAddr, SOffset) = foldFrameIndex(N0);
@@ -1515,6 +1524,7 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFScratchOffset(SDNode *Parent,
SDValue &Offset) const {
const SIRegisterInfo *TRI =
static_cast<const SIRegisterInfo *>(Subtarget->getRegisterInfo());
+ const SIInstrInfo *TII = Subtarget->getInstrInfo();
MachineFunction &MF = CurDAG->getMachineFunction();
const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();
SDLoc DL(Addr);
@@ -1531,14 +1541,14 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFScratchOffset(SDNode *Parent,
if (Addr.getOpcode() == ISD::ADD) {
// Add (CopyFromReg <sgpr>) <constant>
CAddr = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
- if (!CAddr || !SIInstrInfo::isLegalMUBUFImmOffset(CAddr->getZExtValue()))
+ if (!CAddr || !TII->isLegalMUBUFImmOffset(CAddr->getZExtValue()))
return false;
if (!IsCopyFromSGPR(*TRI, Addr.getOperand(0)))
return false;
SOffset = Addr.getOperand(0);
} else if ((CAddr = dyn_cast<ConstantSDNode>(Addr)) &&
- SIInstrInfo::isLegalMUBUFImmOffset(CAddr->getZExtValue())) {
+ TII->isLegalMUBUFImmOffset(CAddr->getZExtValue())) {
// <constant>
SOffset = CurDAG->getTargetConstant(0, DL, MVT::i32);
} else {
@@ -1555,8 +1565,7 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc,
SDValue &SOffset, SDValue &Offset
) const {
SDValue Ptr, VAddr, Offen, Idxen, Addr64;
- const SIInstrInfo *TII =
- static_cast<const SIInstrInfo *>(Subtarget->getInstrInfo());
+ const SIInstrInfo *TII = Subtarget->getInstrInfo();
if (!SelectMUBUF(Addr, Ptr, VAddr, SOffset, Offset, Offen, Idxen, Addr64))
return false;
@@ -1577,6 +1586,21 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc,
return false;
}
+bool AMDGPUDAGToDAGISel::SelectBUFSOffset(SDValue ByteOffsetNode,
+ SDValue &SOffset) const {
+ if (Subtarget->hasRestrictedSOffset()) {
+ if (auto SOffsetConst = dyn_cast<ConstantSDNode>(ByteOffsetNode)) {
+ if (SOffsetConst->isZero()) {
+ SOffset = CurDAG->getRegister(AMDGPU::SGPR_NULL, MVT::i32);
+ return true;
+ }
+ }
+ }
+
+ SOffset = ByteOffsetNode;
+ return true;
+}
+
// Find a load or store from corresponding pattern root.
// Roots may be build_vector, bitconvert or their combinations.
static MemSDNode* findMemSDNode(SDNode *N) {
@@ -1682,7 +1706,7 @@ bool AMDGPUDAGToDAGISel::SelectFlatOffsetImpl(SDNode *N, SDValue Addr,
}
VAddr = Addr;
- Offset = CurDAG->getTargetConstant(OffsetVal, SDLoc(), MVT::i16);
+ Offset = CurDAG->getTargetConstant(OffsetVal, SDLoc(), MVT::i32);
return true;
}
@@ -1750,7 +1774,7 @@ bool AMDGPUDAGToDAGISel::SelectGlobalSAddr(SDNode *N,
CurDAG->getTargetConstant(RemainderOffset, SDLoc(), MVT::i32));
VOffset = SDValue(VMov, 0);
SAddr = LHS;
- Offset = CurDAG->getTargetConstant(SplitImmOffset, SDLoc(), MVT::i16);
+ Offset = CurDAG->getTargetConstant(SplitImmOffset, SDLoc(), MVT::i32);
return true;
}
}
@@ -1790,7 +1814,7 @@ bool AMDGPUDAGToDAGISel::SelectGlobalSAddr(SDNode *N,
}
if (SAddr) {
- Offset = CurDAG->getTargetConstant(ImmOffset, SDLoc(), MVT::i16);
+ Offset = CurDAG->getTargetConstant(ImmOffset, SDLoc(), MVT::i32);
return true;
}
}
@@ -1806,7 +1830,7 @@ bool AMDGPUDAGToDAGISel::SelectGlobalSAddr(SDNode *N,
CurDAG->getMachineNode(AMDGPU::V_MOV_B32_e32, SDLoc(Addr), MVT::i32,
CurDAG->getTargetConstant(0, SDLoc(), MVT::i32));
VOffset = SDValue(VMov, 0);
- Offset = CurDAG->getTargetConstant(ImmOffset, SDLoc(), MVT::i16);
+ Offset = CurDAG->getTargetConstant(ImmOffset, SDLoc(), MVT::i32);
return true;
}
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h
index 618c5e02c094..374108af08cd 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h
@@ -179,6 +179,7 @@ private:
bool SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc, SDValue &Soffset,
SDValue &Offset) const;
+ bool SelectBUFSOffset(SDValue Addr, SDValue &SOffset) const;
bool SelectFlatOffsetImpl(SDNode *N, SDValue Addr, SDValue &VAddr,
SDValue &Offset, uint64_t FlatVariant) const;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index fcbdf51b03c1..9d7443012e3d 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -585,6 +585,8 @@ static bool fnegFoldsIntoOpcode(unsigned Opc) {
case ISD::FMAXNUM:
case ISD::FMINNUM_IEEE:
case ISD::FMAXNUM_IEEE:
+ case ISD::FMINIMUM:
+ case ISD::FMAXIMUM:
case ISD::SELECT:
case ISD::FSIN:
case ISD::FTRUNC:
@@ -4572,6 +4574,10 @@ static unsigned inverseMinMax(unsigned Opc) {
return ISD::FMINNUM_IEEE;
case ISD::FMINNUM_IEEE:
return ISD::FMAXNUM_IEEE;
+ case ISD::FMAXIMUM:
+ return ISD::FMINIMUM;
+ case ISD::FMINIMUM:
+ return ISD::FMAXIMUM;
case AMDGPUISD::FMAX_LEGACY:
return AMDGPUISD::FMIN_LEGACY;
case AMDGPUISD::FMIN_LEGACY:
@@ -4695,6 +4701,8 @@ SDValue AMDGPUTargetLowering::performFNegCombine(SDNode *N,
case ISD::FMINNUM:
case ISD::FMAXNUM_IEEE:
case ISD::FMINNUM_IEEE:
+ case ISD::FMINIMUM:
+ case ISD::FMAXIMUM:
case AMDGPUISD::FMAX_LEGACY:
case AMDGPUISD::FMIN_LEGACY: {
// fneg (fmaxnum x, y) -> fminnum (fneg x), (fneg y)
@@ -5305,6 +5313,8 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(FMED3)
NODE_NAME_CASE(SMED3)
NODE_NAME_CASE(UMED3)
+ NODE_NAME_CASE(FMAXIMUM3)
+ NODE_NAME_CASE(FMINIMUM3)
NODE_NAME_CASE(FDOT2)
NODE_NAME_CASE(URECIP)
NODE_NAME_CASE(DIV_SCALE)
@@ -5759,6 +5769,8 @@ bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(SDValue Op,
case AMDGPUISD::FMED3:
case AMDGPUISD::FMIN3:
case AMDGPUISD::FMAX3:
+ case AMDGPUISD::FMINIMUM3:
+ case AMDGPUISD::FMAXIMUM3:
case AMDGPUISD::FMAD_FTZ: {
if (SNaN)
return true;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h
index 6841067e31b3..827fb106b551 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h
@@ -449,6 +449,8 @@ enum NodeType : unsigned {
FMED3,
SMED3,
UMED3,
+ FMAXIMUM3,
+ FMINIMUM3,
FDOT2,
URECIP,
DIV_SCALE,
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
index 5296415ab4c3..ee93d9eb4c0a 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
@@ -992,14 +992,27 @@ GCNTTIImpl::instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const {
return IC.replaceOperand(II, 0, UndefValue::get(Old->getType()));
}
case Intrinsic::amdgcn_permlane16:
- case Intrinsic::amdgcn_permlanex16: {
+ case Intrinsic::amdgcn_permlane16_var:
+ case Intrinsic::amdgcn_permlanex16:
+ case Intrinsic::amdgcn_permlanex16_var: {
// Discard vdst_in if it's not going to be read.
Value *VDstIn = II.getArgOperand(0);
if (isa<UndefValue>(VDstIn))
break;
- ConstantInt *FetchInvalid = cast<ConstantInt>(II.getArgOperand(4));
- ConstantInt *BoundCtrl = cast<ConstantInt>(II.getArgOperand(5));
+ // FetchInvalid operand idx.
+ unsigned int FiIdx = (IID == Intrinsic::amdgcn_permlane16 ||
+ IID == Intrinsic::amdgcn_permlanex16)
+ ? 4 /* for permlane16 and permlanex16 */
+ : 3; /* for permlane16_var and permlanex16_var */
+
+ // BoundCtrl operand idx.
+ // For permlane16 and permlanex16 it should be 5
+ // For Permlane16_var and permlanex16_var it should be 4
+ unsigned int BcIdx = FiIdx + 1;
+
+ ConstantInt *FetchInvalid = cast<ConstantInt>(II.getArgOperand(FiIdx));
+ ConstantInt *BoundCtrl = cast<ConstantInt>(II.getArgOperand(BcIdx));
if (!FetchInvalid->getZExtValue() && !BoundCtrl->getZExtValue())
break;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td b/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td
index fd38739876c4..82f58ea38fd0 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td
@@ -170,6 +170,11 @@ def AMDGPUfmax3 : SDNode<"AMDGPUISD::FMAX3", SDTFPTernaryOp,
[/*SDNPCommutative, SDNPAssociative*/]
>;
+// out = max(a, b, c) a, b and c are floats. Operation is IEEE2019 compliant.
+def AMDGPUfmaximum3 : SDNode<"AMDGPUISD::FMAXIMUM3", SDTFPTernaryOp,
+ [/*SDNPCommutative, SDNPAssociative*/]
+>;
+
// out = max(a, b, c) a, b, and c are signed ints
def AMDGPUsmax3 : SDNode<"AMDGPUISD::SMAX3", AMDGPUDTIntTernaryOp,
[/*SDNPCommutative, SDNPAssociative*/]
@@ -185,6 +190,11 @@ def AMDGPUfmin3 : SDNode<"AMDGPUISD::FMIN3", SDTFPTernaryOp,
[/*SDNPCommutative, SDNPAssociative*/]
>;
+// out = min(a, b, c) a, b and c are floats. Operation is IEEE2019 compliant.
+def AMDGPUfminimum3 : SDNode<"AMDGPUISD::FMINIMUM3", SDTFPTernaryOp,
+ [/*SDNPCommutative, SDNPAssociative*/]
+>;
+
// out = min(a, b, c) a, b and c are signed ints
def AMDGPUsmin3 : SDNode<"AMDGPUISD::SMIN3", AMDGPUDTIntTernaryOp,
[/*SDNPCommutative, SDNPAssociative*/]
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
index d24c7da964ce..88ef4b577424 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
@@ -1791,6 +1791,19 @@ bool AMDGPUInstructionSelector::selectSBarrier(MachineInstr &MI) const {
return true;
}
}
+
+ // On GFX12 lower s_barrier into s_barrier_signal_imm and s_barrier_wait
+ if (STI.hasSplitBarriers()) {
+ MachineBasicBlock *MBB = MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+ BuildMI(*MBB, &MI, DL, TII.get(AMDGPU::S_BARRIER_SIGNAL_IMM))
+ .addImm(AMDGPU::Barrier::WORKGROUP);
+ BuildMI(*MBB, &MI, DL, TII.get(AMDGPU::S_BARRIER_WAIT))
+ .addImm(AMDGPU::Barrier::WORKGROUP);
+ MI.eraseFromParent();
+ return true;
+ }
+
return selectImpl(MI, *CoverageInfo);
}
@@ -1819,6 +1832,7 @@ bool AMDGPUInstructionSelector::selectImageIntrinsic(
unsigned IntrOpcode = Intr->BaseOpcode;
const bool IsGFX10Plus = AMDGPU::isGFX10Plus(STI);
const bool IsGFX11Plus = AMDGPU::isGFX11Plus(STI);
+ const bool IsGFX12Plus = AMDGPU::isGFX12Plus(STI);
const unsigned ArgOffset = MI.getNumExplicitDefs() + 1;
@@ -1903,7 +1917,7 @@ bool AMDGPUInstructionSelector::selectImageIntrinsic(
unsigned CPol = MI.getOperand(ArgOffset + Intr->CachePolicyIndex).getImm();
if (BaseOpcode->Atomic)
CPol |= AMDGPU::CPol::GLC; // TODO no-return optimization
- if (CPol & ~AMDGPU::CPol::ALL)
+ if (CPol & ~(IsGFX12Plus ? AMDGPU::CPol::ALL : AMDGPU::CPol::ALL_pregfx12))
return false;
int NumVAddrRegs = 0;
@@ -1938,7 +1952,10 @@ bool AMDGPUInstructionSelector::selectImageIntrinsic(
++NumVDataDwords;
int Opcode = -1;
- if (IsGFX11Plus) {
+ if (IsGFX12Plus) {
+ Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx12,
+ NumVDataDwords, NumVAddrDwords);
+ } else if (IsGFX11Plus) {
Opcode = AMDGPU::getMIMGOpcode(IntrOpcode,
UseNSA ? AMDGPU::MIMGEncGfx11NSA
: AMDGPU::MIMGEncGfx11Default,
@@ -2011,7 +2028,8 @@ bool AMDGPUInstructionSelector::selectImageIntrinsic(
if (IsGFX10Plus)
MIB.addImm(DimInfo->Encoding);
- MIB.addImm(Unorm);
+ if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::unorm))
+ MIB.addImm(Unorm);
MIB.addImm(CPol);
MIB.addImm(IsA16 && // a16 or r128
@@ -2026,7 +2044,8 @@ bool AMDGPUInstructionSelector::selectImageIntrinsic(
return false;
}
- MIB.addImm(LWE); // lwe
+ if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::lwe))
+ MIB.addImm(LWE); // lwe
if (!IsGFX10Plus)
MIB.addImm(DimInfo->DA ? -1 : 0);
if (BaseOpcode->HasD16)
@@ -2137,6 +2156,16 @@ bool AMDGPUInstructionSelector::selectG_INTRINSIC_W_SIDE_EFFECTS(
break;
case Intrinsic::amdgcn_ds_bvh_stack_rtn:
return selectDSBvhStackIntrinsic(I);
+ case Intrinsic::amdgcn_s_barrier_init:
+ case Intrinsic::amdgcn_s_barrier_join:
+ case Intrinsic::amdgcn_s_wakeup_barrier:
+ case Intrinsic::amdgcn_s_get_barrier_state:
+ return selectNamedBarrierInst(I, IntrinsicID);
+ case Intrinsic::amdgcn_s_barrier_signal_isfirst:
+ case Intrinsic::amdgcn_s_barrier_signal_isfirst_var:
+ return selectSBarrierSignalIsfirst(I, IntrinsicID);
+ case Intrinsic::amdgcn_s_barrier_leave:
+ return selectSBarrierLeave(I);
}
return selectImpl(I, *CoverageInfo);
}
@@ -3200,6 +3229,7 @@ bool AMDGPUInstructionSelector::selectG_INSERT_VECTOR_ELT(
}
bool AMDGPUInstructionSelector::selectBufferLoadLds(MachineInstr &MI) const {
+ assert(!AMDGPU::isGFX12Plus(STI));
unsigned Opc;
unsigned Size = MI.getOperand(3).getImm();
@@ -3266,8 +3296,8 @@ bool AMDGPUInstructionSelector::selectBufferLoadLds(MachineInstr &MI) const {
MIB.add(MI.getOperand(5 + OpOffset)); // soffset
MIB.add(MI.getOperand(6 + OpOffset)); // imm offset
unsigned Aux = MI.getOperand(7 + OpOffset).getImm();
- MIB.addImm(Aux & AMDGPU::CPol::ALL); // cpol
- MIB.addImm((Aux >> 3) & 1); // swz
+ MIB.addImm(Aux & AMDGPU::CPol::ALL); // cpol
+ MIB.addImm(Aux & AMDGPU::CPol::SWZ_pregfx12 ? 1 : 0); // swz
MachineMemOperand *LoadMMO = *MI.memoperands_begin();
MachinePointerInfo LoadPtrI = LoadMMO->getPointerInfo();
@@ -4407,7 +4437,7 @@ AMDGPUInstructionSelector::selectMUBUFScratchOffen(MachineOperand &Root) const {
// TODO: Should this be inside the render function? The iterator seems to
// move.
- const uint32_t MaxOffset = SIInstrInfo::getMaxMUBUFImmOffset();
+ const uint32_t MaxOffset = SIInstrInfo::getMaxMUBUFImmOffset(*Subtarget);
BuildMI(*MBB, MI, MI->getDebugLoc(), TII.get(AMDGPU::V_MOV_B32_e32),
HighBits)
.addImm(Offset & ~MaxOffset);
@@ -4439,7 +4469,7 @@ AMDGPUInstructionSelector::selectMUBUFScratchOffen(MachineOperand &Root) const {
int64_t ConstOffset;
std::tie(PtrBase, ConstOffset) = getPtrBaseWithConstantOffset(VAddr, *MRI);
if (ConstOffset != 0) {
- if (SIInstrInfo::isLegalMUBUFImmOffset(ConstOffset) &&
+ if (TII.isLegalMUBUFImmOffset(ConstOffset) &&
(!STI.privateMemoryResourceIsRangeChecked() ||
KB->signBitIsZero(PtrBase))) {
const MachineInstr *PtrBaseDef = MRI->getVRegDef(PtrBase);
@@ -4518,6 +4548,11 @@ bool AMDGPUInstructionSelector::isFlatScratchBaseLegal(Register Addr) const {
if (isNoUnsignedWrap(AddrMI))
return true;
+ // Starting with GFX12, VADDR and SADDR fields in VSCRATCH can use negative
+ // values.
+ if (AMDGPU::isGFX12Plus(STI))
+ return true;
+
Register LHS = AddrMI->getOperand(1).getReg();
Register RHS = AddrMI->getOperand(2).getReg();
@@ -4622,7 +4657,7 @@ AMDGPUInstructionSelector::selectMUBUFScratchOffset(
if (mi_match(Reg, *MRI,
m_GPtrAdd(m_Reg(BasePtr),
m_any_of(m_ICst(Offset), m_Copy(m_ICst(Offset)))))) {
- if (!SIInstrInfo::isLegalMUBUFImmOffset(Offset))
+ if (!TII.isLegalMUBUFImmOffset(Offset))
return {};
MachineInstr *BasePtrDef = getDefIgnoringCopies(BasePtr, *MRI);
Register WaveBase = getWaveAddress(BasePtrDef);
@@ -4641,7 +4676,7 @@ AMDGPUInstructionSelector::selectMUBUFScratchOffset(
}
if (!mi_match(Root.getReg(), *MRI, m_ICst(Offset)) ||
- !SIInstrInfo::isLegalMUBUFImmOffset(Offset))
+ !TII.isLegalMUBUFImmOffset(Offset))
return {};
return {{
@@ -4884,7 +4919,7 @@ bool AMDGPUInstructionSelector::shouldUseAddr64(MUBUFAddressData Addr) const {
/// component.
void AMDGPUInstructionSelector::splitIllegalMUBUFOffset(
MachineIRBuilder &B, Register &SOffset, int64_t &ImmOffset) const {
- if (SIInstrInfo::isLegalMUBUFImmOffset(ImmOffset))
+ if (TII.isLegalMUBUFImmOffset(ImmOffset))
return;
// Illegal offset, store it in soffset.
@@ -4993,6 +5028,8 @@ AMDGPUInstructionSelector::selectMUBUFAddr64(MachineOperand &Root) const {
[=](MachineInstrBuilder &MIB) { // soffset
if (SOffset)
MIB.addReg(SOffset);
+ else if (STI.hasRestrictedSOffset())
+ MIB.addReg(AMDGPU::SGPR_NULL);
else
MIB.addImm(0);
},
@@ -5021,6 +5058,8 @@ AMDGPUInstructionSelector::selectMUBUFOffset(MachineOperand &Root) const {
[=](MachineInstrBuilder &MIB) { // soffset
if (SOffset)
MIB.addReg(SOffset);
+ else if (STI.hasRestrictedSOffset())
+ MIB.addReg(AMDGPU::SGPR_NULL);
else
MIB.addImm(0);
},
@@ -5031,6 +5070,17 @@ AMDGPUInstructionSelector::selectMUBUFOffset(MachineOperand &Root) const {
}};
}
+InstructionSelector::ComplexRendererFns
+AMDGPUInstructionSelector::selectBUFSOffset(MachineOperand &Root) const {
+
+ Register SOffset = Root.getReg();
+
+ if (STI.hasRestrictedSOffset() && mi_match(SOffset, *MRI, m_ZeroInt()))
+ SOffset = AMDGPU::SGPR_NULL;
+
+ return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(SOffset); }}};
+}
+
/// Get an immediate that must be 32-bits, and treated as zero extended.
static std::optional<uint64_t>
getConstantZext32Val(Register Reg, const MachineRegisterInfo &MRI) {
@@ -5239,6 +5289,135 @@ AMDGPUInstructionSelector::selectVOP3PMadMixMods(MachineOperand &Root) const {
}};
}
+bool AMDGPUInstructionSelector::selectSBarrierSignalIsfirst(
+ MachineInstr &I, Intrinsic::ID IntrID) const {
+ MachineBasicBlock *MBB = I.getParent();
+ const DebugLoc &DL = I.getDebugLoc();
+ Register CCReg = I.getOperand(0).getReg();
+
+ bool HasM0 = IntrID == Intrinsic::amdgcn_s_barrier_signal_isfirst_var;
+
+ if (HasM0) {
+ auto CopyMIB = BuildMI(*MBB, &I, DL, TII.get(AMDGPU::COPY), AMDGPU::M0)
+ .addReg(I.getOperand(2).getReg());
+ BuildMI(*MBB, &I, DL, TII.get(AMDGPU::S_BARRIER_SIGNAL_ISFIRST_M0));
+ if (!constrainSelectedInstRegOperands(*CopyMIB, TII, TRI, RBI))
+ return false;
+ } else {
+ BuildMI(*MBB, &I, DL, TII.get(AMDGPU::S_BARRIER_SIGNAL_ISFIRST_IMM))
+ .addImm(I.getOperand(2).getImm());
+ }
+
+ BuildMI(*MBB, &I, DL, TII.get(AMDGPU::COPY), CCReg).addReg(AMDGPU::SCC);
+
+ I.eraseFromParent();
+ return RBI.constrainGenericRegister(CCReg, AMDGPU::SReg_32_XM0_XEXECRegClass,
+ *MRI);
+}
+
+unsigned getNamedBarrierOp(bool HasInlineConst, Intrinsic::ID IntrID) {
+ if (HasInlineConst) {
+ switch (IntrID) {
+ default:
+ llvm_unreachable("not a named barrier op");
+ case Intrinsic::amdgcn_s_barrier_init:
+ return AMDGPU::S_BARRIER_INIT_IMM;
+ case Intrinsic::amdgcn_s_barrier_join:
+ return AMDGPU::S_BARRIER_JOIN_IMM;
+ case Intrinsic::amdgcn_s_wakeup_barrier:
+ return AMDGPU::S_WAKEUP_BARRIER_IMM;
+ case Intrinsic::amdgcn_s_get_barrier_state:
+ return AMDGPU::S_GET_BARRIER_STATE_IMM;
+ };
+ } else {
+ switch (IntrID) {
+ default:
+ llvm_unreachable("not a named barrier op");
+ case Intrinsic::amdgcn_s_barrier_init:
+ return AMDGPU::S_BARRIER_INIT_M0;
+ case Intrinsic::amdgcn_s_barrier_join:
+ return AMDGPU::S_BARRIER_JOIN_M0;
+ case Intrinsic::amdgcn_s_wakeup_barrier:
+ return AMDGPU::S_WAKEUP_BARRIER_M0;
+ case Intrinsic::amdgcn_s_get_barrier_state:
+ return AMDGPU::S_GET_BARRIER_STATE_M0;
+ };
+ }
+}
+
+bool AMDGPUInstructionSelector::selectNamedBarrierInst(
+ MachineInstr &I, Intrinsic::ID IntrID) const {
+ MachineBasicBlock *MBB = I.getParent();
+ const DebugLoc &DL = I.getDebugLoc();
+ MachineOperand BarOp = IntrID == Intrinsic::amdgcn_s_get_barrier_state
+ ? I.getOperand(2)
+ : I.getOperand(1);
+ std::optional<int64_t> BarValImm =
+ getIConstantVRegSExtVal(BarOp.getReg(), *MRI);
+ Register M0Val;
+ Register TmpReg0;
+
+ // For S_BARRIER_INIT, member count will always be read from M0[16:22]
+ if (IntrID == Intrinsic::amdgcn_s_barrier_init) {
+ Register MemberCount = I.getOperand(2).getReg();
+ TmpReg0 = MRI->createVirtualRegister(&AMDGPU::SReg_32RegClass);
+ // TODO: This should be expanded during legalization so that the the S_LSHL
+ // and S_OR can be constant-folded
+ BuildMI(*MBB, &I, DL, TII.get(AMDGPU::S_LSHL_B32), TmpReg0)
+ .addImm(16)
+ .addReg(MemberCount);
+ M0Val = TmpReg0;
+ }
+
+ // If not inlinable, get reference to barrier depending on the instruction
+ if (!BarValImm) {
+ if (IntrID == Intrinsic::amdgcn_s_barrier_init) {
+ // If reference to barrier id is not an inlinable constant then it must be
+ // referenced with M0[4:0]. Perform an OR with the member count to include
+ // it in M0 for S_BARRIER_INIT.
+ Register TmpReg1 = MRI->createVirtualRegister(&AMDGPU::SReg_32RegClass);
+ BuildMI(*MBB, &I, DL, TII.get(AMDGPU::S_OR_B32), TmpReg1)
+ .addReg(BarOp.getReg())
+ .addReg(TmpReg0);
+ M0Val = TmpReg1;
+ } else {
+ M0Val = BarOp.getReg();
+ }
+ }
+
+ // Build copy to M0 if needed. For S_BARRIER_INIT, M0 is always required.
+ if (M0Val) {
+ auto CopyMIB =
+ BuildMI(*MBB, &I, DL, TII.get(AMDGPU::COPY), AMDGPU::M0).addReg(M0Val);
+ constrainSelectedInstRegOperands(*CopyMIB, TII, TRI, RBI);
+ }
+
+ MachineInstrBuilder MIB;
+ unsigned Opc = getNamedBarrierOp(BarValImm.has_value(), IntrID);
+ MIB = BuildMI(*MBB, &I, DL, TII.get(Opc));
+
+ if (IntrID == Intrinsic::amdgcn_s_get_barrier_state)
+ MIB.addDef(I.getOperand(0).getReg());
+
+ if (BarValImm)
+ MIB.addImm(*BarValImm);
+
+ I.eraseFromParent();
+ return true;
+}
+bool AMDGPUInstructionSelector::selectSBarrierLeave(MachineInstr &I) const {
+ MachineBasicBlock *BB = I.getParent();
+ const DebugLoc &DL = I.getDebugLoc();
+ Register CCReg = I.getOperand(0).getReg();
+
+ BuildMI(*BB, &I, DL, TII.get(AMDGPU::S_BARRIER_LEAVE));
+ BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), CCReg).addReg(AMDGPU::SCC);
+
+ I.eraseFromParent();
+ return RBI.constrainGenericRegister(CCReg, AMDGPU::SReg_32_XM0_XEXECRegClass,
+ *MRI);
+}
+
void AMDGPUInstructionSelector::renderTruncImm32(MachineInstrBuilder &MIB,
const MachineInstr &MI,
int OpIdx) const {
@@ -5296,14 +5475,19 @@ void AMDGPUInstructionSelector::renderExtractCPol(MachineInstrBuilder &MIB,
const MachineInstr &MI,
int OpIdx) const {
assert(OpIdx >= 0 && "expected to match an immediate operand");
- MIB.addImm(MI.getOperand(OpIdx).getImm() & AMDGPU::CPol::ALL);
+ MIB.addImm(MI.getOperand(OpIdx).getImm() &
+ (AMDGPU::isGFX12Plus(STI) ? AMDGPU::CPol::ALL
+ : AMDGPU::CPol::ALL_pregfx12));
}
void AMDGPUInstructionSelector::renderExtractSWZ(MachineInstrBuilder &MIB,
const MachineInstr &MI,
int OpIdx) const {
assert(OpIdx >= 0 && "expected to match an immediate operand");
- MIB.addImm((MI.getOperand(OpIdx).getImm() >> 3) & 1);
+ const bool Swizzle = MI.getOperand(OpIdx).getImm() &
+ (AMDGPU::isGFX12Plus(STI) ? AMDGPU::CPol::SWZ
+ : AMDGPU::CPol::SWZ_pregfx12);
+ MIB.addImm(Swizzle);
}
void AMDGPUInstructionSelector::renderSetGLC(MachineInstrBuilder &MIB,
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h
index c93e3de66d40..ab7cc0a6beb8 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h
@@ -149,6 +149,9 @@ private:
bool selectSMFMACIntrin(MachineInstr &I) const;
bool selectWaveAddress(MachineInstr &I) const;
bool selectStackRestore(MachineInstr &MI) const;
+ bool selectNamedBarrierInst(MachineInstr &I, Intrinsic::ID IID) const;
+ bool selectSBarrierSignalIsfirst(MachineInstr &I, Intrinsic::ID IID) const;
+ bool selectSBarrierLeave(MachineInstr &I) const;
std::pair<Register, unsigned> selectVOP3ModsImpl(MachineOperand &Root,
bool IsCanonicalizing = true,
@@ -290,6 +293,9 @@ private:
Register &SOffset, int64_t &Offset) const;
InstructionSelector::ComplexRendererFns
+ selectBUFSOffset(MachineOperand &Root) const;
+
+ InstructionSelector::ComplexRendererFns
selectMUBUFAddr64(MachineOperand &Root) const;
InstructionSelector::ComplexRendererFns
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td b/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
index d2d09a0b1fc5..eaf72d7157ee 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
@@ -252,6 +252,8 @@ def umin_oneuse : HasOneUseBinOp<umin>;
def fminnum_oneuse : HasOneUseBinOp<fminnum>;
def fmaxnum_oneuse : HasOneUseBinOp<fmaxnum>;
+def fminimum_oneuse : HasOneUseBinOp<fminimum>;
+def fmaximum_oneuse : HasOneUseBinOp<fmaximum>;
def fminnum_ieee_oneuse : HasOneUseBinOp<fminnum_ieee>;
def fmaxnum_ieee_oneuse : HasOneUseBinOp<fmaxnum_ieee>;
@@ -640,6 +642,10 @@ defm int_amdgcn_global_atomic_fmax : noret_op;
defm int_amdgcn_global_atomic_csub : noret_op;
defm int_amdgcn_flat_atomic_fadd : local_addr_space_atomic_op;
defm int_amdgcn_ds_fadd_v2bf16 : noret_op;
+defm int_amdgcn_flat_atomic_fmin_num : noret_op;
+defm int_amdgcn_flat_atomic_fmax_num : noret_op;
+defm int_amdgcn_global_atomic_fmin_num : noret_op;
+defm int_amdgcn_global_atomic_fmax_num : noret_op;
multiclass noret_binary_atomic_op<SDNode atomic_op, bit IsInt = 1> {
let HasNoUse = true in
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
index ccdbd3216e26..fbee28889451 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
@@ -460,8 +460,8 @@ static bool shouldWidenLoad(const GCNSubtarget &ST, LLT MemoryTy,
return false;
// If we have 96-bit memory operations, we shouldn't touch them. Note we may
- // end up widening these for a scalar load during RegBankSelect, since there
- // aren't 96-bit scalar loads.
+ // end up widening these for a scalar load during RegBankSelect, if we don't
+ // have 96-bit scalar loads.
if (SizeInBits == 96 && ST.hasDwordx3LoadStores())
return false;
@@ -633,6 +633,8 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
const LLT PrivatePtr = GetAddrSpacePtr(AMDGPUAS::PRIVATE_ADDRESS);
const LLT BufferFatPtr = GetAddrSpacePtr(AMDGPUAS::BUFFER_FAT_POINTER);
const LLT RsrcPtr = GetAddrSpacePtr(AMDGPUAS::BUFFER_RESOURCE);
+ const LLT BufferStridedPtr =
+ GetAddrSpacePtr(AMDGPUAS::BUFFER_STRIDED_POINTER);
const LLT CodePtr = FlatPtr;
@@ -681,13 +683,23 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
if (ST.hasVOP3PInsts() && ST.hasAddNoCarry() && ST.hasIntClamp()) {
// Full set of gfx9 features.
- getActionDefinitionsBuilder({G_ADD, G_SUB})
- .legalFor({S32, S16, V2S16})
- .clampMaxNumElementsStrict(0, S16, 2)
- .scalarize(0)
- .minScalar(0, S16)
- .widenScalarToNextMultipleOf(0, 32)
- .maxScalar(0, S32);
+ if (ST.hasScalarAddSub64()) {
+ getActionDefinitionsBuilder({G_ADD, G_SUB})
+ .legalFor({S64, S32, S16, V2S16})
+ .clampMaxNumElementsStrict(0, S16, 2)
+ .scalarize(0)
+ .minScalar(0, S16)
+ .widenScalarToNextMultipleOf(0, 32)
+ .maxScalar(0, S32);
+ } else {
+ getActionDefinitionsBuilder({G_ADD, G_SUB})
+ .legalFor({S32, S16, V2S16})
+ .clampMaxNumElementsStrict(0, S16, 2)
+ .scalarize(0)
+ .minScalar(0, S16)
+ .widenScalarToNextMultipleOf(0, 32)
+ .maxScalar(0, S32);
+ }
getActionDefinitionsBuilder(G_MUL)
.legalFor({S32, S16, V2S16})
@@ -1103,7 +1115,7 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
}
getActionDefinitionsBuilder(G_PTR_ADD)
- .unsupportedFor({BufferFatPtr, RsrcPtr})
+ .unsupportedFor({BufferFatPtr, BufferStridedPtr, RsrcPtr})
.legalIf(all(isPointer(0), sameSize(0, 1)))
.scalarize(0)
.scalarSameSizeAs(1, 0);
@@ -1393,7 +1405,8 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
// The custom pointers (fat pointers, buffer resources) don't work with load
// and store at this level. Fat pointers should have been lowered to
// intrinsics before the translation to MIR.
- Actions.unsupportedIf(typeInSet(1, {BufferFatPtr, RsrcPtr}));
+ Actions.unsupportedIf(
+ typeInSet(1, {BufferFatPtr, BufferStridedPtr, RsrcPtr}));
// Address space 8 pointers are handled by a 4xs32 load, bitcast, and
// ptrtoint. This is needed to account for the fact that we can't have i128
@@ -1949,20 +1962,25 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
.widenScalarToNextPow2(0)
.scalarize(0);
- getActionDefinitionsBuilder({
- // TODO: Verify V_BFI_B32 is generated from expanded bit ops
- G_FCOPYSIGN,
+ getActionDefinitionsBuilder(
+ {// TODO: Verify V_BFI_B32 is generated from expanded bit ops
+ G_FCOPYSIGN,
- G_ATOMIC_CMPXCHG_WITH_SUCCESS,
- G_ATOMICRMW_NAND,
- G_ATOMICRMW_FSUB,
- G_READ_REGISTER,
- G_WRITE_REGISTER,
+ G_ATOMIC_CMPXCHG_WITH_SUCCESS, G_ATOMICRMW_NAND, G_ATOMICRMW_FSUB,
+ G_READ_REGISTER, G_WRITE_REGISTER,
- G_SADDO, G_SSUBO,
+ G_SADDO, G_SSUBO})
+ .lower();
- // TODO: Implement
- G_FMINIMUM, G_FMAXIMUM}).lower();
+ if (ST.hasIEEEMinMax()) {
+ getActionDefinitionsBuilder({G_FMINIMUM, G_FMAXIMUM})
+ .legalFor(FPTypesPK16)
+ .clampMaxNumElements(0, S16, 2)
+ .scalarize(0);
+ } else {
+ // TODO: Implement
+ getActionDefinitionsBuilder({G_FMINIMUM, G_FMAXIMUM}).lower();
+ }
getActionDefinitionsBuilder({G_MEMCPY, G_MEMCPY_INLINE, G_MEMMOVE, G_MEMSET})
.lower();
@@ -1972,6 +1990,8 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
G_INDEXED_ZEXTLOAD, G_INDEXED_STORE})
.unsupported();
+ getActionDefinitionsBuilder(G_PREFETCH).alwaysLegal();
+
getLegacyLegalizerInfo().computeTables();
verify(*ST.getInstrInfo());
}
@@ -5397,7 +5417,7 @@ bool AMDGPULegalizerInfo::legalizeIsAddrSpace(MachineInstr &MI,
std::pair<Register, unsigned>
AMDGPULegalizerInfo::splitBufferOffsets(MachineIRBuilder &B,
Register OrigOffset) const {
- const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset();
+ const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset(ST);
Register BaseReg;
unsigned ImmOffset;
const LLT S32 = LLT::scalar(32);
@@ -6136,7 +6156,7 @@ bool AMDGPULegalizerInfo::legalizeImageIntrinsic(
return false;
}
- const unsigned NSAMaxSize = ST.getNSAMaxSize();
+ const unsigned NSAMaxSize = ST.getNSAMaxSize(BaseOpcode->Sampler);
const unsigned HasPartialNSA = ST.hasPartialNSAEncoding();
if (IsA16 || IsG16) {
@@ -6196,7 +6216,7 @@ bool AMDGPULegalizerInfo::legalizeImageIntrinsic(
// SIShrinkInstructions will convert NSA encodings to non-NSA after register
// allocation when possible.
//
- // Partial NSA is allowed on GFX11 where the final register is a contiguous
+ // Partial NSA is allowed on GFX11+ where the final register is a contiguous
// set of the remaining addresses.
const bool UseNSA = ST.hasNSAEncoding() &&
CorrectedNumVAddrs >= ST.getNSAThreshold(MF) &&
@@ -6452,10 +6472,10 @@ bool AMDGPULegalizerInfo::legalizeSBufferLoad(
MemSize, MemAlign);
MI.addMemOperand(MF, MMO);
- // There are no 96-bit result scalar loads, but widening to 128-bit should
+ // If we don't have 96-bit result scalar loads, widening to 128-bit should
// always be legal. We may need to restore this to a 96-bit result if it turns
// out this needs to be converted to a vector load during RegBankSelect.
- if (!isPowerOf2_32(Size)) {
+ if (!isPowerOf2_32(Size) && (Size != 96 || !ST.hasScalarDwordx3Loads())) {
if (Ty.isVector())
Helper.moreElementsVectorDst(MI, getPow2VectorType(Ty), 0);
else
@@ -6620,13 +6640,17 @@ bool AMDGPULegalizerInfo::legalizeBVHIntrinsic(MachineInstr &MI,
return false;
}
+ const bool IsGFX11 = AMDGPU::isGFX11(ST);
const bool IsGFX11Plus = AMDGPU::isGFX11Plus(ST);
+ const bool IsGFX12Plus = AMDGPU::isGFX12Plus(ST);
const bool IsA16 = MRI.getType(RayDir).getElementType().getSizeInBits() == 16;
const bool Is64 = MRI.getType(NodePtr).getSizeInBits() == 64;
const unsigned NumVDataDwords = 4;
const unsigned NumVAddrDwords = IsA16 ? (Is64 ? 9 : 8) : (Is64 ? 12 : 11);
const unsigned NumVAddrs = IsGFX11Plus ? (IsA16 ? 4 : 5) : NumVAddrDwords;
- const bool UseNSA = ST.hasNSAEncoding() && NumVAddrs <= ST.getNSAMaxSize();
+ const bool UseNSA =
+ IsGFX12Plus || (ST.hasNSAEncoding() && NumVAddrs <= ST.getNSAMaxSize());
+
const unsigned BaseOpcodes[2][2] = {
{AMDGPU::IMAGE_BVH_INTERSECT_RAY, AMDGPU::IMAGE_BVH_INTERSECT_RAY_a16},
{AMDGPU::IMAGE_BVH64_INTERSECT_RAY,
@@ -6634,14 +6658,16 @@ bool AMDGPULegalizerInfo::legalizeBVHIntrinsic(MachineInstr &MI,
int Opcode;
if (UseNSA) {
Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
- IsGFX11Plus ? AMDGPU::MIMGEncGfx11NSA
+ IsGFX12Plus ? AMDGPU::MIMGEncGfx12
+ : IsGFX11 ? AMDGPU::MIMGEncGfx11NSA
: AMDGPU::MIMGEncGfx10NSA,
NumVDataDwords, NumVAddrDwords);
} else {
- Opcode = AMDGPU::getMIMGOpcode(
- BaseOpcodes[Is64][IsA16],
- IsGFX11Plus ? AMDGPU::MIMGEncGfx11Default : AMDGPU::MIMGEncGfx10Default,
- NumVDataDwords, NumVAddrDwords);
+ assert(!IsGFX12Plus);
+ Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
+ IsGFX11 ? AMDGPU::MIMGEncGfx11Default
+ : AMDGPU::MIMGEncGfx10Default,
+ NumVDataDwords, NumVAddrDwords);
}
assert(Opcode != -1);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp b/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp
index 5c66fd2b180f..0c21382e5c22 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp
@@ -562,11 +562,10 @@ bool AMDGPULibCalls::fold_read_write_pipe(CallInst *CI, IRBuilder<> &B,
if (!F)
return false;
- auto *BCast = B.CreatePointerCast(PtrArg, PtrTy);
SmallVector<Value *, 6> Args;
for (unsigned I = 0; I != PtrArgLoc; ++I)
Args.push_back(CI->getArgOperand(I));
- Args.push_back(BCast);
+ Args.push_back(PtrArg);
auto *NCI = B.CreateCall(F, Args);
NCI->setAttributes(CI->getAttributes());
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULibFunc.cpp b/llvm/lib/Target/AMDGPU/AMDGPULibFunc.cpp
index c798ab5f03b3..3437b6dc8ae0 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULibFunc.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULibFunc.cpp
@@ -478,7 +478,7 @@ static bool eatTerm(StringRef& mangledName, const char c) {
template <size_t N>
static bool eatTerm(StringRef& mangledName, const char (&str)[N]) {
- if (mangledName.startswith(StringRef(str, N-1))) {
+ if (mangledName.starts_with(StringRef(str, N - 1))) {
drop_front(mangledName, N-1);
return true;
}
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h b/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h
index 25c0b4953ab7..248ee26a47eb 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h
@@ -20,7 +20,6 @@
namespace llvm {
class AMDGPUSubtarget;
-class GCNSubtarget;
class AMDGPUMachineFunction : public MachineFunctionInfo {
/// A map to keep track of local memory objects and their offsets within the
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp
index 62996a3b3fb7..c9412f720c62 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp
@@ -1061,7 +1061,7 @@ bool AMDGPURegisterBankInfo::applyMappingLoad(
if (DstBank == &AMDGPU::SGPRRegBank) {
// There are some special cases that we need to look at for 32 bit and 96
// bit SGPR loads otherwise we have nothing to do.
- if (LoadSize != 32 && LoadSize != 96)
+ if (LoadSize != 32 && (LoadSize != 96 || Subtarget.hasScalarDwordx3Loads()))
return false;
MachineMemOperand *MMO = *MI.memoperands_begin();
@@ -1784,7 +1784,7 @@ getBaseWithConstantOffset(MachineRegisterInfo &MRI, Register Reg) {
std::pair<Register, unsigned>
AMDGPURegisterBankInfo::splitBufferOffsets(MachineIRBuilder &B,
Register OrigOffset) const {
- const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset();
+ const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset(Subtarget);
Register BaseReg;
unsigned ImmOffset;
const LLT S32 = LLT::scalar(32);
@@ -3101,6 +3101,26 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
applyDefaultMapping(OpdMapper);
constrainOpWithReadfirstlane(B, MI, 8); // M0
return;
+ case Intrinsic::amdgcn_s_sleep_var:
+ assert(OpdMapper.getVRegs(1).empty());
+ constrainOpWithReadfirstlane(B, MI, 1);
+ return;
+ case Intrinsic::amdgcn_s_barrier_signal_var:
+ case Intrinsic::amdgcn_s_barrier_join:
+ case Intrinsic::amdgcn_s_wakeup_barrier:
+ constrainOpWithReadfirstlane(B, MI, 1);
+ return;
+ case Intrinsic::amdgcn_s_barrier_signal_isfirst_var:
+ constrainOpWithReadfirstlane(B, MI, 2);
+ return;
+ case Intrinsic::amdgcn_s_barrier_init:
+ constrainOpWithReadfirstlane(B, MI, 1);
+ constrainOpWithReadfirstlane(B, MI, 2);
+ return;
+ case Intrinsic::amdgcn_s_get_barrier_state: {
+ constrainOpWithReadfirstlane(B, MI, 2);
+ return;
+ }
default: {
if (const AMDGPU::RsrcIntrinsic *RSrcIntrin =
AMDGPU::lookupRsrcIntrinsic(IntrID)) {
@@ -3238,6 +3258,24 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
case AMDGPU::G_AMDGPU_MAD_I64_I32:
applyMappingMAD_64_32(B, OpdMapper);
return;
+ case AMDGPU::G_PREFETCH: {
+ if (!Subtarget.hasPrefetch()) {
+ MI.eraseFromParent();
+ return;
+ }
+ unsigned PtrBank =
+ getRegBankID(MI.getOperand(0).getReg(), MRI, AMDGPU::SGPRRegBankID);
+ if (PtrBank == AMDGPU::VGPRRegBankID) {
+ MI.eraseFromParent();
+ return;
+ }
+ // FIXME: There is currently no support for prefetch in global isel.
+ // There is no node equivalence and what's worse there is no MMO produced
+ // for a prefetch on global isel path.
+ // Prefetch does not affect execution so erase it for now.
+ MI.eraseFromParent();
+ return;
+ }
default:
break;
}
@@ -3727,14 +3765,17 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case AMDGPU::G_INTRINSIC_ROUNDEVEN:
case AMDGPU::G_FMINNUM:
case AMDGPU::G_FMAXNUM:
+ case AMDGPU::G_FMINIMUM:
+ case AMDGPU::G_FMAXIMUM:
case AMDGPU::G_INTRINSIC_TRUNC:
case AMDGPU::G_STRICT_FADD:
case AMDGPU::G_STRICT_FSUB:
case AMDGPU::G_STRICT_FMUL:
case AMDGPU::G_STRICT_FMA: {
- unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
- if (Subtarget.hasSALUFloatInsts() && (Size == 32 || Size == 16) &&
- isSALUMapping(MI))
+ LLT Ty = MRI.getType(MI.getOperand(0).getReg());
+ unsigned Size = Ty.getSizeInBits();
+ if (Subtarget.hasSALUFloatInsts() && Ty.isScalar() &&
+ (Size == 32 || Size == 16) && isSALUMapping(MI))
return getDefaultMappingSOP(MI);
return getDefaultMappingVOP(MI);
}
@@ -3758,14 +3799,20 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
return getDefaultMappingSOP(MI);
return getDefaultMappingVOP(MI);
}
+ case AMDGPU::G_FSQRT:
+ case AMDGPU::G_FEXP2:
+ case AMDGPU::G_FLOG2: {
+ unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ if (Subtarget.hasPseudoScalarTrans() && (Size == 16 || Size == 32) &&
+ isSALUMapping(MI))
+ return getDefaultMappingSOP(MI);
+ return getDefaultMappingVOP(MI);
+ }
case AMDGPU::G_SADDSAT: // FIXME: Could lower sat ops for SALU
case AMDGPU::G_SSUBSAT:
case AMDGPU::G_UADDSAT:
case AMDGPU::G_USUBSAT:
case AMDGPU::G_FMAD:
- case AMDGPU::G_FSQRT:
- case AMDGPU::G_FEXP2:
- case AMDGPU::G_FLOG2:
case AMDGPU::G_FLDEXP:
case AMDGPU::G_FMINNUM_IEEE:
case AMDGPU::G_FMAXNUM_IEEE:
@@ -4230,12 +4277,7 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case Intrinsic::amdgcn_sin:
case Intrinsic::amdgcn_cos:
case Intrinsic::amdgcn_log_clamp:
- case Intrinsic::amdgcn_log:
- case Intrinsic::amdgcn_exp2:
- case Intrinsic::amdgcn_rcp:
case Intrinsic::amdgcn_rcp_legacy:
- case Intrinsic::amdgcn_sqrt:
- case Intrinsic::amdgcn_rsq:
case Intrinsic::amdgcn_rsq_legacy:
case Intrinsic::amdgcn_rsq_clamp:
case Intrinsic::amdgcn_fmul_legacy:
@@ -4292,6 +4334,17 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case Intrinsic::amdgcn_wmma_i32_16x16x16_iu4:
case Intrinsic::amdgcn_wmma_i32_16x16x16_iu8:
return getDefaultMappingVOP(MI);
+ case Intrinsic::amdgcn_log:
+ case Intrinsic::amdgcn_exp2:
+ case Intrinsic::amdgcn_rcp:
+ case Intrinsic::amdgcn_rsq:
+ case Intrinsic::amdgcn_sqrt: {
+ unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ if (Subtarget.hasPseudoScalarTrans() && (Size == 16 || Size == 32) &&
+ isSALUMapping(MI))
+ return getDefaultMappingSOP(MI);
+ return getDefaultMappingVOP(MI);
+ }
case Intrinsic::amdgcn_sbfe:
case Intrinsic::amdgcn_ubfe:
if (isSALUMapping(MI))
@@ -4416,6 +4469,15 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[5] = getSGPROpMapping(MI.getOperand(4).getReg(), MRI, *TRI);
break;
}
+ case Intrinsic::amdgcn_permlane16_var:
+ case Intrinsic::amdgcn_permlanex16_var: {
+ unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, *TRI);
+ OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
+ OpdsMapping[2] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
+ OpdsMapping[3] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
+ OpdsMapping[4] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
+ break;
+ }
case Intrinsic::amdgcn_mfma_f32_4x4x1f32:
case Intrinsic::amdgcn_mfma_f32_4x4x4f16:
case Intrinsic::amdgcn_mfma_i32_4x4x4i8:
@@ -4619,9 +4681,13 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case Intrinsic::amdgcn_global_atomic_csub:
case Intrinsic::amdgcn_global_atomic_fmin:
case Intrinsic::amdgcn_global_atomic_fmax:
+ case Intrinsic::amdgcn_global_atomic_fmin_num:
+ case Intrinsic::amdgcn_global_atomic_fmax_num:
case Intrinsic::amdgcn_flat_atomic_fadd:
case Intrinsic::amdgcn_flat_atomic_fmin:
case Intrinsic::amdgcn_flat_atomic_fmax:
+ case Intrinsic::amdgcn_flat_atomic_fmin_num:
+ case Intrinsic::amdgcn_flat_atomic_fmax_num:
case Intrinsic::amdgcn_global_atomic_fadd_v2bf16:
case Intrinsic::amdgcn_flat_atomic_fadd_v2bf16:
return getDefaultMappingAllVGPR(MI);
@@ -4830,7 +4896,37 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
getVGPROpMapping(MI.getOperand(5).getReg(), MRI, *TRI); // %data1
break;
}
-
+ case Intrinsic::amdgcn_s_sleep_var:
+ OpdsMapping[1] = getSGPROpMapping(MI.getOperand(1).getReg(), MRI, *TRI);
+ break;
+ case Intrinsic::amdgcn_s_barrier_signal_var:
+ case Intrinsic::amdgcn_s_barrier_join:
+ case Intrinsic::amdgcn_s_wakeup_barrier:
+ OpdsMapping[1] = getSGPROpMapping(MI.getOperand(1).getReg(), MRI, *TRI);
+ break;
+ case Intrinsic::amdgcn_s_barrier_init:
+ OpdsMapping[1] = getSGPROpMapping(MI.getOperand(1).getReg(), MRI, *TRI);
+ OpdsMapping[2] = getSGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+ break;
+ case Intrinsic::amdgcn_s_barrier_signal_isfirst_var: {
+ const unsigned ResultSize = 1;
+ OpdsMapping[0] =
+ AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, ResultSize);
+ OpdsMapping[2] = getSGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+ break;
+ }
+ case Intrinsic::amdgcn_s_barrier_signal_isfirst:
+ case Intrinsic::amdgcn_s_barrier_leave: {
+ const unsigned ResultSize = 1;
+ OpdsMapping[0] =
+ AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, ResultSize);
+ break;
+ }
+ case Intrinsic::amdgcn_s_get_barrier_state: {
+ OpdsMapping[0] = getSGPROpMapping(MI.getOperand(0).getReg(), MRI, *TRI);
+ OpdsMapping[2] = getSGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+ break;
+ }
default:
return getInvalidInstructionMapping();
}
@@ -4938,6 +5034,9 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case AMDGPU::G_FPTRUNC_ROUND_UPWARD:
case AMDGPU::G_FPTRUNC_ROUND_DOWNWARD:
return getDefaultMappingVOP(MI);
+ case AMDGPU::G_PREFETCH:
+ OpdsMapping[0] = getSGPROpMapping(MI.getOperand(0).getReg(), MRI, *TRI);
+ break;
}
return getInstructionMapping(/*ID*/1, /*Cost*/1,
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURemoveIncompatibleFunctions.cpp b/llvm/lib/Target/AMDGPU/AMDGPURemoveIncompatibleFunctions.cpp
index e387e16d0cf1..552380d54dfd 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURemoveIncompatibleFunctions.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURemoveIncompatibleFunctions.cpp
@@ -89,25 +89,23 @@ const SubtargetSubTypeKV *getGPUInfo(const GCNSubtarget &ST,
return nullptr;
}
-constexpr unsigned FeaturesToCheck[] = {
- AMDGPU::FeatureGFX11Insts,
- AMDGPU::FeatureGFX10Insts,
- AMDGPU::FeatureGFX9Insts,
- AMDGPU::FeatureGFX8Insts,
- AMDGPU::FeatureDPP,
- AMDGPU::Feature16BitInsts,
- AMDGPU::FeatureDot1Insts,
- AMDGPU::FeatureDot2Insts,
- AMDGPU::FeatureDot3Insts,
- AMDGPU::FeatureDot4Insts,
- AMDGPU::FeatureDot5Insts,
- AMDGPU::FeatureDot6Insts,
- AMDGPU::FeatureDot7Insts,
- AMDGPU::FeatureDot8Insts,
- AMDGPU::FeatureExtendedImageInsts,
- AMDGPU::FeatureSMemRealTime,
- AMDGPU::FeatureSMemTimeInst
-};
+constexpr unsigned FeaturesToCheck[] = {AMDGPU::FeatureGFX11Insts,
+ AMDGPU::FeatureGFX10Insts,
+ AMDGPU::FeatureGFX9Insts,
+ AMDGPU::FeatureGFX8Insts,
+ AMDGPU::FeatureDPP,
+ AMDGPU::Feature16BitInsts,
+ AMDGPU::FeatureDot1Insts,
+ AMDGPU::FeatureDot2Insts,
+ AMDGPU::FeatureDot3Insts,
+ AMDGPU::FeatureDot4Insts,
+ AMDGPU::FeatureDot5Insts,
+ AMDGPU::FeatureDot6Insts,
+ AMDGPU::FeatureDot7Insts,
+ AMDGPU::FeatureDot8Insts,
+ AMDGPU::FeatureExtendedImageInsts,
+ AMDGPU::FeatureSMemRealTime,
+ AMDGPU::FeatureSMemTimeInst};
FeatureBitset expandImpliedFeatures(const FeatureBitset &Features) {
FeatureBitset Result = Features;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUSearchableTables.td b/llvm/lib/Target/AMDGPU/AMDGPUSearchableTables.td
index 317f3f21d240..beb670669581 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUSearchableTables.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUSearchableTables.td
@@ -241,9 +241,13 @@ def : SourceOfDivergence<int_amdgcn_global_atomic_csub>;
def : SourceOfDivergence<int_amdgcn_global_atomic_fadd>;
def : SourceOfDivergence<int_amdgcn_global_atomic_fmin>;
def : SourceOfDivergence<int_amdgcn_global_atomic_fmax>;
+def : SourceOfDivergence<int_amdgcn_global_atomic_fmin_num>;
+def : SourceOfDivergence<int_amdgcn_global_atomic_fmax_num>;
def : SourceOfDivergence<int_amdgcn_flat_atomic_fadd>;
def : SourceOfDivergence<int_amdgcn_flat_atomic_fmin>;
def : SourceOfDivergence<int_amdgcn_flat_atomic_fmax>;
+def : SourceOfDivergence<int_amdgcn_flat_atomic_fmin_num>;
+def : SourceOfDivergence<int_amdgcn_flat_atomic_fmax_num>;
def : SourceOfDivergence<int_amdgcn_global_atomic_fadd_v2bf16>;
def : SourceOfDivergence<int_amdgcn_flat_atomic_fadd_v2bf16>;
def : SourceOfDivergence<int_amdgcn_ds_fadd>;
@@ -333,6 +337,8 @@ def : SourceOfDivergence<int_amdgcn_ds_ordered_add>;
def : SourceOfDivergence<int_amdgcn_ds_ordered_swap>;
def : SourceOfDivergence<int_amdgcn_permlane16>;
def : SourceOfDivergence<int_amdgcn_permlanex16>;
+def : SourceOfDivergence<int_amdgcn_permlane16_var>;
+def : SourceOfDivergence<int_amdgcn_permlanex16_var>;
def : SourceOfDivergence<int_amdgcn_mov_dpp>;
def : SourceOfDivergence<int_amdgcn_mov_dpp8>;
def : SourceOfDivergence<int_amdgcn_update_dpp>;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp
index 3c9f9cfd834f..f19c57668564 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp
@@ -201,14 +201,18 @@ unsigned GCNSubtarget::getConstantBusLimit(unsigned Opcode) const {
case AMDGPU::V_LSHLREV_B64_e64:
case AMDGPU::V_LSHLREV_B64_gfx10:
case AMDGPU::V_LSHLREV_B64_e64_gfx11:
+ case AMDGPU::V_LSHLREV_B64_e32_gfx12:
+ case AMDGPU::V_LSHLREV_B64_e64_gfx12:
case AMDGPU::V_LSHL_B64_e64:
case AMDGPU::V_LSHRREV_B64_e64:
case AMDGPU::V_LSHRREV_B64_gfx10:
case AMDGPU::V_LSHRREV_B64_e64_gfx11:
+ case AMDGPU::V_LSHRREV_B64_e64_gfx12:
case AMDGPU::V_LSHR_B64_e64:
case AMDGPU::V_ASHRREV_I64_e64:
case AMDGPU::V_ASHRREV_I64_gfx10:
case AMDGPU::V_ASHRREV_I64_e64_gfx11:
+ case AMDGPU::V_ASHRREV_I64_e64_gfx12:
case AMDGPU::V_ASHR_I64_e64:
return 1;
}
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
index 0c38fa32c6f3..e8c04ecf39ba 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
@@ -352,7 +352,7 @@ static cl::opt<bool> EnableMaxIlpSchedStrategy(
static cl::opt<bool> EnableRewritePartialRegUses(
"amdgpu-enable-rewrite-partial-reg-uses",
- cl::desc("Enable rewrite partial reg uses pass"), cl::init(false),
+ cl::desc("Enable rewrite partial reg uses pass"), cl::init(true),
cl::Hidden);
static cl::opt<bool> EnableHipStdPar(
@@ -375,6 +375,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAMDGPUTarget() {
initializeAMDGPUDAGToDAGISelPass(*PR);
initializeGCNDPPCombinePass(*PR);
initializeSILowerI1CopiesPass(*PR);
+ initializeAMDGPUGlobalISelDivergenceLoweringPass(*PR);
initializeSILowerWWMCopiesPass(*PR);
initializeSILowerSGPRSpillsPass(*PR);
initializeSIFixSGPRCopiesPass(*PR);
@@ -538,9 +539,10 @@ static StringRef computeDataLayout(const Triple &TT) {
// space 8) which cannot be non-trivilally accessed by LLVM memory operations
// like getelementptr.
return "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32"
- "-p7:160:256:256:32-p8:128:128-i64:64-v16:16-v24:32-v32:32-v48:64-v96:"
+ "-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-"
+ "v32:32-v48:64-v96:"
"128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-"
- "G1-ni:7:8";
+ "G1-ni:7:8:9";
}
LLVM_READNONE
@@ -601,8 +603,8 @@ StringRef AMDGPUTargetMachine::getFeatureString(const Function &F) const {
/// Predicate for Internalize pass.
static bool mustPreserveGV(const GlobalValue &GV) {
if (const Function *F = dyn_cast<Function>(&GV))
- return F->isDeclaration() || F->getName().startswith("__asan_") ||
- F->getName().startswith("__sanitizer_") ||
+ return F->isDeclaration() || F->getName().starts_with("__asan_") ||
+ F->getName().starts_with("__sanitizer_") ||
AMDGPU::isEntryFunctionCC(F->getCallingConv());
GV.removeDeadConstantUsers();
@@ -1255,6 +1257,7 @@ bool GCNPassConfig::addLegalizeMachineIR() {
void GCNPassConfig::addPreRegBankSelect() {
bool IsOptNone = getOptLevel() == CodeGenOptLevel::None;
addPass(createAMDGPUPostLegalizeCombiner(IsOptNone));
+ addPass(createAMDGPUGlobalISelDivergenceLoweringPass());
}
bool GCNPassConfig::addRegBankSelect() {
@@ -1499,13 +1502,13 @@ bool GCNTargetMachine::parseMachineFunctionInfo(
static_cast<const yaml::SIMachineFunctionInfo &>(MFI_);
MachineFunction &MF = PFS.MF;
SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
+ const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
if (MFI->initializeBaseYamlFields(YamlMFI, MF, PFS, Error, SourceRange))
return true;
if (MFI->Occupancy == 0) {
// Fixup the subtarget dependent default value.
- const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
MFI->Occupancy = ST.computeOccupancy(MF.getFunction(), MFI->getLDSSize());
}
@@ -1659,8 +1662,10 @@ bool GCNTargetMachine::parseMachineFunctionInfo(
MFI->ArgInfo.WorkItemIDZ, 0, 0)))
return true;
- MFI->Mode.IEEE = YamlMFI.Mode.IEEE;
- MFI->Mode.DX10Clamp = YamlMFI.Mode.DX10Clamp;
+ if (ST.hasIEEEMode())
+ MFI->Mode.IEEE = YamlMFI.Mode.IEEE;
+ if (ST.hasDX10ClampMode())
+ MFI->Mode.DX10Clamp = YamlMFI.Mode.DX10Clamp;
// FIXME: Move proper support for denormal-fp-math into base MachineFunction
MFI->Mode.FP32Denormals.Input = YamlMFI.Mode.FP32InputDenormals
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp
index f854c8c16e5a..584e41bfd546 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp
@@ -30,7 +30,7 @@ MCSection *AMDGPUTargetObjectFile::getExplicitSectionGlobal(
const GlobalObject *GO, SectionKind SK, const TargetMachine &TM) const {
// Set metadata access for the explicit section
StringRef SectionName = GO->getSection();
- if (SectionName.startswith(".AMDGPU.comment."))
+ if (SectionName.starts_with(".AMDGPU.comment."))
SK = SectionKind::getMetadata();
return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, SK, TM);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
index cb877a4695f1..f1da1a61bf4d 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
@@ -296,7 +296,7 @@ GCNTTIImpl::GCNTTIImpl(const AMDGPUTargetMachine *TM, const Function &F)
ST(static_cast<const GCNSubtarget *>(TM->getSubtargetImpl(F))),
TLI(ST->getTargetLowering()), CommonTTI(TM, F),
IsGraphics(AMDGPU::isGraphics(F.getCallingConv())) {
- SIModeRegisterDefaults Mode(F);
+ SIModeRegisterDefaults Mode(F, *ST);
HasFP32Denormals = Mode.FP32Denormals != DenormalMode::getPreserveSign();
HasFP64FP16Denormals =
Mode.FP64FP16Denormals != DenormalMode::getPreserveSign();
@@ -368,7 +368,8 @@ unsigned GCNTTIImpl::getLoadStoreVecRegBitWidth(unsigned AddrSpace) const {
AddrSpace == AMDGPUAS::CONSTANT_ADDRESS ||
AddrSpace == AMDGPUAS::CONSTANT_ADDRESS_32BIT ||
AddrSpace == AMDGPUAS::BUFFER_FAT_POINTER ||
- AddrSpace == AMDGPUAS::BUFFER_RESOURCE) {
+ AddrSpace == AMDGPUAS::BUFFER_RESOURCE ||
+ AddrSpace == AMDGPUAS::BUFFER_STRIDED_POINTER) {
return 512;
}
@@ -892,7 +893,7 @@ bool GCNTTIImpl::isReadRegisterSourceOfDivergence(
return true;
// Special case scalar registers that start with 'v'.
- if (RegName.startswith("vcc") || RegName.empty())
+ if (RegName.starts_with("vcc") || RegName.empty())
return false;
// VGPR or AGPR is divergent. There aren't any specially named vector
@@ -1026,6 +1027,8 @@ bool GCNTTIImpl::collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
case Intrinsic::amdgcn_flat_atomic_fadd:
case Intrinsic::amdgcn_flat_atomic_fmax:
case Intrinsic::amdgcn_flat_atomic_fmin:
+ case Intrinsic::amdgcn_flat_atomic_fmax_num:
+ case Intrinsic::amdgcn_flat_atomic_fmin_num:
OpIndexes.push_back(0);
return true;
default:
@@ -1100,7 +1103,9 @@ Value *GCNTTIImpl::rewriteIntrinsicWithAddressSpace(IntrinsicInst *II,
}
case Intrinsic::amdgcn_flat_atomic_fadd:
case Intrinsic::amdgcn_flat_atomic_fmax:
- case Intrinsic::amdgcn_flat_atomic_fmin: {
+ case Intrinsic::amdgcn_flat_atomic_fmin:
+ case Intrinsic::amdgcn_flat_atomic_fmax_num:
+ case Intrinsic::amdgcn_flat_atomic_fmin_num: {
Type *DestTy = II->getType();
Type *SrcTy = NewV->getType();
unsigned NewAS = SrcTy->getPointerAddressSpace();
@@ -1163,8 +1168,8 @@ bool GCNTTIImpl::areInlineCompatible(const Function *Caller,
// FIXME: dx10_clamp can just take the caller setting, but there seems to be
// no way to support merge for backend defined attributes.
- SIModeRegisterDefaults CallerMode(*Caller);
- SIModeRegisterDefaults CalleeMode(*Callee);
+ SIModeRegisterDefaults CallerMode(*Caller, *CallerST);
+ SIModeRegisterDefaults CalleeMode(*Callee, *CalleeST);
if (!CallerMode.isInlineCompatible(CalleeMode))
return false;
diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
index 092845d391a3..3b69a37728ea 100644
--- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
+++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
@@ -373,7 +373,7 @@ public:
bool isOffen() const { return isImmTy(ImmTyOffen); }
bool isIdxen() const { return isImmTy(ImmTyIdxen); }
bool isAddr64() const { return isImmTy(ImmTyAddr64); }
- bool isOffset() const { return isImmTy(ImmTyOffset) && isUInt<16>(getImm()); }
+ bool isOffset() const { return isImmTy(ImmTyOffset); }
bool isOffset0() const { return isImmTy(ImmTyOffset0) && isUInt<8>(getImm()); }
bool isOffset1() const { return isImmTy(ImmTyOffset1) && isUInt<8>(getImm()); }
bool isSMEMOffsetMod() const { return isImmTy(ImmTySMEMOffsetMod); }
@@ -893,6 +893,7 @@ public:
bool isSDelayALU() const;
bool isHwreg() const;
bool isSendMsg() const;
+ bool isSplitBarrier() const;
bool isSwizzle() const;
bool isSMRDOffset8() const;
bool isSMEMOffset() const;
@@ -1665,6 +1666,7 @@ private:
SMLoc getInstLoc(const OperandVector &Operands) const;
bool validateInstruction(const MCInst &Inst, const SMLoc &IDLoc, const OperandVector &Operands);
+ bool validateOffset(const MCInst &Inst, const OperandVector &Operands);
bool validateFlatOffset(const MCInst &Inst, const OperandVector &Operands);
bool validateSMEMOffset(const MCInst &Inst, const OperandVector &Operands);
bool validateSOPLiteral(const MCInst &Inst) const;
@@ -1856,6 +1858,7 @@ static const fltSemantics *getOpFltSemantics(uint8_t OperandType) {
case AMDGPU::OPERAND_REG_INLINE_C_V2INT32:
case AMDGPU::OPERAND_REG_IMM_V2INT32:
case AMDGPU::OPERAND_KIMM32:
+ case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32:
return &APFloat::IEEEsingle();
case AMDGPU::OPERAND_REG_IMM_INT64:
case AMDGPU::OPERAND_REG_IMM_FP64:
@@ -2185,7 +2188,8 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo
case AMDGPU::OPERAND_REG_INLINE_C_V2INT32:
case AMDGPU::OPERAND_REG_IMM_V2INT32:
case AMDGPU::OPERAND_KIMM32:
- case AMDGPU::OPERAND_KIMM16: {
+ case AMDGPU::OPERAND_KIMM16:
+ case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32: {
bool lost;
APFloat FPLiteral(APFloat::IEEEdouble(), Literal);
// Convert literal to single precision
@@ -2226,6 +2230,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo
case AMDGPU::OPERAND_REG_INLINE_C_V2FP32:
case AMDGPU::OPERAND_REG_IMM_V2INT32:
case AMDGPU::OPERAND_REG_INLINE_C_V2INT32:
+ case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32:
if (isSafeTruncation(Val, 32) &&
AMDGPU::isInlinableLiteral32(static_cast<int32_t>(Val),
AsmParser->hasInv2PiInlineImm())) {
@@ -2570,7 +2575,7 @@ static bool isRegularReg(RegisterKind Kind) {
static const RegInfo* getRegularRegInfo(StringRef Str) {
for (const RegInfo &Reg : RegularRegisters)
- if (Str.startswith(Reg.Name))
+ if (Str.starts_with(Reg.Name))
return &Reg;
return nullptr;
}
@@ -2630,7 +2635,7 @@ AMDGPUAsmParser::getRegularReg(RegisterKind RegKind,
if (RegKind == IS_SGPR || RegKind == IS_TTMP) {
// SGPR and TTMP registers must be aligned.
// Max required alignment is 4 dwords.
- AlignSize = std::min(RegWidth / 32, 4u);
+ AlignSize = std::min(llvm::bit_ceil(RegWidth / 32), 4u);
}
if (RegNum % AlignSize != 0) {
@@ -3411,12 +3416,16 @@ unsigned AMDGPUAsmParser::getConstantBusLimit(unsigned Opcode) const {
case AMDGPU::V_LSHLREV_B64_e64:
case AMDGPU::V_LSHLREV_B64_gfx10:
case AMDGPU::V_LSHLREV_B64_e64_gfx11:
+ case AMDGPU::V_LSHLREV_B64_e32_gfx12:
+ case AMDGPU::V_LSHLREV_B64_e64_gfx12:
case AMDGPU::V_LSHRREV_B64_e64:
case AMDGPU::V_LSHRREV_B64_gfx10:
case AMDGPU::V_LSHRREV_B64_e64_gfx11:
+ case AMDGPU::V_LSHRREV_B64_e64_gfx12:
case AMDGPU::V_ASHRREV_I64_e64:
case AMDGPU::V_ASHRREV_I64_gfx10:
case AMDGPU::V_ASHRREV_I64_e64_gfx11:
+ case AMDGPU::V_ASHRREV_I64_e64_gfx12:
case AMDGPU::V_LSHL_B64_e64:
case AMDGPU::V_LSHR_B64_e64:
case AMDGPU::V_ASHR_I64_e64:
@@ -3571,8 +3580,12 @@ bool AMDGPUAsmParser::validateVOPDRegBankConstraints(
: MCRegister::NoRegister;
};
+ // On GFX12 if both OpX and OpY are V_MOV_B32 then OPY uses SRC2 source-cache.
+ bool SkipSrc = Opcode == AMDGPU::V_DUAL_MOV_B32_e32_X_MOV_B32_e32_gfx12;
+
const auto &InstInfo = getVOPDInstInfo(Opcode, &MII);
- auto InvalidCompOprIdx = InstInfo.getInvalidCompOperandIndex(getVRegIdx);
+ auto InvalidCompOprIdx =
+ InstInfo.getInvalidCompOperandIndex(getVRegIdx, SkipSrc);
if (!InvalidCompOprIdx)
return true;
@@ -4131,6 +4144,40 @@ SMLoc AMDGPUAsmParser::getFlatOffsetLoc(const OperandVector &Operands) const {
return getLoc();
}
+bool AMDGPUAsmParser::validateOffset(const MCInst &Inst,
+ const OperandVector &Operands) {
+ auto Opcode = Inst.getOpcode();
+ auto OpNum = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::offset);
+ if (OpNum == -1)
+ return true;
+
+ uint64_t TSFlags = MII.get(Inst.getOpcode()).TSFlags;
+ if ((TSFlags & SIInstrFlags::FLAT))
+ return validateFlatOffset(Inst, Operands);
+
+ if ((TSFlags & SIInstrFlags::SMRD))
+ return validateSMEMOffset(Inst, Operands);
+
+ const auto &Op = Inst.getOperand(OpNum);
+ if (isGFX12Plus() &&
+ (TSFlags & (SIInstrFlags::MUBUF | SIInstrFlags::MTBUF))) {
+ const unsigned OffsetSize = 24;
+ if (!isIntN(OffsetSize, Op.getImm())) {
+ Error(getFlatOffsetLoc(Operands),
+ Twine("expected a ") + Twine(OffsetSize) + "-bit signed offset");
+ return false;
+ }
+ } else {
+ const unsigned OffsetSize = 16;
+ if (!isUIntN(OffsetSize, Op.getImm())) {
+ Error(getFlatOffsetLoc(Operands),
+ Twine("expected a ") + Twine(OffsetSize) + "-bit unsigned offset");
+ return false;
+ }
+ }
+ return true;
+}
+
bool AMDGPUAsmParser::validateFlatOffset(const MCInst &Inst,
const OperandVector &Operands) {
uint64_t TSFlags = MII.get(Inst.getOpcode()).TSFlags;
@@ -4148,11 +4195,12 @@ bool AMDGPUAsmParser::validateFlatOffset(const MCInst &Inst,
return false;
}
- // For FLAT segment the offset must be positive;
+ // For pre-GFX12 FLAT instructions the offset must be positive;
// MSB is ignored and forced to zero.
unsigned OffsetSize = AMDGPU::getNumFlatOffsetBits(getSTI());
bool AllowNegative =
- TSFlags & (SIInstrFlags::FlatGlobal | SIInstrFlags::FlatScratch);
+ (TSFlags & (SIInstrFlags::FlatGlobal | SIInstrFlags::FlatScratch)) ||
+ isGFX12Plus();
if (!isIntN(OffsetSize, Op.getImm()) || (!AllowNegative && Op.getImm() < 0)) {
Error(getFlatOffsetLoc(Operands),
Twine("expected a ") +
@@ -4479,7 +4527,7 @@ bool AMDGPUAsmParser::validateBLGP(const MCInst &Inst,
SMLoc BLGPLoc = getBLGPLoc(Operands);
if (!BLGPLoc.isValid())
return true;
- bool IsNeg = StringRef(BLGPLoc.getPointer()).startswith("neg:");
+ bool IsNeg = StringRef(BLGPLoc.getPointer()).starts_with("neg:");
auto FB = getFeatureBits();
bool UsesNeg = false;
if (FB[AMDGPU::FeatureGFX940Insts]) {
@@ -4788,10 +4836,7 @@ bool AMDGPUAsmParser::validateInstruction(const MCInst &Inst,
if (!validateMovrels(Inst, Operands)) {
return false;
}
- if (!validateFlatOffset(Inst, Operands)) {
- return false;
- }
- if (!validateSMEMOffset(Inst, Operands)) {
+ if (!validateOffset(Inst, Operands)) {
return false;
}
if (!validateMAIAccWrite(Inst, Operands)) {
@@ -5334,11 +5379,17 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() {
COMPUTE_PGM_RSRC1_FLOAT_DENORM_MODE_16_64, Val,
ValRange);
} else if (ID == ".amdhsa_dx10_clamp") {
+ if (IVersion.Major >= 12)
+ return Error(IDRange.Start, "directive unsupported on gfx12+", IDRange);
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1,
- COMPUTE_PGM_RSRC1_ENABLE_DX10_CLAMP, Val, ValRange);
+ COMPUTE_PGM_RSRC1_GFX6_GFX11_ENABLE_DX10_CLAMP, Val,
+ ValRange);
} else if (ID == ".amdhsa_ieee_mode") {
- PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_ENABLE_IEEE_MODE,
- Val, ValRange);
+ if (IVersion.Major >= 12)
+ return Error(IDRange.Start, "directive unsupported on gfx12+", IDRange);
+ PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1,
+ COMPUTE_PGM_RSRC1_GFX6_GFX11_ENABLE_IEEE_MODE, Val,
+ ValRange);
} else if (ID == ".amdhsa_fp16_overflow") {
if (IVersion.Major < 9)
return Error(IDRange.Start, "directive requires gfx9+", IDRange);
@@ -5401,6 +5452,12 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() {
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_INT_DIVIDE_BY_ZERO,
Val, ValRange);
+ } else if (ID == ".amdhsa_round_robin_scheduling") {
+ if (IVersion.Major < 12)
+ return Error(IDRange.Start, "directive requires gfx12+", IDRange);
+ PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1,
+ COMPUTE_PGM_RSRC1_GFX12_PLUS_ENABLE_WG_RR_EN, Val,
+ ValRange);
} else {
return Error(IDRange.Start, "unknown .amdhsa_kernel directive", IDRange);
}
@@ -5554,6 +5611,18 @@ bool AMDGPUAsmParser::ParseAMDKernelCodeTValue(StringRef ID,
}
Lex();
+ if (ID == "enable_dx10_clamp") {
+ if (G_00B848_DX10_CLAMP(Header.compute_pgm_resource_registers) &&
+ isGFX12Plus())
+ return TokError("enable_dx10_clamp=1 is not allowed on GFX12+");
+ }
+
+ if (ID == "enable_ieee_mode") {
+ if (G_00B848_IEEE_MODE(Header.compute_pgm_resource_registers) &&
+ isGFX12Plus())
+ return TokError("enable_ieee_mode=1 is not allowed on GFX12+");
+ }
+
if (ID == "enable_wavefront_size32") {
if (Header.code_properties & AMD_CODE_PROPERTY_ENABLE_WAVEFRONT_SIZE32) {
if (!isGFX10Plus())
@@ -5974,20 +6043,20 @@ StringRef AMDGPUAsmParser::parseMnemonicSuffix(StringRef Name) {
setForcedDPP(false);
setForcedSDWA(false);
- if (Name.endswith("_e64_dpp")) {
+ if (Name.ends_with("_e64_dpp")) {
setForcedDPP(true);
setForcedEncodingSize(64);
return Name.substr(0, Name.size() - 8);
- } else if (Name.endswith("_e64")) {
+ } else if (Name.ends_with("_e64")) {
setForcedEncodingSize(64);
return Name.substr(0, Name.size() - 4);
- } else if (Name.endswith("_e32")) {
+ } else if (Name.ends_with("_e32")) {
setForcedEncodingSize(32);
return Name.substr(0, Name.size() - 4);
- } else if (Name.endswith("_dpp")) {
+ } else if (Name.ends_with("_dpp")) {
setForcedDPP(true);
return Name.substr(0, Name.size() - 4);
- } else if (Name.endswith("_sdwa")) {
+ } else if (Name.ends_with("_sdwa")) {
setForcedSDWA(true);
return Name.substr(0, Name.size() - 5);
}
@@ -6010,7 +6079,7 @@ bool AMDGPUAsmParser::ParseInstruction(ParseInstructionInfo &Info,
Operands.push_back(AMDGPUOperand::CreateToken(this, Name, NameLoc));
- bool IsMIMG = Name.startswith("image_");
+ bool IsMIMG = Name.starts_with("image_");
while (!trySkipToken(AsmToken::EndOfStatement)) {
OperandMode Mode = OperandMode_Default;
@@ -6150,7 +6219,7 @@ unsigned AMDGPUAsmParser::getCPolKind(StringRef Id, StringRef Mnemo,
bool &Disabling) const {
Disabling = Id.consume_front("no");
- if (isGFX940() && !Mnemo.startswith("s_")) {
+ if (isGFX940() && !Mnemo.starts_with("s_")) {
return StringSwitch<unsigned>(Id)
.Case("nt", AMDGPU::CPol::NT)
.Case("sc0", AMDGPU::CPol::SC0)
@@ -6282,13 +6351,13 @@ ParseStatus AMDGPUAsmParser::parseTH(OperandVector &Operands, int64_t &TH) {
else if (Value == "TH_STORE_LU" || Value == "TH_LOAD_RT_WB" ||
Value == "TH_LOAD_NT_WB") {
return Error(StringLoc, "invalid th value");
- } else if (Value.startswith("TH_ATOMIC_")) {
+ } else if (Value.starts_with("TH_ATOMIC_")) {
Value = Value.drop_front(10);
TH = AMDGPU::CPol::TH_TYPE_ATOMIC;
- } else if (Value.startswith("TH_LOAD_")) {
+ } else if (Value.starts_with("TH_LOAD_")) {
Value = Value.drop_front(8);
TH = AMDGPU::CPol::TH_TYPE_LOAD;
- } else if (Value.startswith("TH_STORE_")) {
+ } else if (Value.starts_with("TH_STORE_")) {
Value = Value.drop_front(9);
TH = AMDGPU::CPol::TH_TYPE_STORE;
} else {
@@ -6733,7 +6802,7 @@ bool AMDGPUAsmParser::parseCnt(int64_t &IntVal) {
AMDGPU::IsaVersion ISA = AMDGPU::getIsaVersion(getSTI().getCPU());
bool Failed = true;
- bool Sat = CntName.endswith("_sat");
+ bool Sat = CntName.ends_with("_sat");
if (CntName == "vmcnt" || CntName == "vmcnt_sat") {
Failed = encodeCnt(ISA, IntVal, CntVal, Sat, encodeVmcnt, decodeVmcnt);
@@ -7206,7 +7275,7 @@ ParseStatus AMDGPUAsmParser::parseInterpAttr(OperandVector &Operands) {
if (!parseId(Str))
return ParseStatus::NoMatch;
- if (!Str.startswith("attr"))
+ if (!Str.starts_with("attr"))
return Error(S, "invalid interpolation attribute");
StringRef Chan = Str.take_back(2);
@@ -7297,7 +7366,7 @@ bool
AMDGPUAsmParser::trySkipId(const StringRef Pref, const StringRef Id) {
if (isToken(AsmToken::Identifier)) {
StringRef Tok = getTokenStr();
- if (Tok.startswith(Pref) && Tok.drop_front(Pref.size()) == Id) {
+ if (Tok.starts_with(Pref) && Tok.drop_front(Pref.size()) == Id) {
lex();
return true;
}
@@ -8446,7 +8515,7 @@ bool AMDGPUAsmParser::parseDimId(unsigned &Encoding) {
Token += Suffix;
StringRef DimId = Token;
- if (DimId.startswith("SQ_RSRC_IMG_"))
+ if (DimId.starts_with("SQ_RSRC_IMG_"))
DimId = DimId.drop_front(12);
const AMDGPU::MIMGDimInfo *DimInfo = AMDGPU::getMIMGDimInfoByAsmSuffix(DimId);
@@ -9129,3 +9198,9 @@ bool AMDGPUOperand::isWaitVDST() const {
bool AMDGPUOperand::isWaitEXP() const {
return isImmTy(ImmTyWaitEXP) && isUInt<3>(getImm());
}
+
+//===----------------------------------------------------------------------===//
+// Split Barrier
+//===----------------------------------------------------------------------===//
+
+bool AMDGPUOperand::isSplitBarrier() const { return isInlinableImm(MVT::i32); }
diff --git a/llvm/lib/Target/AMDGPU/BUFInstructions.td b/llvm/lib/Target/AMDGPU/BUFInstructions.td
index 44fd4ef86412..43d35fa5291c 100644
--- a/llvm/lib/Target/AMDGPU/BUFInstructions.td
+++ b/llvm/lib/Target/AMDGPU/BUFInstructions.td
@@ -12,6 +12,8 @@ def MUBUFOffset : ComplexPattern<iPTR, 3, "SelectMUBUFOffset">;
def MUBUFScratchOffen : ComplexPattern<iPTR, 4, "SelectMUBUFScratchOffen", [], [SDNPWantParent]>;
def MUBUFScratchOffset : ComplexPattern<iPTR, 3, "SelectMUBUFScratchOffset", [], [SDNPWantParent], 20>;
+def BUFSOffset : ComplexPattern<iPTR, 1, "SelectBUFSOffset">;
+
def BUFAddrKind {
int Offset = 0;
int OffEn = 1;
@@ -152,24 +154,32 @@ class MTBUF_Real <MTBUF_Pseudo ps, string real_name = ps.Mnemonic> :
}
class getMTBUFInsDA<list<RegisterClass> vdataList,
- list<RegisterClass> vaddrList=[]> {
+ list<RegisterClass> vaddrList=[], bit hasGFX12Enc> {
RegisterClass vdataClass = !if(!empty(vdataList), ?, !head(vdataList));
RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList));
RegisterOperand vdata_op = getLdStRegisterOperand<vdataClass>.ret;
- dag NonVaddrInputs = (ins SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, FORMAT:$format, CPol:$cpol, i1imm:$swz);
- dag Inputs = !if(!empty(vaddrList), NonVaddrInputs, !con((ins vaddrClass:$vaddr), NonVaddrInputs));
- dag ret = !if(!empty(vdataList), Inputs, !con((ins vdata_op:$vdata), Inputs));
-}
+ dag SOffset = !if(hasGFX12Enc, (ins SReg_32:$soffset),
+ (ins SCSrc_b32:$soffset));
+ dag NonVaddrInputs = !con((ins SReg_128:$srsrc), SOffset,
+ (ins offset:$offset, FORMAT:$format, CPol_0:$cpol, i1imm_0:$swz));
-class getMTBUFIns<int addrKind, list<RegisterClass> vdataList=[]> {
+ dag Inputs = !if(!empty(vaddrList),
+ NonVaddrInputs,
+ !con((ins vaddrClass:$vaddr), NonVaddrInputs));
+ dag ret = !if(!empty(vdataList),
+ Inputs,
+ !con((ins vdata_op:$vdata), Inputs));
+}
+
+class getMTBUFIns<int addrKind, list<RegisterClass> vdataList=[], bit hasGFX12Enc> {
dag ret =
- !if(!eq(addrKind, BUFAddrKind.Offset), getMTBUFInsDA<vdataList>.ret,
- !if(!eq(addrKind, BUFAddrKind.OffEn), getMTBUFInsDA<vdataList, [VGPR_32]>.ret,
- !if(!eq(addrKind, BUFAddrKind.IdxEn), getMTBUFInsDA<vdataList, [VGPR_32]>.ret,
- !if(!eq(addrKind, BUFAddrKind.BothEn), getMTBUFInsDA<vdataList, [VReg_64]>.ret,
- !if(!eq(addrKind, BUFAddrKind.Addr64), getMTBUFInsDA<vdataList, [VReg_64]>.ret,
+ !if(!eq(addrKind, BUFAddrKind.Offset), getMTBUFInsDA<vdataList, [], hasGFX12Enc>.ret,
+ !if(!eq(addrKind, BUFAddrKind.OffEn), getMTBUFInsDA<vdataList, [VGPR_32], hasGFX12Enc>.ret,
+ !if(!eq(addrKind, BUFAddrKind.IdxEn), getMTBUFInsDA<vdataList, [VGPR_32], hasGFX12Enc>.ret,
+ !if(!eq(addrKind, BUFAddrKind.BothEn), getMTBUFInsDA<vdataList, [VReg_64], hasGFX12Enc>.ret,
+ !if(!eq(addrKind, BUFAddrKind.Addr64), getMTBUFInsDA<vdataList, [VReg_64], hasGFX12Enc>.ret,
(ins))))));
}
@@ -204,12 +214,13 @@ class MTBUF_Load_Pseudo <string opName,
int addrKind,
RegisterClass vdataClass,
int elems,
+ bit hasGFX12Enc = 0,
list<dag> pattern=[],
// Workaround bug bz30254
int addrKindCopy = addrKind>
: MTBUF_Pseudo<opName,
(outs getLdStRegisterOperand<vdataClass>.ret:$vdata),
- getMTBUFIns<addrKindCopy>.ret,
+ getMTBUFIns<addrKindCopy, [], hasGFX12Enc>.ret,
getMTBUFAsmOps<addrKindCopy>.ret,
pattern>,
MTBUF_SetupAddr<addrKindCopy> {
@@ -219,38 +230,45 @@ class MTBUF_Load_Pseudo <string opName,
let elements = elems;
}
-multiclass MTBUF_Pseudo_Loads<string opName, RegisterClass vdataClass,
- int elems> {
+multiclass MTBUF_Pseudo_Loads_Helper<string opName, RegisterClass vdataClass,
+ int elems, bit hasGFX12Enc> {
- def _OFFSET : MTBUF_Load_Pseudo <opName, BUFAddrKind.Offset, vdataClass, elems>,
+ def _OFFSET : MTBUF_Load_Pseudo <opName, BUFAddrKind.Offset, vdataClass, elems, hasGFX12Enc>,
MTBUFAddr64Table<0, NAME>;
- def _ADDR64 : MTBUF_Load_Pseudo <opName, BUFAddrKind.Addr64, vdataClass, elems>,
+ def _ADDR64 : MTBUF_Load_Pseudo <opName, BUFAddrKind.Addr64, vdataClass, elems, hasGFX12Enc>,
MTBUFAddr64Table<1, NAME>;
- def _OFFEN : MTBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, elems>;
- def _IDXEN : MTBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, elems>;
- def _BOTHEN : MTBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, elems>;
+ def _OFFEN : MTBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, elems, hasGFX12Enc>;
+ def _IDXEN : MTBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, elems, hasGFX12Enc>;
+ def _BOTHEN : MTBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, elems, hasGFX12Enc>;
let DisableWQM = 1 in {
- def _OFFSET_exact : MTBUF_Load_Pseudo <opName, BUFAddrKind.Offset, vdataClass, elems>;
- def _OFFEN_exact : MTBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, elems>;
- def _IDXEN_exact : MTBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, elems>;
- def _BOTHEN_exact : MTBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, elems>;
+ def _OFFSET_exact : MTBUF_Load_Pseudo <opName, BUFAddrKind.Offset, vdataClass, elems, hasGFX12Enc>;
+ def _OFFEN_exact : MTBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, elems, hasGFX12Enc>;
+ def _IDXEN_exact : MTBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, elems, hasGFX12Enc>;
+ def _BOTHEN_exact : MTBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, elems, hasGFX12Enc>;
}
}
+multiclass MTBUF_Pseudo_Loads<string opName, RegisterClass vdataClass,
+ int elems> {
+ defm NAME : MTBUF_Pseudo_Loads_Helper<opName, vdataClass, elems, 0>;
+ defm _VBUFFER : MTBUF_Pseudo_Loads_Helper<opName, vdataClass, elems, 1>;
+}
+
class MTBUF_Store_Pseudo <string opName,
int addrKind,
RegisterClass vdataClass,
int elems,
+ bit hasGFX12Enc = 0,
list<dag> pattern=[],
// Workaround bug bz30254
int addrKindCopy = addrKind,
RegisterClass vdataClassCopy = vdataClass>
: MTBUF_Pseudo<opName,
(outs),
- getMTBUFIns<addrKindCopy, [vdataClassCopy]>.ret,
+ getMTBUFIns<addrKindCopy, [vdataClassCopy], hasGFX12Enc>.ret,
getMTBUFAsmOps<addrKindCopy>.ret,
pattern>,
MTBUF_SetupAddr<addrKindCopy> {
@@ -260,27 +278,32 @@ class MTBUF_Store_Pseudo <string opName,
let elements = elems;
}
-multiclass MTBUF_Pseudo_Stores<string opName, RegisterClass vdataClass,
- int elems> {
+multiclass MTBUF_Pseudo_Stores_Helper<string opName, RegisterClass vdataClass,
+ int elems, bit hasGFX12Enc> {
- def _OFFSET : MTBUF_Store_Pseudo <opName, BUFAddrKind.Offset, vdataClass, elems>,
+ def _OFFSET : MTBUF_Store_Pseudo <opName, BUFAddrKind.Offset, vdataClass, elems, hasGFX12Enc>,
MTBUFAddr64Table<0, NAME>;
- def _ADDR64 : MTBUF_Store_Pseudo <opName, BUFAddrKind.Addr64, vdataClass, elems>,
+ def _ADDR64 : MTBUF_Store_Pseudo <opName, BUFAddrKind.Addr64, vdataClass, elems, hasGFX12Enc>,
MTBUFAddr64Table<1, NAME>;
- def _OFFEN : MTBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, elems>;
- def _IDXEN : MTBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, elems>;
- def _BOTHEN : MTBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, elems>;
+ def _OFFEN : MTBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, elems, hasGFX12Enc>;
+ def _IDXEN : MTBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, elems, hasGFX12Enc>;
+ def _BOTHEN : MTBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, elems, hasGFX12Enc>;
let DisableWQM = 1 in {
- def _OFFSET_exact : MTBUF_Store_Pseudo <opName, BUFAddrKind.Offset, vdataClass, elems>;
- def _OFFEN_exact : MTBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, elems>;
- def _IDXEN_exact : MTBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, elems>;
- def _BOTHEN_exact : MTBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, elems>;
+ def _OFFSET_exact : MTBUF_Store_Pseudo <opName, BUFAddrKind.Offset, vdataClass, elems, hasGFX12Enc>;
+ def _OFFEN_exact : MTBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, elems, hasGFX12Enc>;
+ def _IDXEN_exact : MTBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, elems, hasGFX12Enc>;
+ def _BOTHEN_exact : MTBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, elems, hasGFX12Enc>;
}
}
+multiclass MTBUF_Pseudo_Stores<string opName, RegisterClass vdataClass,
+ int elems> {
+ defm NAME : MTBUF_Pseudo_Stores_Helper<opName, vdataClass, elems, 0>;
+ defm _VBUFFER : MTBUF_Pseudo_Stores_Helper<opName, vdataClass, elems, 1>;
+}
//===----------------------------------------------------------------------===//
// MUBUF classes
@@ -381,12 +404,14 @@ class getLdStVDataRegisterOperand<RegisterClass RC, bit isTFE> {
}
class getMUBUFInsDA<list<RegisterClass> vdataList,
- list<RegisterClass> vaddrList, bit isTFE> {
+ list<RegisterClass> vaddrList, bit isTFE, bit hasGFX12Enc> {
RegisterClass vdataClass = !if(!empty(vdataList), ?, !head(vdataList));
RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList));
RegisterOperand vdata_op = getLdStVDataRegisterOperand<vdataClass, isTFE>.ret;
- dag NonVaddrInputs = (ins SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, CPol_0:$cpol, i1imm_0:$swz);
+ dag SOffset = !if(hasGFX12Enc, (ins SReg_32:$soffset), (ins SCSrc_b32:$soffset));
+ dag NonVaddrInputs = !con((ins SReg_128:$srsrc), SOffset, (ins offset:$offset, CPol_0:$cpol, i1imm_0:$swz));
+
dag Inputs = !if(!empty(vaddrList), NonVaddrInputs, !con((ins vaddrClass:$vaddr), NonVaddrInputs));
dag ret = !if(!empty(vdataList), Inputs, !con((ins vdata_op:$vdata), Inputs));
}
@@ -410,13 +435,13 @@ class getMUBUFElements<ValueType vt> {
);
}
-class getMUBUFIns<int addrKind, list<RegisterClass> vdataList, bit isTFE> {
+class getMUBUFIns<int addrKind, list<RegisterClass> vdataList, bit isTFE, bit hasGFX12Enc> {
dag ret =
- !if(!eq(addrKind, BUFAddrKind.Offset), getMUBUFInsDA<vdataList, [], isTFE>.ret,
- !if(!eq(addrKind, BUFAddrKind.OffEn), getMUBUFInsDA<vdataList, [VGPR_32], isTFE>.ret,
- !if(!eq(addrKind, BUFAddrKind.IdxEn), getMUBUFInsDA<vdataList, [VGPR_32], isTFE>.ret,
- !if(!eq(addrKind, BUFAddrKind.BothEn), getMUBUFInsDA<vdataList, [VReg_64], isTFE>.ret,
- !if(!eq(addrKind, BUFAddrKind.Addr64), getMUBUFInsDA<vdataList, [VReg_64], isTFE>.ret,
+ !if(!eq(addrKind, BUFAddrKind.Offset), getMUBUFInsDA<vdataList, [], isTFE, hasGFX12Enc>.ret,
+ !if(!eq(addrKind, BUFAddrKind.OffEn), getMUBUFInsDA<vdataList, [VGPR_32], isTFE, hasGFX12Enc>.ret,
+ !if(!eq(addrKind, BUFAddrKind.IdxEn), getMUBUFInsDA<vdataList, [VGPR_32], isTFE, hasGFX12Enc>.ret,
+ !if(!eq(addrKind, BUFAddrKind.BothEn), getMUBUFInsDA<vdataList, [VReg_64], isTFE, hasGFX12Enc>.ret,
+ !if(!eq(addrKind, BUFAddrKind.Addr64), getMUBUFInsDA<vdataList, [VReg_64], isTFE, hasGFX12Enc>.ret,
(ins))))));
}
@@ -456,6 +481,7 @@ class MUBUF_Load_Pseudo <string opName,
bit isLds = 0,
bit isLdsOpc = 0,
bit isTFE = 0,
+ bit hasGFX12Enc = 0,
list<dag> pattern=[],
// Workaround bug bz30254
int addrKindCopy = addrKind,
@@ -463,7 +489,7 @@ class MUBUF_Load_Pseudo <string opName,
RegisterOperand vdata_op = getLdStVDataRegisterOperand<vdata_rc, isTFE>.ret>
: MUBUF_Pseudo<opName,
!if(!or(isLds, isLdsOpc), (outs), (outs vdata_op:$vdata)),
- !con(getMUBUFIns<addrKindCopy, [], isTFE>.ret,
+ !con(getMUBUFIns<addrKindCopy, [], isTFE, hasGFX12Enc>.ret,
!if(HasTiedDest, (ins vdata_op:$vdata_in), (ins))),
getMUBUFAsmOps<addrKindCopy, !or(isLds, isLdsOpc), isLds, isTFE>.ret,
pattern>,
@@ -497,38 +523,49 @@ class MUBUF_Addr64_Load_Pat <Instruction inst,
(load_vt (inst i64:$vaddr, v4i32:$srsrc, i32:$soffset, i32:$offset))
>;
-multiclass MUBUF_Pseudo_Load_Pats<string BaseInst, ValueType load_vt = i32, SDPatternOperator ld = null_frag> {
+multiclass MUBUF_Pseudo_Load_Pats_Common<string BaseInst, ValueType load_vt = i32, SDPatternOperator ld = null_frag> {
def : MUBUF_Offset_Load_Pat<!cast<Instruction>(BaseInst#"_OFFSET"), load_vt, ld>;
def : MUBUF_Addr64_Load_Pat<!cast<Instruction>(BaseInst#"_ADDR64"), load_vt, ld>;
}
+multiclass MUBUF_Pseudo_Load_Pats<string BaseInst, ValueType load_vt = i32, SDPatternOperator ld = null_frag>{
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MUBUF_Pseudo_Load_Pats_Common<BaseInst, load_vt, ld>;
+ }
+ defm : MUBUF_Pseudo_Load_Pats_Common<BaseInst # "_VBUFFER", load_vt, ld>;
+}
+
multiclass MUBUF_Pseudo_Loads_Helper<string opName, ValueType load_vt,
- bit TiedDest, bit isLds, bit isTFE> {
+ bit TiedDest, bit isLds, bit isTFE, bit hasGFX12Enc> {
defvar legal_load_vt = !if(!eq(load_vt, v3f16), v4f16, load_vt);
- def _OFFSET : MUBUF_Load_Pseudo <opName, BUFAddrKind.Offset, legal_load_vt, TiedDest, isLds, 0, isTFE>,
+ def _OFFSET : MUBUF_Load_Pseudo <opName, BUFAddrKind.Offset, legal_load_vt, TiedDest, isLds, 0, isTFE, hasGFX12Enc>,
MUBUFAddr64Table<0, NAME # !if(isLds, "_LDS", "")>;
- def _ADDR64 : MUBUF_Load_Pseudo <opName, BUFAddrKind.Addr64, legal_load_vt, TiedDest, isLds, 0, isTFE>,
+ def _ADDR64 : MUBUF_Load_Pseudo <opName, BUFAddrKind.Addr64, legal_load_vt, TiedDest, isLds, 0, isTFE, hasGFX12Enc>,
MUBUFAddr64Table<1, NAME # !if(isLds, "_LDS", "")>;
- def _OFFEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, legal_load_vt, TiedDest, isLds, 0, isTFE>;
- def _IDXEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, legal_load_vt, TiedDest, isLds, 0, isTFE>;
- def _BOTHEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, legal_load_vt, TiedDest, isLds, 0, isTFE>;
+ def _OFFEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, legal_load_vt, TiedDest, isLds, 0, isTFE, hasGFX12Enc>;
+ def _IDXEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, legal_load_vt, TiedDest, isLds, 0, isTFE, hasGFX12Enc>;
+ def _BOTHEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, legal_load_vt, TiedDest, isLds, 0, isTFE, hasGFX12Enc>;
let DisableWQM = 1 in {
- def _OFFSET_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.Offset, legal_load_vt, TiedDest, isLds, 0, isTFE>;
- def _OFFEN_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, legal_load_vt, TiedDest, isLds, 0, isTFE>;
- def _IDXEN_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, legal_load_vt, TiedDest, isLds, 0, isTFE>;
- def _BOTHEN_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, legal_load_vt, TiedDest, isLds, 0, isTFE>;
+ def _OFFSET_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.Offset, legal_load_vt, TiedDest, isLds, 0, isTFE, hasGFX12Enc>;
+ def _OFFEN_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, legal_load_vt, TiedDest, isLds, 0, isTFE, hasGFX12Enc>;
+ def _IDXEN_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, legal_load_vt, TiedDest, isLds, 0, isTFE, hasGFX12Enc>;
+ def _BOTHEN_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, legal_load_vt, TiedDest, isLds, 0, isTFE, hasGFX12Enc>;
}
}
multiclass MUBUF_Pseudo_Loads<string opName, ValueType load_vt = i32,
bit TiedDest = 0, bit isLds = 0> {
- defm NAME : MUBUF_Pseudo_Loads_Helper<opName, load_vt, TiedDest, isLds, 0>;
- if !not(isLds) then
- defm _TFE : MUBUF_Pseudo_Loads_Helper<opName, load_vt, TiedDest, isLds, 1>;
+ defm NAME : MUBUF_Pseudo_Loads_Helper<opName, load_vt, TiedDest, isLds, 0, 0>;
+ defm _VBUFFER : MUBUF_Pseudo_Loads_Helper<opName, load_vt, TiedDest, isLds, 0, 1>;
+
+ if !not(isLds) then {
+ defm _TFE : MUBUF_Pseudo_Loads_Helper<opName, load_vt, TiedDest, isLds, 1, 0>;
+ defm _TFE_VBUFFER : MUBUF_Pseudo_Loads_Helper<opName, load_vt, TiedDest, isLds, 1, 1>;
+ }
}
multiclass MUBUF_Pseudo_Loads_Lds<string opName, ValueType load_vt = i32> {
@@ -548,18 +585,24 @@ multiclass MUBUF_Pseudo_Loads_LDSOpc<string opName,
def _OFFEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, legal_load_vt, TiedDest, isLds, isLdsOpc>;
def _IDXEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, legal_load_vt, TiedDest, isLds, isLdsOpc>;
def _BOTHEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, legal_load_vt, TiedDest, isLds, isLdsOpc>;
+
+ def _VBUFFER_OFFSET : MUBUF_Load_Pseudo <opName, BUFAddrKind.Offset, legal_load_vt, TiedDest, isLds, isLdsOpc, 0, 1>;
+ def _VBUFFER_OFFEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, legal_load_vt, TiedDest, isLds, isLdsOpc, 0, 1>;
+ def _VBUFFER_IDXEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, legal_load_vt, TiedDest, isLds, isLdsOpc, 0, 1>;
+ def _VBUFFER_BOTHEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, legal_load_vt, TiedDest, isLds, isLdsOpc, 0, 1>;
}
class MUBUF_Store_Pseudo <string opName,
int addrKind,
ValueType store_vt,
bit isTFE = 0,
+ bit hasGFX12Enc = 0,
list<dag> pattern=[],
// Workaround bug bz30254
int addrKindCopy = addrKind>
: MUBUF_Pseudo<opName,
(outs),
- getMUBUFIns<addrKindCopy, [getVregSrcForVT<store_vt>.ret], isTFE>.ret,
+ getMUBUFIns<addrKindCopy, [getVregSrcForVT<store_vt>.ret], isTFE, hasGFX12Enc>.ret,
getMUBUFAsmOps<addrKindCopy, 0, 0, isTFE>.ret,
pattern>,
MUBUF_SetupAddr<addrKindCopy> {
@@ -572,7 +615,7 @@ class MUBUF_Store_Pseudo <string opName,
let tfe = isTFE;
}
-multiclass MUBUF_Pseudo_Store_Pats<string BaseInst, ValueType store_vt = i32, SDPatternOperator st = null_frag> {
+multiclass MUBUF_Pseudo_Store_Pats_Common<string BaseInst, ValueType store_vt = i32, SDPatternOperator st = null_frag> {
def : GCNPat <
(st store_vt:$vdata, (MUBUFOffset v4i32:$srsrc, i32:$soffset, i32:$offset)),
@@ -583,31 +626,41 @@ multiclass MUBUF_Pseudo_Store_Pats<string BaseInst, ValueType store_vt = i32, SD
(!cast<MUBUF_Pseudo>(BaseInst # _ADDR64) store_vt:$vdata, i64:$vaddr, v4i32:$srsrc, i32:$soffset, i32:$offset)>;
}
+multiclass MUBUF_Pseudo_Store_Pats<string BaseInst, ValueType store_vt = i32, SDPatternOperator st = null_frag> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MUBUF_Pseudo_Store_Pats_Common<BaseInst, store_vt, st>;
+ }
+ defm : MUBUF_Pseudo_Store_Pats_Common<BaseInst # "_VBUFFER", store_vt, st>;
+}
+
multiclass MUBUF_Pseudo_Stores_Helper<string opName, ValueType store_vt,
- bit isTFE> {
+ bit isTFE, bit hasGFX12Enc> {
defvar legal_store_vt = !if(!eq(store_vt, v3f16), v4f16, store_vt);
- def _OFFSET : MUBUF_Store_Pseudo <opName, BUFAddrKind.Offset, legal_store_vt, isTFE>,
+ def _OFFSET : MUBUF_Store_Pseudo <opName, BUFAddrKind.Offset, legal_store_vt, isTFE, hasGFX12Enc>,
MUBUFAddr64Table<0, NAME>;
- def _ADDR64 : MUBUF_Store_Pseudo <opName, BUFAddrKind.Addr64, legal_store_vt, isTFE>,
+ def _ADDR64 : MUBUF_Store_Pseudo <opName, BUFAddrKind.Addr64, legal_store_vt, isTFE, hasGFX12Enc>,
MUBUFAddr64Table<1, NAME>;
- def _OFFEN : MUBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, legal_store_vt, isTFE>;
- def _IDXEN : MUBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, legal_store_vt, isTFE>;
- def _BOTHEN : MUBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, legal_store_vt, isTFE>;
+ def _OFFEN : MUBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, legal_store_vt, isTFE, hasGFX12Enc>;
+ def _IDXEN : MUBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, legal_store_vt, isTFE, hasGFX12Enc>;
+ def _BOTHEN : MUBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, legal_store_vt, isTFE, hasGFX12Enc>;
let DisableWQM = 1 in {
- def _OFFSET_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.Offset, legal_store_vt, isTFE>;
- def _OFFEN_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, legal_store_vt, isTFE>;
- def _IDXEN_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, legal_store_vt, isTFE>;
- def _BOTHEN_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, legal_store_vt, isTFE>;
+ def _OFFSET_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.Offset, legal_store_vt, isTFE, hasGFX12Enc>;
+ def _OFFEN_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, legal_store_vt, isTFE, hasGFX12Enc>;
+ def _IDXEN_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, legal_store_vt, isTFE, hasGFX12Enc>;
+ def _BOTHEN_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, legal_store_vt, isTFE, hasGFX12Enc>;
}
}
multiclass MUBUF_Pseudo_Stores<string opName, ValueType store_vt = i32> {
- defm NAME : MUBUF_Pseudo_Stores_Helper<opName, store_vt, 0>;
- defm _TFE : MUBUF_Pseudo_Stores_Helper<opName, store_vt, 1>;
+ defm NAME : MUBUF_Pseudo_Stores_Helper<opName, store_vt, 0, 0>;
+ defm _TFE : MUBUF_Pseudo_Stores_Helper<opName, store_vt, 1, 0>;
+
+ defm _VBUFFER : MUBUF_Pseudo_Stores_Helper<opName, store_vt, 0, 1>;
+ defm _TFE_VBUFFER : MUBUF_Pseudo_Stores_Helper<opName, store_vt, 1, 1>;
}
class MUBUF_Pseudo_Store_Lds<string opName>
@@ -629,14 +682,15 @@ class MUBUF_Pseudo_Store_Lds<string opName>
let AsmMatchConverter = "cvtMubuf";
}
-class getMUBUFAtomicInsDA<RegisterClass vdataClass, bit vdata_in,
+class getMUBUFAtomicInsDA<RegisterClass vdataClass, bit vdata_in, bit hasGFX12Enc,
list<RegisterClass> vaddrList=[]> {
RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList));
RegisterOperand vdata_op = getLdStRegisterOperand<vdataClass>.ret;
dag VData = !if(vdata_in, (ins vdata_op:$vdata_in), (ins vdata_op:$vdata));
dag Data = !if(!empty(vaddrList), VData, !con(VData, (ins vaddrClass:$vaddr)));
- dag MainInputs = (ins SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset);
+ dag SOffset = !if(hasGFX12Enc, (ins SReg_32:$soffset), (ins SCSrc_b32:$soffset));
+ dag MainInputs = !con((ins SReg_128:$srsrc), SOffset, (ins offset:$offset));
dag CPol = !if(vdata_in, (ins CPol_GLC_WithDefault:$cpol),
(ins CPol_NonGLC_WithDefault:$cpol));
@@ -646,19 +700,20 @@ class getMUBUFAtomicInsDA<RegisterClass vdataClass, bit vdata_in,
class getMUBUFAtomicIns<int addrKind,
RegisterClass vdataClass,
bit vdata_in,
+ bit hasGFX12Enc,
// Workaround bug bz30254
RegisterClass vdataClassCopy=vdataClass> {
dag ret =
!if(!eq(addrKind, BUFAddrKind.Offset),
- getMUBUFAtomicInsDA<vdataClassCopy, vdata_in>.ret,
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, hasGFX12Enc>.ret,
!if(!eq(addrKind, BUFAddrKind.OffEn),
- getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, [VGPR_32]>.ret,
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, hasGFX12Enc, [VGPR_32]>.ret,
!if(!eq(addrKind, BUFAddrKind.IdxEn),
- getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, [VGPR_32]>.ret,
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, hasGFX12Enc, [VGPR_32]>.ret,
!if(!eq(addrKind, BUFAddrKind.BothEn),
- getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, [VReg_64]>.ret,
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, hasGFX12Enc, [VReg_64]>.ret,
!if(!eq(addrKind, BUFAddrKind.Addr64),
- getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, [VReg_64]>.ret,
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, hasGFX12Enc, [VReg_64]>.ret,
(ins))))));
}
@@ -686,13 +741,14 @@ class MUBUF_Atomic_Pseudo<string opName,
class MUBUF_AtomicNoRet_Pseudo<string opName, int addrKind,
RegisterClass vdataClass,
+ bit hasGFX12Enc = 0,
list<dag> pattern=[],
// Workaround bug bz30254
int addrKindCopy = addrKind,
RegisterClass vdataClassCopy = vdataClass>
: MUBUF_Atomic_Pseudo<opName, addrKindCopy,
(outs),
- getMUBUFAtomicIns<addrKindCopy, vdataClassCopy, 0>.ret,
+ getMUBUFAtomicIns<addrKindCopy, vdataClassCopy, 0, hasGFX12Enc>.ret,
getMUBUFAsmOps<addrKindCopy>.ret,
pattern>,
AtomicNoRet<opName # "_" # getAddrName<addrKindCopy>.ret, 0> {
@@ -705,6 +761,7 @@ class MUBUF_AtomicNoRet_Pseudo<string opName, int addrKind,
class MUBUF_AtomicRet_Pseudo<string opName, int addrKind,
RegisterClass vdataClass,
+ bit hasGFX12Enc = 0,
list<dag> pattern=[],
// Workaround bug bz30254
int addrKindCopy = addrKind,
@@ -712,7 +769,7 @@ class MUBUF_AtomicRet_Pseudo<string opName, int addrKind,
RegisterOperand vdata_op = getLdStRegisterOperand<vdataClass>.ret>
: MUBUF_Atomic_Pseudo<opName, addrKindCopy,
(outs vdata_op:$vdata),
- getMUBUFAtomicIns<addrKindCopy, vdataClassCopy, 1>.ret,
+ getMUBUFAtomicIns<addrKindCopy, vdataClassCopy, 1, hasGFX12Enc>.ret,
getMUBUFAsmOps<addrKindCopy>.ret,
pattern>,
AtomicNoRet<opName # "_" # getAddrName<addrKindCopy>.ret, 1> {
@@ -730,13 +787,21 @@ multiclass MUBUF_Pseudo_Atomics_NO_RTN <string opName,
ValueType vdataType,
bit isFP = isFloatType<vdataType>.ret> {
let FPAtomic = isFP in {
- def _OFFSET : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.Offset, vdataClass>,
+ def _OFFSET : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.Offset, vdataClass, 0>,
MUBUFAddr64Table <0, NAME>;
- def _ADDR64 : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.Addr64, vdataClass>,
+ def _ADDR64 : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.Addr64, vdataClass, 0>,
MUBUFAddr64Table <1, NAME>;
- def _OFFEN : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.OffEn, vdataClass>;
- def _IDXEN : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass>;
- def _BOTHEN : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.BothEn, vdataClass>;
+ def _OFFEN : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, 0>;
+ def _IDXEN : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, 0>;
+ def _BOTHEN : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, 0>;
+
+ def _VBUFFER_OFFSET : MUBUF_AtomicNoRet_Pseudo <opName #_vbuffer, BUFAddrKind.Offset, vdataClass, 1>,
+ MUBUFAddr64Table <0, NAME # "_VBUFFER">;
+ def _VBUFFER_ADDR64 : MUBUF_AtomicNoRet_Pseudo <opName #_vbuffer, BUFAddrKind.Addr64, vdataClass, 1>,
+ MUBUFAddr64Table <1, NAME # "_VBUFFER">;
+ def _VBUFFER_OFFEN : MUBUF_AtomicNoRet_Pseudo <opName #_vbuffer, BUFAddrKind.OffEn, vdataClass, 1>;
+ def _VBUFFER_IDXEN : MUBUF_AtomicNoRet_Pseudo <opName #_vbuffer, BUFAddrKind.IdxEn, vdataClass, 1>;
+ def _VBUFFER_BOTHEN : MUBUF_AtomicNoRet_Pseudo <opName #_vbuffer, BUFAddrKind.BothEn, vdataClass, 1>;
}
}
@@ -746,21 +811,37 @@ multiclass MUBUF_Pseudo_Atomics_RTN <string opName,
SDPatternOperator atomic,
bit isFP = isFloatType<vdataType>.ret> {
let FPAtomic = isFP in {
- def _OFFSET_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.Offset, vdataClass,
+ def _OFFSET_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.Offset, vdataClass, 0,
[(set vdataType:$vdata,
(atomic (MUBUFOffset v4i32:$srsrc, i32:$soffset, i32:$offset),
vdataType:$vdata_in))]>,
MUBUFAddr64Table <0, NAME # "_RTN">;
- def _ADDR64_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.Addr64, vdataClass,
+ def _ADDR64_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.Addr64, vdataClass, 0,
[(set vdataType:$vdata,
(atomic (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset, i32:$offset),
vdataType:$vdata_in))]>,
MUBUFAddr64Table <1, NAME # "_RTN">;
- def _OFFEN_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.OffEn, vdataClass>;
- def _IDXEN_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass>;
- def _BOTHEN_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.BothEn, vdataClass>;
+ def _OFFEN_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.OffEn, vdataClass, 0>;
+ def _IDXEN_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass, 0>;
+ def _BOTHEN_RTN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.BothEn, vdataClass, 0>;
+
+ def _VBUFFER_OFFSET_RTN : MUBUF_AtomicRet_Pseudo <opName #_vbuffer, BUFAddrKind.Offset, vdataClass, 1,
+ [(set vdataType:$vdata,
+ (atomic (MUBUFOffset v4i32:$srsrc, i32:$soffset, i32:$offset),
+ vdataType:$vdata_in))]>,
+ MUBUFAddr64Table <0, NAME # "_VBUFFER_RTN">;
+
+ def _VBUFFER_ADDR64_RTN : MUBUF_AtomicRet_Pseudo <opName #_vbuffer, BUFAddrKind.Addr64, vdataClass, 1,
+ [(set vdataType:$vdata,
+ (atomic (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset, i32:$offset),
+ vdataType:$vdata_in))]>,
+ MUBUFAddr64Table <1, NAME # "_VBUFFER_RTN">;
+
+ def _VBUFFER_OFFEN_RTN : MUBUF_AtomicRet_Pseudo <opName #_vbuffer, BUFAddrKind.OffEn, vdataClass, 1>;
+ def _VBUFFER_IDXEN_RTN : MUBUF_AtomicRet_Pseudo <opName #_vbuffer, BUFAddrKind.IdxEn, vdataClass, 1>;
+ def _VBUFFER_BOTHEN_RTN : MUBUF_AtomicRet_Pseudo <opName #_vbuffer, BUFAddrKind.BothEn, vdataClass, 1>;
}
}
@@ -1249,33 +1330,33 @@ def BUFFER_GL1_INV : MUBUF_Invalidate<"buffer_gl1_inv">;
// buffer_load/store_format patterns
//===----------------------------------------------------------------------===//
-multiclass MUBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
+multiclass MUBUF_LoadIntrinsicPat_Common<SDPatternOperator name, ValueType vt,
string opcode, ValueType memoryVt = vt> {
defvar st = !if(!eq(memoryVt, vt), name, mubuf_intrinsic_load<name, memoryVt>);
def : GCNPat<
- (vt (st v4i32:$rsrc, 0, 0, i32:$soffset, timm:$offset,
+ (vt (st v4i32:$rsrc, 0, 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$auxiliary, 0)),
(!cast<MUBUF_Pseudo>(opcode # _OFFSET) SReg_128:$rsrc, SCSrc_b32:$soffset, timm:$offset,
(extract_cpol $auxiliary), (extract_swz $auxiliary))
>;
def : GCNPat<
- (vt (st v4i32:$rsrc, 0, i32:$voffset, i32:$soffset, timm:$offset,
+ (vt (st v4i32:$rsrc, 0, i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$auxiliary, 0)),
(!cast<MUBUF_Pseudo>(opcode # _OFFEN) VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset, timm:$offset,
(extract_cpol $auxiliary), (extract_swz $auxiliary))
>;
def : GCNPat<
- (vt (st v4i32:$rsrc, i32:$vindex, 0, i32:$soffset, timm:$offset,
+ (vt (st v4i32:$rsrc, i32:$vindex, 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$auxiliary, timm)),
(!cast<MUBUF_Pseudo>(opcode # _IDXEN) VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset, timm:$offset,
(extract_cpol $auxiliary), (extract_swz $auxiliary))
>;
def : GCNPat<
- (vt (st v4i32:$rsrc, i32:$vindex, i32:$voffset, i32:$soffset, timm:$offset,
+ (vt (st v4i32:$rsrc, i32:$vindex, i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$auxiliary, timm)),
(!cast<MUBUF_Pseudo>(opcode # _BOTHEN)
(REG_SEQUENCE VReg_64, VGPR_32:$vindex, sub0, VGPR_32:$voffset, sub1),
@@ -1284,6 +1365,14 @@ multiclass MUBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
}
+multiclass MUBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
+ string opcode, ValueType memoryVt = vt>{
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MUBUF_LoadIntrinsicPat_Common<name, vt, opcode, memoryVt>;
+ }
+ defm : MUBUF_LoadIntrinsicPat_Common<name, vt, opcode # "_VBUFFER", memoryVt>;
+}
+
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format, f32, "BUFFER_LOAD_FORMAT_X">;
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format, i32, "BUFFER_LOAD_FORMAT_X">;
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format, v2f32, "BUFFER_LOAD_FORMAT_XY">;
@@ -1298,16 +1387,16 @@ defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_tfe, v3i32, "BUFFER_LOAD_FORM
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_tfe, v4i32, "BUFFER_LOAD_FORMAT_XYZ_TFE">;
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_tfe, v5i32, "BUFFER_LOAD_FORMAT_XYZW_TFE">;
-let SubtargetPredicate = HasUnpackedD16VMem in {
- defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_d16, f16, "BUFFER_LOAD_FORMAT_D16_X_gfx80">;
- defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_d16, i16, "BUFFER_LOAD_FORMAT_D16_X_gfx80">;
- defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_d16, i32, "BUFFER_LOAD_FORMAT_D16_X_gfx80">;
- defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_d16, v2i32, "BUFFER_LOAD_FORMAT_D16_XY_gfx80">;
- defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_d16, v3i32, "BUFFER_LOAD_FORMAT_D16_XYZ_gfx80">;
- defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_d16, v4i32, "BUFFER_LOAD_FORMAT_D16_XYZW_gfx80">;
+let OtherPredicates = [HasUnpackedD16VMem] in {
+ defm : MUBUF_LoadIntrinsicPat_Common<SIbuffer_load_format_d16, f16, "BUFFER_LOAD_FORMAT_D16_X_gfx80">;
+ defm : MUBUF_LoadIntrinsicPat_Common<SIbuffer_load_format_d16, i16, "BUFFER_LOAD_FORMAT_D16_X_gfx80">;
+ defm : MUBUF_LoadIntrinsicPat_Common<SIbuffer_load_format_d16, i32, "BUFFER_LOAD_FORMAT_D16_X_gfx80">;
+ defm : MUBUF_LoadIntrinsicPat_Common<SIbuffer_load_format_d16, v2i32, "BUFFER_LOAD_FORMAT_D16_XY_gfx80">;
+ defm : MUBUF_LoadIntrinsicPat_Common<SIbuffer_load_format_d16, v3i32, "BUFFER_LOAD_FORMAT_D16_XYZ_gfx80">;
+ defm : MUBUF_LoadIntrinsicPat_Common<SIbuffer_load_format_d16, v4i32, "BUFFER_LOAD_FORMAT_D16_XYZW_gfx80">;
} // End HasUnpackedD16VMem.
-let SubtargetPredicate = HasPackedD16VMem in {
+let OtherPredicates = [HasPackedD16VMem] in {
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_d16, f16, "BUFFER_LOAD_FORMAT_D16_X">;
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_d16, i16, "BUFFER_LOAD_FORMAT_D16_X">;
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format_d16, i32, "BUFFER_LOAD_FORMAT_D16_X">;
@@ -1336,33 +1425,33 @@ defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_short, i32, "BUFFER_LOAD_SSHORT">;
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_ubyte, i32, "BUFFER_LOAD_UBYTE">;
defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_ushort, i32, "BUFFER_LOAD_USHORT">;
-multiclass MUBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
+multiclass MUBUF_StoreIntrinsicPat_Common<SDPatternOperator name, ValueType vt,
string opcode, ValueType memoryVt = vt> {
defvar st = !if(!eq(memoryVt, vt), name, mubuf_intrinsic_store<name, memoryVt>);
def : GCNPat<
- (st vt:$vdata, v4i32:$rsrc, 0, 0, i32:$soffset, timm:$offset,
+ (st vt:$vdata, v4i32:$rsrc, 0, 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$auxiliary, 0),
(!cast<MUBUF_Pseudo>(opcode # _OFFSET_exact) getVregSrcForVT<vt>.ret:$vdata, SReg_128:$rsrc, SCSrc_b32:$soffset, timm:$offset,
(extract_cpol $auxiliary), (extract_swz $auxiliary))
>;
def : GCNPat<
- (st vt:$vdata, v4i32:$rsrc, 0, i32:$voffset, i32:$soffset, timm:$offset,
+ (st vt:$vdata, v4i32:$rsrc, 0, i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$auxiliary, 0),
(!cast<MUBUF_Pseudo>(opcode # _OFFEN_exact) getVregSrcForVT<vt>.ret:$vdata, VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset,
timm:$offset, (extract_cpol $auxiliary), (extract_swz $auxiliary))
>;
def : GCNPat<
- (st vt:$vdata, v4i32:$rsrc, i32:$vindex, 0, i32:$soffset, timm:$offset,
+ (st vt:$vdata, v4i32:$rsrc, i32:$vindex, 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$auxiliary, timm),
(!cast<MUBUF_Pseudo>(opcode # _IDXEN_exact) getVregSrcForVT<vt>.ret:$vdata, VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset,
timm:$offset, (extract_cpol $auxiliary), (extract_swz $auxiliary))
>;
def : GCNPat<
- (st vt:$vdata, v4i32:$rsrc, i32:$vindex, i32:$voffset, i32:$soffset, timm:$offset,
+ (st vt:$vdata, v4i32:$rsrc, i32:$vindex, i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$auxiliary, timm),
(!cast<MUBUF_Pseudo>(opcode # _BOTHEN_exact)
getVregSrcForVT<vt>.ret:$vdata,
@@ -1372,6 +1461,14 @@ multiclass MUBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
}
+multiclass MUBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
+ string opcode, ValueType memoryVt = vt> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MUBUF_StoreIntrinsicPat_Common<name, vt, opcode, memoryVt>;
+ }
+ defm : MUBUF_StoreIntrinsicPat_Common<name, vt, opcode # "_VBUFFER", memoryVt>;
+}
+
defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format, f32, "BUFFER_STORE_FORMAT_X">;
defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format, i32, "BUFFER_STORE_FORMAT_X">;
defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format, v2f32, "BUFFER_STORE_FORMAT_XY">;
@@ -1381,16 +1478,16 @@ defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format, v3i32, "BUFFER_STORE_FORMA
defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format, v4f32, "BUFFER_STORE_FORMAT_XYZW">;
defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format, v4i32, "BUFFER_STORE_FORMAT_XYZW">;
-let SubtargetPredicate = HasUnpackedD16VMem in {
- defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format_d16, f16, "BUFFER_STORE_FORMAT_D16_X_gfx80">;
- defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format_d16, i16, "BUFFER_STORE_FORMAT_D16_X_gfx80">;
- defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format_d16, i32, "BUFFER_STORE_FORMAT_D16_X_gfx80">;
- defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format_d16, v2i32, "BUFFER_STORE_FORMAT_D16_XY_gfx80">;
- defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format_d16, v3i32, "BUFFER_STORE_FORMAT_D16_XYZ_gfx80">;
- defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format_d16, v4i32, "BUFFER_STORE_FORMAT_D16_XYZW_gfx80">;
+let OtherPredicates = [HasUnpackedD16VMem] in {
+ defm : MUBUF_StoreIntrinsicPat_Common<SIbuffer_store_format_d16, f16, "BUFFER_STORE_FORMAT_D16_X_gfx80">;
+ defm : MUBUF_StoreIntrinsicPat_Common<SIbuffer_store_format_d16, i16, "BUFFER_STORE_FORMAT_D16_X_gfx80">;
+ defm : MUBUF_StoreIntrinsicPat_Common<SIbuffer_store_format_d16, i32, "BUFFER_STORE_FORMAT_D16_X_gfx80">;
+ defm : MUBUF_StoreIntrinsicPat_Common<SIbuffer_store_format_d16, v2i32, "BUFFER_STORE_FORMAT_D16_XY_gfx80">;
+ defm : MUBUF_StoreIntrinsicPat_Common<SIbuffer_store_format_d16, v3i32, "BUFFER_STORE_FORMAT_D16_XYZ_gfx80">;
+ defm : MUBUF_StoreIntrinsicPat_Common<SIbuffer_store_format_d16, v4i32, "BUFFER_STORE_FORMAT_D16_XYZW_gfx80">;
} // End HasUnpackedD16VMem.
-let SubtargetPredicate = HasPackedD16VMem in {
+let OtherPredicates = [HasPackedD16VMem] in {
defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format_d16, f16, "BUFFER_STORE_FORMAT_D16_X">;
defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format_d16, i16, "BUFFER_STORE_FORMAT_D16_X">;
defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_format_d16, i32, "BUFFER_STORE_FORMAT_D16_X">;
@@ -1421,7 +1518,7 @@ defm : MUBUF_StoreIntrinsicPat<SIbuffer_store_short, i32, "BUFFER_STORE_SHORT">;
// buffer_atomic patterns
//===----------------------------------------------------------------------===//
-multiclass BufferAtomicPat<string OpPrefix, ValueType vt, string Inst, bit isIntr = 0> {
+multiclass BufferAtomicPat_Common<string OpPrefix, ValueType vt, string Inst, bit isIntr = 0> {
foreach RtnMode = ["ret", "noret"] in {
defvar Op = !cast<SDPatternOperator>(OpPrefix
@@ -1447,11 +1544,18 @@ multiclass BufferAtomicPat<string OpPrefix, ValueType vt, string Inst, bit isInt
} // end foreach RtnMode
}
+multiclass BufferAtomicPat<string OpPrefix, ValueType vt, string Inst, bit isIntr = 0> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : BufferAtomicPat_Common<OpPrefix, vt, Inst, isIntr>;
+ }
+ defm : BufferAtomicPat_Common<OpPrefix, vt, Inst # "_VBUFFER", isIntr>;
+}
+
multiclass BufferAtomicIntrPat<string OpPrefix, ValueType vt, string Inst> {
defm : BufferAtomicPat<OpPrefix, vt, Inst, /* isIntr */ 1>;
}
-multiclass BufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst> {
+multiclass BufferAtomicCmpSwapPat_Common<ValueType vt, ValueType data_vt, string Inst> {
foreach RtnMode = ["ret", "noret"] in {
defvar Op = !cast<SDPatternOperator>("AMDGPUatomic_cmp_swap_global"
@@ -1487,6 +1591,14 @@ multiclass BufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst>
} // end foreach RtnMode
}
+multiclass BufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : BufferAtomicCmpSwapPat_Common<vt, data_vt, Inst>;
+ }
+ defm : BufferAtomicCmpSwapPat_Common<vt, data_vt, Inst # "_VBUFFER">;
+}
+
+
foreach Ty = [i32, i64] in {
defvar Suffix = !if(!eq(Ty, i64), "_X2", "");
@@ -1509,7 +1621,7 @@ defm : BufferAtomicPat<"atomic_load_udec_wrap_global", Ty, "BUFFER_ATOMIC_DEC" #
defm : BufferAtomicCmpSwapPat<i32, v2i32, "BUFFER_ATOMIC_CMPSWAP">;
defm : BufferAtomicCmpSwapPat<i64, v2i64, "BUFFER_ATOMIC_CMPSWAP_X2">;
-multiclass SIBufferAtomicPat<string OpPrefix, ValueType vt, string Inst,
+multiclass SIBufferAtomicPat_Common<string OpPrefix, ValueType vt, string Inst,
list<string> RtnModes = ["ret", "noret"]> {
foreach RtnMode = RtnModes in {
@@ -1522,7 +1634,7 @@ multiclass SIBufferAtomicPat<string OpPrefix, ValueType vt, string Inst,
let AddedComplexity = !if(!eq(RtnMode, "ret"), 0, 1) in {
def : GCNPat<
- (vt (Op vt:$vdata_in, v4i32:$rsrc, 0, 0, i32:$soffset,
+ (vt (Op vt:$vdata_in, v4i32:$rsrc, 0, 0, (BUFSOffset i32:$soffset),
timm:$offset, timm:$cachepolicy, 0)),
(!cast<MUBUF_Pseudo>(Inst # "_OFFSET" # InstSuffix)
getVregSrcForVT<vt>.ret:$vdata_in, SReg_128:$rsrc, SCSrc_b32:$soffset,
@@ -1530,7 +1642,7 @@ multiclass SIBufferAtomicPat<string OpPrefix, ValueType vt, string Inst,
>;
def : GCNPat<
- (vt (Op vt:$vdata_in, v4i32:$rsrc, i32:$vindex, 0, i32:$soffset,
+ (vt (Op vt:$vdata_in, v4i32:$rsrc, i32:$vindex, 0, (BUFSOffset i32:$soffset),
timm:$offset, timm:$cachepolicy, timm)),
(!cast<MUBUF_Pseudo>(Inst # "_IDXEN" # InstSuffix)
getVregSrcForVT<vt>.ret:$vdata_in, VGPR_32:$vindex, SReg_128:$rsrc,
@@ -1539,7 +1651,7 @@ multiclass SIBufferAtomicPat<string OpPrefix, ValueType vt, string Inst,
def : GCNPat<
(vt (Op vt:$vdata_in, v4i32:$rsrc, 0, i32:$voffset,
- i32:$soffset, timm:$offset, timm:$cachepolicy, 0)),
+ (BUFSOffset i32:$soffset), timm:$offset, timm:$cachepolicy, 0)),
(!cast<MUBUF_Pseudo>(Inst # "_OFFEN" # InstSuffix)
getVregSrcForVT<vt>.ret:$vdata_in, VGPR_32:$voffset, SReg_128:$rsrc,
SCSrc_b32:$soffset, timm:$offset, CachePolicy)
@@ -1547,7 +1659,7 @@ multiclass SIBufferAtomicPat<string OpPrefix, ValueType vt, string Inst,
def : GCNPat<
(vt (Op vt:$vdata_in, v4i32:$rsrc, i32:$vindex, i32:$voffset,
- i32:$soffset, timm:$offset, timm:$cachepolicy, timm)),
+ (BUFSOffset i32:$soffset), timm:$offset, timm:$cachepolicy, timm)),
(!cast<MUBUF_Pseudo>(Inst # "_BOTHEN" # InstSuffix)
getVregSrcForVT<vt>.ret:$vdata_in,
(REG_SEQUENCE VReg_64, VGPR_32:$vindex, sub0, VGPR_32:$voffset, sub1),
@@ -1558,6 +1670,14 @@ multiclass SIBufferAtomicPat<string OpPrefix, ValueType vt, string Inst,
} // end foreach RtnMode
}
+multiclass SIBufferAtomicPat<string OpPrefix, ValueType vt, string Inst,
+ list<string> RtnModes = ["ret", "noret"]> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : SIBufferAtomicPat_Common<OpPrefix, vt, Inst, RtnModes>;
+ }
+ defm : SIBufferAtomicPat_Common<OpPrefix, vt, Inst # "_VBUFFER", RtnModes>;
+}
+
defm : SIBufferAtomicPat<"SIbuffer_atomic_swap", i32, "BUFFER_ATOMIC_SWAP">;
defm : SIBufferAtomicPat<"SIbuffer_atomic_swap", f32, "BUFFER_ATOMIC_SWAP">;
defm : SIBufferAtomicPat<"SIbuffer_atomic_add", i32, "BUFFER_ATOMIC_ADD">;
@@ -1603,11 +1723,11 @@ class NoUseBufferAtomic<SDPatternOperator Op, ValueType vt> : PatFrag <
let HasNoUse = true;
}
-multiclass BufferAtomicPatterns_NO_RTN<SDPatternOperator name, ValueType vt,
+multiclass BufferAtomicPatterns_NO_RTN_Common<SDPatternOperator name, ValueType vt,
string opcode> {
def : GCNPat<
(NoUseBufferAtomic<name, vt> vt:$vdata_in, v4i32:$rsrc, 0,
- 0, i32:$soffset, timm:$offset,
+ 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$cachepolicy, 0),
(!cast<MUBUF_Pseudo>(opcode # _OFFSET) getVregSrcForVT<vt>.ret:$vdata_in, SReg_128:$rsrc, SCSrc_b32:$soffset,
timm:$offset, timm:$cachepolicy)
@@ -1615,7 +1735,7 @@ multiclass BufferAtomicPatterns_NO_RTN<SDPatternOperator name, ValueType vt,
def : GCNPat<
(NoUseBufferAtomic<name, vt> vt:$vdata_in, v4i32:$rsrc, i32:$vindex,
- 0, i32:$soffset, timm:$offset,
+ 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$cachepolicy, timm),
(!cast<MUBUF_Pseudo>(opcode # _IDXEN) getVregSrcForVT<vt>.ret:$vdata_in, VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset,
timm:$offset, timm:$cachepolicy)
@@ -1623,7 +1743,7 @@ multiclass BufferAtomicPatterns_NO_RTN<SDPatternOperator name, ValueType vt,
def : GCNPat<
(NoUseBufferAtomic<name, vt> vt:$vdata_in, v4i32:$rsrc, 0,
- i32:$voffset, i32:$soffset, timm:$offset,
+ i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$cachepolicy, 0),
(!cast<MUBUF_Pseudo>(opcode # _OFFEN) getVregSrcForVT<vt>.ret:$vdata_in, VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset,
timm:$offset, timm:$cachepolicy)
@@ -1631,7 +1751,7 @@ multiclass BufferAtomicPatterns_NO_RTN<SDPatternOperator name, ValueType vt,
def : GCNPat<
(NoUseBufferAtomic<name, vt> vt:$vdata_in, v4i32:$rsrc, i32:$vindex,
- i32:$voffset, i32:$soffset, timm:$offset,
+ i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$cachepolicy, timm),
(!cast<MUBUF_Pseudo>(opcode # _BOTHEN)
getVregSrcForVT<vt>.ret:$vdata_in,
@@ -1640,25 +1760,35 @@ multiclass BufferAtomicPatterns_NO_RTN<SDPatternOperator name, ValueType vt,
>;
}
-let SubtargetPredicate = HasAtomicFaddNoRtnInsts in
-defm : SIBufferAtomicPat<"SIbuffer_atomic_fadd", f32, "BUFFER_ATOMIC_ADD_F32", ["noret"]>;
+multiclass BufferAtomicPatterns_NO_RTN<SDPatternOperator name, ValueType vt,
+ string opcode> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : BufferAtomicPatterns_NO_RTN_Common<name, vt, opcode>;
+ }
+ defm : BufferAtomicPatterns_NO_RTN_Common<name, vt, opcode # "_VBUFFER">;
+}
-let SubtargetPredicate = HasAtomicBufferGlobalPkAddF16NoRtnInsts in
-defm : SIBufferAtomicPat<"SIbuffer_atomic_fadd", v2f16, "BUFFER_ATOMIC_PK_ADD_F16", ["noret"]>;
+let OtherPredicates = [HasAtomicFaddNoRtnInsts] in
+ defm : SIBufferAtomicPat<"SIbuffer_atomic_fadd", f32, "BUFFER_ATOMIC_ADD_F32", ["noret"]>;
-let SubtargetPredicate = HasAtomicFaddRtnInsts in
-defm : SIBufferAtomicPat<"SIbuffer_atomic_fadd", f32, "BUFFER_ATOMIC_ADD_F32", ["ret"]>;
+let OtherPredicates = [HasAtomicBufferGlobalPkAddF16NoRtnInsts] in {
+ defm : SIBufferAtomicPat_Common<"SIbuffer_atomic_fadd", v2f16, "BUFFER_ATOMIC_PK_ADD_F16", ["noret"]>;
+} // End OtherPredicates = [HasAtomicBufferGlobalPkAddF16NoRtnInsts]
-let SubtargetPredicate = HasAtomicBufferGlobalPkAddF16Insts in
-defm : SIBufferAtomicPat<"SIbuffer_atomic_fadd", v2f16, "BUFFER_ATOMIC_PK_ADD_F16", ["ret"]>;
+let OtherPredicates = [HasAtomicFaddRtnInsts] in
+ defm : SIBufferAtomicPat<"SIbuffer_atomic_fadd", f32, "BUFFER_ATOMIC_ADD_F32", ["ret"]>;
-let SubtargetPredicate = isGFX90APlus in {
+let OtherPredicates = [HasAtomicBufferGlobalPkAddF16Insts] in {
+ defm : SIBufferAtomicPat_Common<"SIbuffer_atomic_fadd", v2f16, "BUFFER_ATOMIC_PK_ADD_F16", ["ret"]>;
+} // End OtherPredicates = [HasAtomicBufferGlobalPkAddF16Insts]
+
+let OtherPredicates = [isGFX90APlus] in {
defm : SIBufferAtomicPat<"SIbuffer_atomic_fadd", f64, "BUFFER_ATOMIC_ADD_F64">;
defm : SIBufferAtomicPat<"SIbuffer_atomic_fmin", f64, "BUFFER_ATOMIC_MIN_F64">;
defm : SIBufferAtomicPat<"SIbuffer_atomic_fmax", f64, "BUFFER_ATOMIC_MAX_F64">;
} // End SubtargetPredicate = isGFX90APlus
-multiclass SIBufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst> {
+multiclass SIBufferAtomicCmpSwapPat_Common<ValueType vt, ValueType data_vt, string Inst> {
foreach RtnMode = ["ret", "noret"] in {
defvar Op = !cast<SDPatternOperator>(SIbuffer_atomic_cmpswap
# !if(!eq(RtnMode, "ret"), "", "_noret"));
@@ -1675,7 +1805,7 @@ multiclass SIBufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst
SReg_128:$rsrc, SCSrc_b32:$soffset, timm:$offset, CachePolicy);
def : GCNPat<
(vt (Op
- vt:$data, vt:$cmp, v4i32:$rsrc, 0, 0, i32:$soffset,
+ vt:$data, vt:$cmp, v4i32:$rsrc, 0, 0, (BUFSOffset i32:$soffset),
timm:$offset, timm:$cachepolicy, 0)),
!if(!eq(RtnMode, "ret"),
(EXTRACT_SUBREG OffsetResDag, SubLo),
@@ -1689,7 +1819,7 @@ multiclass SIBufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst
def : GCNPat<
(vt (Op
vt:$data, vt:$cmp, v4i32:$rsrc, i32:$vindex,
- 0, i32:$soffset, timm:$offset,
+ 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$cachepolicy, timm)),
!if(!eq(RtnMode, "ret"),
(EXTRACT_SUBREG IdxenResDag, SubLo),
@@ -1703,7 +1833,7 @@ multiclass SIBufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst
def : GCNPat<
(vt (Op
vt:$data, vt:$cmp, v4i32:$rsrc, 0,
- i32:$voffset, i32:$soffset, timm:$offset,
+ i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$cachepolicy, 0)),
!if(!eq(RtnMode, "ret"),
(EXTRACT_SUBREG OffenResDag, SubLo),
@@ -1717,7 +1847,7 @@ multiclass SIBufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst
def : GCNPat<
(vt (Op
vt:$data, vt:$cmp, v4i32:$rsrc, i32:$vindex,
- i32:$voffset, i32:$soffset, timm:$offset,
+ i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$cachepolicy, timm)),
!if(!eq(RtnMode, "ret"),
(EXTRACT_SUBREG BothenResDag, SubLo),
@@ -1726,6 +1856,13 @@ multiclass SIBufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst
} // end foreach RtnMode
}
+multiclass SIBufferAtomicCmpSwapPat<ValueType vt, ValueType data_vt, string Inst> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : SIBufferAtomicCmpSwapPat_Common<vt, data_vt, Inst>;
+ }
+ defm : SIBufferAtomicCmpSwapPat_Common<vt, data_vt, Inst # "_VBUFFER">;
+}
+
defm : SIBufferAtomicCmpSwapPat<i32, v2i32, "BUFFER_ATOMIC_CMPSWAP">;
defm : SIBufferAtomicCmpSwapPat<i64, v2i64, "BUFFER_ATOMIC_CMPSWAP_X2">;
@@ -1761,15 +1898,22 @@ defm : MUBUFLoad_Atomic_Pattern <BUFFER_LOAD_DWORD_ADDR64, BUFFER_LOAD_DWORD_OFF
defm : MUBUFLoad_Atomic_Pattern <BUFFER_LOAD_DWORDX2_ADDR64, BUFFER_LOAD_DWORDX2_OFFSET, i64, atomic_load_64_global>;
} // End SubtargetPredicate = isGFX6GFX7
-multiclass MUBUFLoad_PatternOffset <string Instr, ValueType vt,
+multiclass MUBUFLoad_PatternOffset_Common <string Instr, ValueType vt,
PatFrag ld> {
-
def : GCNPat <
(vt (ld (MUBUFOffset v4i32:$srsrc, i32:$soffset, i32:$offset))),
(!cast<MUBUF_Pseudo>(Instr # "_OFFSET") $srsrc, $soffset, $offset)
>;
}
+multiclass MUBUFLoad_PatternOffset <string Instr, ValueType vt,
+ PatFrag ld> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MUBUFLoad_PatternOffset_Common<Instr, vt, ld>;
+ }
+ defm : MUBUFLoad_PatternOffset_Common<Instr # "_VBUFFER", vt, ld>;
+}
+
let OtherPredicates = [Has16BitInsts] in {
defm : MUBUFLoad_PatternOffset <"BUFFER_LOAD_SBYTE", i16, sextloadi8_constant>;
@@ -1783,7 +1927,7 @@ defm : MUBUFLoad_PatternOffset <"BUFFER_LOAD_USHORT", i16, load_global>;
} // End OtherPredicates = [Has16BitInsts]
-multiclass MUBUFScratchLoadPat <string Instr,
+multiclass MUBUFScratchLoadPat_Common <string Instr,
ValueType vt, PatFrag ld> {
def : GCNPat <
(vt (ld (MUBUFScratchOffen v4i32:$srsrc, i32:$vaddr,
@@ -1797,8 +1941,16 @@ multiclass MUBUFScratchLoadPat <string Instr,
>;
}
+multiclass MUBUFScratchLoadPat <string Instr,
+ ValueType vt, PatFrag ld> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MUBUFScratchLoadPat_Common<Instr, vt, ld>;
+ }
+ defm : MUBUFScratchLoadPat_Common<Instr # "_VBUFFER", vt, ld>;
+}
+
// XXX - Is it possible to have a complex pattern in a PatFrag?
-multiclass MUBUFScratchLoadPat_D16 <string Instr,
+multiclass MUBUFScratchLoadPat_D16_Common <string Instr,
ValueType vt, PatFrag ld_frag> {
def : GCNPat <
(ld_frag (MUBUFScratchOffen v4i32:$srsrc, i32:$vaddr, i32:$soffset, i32:$offset), vt:$in),
@@ -1811,6 +1963,14 @@ multiclass MUBUFScratchLoadPat_D16 <string Instr,
>;
}
+multiclass MUBUFScratchLoadPat_D16 <string Instr,
+ ValueType vt, PatFrag ld_frag> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MUBUFScratchLoadPat_D16_Common<Instr, vt, ld_frag>;
+ }
+ defm : MUBUFScratchLoadPat_D16_Common<Instr # "_VBUFFER", vt, ld_frag>;
+}
+
let OtherPredicates = [DisableFlatScratch] in {
defm : MUBUFScratchLoadPat <"BUFFER_LOAD_SBYTE", i32, sextloadi8_private>;
defm : MUBUFScratchLoadPat <"BUFFER_LOAD_UBYTE", i32, extloadi8_private>;
@@ -1870,7 +2030,7 @@ defm : MUBUFStore_Atomic_Pattern <BUFFER_STORE_DWORDX2_ADDR64, BUFFER_STORE_DWOR
} // End Predicates = isGFX6GFX7
-multiclass MUBUFStore_PatternOffset <string Instr, ValueType vt,
+multiclass MUBUFStore_PatternOffset_Common <string Instr, ValueType vt,
PatFrag st> {
def : GCNPat <
@@ -1879,10 +2039,18 @@ multiclass MUBUFStore_PatternOffset <string Instr, ValueType vt,
>;
}
+multiclass MUBUFStore_PatternOffset <string Instr, ValueType vt,
+ PatFrag st> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MUBUFStore_PatternOffset_Common<Instr, vt, st>;
+ }
+ defm : MUBUFStore_PatternOffset_Common<Instr # "_VBUFFER", vt, st>;
+}
+
defm : MUBUFStore_PatternOffset <"BUFFER_STORE_BYTE", i16, truncstorei8_global>;
defm : MUBUFStore_PatternOffset <"BUFFER_STORE_SHORT", i16, store_global>;
-multiclass MUBUFScratchStorePat <string Instr,
+multiclass MUBUFScratchStorePat_Common <string Instr,
ValueType vt, PatFrag st,
RegisterClass rc = VGPR_32> {
def : GCNPat <
@@ -1898,6 +2066,15 @@ multiclass MUBUFScratchStorePat <string Instr,
>;
}
+multiclass MUBUFScratchStorePat <string Instr,
+ ValueType vt, PatFrag st,
+ RegisterClass rc = VGPR_32> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MUBUFScratchStorePat_Common<Instr, vt, st, rc>;
+ }
+ defm : MUBUFScratchStorePat_Common<Instr # "_VBUFFER", vt, st, rc>;
+}
+
let OtherPredicates = [DisableFlatScratch] in {
defm : MUBUFScratchStorePat <"BUFFER_STORE_BYTE", i32, truncstorei8_private>;
defm : MUBUFScratchStorePat <"BUFFER_STORE_SHORT", i32, truncstorei16_private>;
@@ -1931,12 +2108,12 @@ defm : MUBUFScratchStorePat <"BUFFER_STORE_BYTE_D16_HI", i32, truncstorei8_hi16_
// tbuffer_load/store_format patterns
//===----------------------------------------------------------------------===//
-multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
+multiclass MTBUF_LoadIntrinsicPat_Common<SDPatternOperator name, ValueType vt,
string opcode, ValueType memoryVt = vt> {
defvar st = !if(!eq(memoryVt, vt), name, mtbuf_intrinsic_load<name, memoryVt>);
def : GCNPat<
- (vt (st v4i32:$rsrc, 0, 0, i32:$soffset, timm:$offset,
+ (vt (st v4i32:$rsrc, 0, 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$format, timm:$auxiliary, 0)),
(!cast<MTBUF_Pseudo>(opcode # _OFFSET) SReg_128:$rsrc, SCSrc_b32:$soffset, timm:$offset,
(as_i8timm $format),
@@ -1944,7 +2121,7 @@ multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
def : GCNPat<
- (vt (st v4i32:$rsrc, i32:$vindex, 0, i32:$soffset, timm:$offset,
+ (vt (st v4i32:$rsrc, i32:$vindex, 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$format, timm:$auxiliary, timm)),
(!cast<MTBUF_Pseudo>(opcode # _IDXEN) VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset, timm:$offset,
(as_i8timm $format),
@@ -1952,7 +2129,7 @@ multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
def : GCNPat<
- (vt (st v4i32:$rsrc, 0, i32:$voffset, i32:$soffset, timm:$offset,
+ (vt (st v4i32:$rsrc, 0, i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$format, timm:$auxiliary, 0)),
(!cast<MTBUF_Pseudo>(opcode # _OFFEN) VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset, timm:$offset,
(as_i8timm $format),
@@ -1960,7 +2137,7 @@ multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
def : GCNPat<
- (vt (st v4i32:$rsrc, i32:$vindex, i32:$voffset, i32:$soffset, timm:$offset,
+ (vt (st v4i32:$rsrc, i32:$vindex, i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$format, timm:$auxiliary, timm)),
(!cast<MTBUF_Pseudo>(opcode # _BOTHEN)
(REG_SEQUENCE VReg_64, VGPR_32:$vindex, sub0, VGPR_32:$voffset, sub1),
@@ -1970,6 +2147,14 @@ multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
}
+multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
+ string opcode, ValueType memoryVt = vt> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MTBUF_LoadIntrinsicPat_Common<name, vt, opcode, memoryVt>;
+ }
+ defm : MTBUF_LoadIntrinsicPat_Common<name, vt, opcode # "_VBUFFER", memoryVt>;
+}
+
defm : MTBUF_LoadIntrinsicPat<SItbuffer_load, i32, "TBUFFER_LOAD_FORMAT_X">;
defm : MTBUF_LoadIntrinsicPat<SItbuffer_load, v2i32, "TBUFFER_LOAD_FORMAT_XY">;
defm : MTBUF_LoadIntrinsicPat<SItbuffer_load, v3i32, "TBUFFER_LOAD_FORMAT_XYZ">;
@@ -1979,15 +2164,15 @@ defm : MTBUF_LoadIntrinsicPat<SItbuffer_load, v2f32, "TBUFFER_LOAD_FORMAT_XY">;
defm : MTBUF_LoadIntrinsicPat<SItbuffer_load, v3f32, "TBUFFER_LOAD_FORMAT_XYZ">;
defm : MTBUF_LoadIntrinsicPat<SItbuffer_load, v4f32, "TBUFFER_LOAD_FORMAT_XYZW">;
-let SubtargetPredicate = HasUnpackedD16VMem in {
- defm : MTBUF_LoadIntrinsicPat<SItbuffer_load_d16, f16, "TBUFFER_LOAD_FORMAT_D16_X_gfx80">;
- defm : MTBUF_LoadIntrinsicPat<SItbuffer_load_d16, i32, "TBUFFER_LOAD_FORMAT_D16_X_gfx80">;
- defm : MTBUF_LoadIntrinsicPat<SItbuffer_load_d16, v2i32, "TBUFFER_LOAD_FORMAT_D16_XY_gfx80">;
- defm : MTBUF_LoadIntrinsicPat<SItbuffer_load_d16, v3i32, "TBUFFER_LOAD_FORMAT_D16_XYZ_gfx80">;
- defm : MTBUF_LoadIntrinsicPat<SItbuffer_load_d16, v4i32, "TBUFFER_LOAD_FORMAT_D16_XYZW_gfx80">;
+let OtherPredicates = [HasUnpackedD16VMem] in {
+ defm : MTBUF_LoadIntrinsicPat_Common<SItbuffer_load_d16, f16, "TBUFFER_LOAD_FORMAT_D16_X_gfx80">;
+ defm : MTBUF_LoadIntrinsicPat_Common<SItbuffer_load_d16, i32, "TBUFFER_LOAD_FORMAT_D16_X_gfx80">;
+ defm : MTBUF_LoadIntrinsicPat_Common<SItbuffer_load_d16, v2i32, "TBUFFER_LOAD_FORMAT_D16_XY_gfx80">;
+ defm : MTBUF_LoadIntrinsicPat_Common<SItbuffer_load_d16, v3i32, "TBUFFER_LOAD_FORMAT_D16_XYZ_gfx80">;
+ defm : MTBUF_LoadIntrinsicPat_Common<SItbuffer_load_d16, v4i32, "TBUFFER_LOAD_FORMAT_D16_XYZW_gfx80">;
} // End HasUnpackedD16VMem.
-let SubtargetPredicate = HasPackedD16VMem in {
+let OtherPredicates = [HasPackedD16VMem] in {
defm : MTBUF_LoadIntrinsicPat<SItbuffer_load_d16, f16, "TBUFFER_LOAD_FORMAT_D16_X">;
defm : MTBUF_LoadIntrinsicPat<SItbuffer_load_d16, i32, "TBUFFER_LOAD_FORMAT_D16_X">;
defm : MTBUF_LoadIntrinsicPat<SItbuffer_load_d16, v2f16, "TBUFFER_LOAD_FORMAT_D16_XY">;
@@ -1995,12 +2180,12 @@ let SubtargetPredicate = HasPackedD16VMem in {
defm : MTBUF_LoadIntrinsicPat<SItbuffer_load_d16, v4f16, "TBUFFER_LOAD_FORMAT_D16_XYZW">;
} // End HasPackedD16VMem.
-multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
+multiclass MTBUF_StoreIntrinsicPat_Common<SDPatternOperator name, ValueType vt,
string opcode, ValueType memoryVt = vt> {
defvar st = !if(!eq(memoryVt, vt), name, mtbuf_intrinsic_store<name, memoryVt>);
def : GCNPat<
- (st vt:$vdata, v4i32:$rsrc, 0, 0, i32:$soffset, timm:$offset,
+ (st vt:$vdata, v4i32:$rsrc, 0, 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$format, timm:$auxiliary, 0),
(!cast<MTBUF_Pseudo>(opcode # _OFFSET_exact) getVregSrcForVT<vt>.ret:$vdata, SReg_128:$rsrc, SCSrc_b32:$soffset,
timm:$offset, (as_i8timm $format),
@@ -2008,7 +2193,7 @@ multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
def : GCNPat<
- (st vt:$vdata, v4i32:$rsrc, i32:$vindex, 0, i32:$soffset, timm:$offset,
+ (st vt:$vdata, v4i32:$rsrc, i32:$vindex, 0, (BUFSOffset i32:$soffset), timm:$offset,
timm:$format, timm:$auxiliary, timm),
(!cast<MTBUF_Pseudo>(opcode # _IDXEN_exact) getVregSrcForVT<vt>.ret:$vdata, VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset,
timm:$offset, (as_i8timm $format),
@@ -2016,7 +2201,7 @@ multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
def : GCNPat<
- (st vt:$vdata, v4i32:$rsrc, 0, i32:$voffset, i32:$soffset, timm:$offset,
+ (st vt:$vdata, v4i32:$rsrc, 0, i32:$voffset, (BUFSOffset i32:$soffset), timm:$offset,
timm:$format, timm:$auxiliary, 0),
(!cast<MTBUF_Pseudo>(opcode # _OFFEN_exact) getVregSrcForVT<vt>.ret:$vdata, VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset,
timm:$offset, (as_i8timm $format),
@@ -2024,7 +2209,7 @@ multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
def : GCNPat<
- (st vt:$vdata, v4i32:$rsrc, i32:$vindex, i32:$voffset, i32:$soffset,
+ (st vt:$vdata, v4i32:$rsrc, i32:$vindex, i32:$voffset, (BUFSOffset i32:$soffset),
timm:$offset, timm:$format, timm:$auxiliary, timm),
(!cast<MTBUF_Pseudo>(opcode # _BOTHEN_exact)
getVregSrcForVT<vt>.ret:$vdata,
@@ -2034,6 +2219,14 @@ multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
>;
}
+multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
+ string opcode, ValueType memoryVt = vt> {
+ let SubtargetPredicate = HasUnrestrictedSOffset in {
+ defm : MTBUF_StoreIntrinsicPat_Common<name, vt, opcode, memoryVt>;
+ }
+ defm : MTBUF_StoreIntrinsicPat_Common<name, vt, opcode # "_VBUFFER", memoryVt>;
+}
+
defm : MTBUF_StoreIntrinsicPat<SItbuffer_store, i32, "TBUFFER_STORE_FORMAT_X">;
defm : MTBUF_StoreIntrinsicPat<SItbuffer_store, v2i32, "TBUFFER_STORE_FORMAT_XY">;
defm : MTBUF_StoreIntrinsicPat<SItbuffer_store, v3i32, "TBUFFER_STORE_FORMAT_XYZ">;
@@ -2043,15 +2236,15 @@ defm : MTBUF_StoreIntrinsicPat<SItbuffer_store, v2f32, "TBUFFER_STORE_FORMAT_XY"
defm : MTBUF_StoreIntrinsicPat<SItbuffer_store, v3f32, "TBUFFER_STORE_FORMAT_XYZ">;
defm : MTBUF_StoreIntrinsicPat<SItbuffer_store, v4f32, "TBUFFER_STORE_FORMAT_XYZW">;
-let SubtargetPredicate = HasUnpackedD16VMem in {
- defm : MTBUF_StoreIntrinsicPat<SItbuffer_store_d16, f16, "TBUFFER_STORE_FORMAT_D16_X_gfx80">;
- defm : MTBUF_StoreIntrinsicPat<SItbuffer_store_d16, i32, "TBUFFER_STORE_FORMAT_D16_X_gfx80">;
- defm : MTBUF_StoreIntrinsicPat<SItbuffer_store_d16, v2i32, "TBUFFER_STORE_FORMAT_D16_XY_gfx80">;
- defm : MTBUF_StoreIntrinsicPat<SItbuffer_store_d16, v3i32, "TBUFFER_STORE_FORMAT_D16_XYZ_gfx80">;
- defm : MTBUF_StoreIntrinsicPat<SItbuffer_store_d16, v4i32, "TBUFFER_STORE_FORMAT_D16_XYZW_gfx80">;
+let OtherPredicates = [HasUnpackedD16VMem] in {
+ defm : MTBUF_StoreIntrinsicPat_Common<SItbuffer_store_d16, f16, "TBUFFER_STORE_FORMAT_D16_X_gfx80">;
+ defm : MTBUF_StoreIntrinsicPat_Common<SItbuffer_store_d16, i32, "TBUFFER_STORE_FORMAT_D16_X_gfx80">;
+ defm : MTBUF_StoreIntrinsicPat_Common<SItbuffer_store_d16, v2i32, "TBUFFER_STORE_FORMAT_D16_XY_gfx80">;
+ defm : MTBUF_StoreIntrinsicPat_Common<SItbuffer_store_d16, v3i32, "TBUFFER_STORE_FORMAT_D16_XYZ_gfx80">;
+ defm : MTBUF_StoreIntrinsicPat_Common<SItbuffer_store_d16, v4i32, "TBUFFER_STORE_FORMAT_D16_XYZW_gfx80">;
} // End HasUnpackedD16VMem.
-let SubtargetPredicate = HasPackedD16VMem in {
+let OtherPredicates = [HasPackedD16VMem] in {
defm : MTBUF_StoreIntrinsicPat<SItbuffer_store_d16, f16, "TBUFFER_STORE_FORMAT_D16_X">;
defm : MTBUF_StoreIntrinsicPat<SItbuffer_store_d16, i32, "TBUFFER_STORE_FORMAT_D16_X">;
defm : MTBUF_StoreIntrinsicPat<SItbuffer_store_d16, v2f16, "TBUFFER_STORE_FORMAT_D16_XY">;
@@ -2122,7 +2315,88 @@ class MUBUF_Real_gfx6_gfx7<bits<8> op, MUBUF_Pseudo ps> :
}
//===----------------------------------------------------------------------===//
-// MUBUF - GFX11.
+// Base ENC_VBUFFER for GFX12.
+//===----------------------------------------------------------------------===//
+
+class VBUFFER_Real <BUF_Pseudo ps, string real_name = ps.Mnemonic> :
+ InstSI <ps.OutOperandList, ps.InOperandList, real_name # ps.AsmOperands, []>, Enc96 {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ let VM_CNT = 1;
+ let EXP_CNT = 1;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let OtherPredicates = ps.OtherPredicates;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+ let TSFlags = ps.TSFlags;
+ let UseNamedOperandTable = ps.UseNamedOperandTable;
+ let SchedRW = ps.SchedRW;
+ let mayLoad = ps.mayLoad;
+ let mayStore = ps.mayStore;
+ let IsAtomicRet = ps.IsAtomicRet;
+ let IsAtomicNoRet = ps.IsAtomicNoRet;
+ let VALU = ps.VALU;
+ let LGKM_CNT = ps.LGKM_CNT;
+
+ bits<24> offset;
+ bits<8> vaddr;
+ bits<10> vdata;
+
+ bits<7> srsrc;
+ bits<7> soffset;
+ bits<6> cpol;
+
+ let Inst{95-72} = !if(ps.has_offset, offset, ?);
+ let Inst{71-64} = !if(ps.has_vaddr, vaddr, ?);
+ let Inst{39-32} = !if(ps.has_vdata, vdata{7-0}, ?);
+
+ let Inst{47-41} = !if(ps.has_srsrc, srsrc, ?);
+ let Inst{49-48} = 0b00;
+ let Inst{6-0} = !if(ps.has_soffset, soffset, ?);
+ let Inst{22} = ps.tfe;
+ let Inst{62} = ps.offen;
+ let Inst{63} = ps.idxen;
+
+ let Inst{54-53} = cpol{2-1}; // th{2-1}
+ let Inst{52} = !if(ps.IsAtomicRet, 1, cpol{0}); // th{0}
+ let Inst{51-50} = cpol{4-3}; // scope
+
+ let Inst{31-26} = 0b110001;
+}
+
+class VBUFFER_MUBUF_Real_gfx12<bits<8> op, MUBUF_Pseudo ps,
+ string real_name = ps.Mnemonic> :
+ VBUFFER_Real<ps, real_name>, SIMCInstr<ps.PseudoInstr, SIEncodingFamily.GFX12> {
+
+ let MUBUF = 1;
+
+ // Set the last bit of format to 1 to avoid round-trip issues, as some tools
+ // print BUF_FMT_INVALID for format 0.
+ let Inst{55} = 0b1;
+ let Inst{21-14} = op;
+ let SubtargetPredicate = isGFX12Only;
+}
+
+class VBUFFER_MTBUF_Real_gfx12<bits<4> op, MTBUF_Pseudo ps,
+ string real_name = ps.Mnemonic> :
+ VBUFFER_Real<ps, real_name>, SIMCInstr<ps.PseudoInstr, SIEncodingFamily.GFX12> {
+
+ let MTBUF = 1;
+
+ bits<7> format;
+
+ let Inst{17-14} = op;
+ let Inst{21-18} = 0b1000;
+ let Inst{61-55} = format;
+}
+
+//===----------------------------------------------------------------------===//
+// MUBUF - GFX11, GFX12.
//===----------------------------------------------------------------------===//
// Shortcut to default Mnemonic from MUBUF_Pseudo. Hides the cast to the
@@ -2132,19 +2406,43 @@ class get_MUBUF_ps<string name> {
}
// gfx11 instruction that accept both old and new assembler name.
-class Pre_gfx11_MUBUF_Name <string mnemonic, string real_name> :
+class Mnem_gfx11_gfx12 <string mnemonic, string real_name> :
MnemonicAlias<mnemonic, real_name>, Requires<[isGFX11Plus]>;
+class Mnem_gfx11 <string mnemonic, string real_name> :
+ MnemonicAlias<mnemonic, real_name>, Requires<[isGFX11Only]>;
+
+class Mnem_gfx12 <string mnemonic, string real_name> :
+ MnemonicAlias<mnemonic, real_name>, Requires<[isGFX12Plus]>;
+
class MUBUF_Real_gfx11_impl<bits<8> op, string ps_name, string real_name> :
MUBUF_Real_gfx11<op, !cast<MUBUF_Pseudo>(ps_name), real_name>;
-let DecoderNamespace = "GFX11" in
+
+class VBUFFER_MUBUF_Real_gfx12_impl<bits<8> op, string ps_name, string real_name> :
+ VBUFFER_MUBUF_Real_gfx12<op, !cast<MUBUF_Pseudo>(ps_name), real_name>;
+
multiclass MUBUF_Real_AllAddr_gfx11_Renamed_Impl2<bits<8> op, string real_name> {
- def _BOTHEN_gfx11 : MUBUF_Real_gfx11_impl<op, NAME # "_BOTHEN", real_name>;
- def _IDXEN_gfx11 : MUBUF_Real_gfx11_impl<op, NAME # "_IDXEN", real_name>;
- def _OFFEN_gfx11 : MUBUF_Real_gfx11_impl<op, NAME # "_OFFEN", real_name>;
- def _OFFSET_gfx11 : MUBUF_Real_gfx11_impl<op, NAME # "_OFFSET", real_name>;
+ let DecoderNamespace = "GFX11" in {
+ def _BOTHEN_gfx11 : MUBUF_Real_gfx11_impl<op, NAME # "_BOTHEN", real_name>;
+ def _IDXEN_gfx11 : MUBUF_Real_gfx11_impl<op, NAME # "_IDXEN", real_name>;
+ def _OFFEN_gfx11 : MUBUF_Real_gfx11_impl<op, NAME # "_OFFEN", real_name>;
+ def _OFFSET_gfx11 : MUBUF_Real_gfx11_impl<op, NAME # "_OFFSET", real_name>;
+ }
+}
+
+multiclass MUBUF_Real_AllAddr_gfx12_Renamed_Impl2<bits<8> op, string real_name> {
+ let DecoderNamespace = "GFX12" in {
+ def _BOTHEN_gfx12 : VBUFFER_MUBUF_Real_gfx12_impl<op, NAME # "_VBUFFER_BOTHEN", real_name>;
+ def _IDXEN_gfx12 : VBUFFER_MUBUF_Real_gfx12_impl<op, NAME # "_VBUFFER_IDXEN", real_name>;
+ def _OFFEN_gfx12 : VBUFFER_MUBUF_Real_gfx12_impl<op, NAME # "_VBUFFER_OFFEN", real_name>;
+ def _OFFSET_gfx12 : VBUFFER_MUBUF_Real_gfx12_impl<op, NAME # "_VBUFFER_OFFSET", real_name>;
+ }
}
+multiclass MUBUF_Real_AllAddr_gfx11_gfx12_Renamed_Impl2<bits<8> op, string real_name> :
+ MUBUF_Real_AllAddr_gfx11_Renamed_Impl2<op, real_name>,
+ MUBUF_Real_AllAddr_gfx12_Renamed_Impl2<op, real_name>;
+
multiclass MUBUF_Real_AllAddr_gfx11_Renamed_Impl<bits<8> op, string real_name,
bit hasTFE = 1> {
defm NAME : MUBUF_Real_AllAddr_gfx11_Renamed_Impl2<op, real_name>;
@@ -2152,45 +2450,105 @@ multiclass MUBUF_Real_AllAddr_gfx11_Renamed_Impl<bits<8> op, string real_name,
defm _TFE : MUBUF_Real_AllAddr_gfx11_Renamed_Impl2<op, real_name>;
}
-// Non-renamed, non-atomic gfx11 mubuf instructions.
+multiclass MUBUF_Real_AllAddr_gfx11_gfx12_Renamed_Impl<bits<8> op, string real_name,
+ bit hasTFE = 1> {
+ defm NAME : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed_Impl2<op, real_name>;
+ if hasTFE then
+ defm _TFE : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed_Impl2<op, real_name>;
+}
+
+// Non-renamed, non-atomic gfx11/gfx12 mubuf instructions.
multiclass MUBUF_Real_AllAddr_gfx11<bits<8> op, bit hasTFE = 1> :
MUBUF_Real_AllAddr_gfx11_Renamed_Impl<op, get_MUBUF_ps<NAME>.Mnemonic, hasTFE>;
-multiclass MUBUF_Real_AllAddr_gfx11_Renamed<bits<8> op, string real_name> :
- MUBUF_Real_AllAddr_gfx11_Renamed_Impl<op, real_name> {
- def : Pre_gfx11_MUBUF_Name<get_MUBUF_ps<NAME>.Mnemonic, real_name>;
+multiclass MUBUF_Real_AllAddr_gfx11_gfx12<bits<8> op, bit hasTFE = 1> :
+ MUBUF_Real_AllAddr_gfx11_gfx12_Renamed_Impl<op, get_MUBUF_ps<NAME>.Mnemonic, hasTFE>;
+
+multiclass MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<bits<8> op, string real_name> :
+ MUBUF_Real_AllAddr_gfx11_gfx12_Renamed_Impl<op, real_name> {
+ def : Mnem_gfx11_gfx12<get_MUBUF_ps<NAME>.Mnemonic, real_name>;
}
class MUBUF_Real_Atomic_gfx11_impl<bits<8> op, string ps_name,
string real_name> :
Base_MUBUF_Real_Atomic_gfx11<op, !cast<MUBUF_Pseudo>(ps_name), real_name>;
-let DecoderNamespace = "GFX11" in
+
+class MUBUF_Real_Atomic_gfx12_impl<bits<8> op, string ps_name,
+ string real_name> :
+ VBUFFER_MUBUF_Real_gfx12<op, !cast<MUBUF_Pseudo>(ps_name), real_name>;
+
multiclass MUBUF_Real_Atomic_gfx11_Renamed_impl<bits<8> op, bit is_return,
string real_name> {
- defvar Rtn = !if(!eq(is_return, 1), "_RTN", "");
- def _BOTHEN#Rtn#_gfx11 :
- MUBUF_Real_Atomic_gfx11_impl<op, NAME # "_BOTHEN" # Rtn, real_name>,
- AtomicNoRet<NAME # "_BOTHEN_gfx11", is_return>;
- def _IDXEN#Rtn#_gfx11 :
- MUBUF_Real_Atomic_gfx11_impl<op, NAME # "_IDXEN" # Rtn, real_name>,
- AtomicNoRet<NAME # "_IDXEN_gfx11", is_return>;
- def _OFFEN#Rtn#_gfx11 :
- MUBUF_Real_Atomic_gfx11_impl<op, NAME # "_OFFEN" # Rtn, real_name>,
- AtomicNoRet<NAME # "_OFFEN_gfx11", is_return>;
- def _OFFSET#Rtn#_gfx11 :
- MUBUF_Real_Atomic_gfx11_impl<op, NAME # "_OFFSET" # Rtn, real_name>,
- AtomicNoRet<NAME # "_OFFSET_gfx11", is_return>;
-}
-
-// Non-renamed gfx11 mubuf atomic.
-multiclass MUBUF_Real_Atomic_gfx11<bits<8> op> :
- MUBUF_Real_Atomic_gfx11_Renamed_impl<op, 0, get_MUBUF_ps<NAME>.Mnemonic>,
- MUBUF_Real_Atomic_gfx11_Renamed_impl<op, 1, get_MUBUF_ps<NAME>.Mnemonic>;
+ let DecoderNamespace = "GFX11" in {
+ defvar Rtn = !if(!eq(is_return, 1), "_RTN", "");
+ def _BOTHEN#Rtn#_gfx11 :
+ MUBUF_Real_Atomic_gfx11_impl<op, NAME # "_BOTHEN" # Rtn, real_name>,
+ AtomicNoRet<NAME # "_BOTHEN_gfx11", is_return>;
+ def _IDXEN#Rtn#_gfx11 :
+ MUBUF_Real_Atomic_gfx11_impl<op, NAME # "_IDXEN" # Rtn, real_name>,
+ AtomicNoRet<NAME # "_IDXEN_gfx11", is_return>;
+ def _OFFEN#Rtn#_gfx11 :
+ MUBUF_Real_Atomic_gfx11_impl<op, NAME # "_OFFEN" # Rtn, real_name>,
+ AtomicNoRet<NAME # "_OFFEN_gfx11", is_return>;
+ def _OFFSET#Rtn#_gfx11 :
+ MUBUF_Real_Atomic_gfx11_impl<op, NAME # "_OFFSET" # Rtn, real_name>,
+ AtomicNoRet<NAME # "_OFFSET_gfx11", is_return>;
+ }
+}
+
+multiclass MUBUF_Real_Atomic_gfx12_Renamed_impl<bits<8> op, bit is_return,
+ string real_name> {
+ let DecoderNamespace = "GFX12" in {
+ defvar Rtn = !if(!eq(is_return, 1), "_RTN", "");
+ def _BOTHEN#Rtn#_gfx12 :
+ MUBUF_Real_Atomic_gfx12_impl<op, NAME # "_VBUFFER_BOTHEN" # Rtn, real_name>,
+ AtomicNoRet<NAME # "_BOTHEN_gfx12", is_return>;
+ def _IDXEN#Rtn#_gfx12 :
+ MUBUF_Real_Atomic_gfx12_impl<op, NAME # "_VBUFFER_IDXEN" # Rtn, real_name>,
+ AtomicNoRet<NAME # "_IDXEN_gfx12", is_return>;
+ def _OFFEN#Rtn#_gfx12 :
+ MUBUF_Real_Atomic_gfx12_impl<op, NAME # "_VBUFFER_OFFEN" # Rtn, real_name>,
+ AtomicNoRet<NAME # "_OFFEN_gfx12", is_return>;
+ def _OFFSET#Rtn#_gfx12 :
+ MUBUF_Real_Atomic_gfx12_impl<op, NAME # "_VBUFFER_OFFSET" # Rtn, real_name>,
+ AtomicNoRet<NAME # "_OFFSET_gfx12", is_return>;
+ }
+}
+
+multiclass MUBUF_Real_Atomic_gfx11_gfx12_Renamed_impl<bits<8> op, bit is_return,
+ string real_name> :
+ MUBUF_Real_Atomic_gfx11_Renamed_impl<op, is_return, real_name>,
+ MUBUF_Real_Atomic_gfx12_Renamed_impl<op, is_return, real_name>;
+
+// Non-renamed gfx11/gfx12 mubuf atomic.
+multiclass MUBUF_Real_Atomic_gfx11_gfx12<bits<8> op> :
+ MUBUF_Real_Atomic_gfx11_gfx12_Renamed_impl<op, 0, get_MUBUF_ps<NAME>.Mnemonic>,
+ MUBUF_Real_Atomic_gfx11_gfx12_Renamed_impl<op, 1, get_MUBUF_ps<NAME>.Mnemonic>;
+
+multiclass MUBUF_Real_Atomic_gfx12<bits<8> op> :
+ MUBUF_Real_Atomic_gfx12_Renamed_impl<op, 0, get_MUBUF_ps<NAME>.Mnemonic>,
+ MUBUF_Real_Atomic_gfx12_Renamed_impl<op, 1, get_MUBUF_ps<NAME>.Mnemonic>;
multiclass MUBUF_Real_Atomic_gfx11_Renamed<bits<8> op, string real_name> :
MUBUF_Real_Atomic_gfx11_Renamed_impl<op, 0, real_name>,
- MUBUF_Real_Atomic_gfx11_Renamed_impl<op, 1, real_name> {
- def : Pre_gfx11_MUBUF_Name<get_MUBUF_ps<NAME>.Mnemonic, real_name>;
+ MUBUF_Real_Atomic_gfx11_Renamed_impl<op, 1, real_name> {
+ def : Mnem_gfx11_gfx12<get_MUBUF_ps<NAME>.Mnemonic, real_name>;
+}
+
+multiclass MUBUF_Real_Atomic_gfx11_gfx12_Renamed<bits<8> op, string real_name> :
+ MUBUF_Real_Atomic_gfx11_gfx12_Renamed_impl<op, 0, real_name>,
+ MUBUF_Real_Atomic_gfx11_gfx12_Renamed_impl<op, 1, real_name> {
+ def : Mnem_gfx11_gfx12<get_MUBUF_ps<NAME>.Mnemonic, real_name>;
+}
+
+multiclass MUBUF_Real_Atomic_gfx11_gfx12_Renamed_gfx12_Renamed<bits<8> op, string gfx12_name, string gfx11_name> :
+ MUBUF_Real_Atomic_gfx11_Renamed_impl<op, 0, gfx11_name>,
+ MUBUF_Real_Atomic_gfx11_Renamed_impl<op, 1, gfx11_name>,
+ MUBUF_Real_Atomic_gfx12_Renamed_impl<op, 0, gfx12_name>,
+ MUBUF_Real_Atomic_gfx12_Renamed_impl<op, 1, gfx12_name> {
+ def : Mnem_gfx11<get_MUBUF_ps<NAME>.Mnemonic, gfx11_name>;
+ def : Mnem_gfx12<get_MUBUF_ps<NAME>.Mnemonic, gfx12_name>;
+ def : Mnem_gfx12<gfx11_name, gfx12_name>;
}
let DecoderNamespace = "GFX11" in {
@@ -2198,84 +2556,84 @@ def BUFFER_GL0_INV_gfx11 : MUBUF_Real_gfx11<0x02B, BUFFER_GL0_INV>;
def BUFFER_GL1_INV_gfx11 : MUBUF_Real_gfx11<0x02C, BUFFER_GL1_INV>;
}
-defm BUFFER_LOAD_DWORD : MUBUF_Real_AllAddr_gfx11_Renamed<0x014, "buffer_load_b32">;
-defm BUFFER_LOAD_DWORDX2 : MUBUF_Real_AllAddr_gfx11_Renamed<0x015, "buffer_load_b64">;
-defm BUFFER_LOAD_DWORDX3 : MUBUF_Real_AllAddr_gfx11_Renamed<0x016, "buffer_load_b96">;
-defm BUFFER_LOAD_DWORDX4 : MUBUF_Real_AllAddr_gfx11_Renamed<0x017, "buffer_load_b128">;
-defm BUFFER_LOAD_SHORT_D16 : MUBUF_Real_AllAddr_gfx11_Renamed<0x020, "buffer_load_d16_b16">;
-defm BUFFER_LOAD_FORMAT_D16_X : MUBUF_Real_AllAddr_gfx11_Renamed<0x008, "buffer_load_d16_format_x">;
-defm BUFFER_LOAD_FORMAT_D16_XY : MUBUF_Real_AllAddr_gfx11_Renamed<0x009, "buffer_load_d16_format_xy">;
-defm BUFFER_LOAD_FORMAT_D16_XYZ : MUBUF_Real_AllAddr_gfx11_Renamed<0x00a, "buffer_load_d16_format_xyz">;
-defm BUFFER_LOAD_FORMAT_D16_XYZW : MUBUF_Real_AllAddr_gfx11_Renamed<0x00b, "buffer_load_d16_format_xyzw">;
-defm BUFFER_LOAD_SHORT_D16_HI : MUBUF_Real_AllAddr_gfx11_Renamed<0x023, "buffer_load_d16_hi_b16">;
-defm BUFFER_LOAD_FORMAT_D16_HI_X : MUBUF_Real_AllAddr_gfx11_Renamed<0x026, "buffer_load_d16_hi_format_x">;
-defm BUFFER_LOAD_SBYTE_D16_HI : MUBUF_Real_AllAddr_gfx11_Renamed<0x022, "buffer_load_d16_hi_i8">;
-defm BUFFER_LOAD_UBYTE_D16_HI : MUBUF_Real_AllAddr_gfx11_Renamed<0x021, "buffer_load_d16_hi_u8">;
-defm BUFFER_LOAD_SBYTE_D16 : MUBUF_Real_AllAddr_gfx11_Renamed<0x01f, "buffer_load_d16_i8">;
-defm BUFFER_LOAD_UBYTE_D16 : MUBUF_Real_AllAddr_gfx11_Renamed<0x01e, "buffer_load_d16_u8">;
-defm BUFFER_LOAD_FORMAT_X : MUBUF_Real_AllAddr_gfx11<0x000>;
-defm BUFFER_LOAD_FORMAT_XY : MUBUF_Real_AllAddr_gfx11<0x001>;
-defm BUFFER_LOAD_FORMAT_XYZ : MUBUF_Real_AllAddr_gfx11<0x002>;
-defm BUFFER_LOAD_FORMAT_XYZW : MUBUF_Real_AllAddr_gfx11<0x003>;
-defm BUFFER_LOAD_SBYTE : MUBUF_Real_AllAddr_gfx11_Renamed<0x011, "buffer_load_i8">;
-defm BUFFER_LOAD_SSHORT : MUBUF_Real_AllAddr_gfx11_Renamed<0x013, "buffer_load_i16">;
-defm BUFFER_LOAD_UBYTE : MUBUF_Real_AllAddr_gfx11_Renamed<0x010, "buffer_load_u8">;
-defm BUFFER_LOAD_USHORT : MUBUF_Real_AllAddr_gfx11_Renamed<0x012, "buffer_load_u16">;
+defm BUFFER_LOAD_DWORD : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x014, "buffer_load_b32">;
+defm BUFFER_LOAD_DWORDX2 : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x015, "buffer_load_b64">;
+defm BUFFER_LOAD_DWORDX3 : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x016, "buffer_load_b96">;
+defm BUFFER_LOAD_DWORDX4 : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x017, "buffer_load_b128">;
+defm BUFFER_LOAD_SHORT_D16 : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x020, "buffer_load_d16_b16">;
+defm BUFFER_LOAD_FORMAT_D16_X : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x008, "buffer_load_d16_format_x">;
+defm BUFFER_LOAD_FORMAT_D16_XY : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x009, "buffer_load_d16_format_xy">;
+defm BUFFER_LOAD_FORMAT_D16_XYZ : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00a, "buffer_load_d16_format_xyz">;
+defm BUFFER_LOAD_FORMAT_D16_XYZW : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00b, "buffer_load_d16_format_xyzw">;
+defm BUFFER_LOAD_SHORT_D16_HI : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x023, "buffer_load_d16_hi_b16">;
+defm BUFFER_LOAD_FORMAT_D16_HI_X : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x026, "buffer_load_d16_hi_format_x">;
+defm BUFFER_LOAD_SBYTE_D16_HI : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x022, "buffer_load_d16_hi_i8">;
+defm BUFFER_LOAD_UBYTE_D16_HI : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x021, "buffer_load_d16_hi_u8">;
+defm BUFFER_LOAD_SBYTE_D16 : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x01f, "buffer_load_d16_i8">;
+defm BUFFER_LOAD_UBYTE_D16 : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x01e, "buffer_load_d16_u8">;
+defm BUFFER_LOAD_FORMAT_X : MUBUF_Real_AllAddr_gfx11_gfx12<0x000>;
+defm BUFFER_LOAD_FORMAT_XY : MUBUF_Real_AllAddr_gfx11_gfx12<0x001>;
+defm BUFFER_LOAD_FORMAT_XYZ : MUBUF_Real_AllAddr_gfx11_gfx12<0x002>;
+defm BUFFER_LOAD_FORMAT_XYZW : MUBUF_Real_AllAddr_gfx11_gfx12<0x003>;
+defm BUFFER_LOAD_SBYTE : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x011, "buffer_load_i8">;
+defm BUFFER_LOAD_SSHORT : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x013, "buffer_load_i16">;
+defm BUFFER_LOAD_UBYTE : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x010, "buffer_load_u8">;
+defm BUFFER_LOAD_USHORT : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x012, "buffer_load_u16">;
defm BUFFER_LOAD_LDS_B32 : MUBUF_Real_AllAddr_gfx11<0x031, 0>;
defm BUFFER_LOAD_LDS_FORMAT_X : MUBUF_Real_AllAddr_gfx11<0x032, 0>;
defm BUFFER_LOAD_LDS_I8 : MUBUF_Real_AllAddr_gfx11<0x02e, 0>;
defm BUFFER_LOAD_LDS_I16 : MUBUF_Real_AllAddr_gfx11<0x030, 0>;
defm BUFFER_LOAD_LDS_U8 : MUBUF_Real_AllAddr_gfx11<0x02d, 0>;
defm BUFFER_LOAD_LDS_U16 : MUBUF_Real_AllAddr_gfx11<0x02f, 0>;
-defm BUFFER_STORE_BYTE : MUBUF_Real_AllAddr_gfx11_Renamed<0x018, "buffer_store_b8">;
-defm BUFFER_STORE_SHORT : MUBUF_Real_AllAddr_gfx11_Renamed<0x019, "buffer_store_b16">;
-defm BUFFER_STORE_DWORD : MUBUF_Real_AllAddr_gfx11_Renamed<0x01A, "buffer_store_b32">;
-defm BUFFER_STORE_DWORDX2 : MUBUF_Real_AllAddr_gfx11_Renamed<0x01B, "buffer_store_b64">;
-defm BUFFER_STORE_DWORDX3 : MUBUF_Real_AllAddr_gfx11_Renamed<0x01C, "buffer_store_b96">;
-defm BUFFER_STORE_DWORDX4 : MUBUF_Real_AllAddr_gfx11_Renamed<0x01D, "buffer_store_b128">;
-defm BUFFER_STORE_FORMAT_D16_X : MUBUF_Real_AllAddr_gfx11_Renamed<0x00C, "buffer_store_d16_format_x">;
-defm BUFFER_STORE_FORMAT_D16_XY : MUBUF_Real_AllAddr_gfx11_Renamed<0x00D, "buffer_store_d16_format_xy">;
-defm BUFFER_STORE_FORMAT_D16_XYZ : MUBUF_Real_AllAddr_gfx11_Renamed<0x00E, "buffer_store_d16_format_xyz">;
-defm BUFFER_STORE_FORMAT_D16_XYZW : MUBUF_Real_AllAddr_gfx11_Renamed<0x00F, "buffer_store_d16_format_xyzw">;
-defm BUFFER_STORE_BYTE_D16_HI : MUBUF_Real_AllAddr_gfx11_Renamed<0x024, "buffer_store_d16_hi_b8">;
-defm BUFFER_STORE_SHORT_D16_HI : MUBUF_Real_AllAddr_gfx11_Renamed<0x025, "buffer_store_d16_hi_b16">;
-defm BUFFER_STORE_FORMAT_D16_HI_X : MUBUF_Real_AllAddr_gfx11_Renamed<0x027, "buffer_store_d16_hi_format_x">;
-defm BUFFER_STORE_FORMAT_X : MUBUF_Real_AllAddr_gfx11<0x004>;
-defm BUFFER_STORE_FORMAT_XY : MUBUF_Real_AllAddr_gfx11<0x005>;
-defm BUFFER_STORE_FORMAT_XYZ : MUBUF_Real_AllAddr_gfx11<0x006>;
-defm BUFFER_STORE_FORMAT_XYZW : MUBUF_Real_AllAddr_gfx11<0x007>;
-defm BUFFER_ATOMIC_ADD_F32 : MUBUF_Real_Atomic_gfx11<0x056>;
-defm BUFFER_ATOMIC_ADD : MUBUF_Real_Atomic_gfx11_Renamed<0x035, "buffer_atomic_add_u32">;
-defm BUFFER_ATOMIC_ADD_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x043, "buffer_atomic_add_u64">;
-defm BUFFER_ATOMIC_AND : MUBUF_Real_Atomic_gfx11_Renamed<0x03C, "buffer_atomic_and_b32">;
-defm BUFFER_ATOMIC_AND_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x049, "buffer_atomic_and_b64">;
-defm BUFFER_ATOMIC_CMPSWAP : MUBUF_Real_Atomic_gfx11_Renamed<0x034, "buffer_atomic_cmpswap_b32">;
-defm BUFFER_ATOMIC_CMPSWAP_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x042, "buffer_atomic_cmpswap_b64">;
+defm BUFFER_STORE_BYTE : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x018, "buffer_store_b8">;
+defm BUFFER_STORE_SHORT : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x019, "buffer_store_b16">;
+defm BUFFER_STORE_DWORD : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x01A, "buffer_store_b32">;
+defm BUFFER_STORE_DWORDX2 : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x01B, "buffer_store_b64">;
+defm BUFFER_STORE_DWORDX3 : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x01C, "buffer_store_b96">;
+defm BUFFER_STORE_DWORDX4 : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x01D, "buffer_store_b128">;
+defm BUFFER_STORE_FORMAT_D16_X : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00C, "buffer_store_d16_format_x">;
+defm BUFFER_STORE_FORMAT_D16_XY : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00D, "buffer_store_d16_format_xy">;
+defm BUFFER_STORE_FORMAT_D16_XYZ : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00E, "buffer_store_d16_format_xyz">;
+defm BUFFER_STORE_FORMAT_D16_XYZW : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00F, "buffer_store_d16_format_xyzw">;
+defm BUFFER_STORE_BYTE_D16_HI : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x024, "buffer_store_d16_hi_b8">;
+defm BUFFER_STORE_SHORT_D16_HI : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x025, "buffer_store_d16_hi_b16">;
+defm BUFFER_STORE_FORMAT_D16_HI_X : MUBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x027, "buffer_store_d16_hi_format_x">;
+defm BUFFER_STORE_FORMAT_X : MUBUF_Real_AllAddr_gfx11_gfx12<0x004>;
+defm BUFFER_STORE_FORMAT_XY : MUBUF_Real_AllAddr_gfx11_gfx12<0x005>;
+defm BUFFER_STORE_FORMAT_XYZ : MUBUF_Real_AllAddr_gfx11_gfx12<0x006>;
+defm BUFFER_STORE_FORMAT_XYZW : MUBUF_Real_AllAddr_gfx11_gfx12<0x007>;
+defm BUFFER_ATOMIC_ADD_F32 : MUBUF_Real_Atomic_gfx11_gfx12<0x056>;
+defm BUFFER_ATOMIC_ADD : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x035, "buffer_atomic_add_u32">;
+defm BUFFER_ATOMIC_ADD_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x043, "buffer_atomic_add_u64">;
+defm BUFFER_ATOMIC_AND : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x03C, "buffer_atomic_and_b32">;
+defm BUFFER_ATOMIC_AND_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x049, "buffer_atomic_and_b64">;
+defm BUFFER_ATOMIC_CMPSWAP : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x034, "buffer_atomic_cmpswap_b32">;
+defm BUFFER_ATOMIC_CMPSWAP_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x042, "buffer_atomic_cmpswap_b64">;
defm BUFFER_ATOMIC_FCMPSWAP : MUBUF_Real_Atomic_gfx11_Renamed<0x050, "buffer_atomic_cmpswap_f32">;
-defm BUFFER_ATOMIC_CSUB : MUBUF_Real_Atomic_gfx11_Renamed<0x037, "buffer_atomic_csub_u32">;
-def : Pre_gfx11_MUBUF_Name<"buffer_atomic_csub", "buffer_atomic_csub_u32">;
-defm BUFFER_ATOMIC_DEC : MUBUF_Real_Atomic_gfx11_Renamed<0x040, "buffer_atomic_dec_u32">;
-defm BUFFER_ATOMIC_DEC_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x04D, "buffer_atomic_dec_u64">;
-defm BUFFER_ATOMIC_INC : MUBUF_Real_Atomic_gfx11_Renamed<0x03F, "buffer_atomic_inc_u32">;
-defm BUFFER_ATOMIC_INC_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x04C, "buffer_atomic_inc_u64">;
-defm BUFFER_ATOMIC_FMAX : MUBUF_Real_Atomic_gfx11_Renamed<0x052, "buffer_atomic_max_f32">;
-defm BUFFER_ATOMIC_SMAX : MUBUF_Real_Atomic_gfx11_Renamed<0x03A, "buffer_atomic_max_i32">;
-defm BUFFER_ATOMIC_SMAX_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x047, "buffer_atomic_max_i64">;
-defm BUFFER_ATOMIC_UMAX : MUBUF_Real_Atomic_gfx11_Renamed<0x03B, "buffer_atomic_max_u32">;
-defm BUFFER_ATOMIC_UMAX_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x048, "buffer_atomic_max_u64">;
-defm BUFFER_ATOMIC_FMIN : MUBUF_Real_Atomic_gfx11_Renamed<0x051, "buffer_atomic_min_f32">;
-defm BUFFER_ATOMIC_SMIN : MUBUF_Real_Atomic_gfx11_Renamed<0x038, "buffer_atomic_min_i32">;
-defm BUFFER_ATOMIC_SMIN_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x045, "buffer_atomic_min_i64">;
-defm BUFFER_ATOMIC_UMIN : MUBUF_Real_Atomic_gfx11_Renamed<0x039, "buffer_atomic_min_u32">;
-defm BUFFER_ATOMIC_UMIN_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x046, "buffer_atomic_min_u64">;
-defm BUFFER_ATOMIC_OR : MUBUF_Real_Atomic_gfx11_Renamed<0x03D, "buffer_atomic_or_b32">;
-defm BUFFER_ATOMIC_OR_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x04A, "buffer_atomic_or_b64">;
-defm BUFFER_ATOMIC_SUB : MUBUF_Real_Atomic_gfx11_Renamed<0x036, "buffer_atomic_sub_u32">;
-defm BUFFER_ATOMIC_SUB_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x044, "buffer_atomic_sub_u64">;
-defm BUFFER_ATOMIC_SWAP : MUBUF_Real_Atomic_gfx11_Renamed<0x033, "buffer_atomic_swap_b32">;
-defm BUFFER_ATOMIC_SWAP_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x041, "buffer_atomic_swap_b64">;
-defm BUFFER_ATOMIC_XOR : MUBUF_Real_Atomic_gfx11_Renamed<0x03E, "buffer_atomic_xor_b32">;
-defm BUFFER_ATOMIC_XOR_X2 : MUBUF_Real_Atomic_gfx11_Renamed<0x04B, "buffer_atomic_xor_b64">;
+defm BUFFER_ATOMIC_CSUB : MUBUF_Real_Atomic_gfx11_gfx12_Renamed_gfx12_Renamed<0x037, "buffer_atomic_sub_clamp_u32", "buffer_atomic_csub_u32">;
+def : Mnem_gfx11_gfx12<"buffer_atomic_csub", "buffer_atomic_csub_u32">;
+defm BUFFER_ATOMIC_DEC : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x040, "buffer_atomic_dec_u32">;
+defm BUFFER_ATOMIC_DEC_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x04D, "buffer_atomic_dec_u64">;
+defm BUFFER_ATOMIC_INC : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x03F, "buffer_atomic_inc_u32">;
+defm BUFFER_ATOMIC_INC_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x04C, "buffer_atomic_inc_u64">;
+defm BUFFER_ATOMIC_FMAX : MUBUF_Real_Atomic_gfx11_gfx12_Renamed_gfx12_Renamed<0x052, "buffer_atomic_max_num_f32", "buffer_atomic_max_f32">;
+defm BUFFER_ATOMIC_SMAX : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x03A, "buffer_atomic_max_i32">;
+defm BUFFER_ATOMIC_SMAX_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x047, "buffer_atomic_max_i64">;
+defm BUFFER_ATOMIC_UMAX : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x03B, "buffer_atomic_max_u32">;
+defm BUFFER_ATOMIC_UMAX_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x048, "buffer_atomic_max_u64">;
+defm BUFFER_ATOMIC_FMIN : MUBUF_Real_Atomic_gfx11_gfx12_Renamed_gfx12_Renamed<0x051, "buffer_atomic_min_num_f32", "buffer_atomic_min_f32">;
+defm BUFFER_ATOMIC_SMIN : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x038, "buffer_atomic_min_i32">;
+defm BUFFER_ATOMIC_SMIN_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x045, "buffer_atomic_min_i64">;
+defm BUFFER_ATOMIC_UMIN : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x039, "buffer_atomic_min_u32">;
+defm BUFFER_ATOMIC_UMIN_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x046, "buffer_atomic_min_u64">;
+defm BUFFER_ATOMIC_OR : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x03D, "buffer_atomic_or_b32">;
+defm BUFFER_ATOMIC_OR_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x04A, "buffer_atomic_or_b64">;
+defm BUFFER_ATOMIC_SUB : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x036, "buffer_atomic_sub_u32">;
+defm BUFFER_ATOMIC_SUB_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x044, "buffer_atomic_sub_u64">;
+defm BUFFER_ATOMIC_SWAP : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x033, "buffer_atomic_swap_b32">;
+defm BUFFER_ATOMIC_SWAP_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x041, "buffer_atomic_swap_b64">;
+defm BUFFER_ATOMIC_XOR : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x03E, "buffer_atomic_xor_b32">;
+defm BUFFER_ATOMIC_XOR_X2 : MUBUF_Real_Atomic_gfx11_gfx12_Renamed<0x04B, "buffer_atomic_xor_b64">;
//===----------------------------------------------------------------------===//
// MUBUF - GFX10.
@@ -2571,47 +2929,59 @@ class Base_MTBUF_Real_gfx6_gfx7_gfx10<bits<3> op, MTBUF_Pseudo ps, int ef> :
// MTBUF - GFX11.
//===----------------------------------------------------------------------===//
-let AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11" in
-multiclass MTBUF_Real_AllAddr_gfx11_Renamed_Impl<bits<4> op, string real_name> {
- def _BOTHEN_gfx11 :
- Base_MTBUF_Real_gfx11<op, !cast<MTBUF_Pseudo>(NAME#"_BOTHEN"), real_name>;
- def _IDXEN_gfx11 :
- Base_MTBUF_Real_gfx11<op, !cast<MTBUF_Pseudo>(NAME#"_IDXEN"), real_name>;
- def _OFFEN_gfx11 :
- Base_MTBUF_Real_gfx11<op, !cast<MTBUF_Pseudo>(NAME#"_OFFEN"), real_name>;
- def _OFFSET_gfx11 :
- Base_MTBUF_Real_gfx11<op, !cast<MTBUF_Pseudo>(NAME#"_OFFSET"), real_name>;
+multiclass MTBUF_Real_AllAddr_gfx11_gfx12_Renamed_Impl<bits<4> op, string real_name> {
+ let AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11" in {
+ def _BOTHEN_gfx11 :
+ Base_MTBUF_Real_gfx11<op, !cast<MTBUF_Pseudo>(NAME#"_BOTHEN"), real_name>;
+ def _IDXEN_gfx11 :
+ Base_MTBUF_Real_gfx11<op, !cast<MTBUF_Pseudo>(NAME#"_IDXEN"), real_name>;
+ def _OFFEN_gfx11 :
+ Base_MTBUF_Real_gfx11<op, !cast<MTBUF_Pseudo>(NAME#"_OFFEN"), real_name>;
+ def _OFFSET_gfx11 :
+ Base_MTBUF_Real_gfx11<op, !cast<MTBUF_Pseudo>(NAME#"_OFFSET"), real_name>;
+ }
+
+ let AssemblerPredicate = isGFX12Plus, DecoderNamespace = "GFX12" in {
+ def _BOTHEN_gfx12 :
+ VBUFFER_MTBUF_Real_gfx12<op, !cast<MTBUF_Pseudo>(NAME#"_VBUFFER_BOTHEN"), real_name>;
+ def _IDXEN_gfx12 :
+ VBUFFER_MTBUF_Real_gfx12<op, !cast<MTBUF_Pseudo>(NAME#"_VBUFFER_IDXEN"), real_name>;
+ def _OFFEN_gfx12 :
+ VBUFFER_MTBUF_Real_gfx12<op, !cast<MTBUF_Pseudo>(NAME#"_VBUFFER_OFFEN"), real_name>;
+ def _OFFSET_gfx12 :
+ VBUFFER_MTBUF_Real_gfx12<op, !cast<MTBUF_Pseudo>(NAME#"_VBUFFER_OFFSET"), real_name>;
+ }
}
-multiclass MTBUF_Real_AllAddr_gfx11_Impl<bits<4> op, MTBUF_Pseudo ps>
- : MTBUF_Real_AllAddr_gfx11_Renamed_Impl<op, ps.Mnemonic>;
-multiclass MTBUF_Real_AllAddr_gfx11<bits<4> op>
- : MTBUF_Real_AllAddr_gfx11_Impl<op, !cast<MTBUF_Pseudo>(NAME#"_BOTHEN")>;
+multiclass MTBUF_Real_AllAddr_gfx11_gfx12_Impl<bits<4> op, MTBUF_Pseudo ps>
+ : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed_Impl<op, ps.Mnemonic>;
+multiclass MTBUF_Real_AllAddr_gfx11_gfx12<bits<4> op>
+ : MTBUF_Real_AllAddr_gfx11_gfx12_Impl<op, !cast<MTBUF_Pseudo>(NAME#"_BOTHEN")>;
class Pre_gfx11_MTBUF_Name <MTBUF_Pseudo ps, string real_name>
: MnemonicAlias<ps.Mnemonic, real_name>, Requires<[isGFX11Plus]>;
-multiclass MTBUF_Real_AllAddr_gfx11_Renamed<bits<4> op, string real_name>
- : MTBUF_Real_AllAddr_gfx11_Renamed_Impl<op, real_name> {
+multiclass MTBUF_Real_AllAddr_gfx11_gfx12_Renamed<bits<4> op, string real_name>
+ : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed_Impl<op, real_name> {
def : Pre_gfx11_MTBUF_Name<!cast<MTBUF_Pseudo>(NAME#"_BOTHEN"), real_name>;
}
-defm TBUFFER_LOAD_FORMAT_D16_X : MTBUF_Real_AllAddr_gfx11_Renamed<0x008, "tbuffer_load_d16_format_x">;
-defm TBUFFER_LOAD_FORMAT_D16_XY : MTBUF_Real_AllAddr_gfx11_Renamed<0x009, "tbuffer_load_d16_format_xy">;
-defm TBUFFER_LOAD_FORMAT_D16_XYZ : MTBUF_Real_AllAddr_gfx11_Renamed<0x00a, "tbuffer_load_d16_format_xyz">;
-defm TBUFFER_LOAD_FORMAT_D16_XYZW : MTBUF_Real_AllAddr_gfx11_Renamed<0x00b, "tbuffer_load_d16_format_xyzw">;
-defm TBUFFER_LOAD_FORMAT_X : MTBUF_Real_AllAddr_gfx11<0x000>;
-defm TBUFFER_LOAD_FORMAT_XY : MTBUF_Real_AllAddr_gfx11<0x001>;
-defm TBUFFER_LOAD_FORMAT_XYZ : MTBUF_Real_AllAddr_gfx11<0x002>;
-defm TBUFFER_LOAD_FORMAT_XYZW : MTBUF_Real_AllAddr_gfx11<0x003>;
-defm TBUFFER_STORE_FORMAT_D16_X : MTBUF_Real_AllAddr_gfx11_Renamed<0x00c, "tbuffer_store_d16_format_x">;
-defm TBUFFER_STORE_FORMAT_D16_XY : MTBUF_Real_AllAddr_gfx11_Renamed<0x00d, "tbuffer_store_d16_format_xy">;
-defm TBUFFER_STORE_FORMAT_D16_XYZ : MTBUF_Real_AllAddr_gfx11_Renamed<0x00e, "tbuffer_store_d16_format_xyz">;
-defm TBUFFER_STORE_FORMAT_D16_XYZW : MTBUF_Real_AllAddr_gfx11_Renamed<0x00f, "tbuffer_store_d16_format_xyzw">;
-defm TBUFFER_STORE_FORMAT_X : MTBUF_Real_AllAddr_gfx11<0x004>;
-defm TBUFFER_STORE_FORMAT_XY : MTBUF_Real_AllAddr_gfx11<0x005>;
-defm TBUFFER_STORE_FORMAT_XYZ : MTBUF_Real_AllAddr_gfx11<0x006>;
-defm TBUFFER_STORE_FORMAT_XYZW : MTBUF_Real_AllAddr_gfx11<0x007>;
+defm TBUFFER_LOAD_FORMAT_D16_X : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x008, "tbuffer_load_d16_format_x">;
+defm TBUFFER_LOAD_FORMAT_D16_XY : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x009, "tbuffer_load_d16_format_xy">;
+defm TBUFFER_LOAD_FORMAT_D16_XYZ : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00a, "tbuffer_load_d16_format_xyz">;
+defm TBUFFER_LOAD_FORMAT_D16_XYZW : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00b, "tbuffer_load_d16_format_xyzw">;
+defm TBUFFER_LOAD_FORMAT_X : MTBUF_Real_AllAddr_gfx11_gfx12<0x000>;
+defm TBUFFER_LOAD_FORMAT_XY : MTBUF_Real_AllAddr_gfx11_gfx12<0x001>;
+defm TBUFFER_LOAD_FORMAT_XYZ : MTBUF_Real_AllAddr_gfx11_gfx12<0x002>;
+defm TBUFFER_LOAD_FORMAT_XYZW : MTBUF_Real_AllAddr_gfx11_gfx12<0x003>;
+defm TBUFFER_STORE_FORMAT_D16_X : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00c, "tbuffer_store_d16_format_x">;
+defm TBUFFER_STORE_FORMAT_D16_XY : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00d, "tbuffer_store_d16_format_xy">;
+defm TBUFFER_STORE_FORMAT_D16_XYZ : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00e, "tbuffer_store_d16_format_xyz">;
+defm TBUFFER_STORE_FORMAT_D16_XYZW : MTBUF_Real_AllAddr_gfx11_gfx12_Renamed<0x00f, "tbuffer_store_d16_format_xyzw">;
+defm TBUFFER_STORE_FORMAT_X : MTBUF_Real_AllAddr_gfx11_gfx12<0x004>;
+defm TBUFFER_STORE_FORMAT_XY : MTBUF_Real_AllAddr_gfx11_gfx12<0x005>;
+defm TBUFFER_STORE_FORMAT_XYZ : MTBUF_Real_AllAddr_gfx11_gfx12<0x006>;
+defm TBUFFER_STORE_FORMAT_XYZW : MTBUF_Real_AllAddr_gfx11_gfx12<0x007>;
//===----------------------------------------------------------------------===//
// MTBUF - GFX10.
diff --git a/llvm/lib/Target/AMDGPU/DSInstructions.td b/llvm/lib/Target/AMDGPU/DSInstructions.td
index 1a10a8fcaadc..3a895923fa4b 100644
--- a/llvm/lib/Target/AMDGPU/DSInstructions.td
+++ b/llvm/lib/Target/AMDGPU/DSInstructions.td
@@ -711,18 +711,34 @@ def DS_ADD_SRC2_F32 : DS_1A<"ds_add_src2_f32">;
//===----------------------------------------------------------------------===//
-// Instruction definitions for GFX11 and newer.
+// Instruction definitions for GFX11.
//===----------------------------------------------------------------------===//
-let SubtargetPredicate = isGFX11Plus in {
+let SubtargetPredicate = isGFX11Only in {
def DS_ADD_GS_REG_RTN : DS_0A1D_RET_GDS<"ds_add_gs_reg_rtn", VReg_64, VGPR_32>;
def DS_SUB_GS_REG_RTN : DS_0A1D_RET_GDS<"ds_sub_gs_reg_rtn", VReg_64, VGPR_32>;
+
+} // let SubtargetPredicate = isGFX11Only
+
+let SubtargetPredicate = isGFX11Plus in {
+
def DS_BVH_STACK_RTN_B32 : DS_BVH_STACK<"ds_bvh_stack_rtn_b32">;
} // let SubtargetPredicate = isGFX11Plus
//===----------------------------------------------------------------------===//
+// Instruction definitions for GFX12 and newer.
+//===----------------------------------------------------------------------===//
+
+let SubtargetPredicate = isGFX12Plus in {
+
+defm DS_SUB_CLAMP_U32 : DS_1A1D_NORET_mc<"ds_sub_clamp_u32">;
+defm DS_SUB_CLAMP_RTN_U32 : DS_1A1D_RET_mc<"ds_sub_clamp_rtn_u32", VGPR_32, "ds_sub_clamp_u32">;
+
+} // let SubtargetPredicate = isGFX12Plus
+
+//===----------------------------------------------------------------------===//
// DS Patterns
//===----------------------------------------------------------------------===//
@@ -1169,11 +1185,12 @@ def : GCNPat <
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
-// Base ENC_DS for GFX6, GFX7, GFX10, GFX11.
+// Base ENC_DS for GFX6, GFX7, GFX10, GFX11, GFX12.
//===----------------------------------------------------------------------===//
-class Base_DS_Real_gfx6_gfx7_gfx10_gfx11<bits<8> op, DS_Pseudo ps, int ef, string opName = ps.Mnemonic> :
- DS_Real<ps, opName>, SIMCInstr <ps.Mnemonic, ef> {
+class Base_DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<bits<8> op, DS_Pseudo ps, int ef,
+ string opName = ps.Mnemonic>
+ : DS_Real<ps, opName>, SIMCInstr <ps.Mnemonic, ef> {
let Inst{7-0} = !if(ps.has_offset0, offset0, 0);
let Inst{15-8} = !if(ps.has_offset1, offset1, 0);
@@ -1187,74 +1204,117 @@ class Base_DS_Real_gfx6_gfx7_gfx10_gfx11<bits<8> op, DS_Pseudo ps, int ef, strin
}
//===----------------------------------------------------------------------===//
+// GFX12.
+//===----------------------------------------------------------------------===//
+
+let AssemblerPredicate = isGFX12Plus, DecoderNamespace = "GFX12" in {
+ multiclass DS_Real_gfx12<bits<8> op> {
+ defvar ps = !cast<DS_Pseudo>(NAME);
+ def _gfx12 :
+ Base_DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<op, ps, SIEncodingFamily.GFX12,
+ ps.Mnemonic>;
+ }
+
+ multiclass DS_Real_Renamed_gfx12<bits<8> op, DS_Pseudo backing_pseudo,
+ string real_name> {
+ def _gfx12 :
+ Base_DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<op, backing_pseudo,
+ SIEncodingFamily.GFX12,
+ real_name>,
+ MnemonicAlias<backing_pseudo.Mnemonic, real_name>,
+ Requires<[isGFX12Plus]>;
+ }
+} // End AssemblerPredicate = isGFX12Plus, DecoderNamespace = "GFX12"
+
+defm DS_MIN_NUM_F32 : DS_Real_Renamed_gfx12<0x012, DS_MIN_F32, "ds_min_num_f32">;
+defm DS_MAX_NUM_F32 : DS_Real_Renamed_gfx12<0x013, DS_MAX_F32, "ds_max_num_f32">;
+defm DS_MIN_NUM_RTN_F32 : DS_Real_Renamed_gfx12<0x032, DS_MIN_RTN_F32, "ds_min_num_rtn_f32">;
+defm DS_MAX_NUM_RTN_F32 : DS_Real_Renamed_gfx12<0x033, DS_MAX_RTN_F32, "ds_max_num_rtn_f32">;
+defm DS_MIN_NUM_F64 : DS_Real_Renamed_gfx12<0x052, DS_MIN_F64, "ds_min_num_f64">;
+defm DS_MAX_NUM_F64 : DS_Real_Renamed_gfx12<0x053, DS_MAX_F64, "ds_max_num_f64">;
+defm DS_MIN_NUM_RTN_F64 : DS_Real_Renamed_gfx12<0x072, DS_MIN_RTN_F64, "ds_min_num_rtn_f64">;
+defm DS_MAX_NUM_RTN_F64 : DS_Real_Renamed_gfx12<0x073, DS_MAX_RTN_F64, "ds_max_num_rtn_f64">;
+defm DS_SUB_CLAMP_U32 : DS_Real_gfx12<0x099>;
+defm DS_SUB_CLAMP_RTN_U32 : DS_Real_gfx12<0x0a9>;
+
+//===----------------------------------------------------------------------===//
// GFX11.
//===----------------------------------------------------------------------===//
-let AssemblerPredicate = isGFX11Plus, DecoderNamespace = "GFX11" in {
+let AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11" in {
multiclass DS_Real_gfx11<bits<8> op> {
- def _gfx11 : Base_DS_Real_gfx6_gfx7_gfx10_gfx11<op, !cast<DS_Pseudo>(NAME),
+ def _gfx11 :
+ Base_DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<op, !cast<DS_Pseudo>(NAME),
SIEncodingFamily.GFX11>;
}
multiclass DS_Real_Renamed_gfx11<bits<8> op, DS_Pseudo backing_pseudo, string real_name> {
- def _gfx11 : Base_DS_Real_gfx6_gfx7_gfx10_gfx11<op, backing_pseudo, SIEncodingFamily.GFX11, real_name>,
- MnemonicAlias<backing_pseudo.Mnemonic, real_name>, Requires<[isGFX11Plus]>;
+ def _gfx11 : Base_DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<op, backing_pseudo, SIEncodingFamily.GFX11, real_name>,
+ MnemonicAlias<backing_pseudo.Mnemonic, real_name>, Requires<[isGFX11Only]>;
}
-} // End AssemblerPredicate = isGFX11Plus, DecoderNamespace = "GFX11"
-
-defm DS_STORE_B32 : DS_Real_Renamed_gfx11<0x00d, DS_WRITE_B32, "ds_store_b32">;
-defm DS_STORE_2ADDR_B32 : DS_Real_Renamed_gfx11<0x00e, DS_WRITE2_B32, "ds_store_2addr_b32">;
-defm DS_STORE_2ADDR_STRIDE64_B32 : DS_Real_Renamed_gfx11<0x00f, DS_WRITE2ST64_B32, "ds_store_2addr_stride64_b32">;
-defm DS_STORE_B8 : DS_Real_Renamed_gfx11<0x01e, DS_WRITE_B8, "ds_store_b8">;
-defm DS_STORE_B16 : DS_Real_Renamed_gfx11<0x01f, DS_WRITE_B16, "ds_store_b16">;
-defm DS_STOREXCHG_RTN_B32 : DS_Real_Renamed_gfx11<0x02d, DS_WRXCHG_RTN_B32, "ds_storexchg_rtn_b32">;
-defm DS_STOREXCHG_2ADDR_RTN_B32 : DS_Real_Renamed_gfx11<0x02e, DS_WRXCHG2_RTN_B32, "ds_storexchg_2addr_rtn_b32">;
-defm DS_STOREXCHG_2ADDR_STRIDE64_RTN_B32 : DS_Real_Renamed_gfx11<0x02f, DS_WRXCHG2ST64_RTN_B32, "ds_storexchg_2addr_stride64_rtn_b32">;
-defm DS_LOAD_B32 : DS_Real_Renamed_gfx11<0x036, DS_READ_B32, "ds_load_b32">;
-defm DS_LOAD_2ADDR_B32 : DS_Real_Renamed_gfx11<0x037, DS_READ2_B32, "ds_load_2addr_b32">;
-defm DS_LOAD_2ADDR_STRIDE64_B32 : DS_Real_Renamed_gfx11<0x038, DS_READ2ST64_B32, "ds_load_2addr_stride64_b32">;
-defm DS_LOAD_I8 : DS_Real_Renamed_gfx11<0x039, DS_READ_I8, "ds_load_i8">;
-defm DS_LOAD_U8 : DS_Real_Renamed_gfx11<0x03a, DS_READ_U8, "ds_load_u8">;
-defm DS_LOAD_I16 : DS_Real_Renamed_gfx11<0x03b, DS_READ_I16, "ds_load_i16">;
-defm DS_LOAD_U16 : DS_Real_Renamed_gfx11<0x03c, DS_READ_U16, "ds_load_u16">;
-defm DS_STORE_B64 : DS_Real_Renamed_gfx11<0x04d, DS_WRITE_B64, "ds_store_b64">;
-defm DS_STORE_2ADDR_B64 : DS_Real_Renamed_gfx11<0x04e, DS_WRITE2_B64, "ds_store_2addr_b64">;
-defm DS_STORE_2ADDR_STRIDE64_B64 : DS_Real_Renamed_gfx11<0x04f, DS_WRITE2ST64_B64, "ds_store_2addr_stride64_b64">;
-defm DS_STOREXCHG_RTN_B64 : DS_Real_Renamed_gfx11<0x06d, DS_WRXCHG_RTN_B64, "ds_storexchg_rtn_b64">;
-defm DS_STOREXCHG_2ADDR_RTN_B64 : DS_Real_Renamed_gfx11<0x06e, DS_WRXCHG2_RTN_B64, "ds_storexchg_2addr_rtn_b64">;
-defm DS_STOREXCHG_2ADDR_STRIDE64_RTN_B64 : DS_Real_Renamed_gfx11<0x06f, DS_WRXCHG2ST64_RTN_B64, "ds_storexchg_2addr_stride64_rtn_b64">;
-defm DS_LOAD_B64 : DS_Real_Renamed_gfx11<0x076, DS_READ_B64, "ds_load_b64">;
-defm DS_LOAD_2ADDR_B64 : DS_Real_Renamed_gfx11<0x077, DS_READ2_B64, "ds_load_2addr_b64">;
-defm DS_LOAD_2ADDR_STRIDE64_B64 : DS_Real_Renamed_gfx11<0x078, DS_READ2ST64_B64, "ds_load_2addr_stride64_b64">;
-defm DS_STORE_B8_D16_HI : DS_Real_Renamed_gfx11<0x0a0, DS_WRITE_B8_D16_HI, "ds_store_b8_d16_hi">;
-defm DS_STORE_B16_D16_HI : DS_Real_Renamed_gfx11<0x0a1, DS_WRITE_B16_D16_HI, "ds_store_b16_d16_hi">;
-defm DS_LOAD_U8_D16 : DS_Real_Renamed_gfx11<0x0a2, DS_READ_U8_D16, "ds_load_u8_d16">;
-defm DS_LOAD_U8_D16_HI : DS_Real_Renamed_gfx11<0x0a3, DS_READ_U8_D16_HI, "ds_load_u8_d16_hi">;
-defm DS_LOAD_I8_D16 : DS_Real_Renamed_gfx11<0x0a4, DS_READ_I8_D16, "ds_load_i8_d16">;
-defm DS_LOAD_I8_D16_HI : DS_Real_Renamed_gfx11<0x0a5, DS_READ_I8_D16_HI, "ds_load_i8_d16_hi">;
-defm DS_LOAD_U16_D16 : DS_Real_Renamed_gfx11<0x0a6, DS_READ_U16_D16, "ds_load_u16_d16">;
-defm DS_LOAD_U16_D16_HI : DS_Real_Renamed_gfx11<0x0a7, DS_READ_U16_D16_HI, "ds_load_u16_d16_hi">;
-defm DS_STORE_ADDTID_B32 : DS_Real_Renamed_gfx11<0x0b0, DS_WRITE_ADDTID_B32, "ds_store_addtid_b32">;
-defm DS_LOAD_ADDTID_B32 : DS_Real_Renamed_gfx11<0x0b1, DS_READ_ADDTID_B32, "ds_load_addtid_b32">;
-defm DS_STORE_B96 : DS_Real_Renamed_gfx11<0x0de, DS_WRITE_B96, "ds_store_b96">;
-defm DS_STORE_B128 : DS_Real_Renamed_gfx11<0x0df, DS_WRITE_B128, "ds_store_b128">;
-defm DS_LOAD_B96 : DS_Real_Renamed_gfx11<0x0fe, DS_READ_B96, "ds_load_b96">;
-defm DS_LOAD_B128 : DS_Real_Renamed_gfx11<0x0ff, DS_READ_B128, "ds_load_b128">;
+} // End AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11"
+
+multiclass DS_Real_gfx11_gfx12<bits<8> op>
+ : DS_Real_gfx11<op>, DS_Real_gfx12<op>;
+
+multiclass DS_Real_Renamed_gfx11_gfx12<bits<8> op, DS_Pseudo backing_pseudo,
+ string real_name>
+ : DS_Real_Renamed_gfx11<op, backing_pseudo, real_name>,
+ DS_Real_Renamed_gfx12<op, backing_pseudo, real_name>;
+
+defm DS_STORE_B32 : DS_Real_Renamed_gfx11_gfx12<0x00d, DS_WRITE_B32, "ds_store_b32">;
+defm DS_STORE_2ADDR_B32 : DS_Real_Renamed_gfx11_gfx12<0x00e, DS_WRITE2_B32, "ds_store_2addr_b32">;
+defm DS_STORE_2ADDR_STRIDE64_B32 : DS_Real_Renamed_gfx11_gfx12<0x00f, DS_WRITE2ST64_B32, "ds_store_2addr_stride64_b32">;
+defm DS_STORE_B8 : DS_Real_Renamed_gfx11_gfx12<0x01e, DS_WRITE_B8, "ds_store_b8">;
+defm DS_STORE_B16 : DS_Real_Renamed_gfx11_gfx12<0x01f, DS_WRITE_B16, "ds_store_b16">;
+defm DS_STOREXCHG_RTN_B32 : DS_Real_Renamed_gfx11_gfx12<0x02d, DS_WRXCHG_RTN_B32, "ds_storexchg_rtn_b32">;
+defm DS_STOREXCHG_2ADDR_RTN_B32 : DS_Real_Renamed_gfx11_gfx12<0x02e, DS_WRXCHG2_RTN_B32, "ds_storexchg_2addr_rtn_b32">;
+defm DS_STOREXCHG_2ADDR_STRIDE64_RTN_B32 : DS_Real_Renamed_gfx11_gfx12<0x02f, DS_WRXCHG2ST64_RTN_B32, "ds_storexchg_2addr_stride64_rtn_b32">;
+defm DS_LOAD_B32 : DS_Real_Renamed_gfx11_gfx12<0x036, DS_READ_B32, "ds_load_b32">;
+defm DS_LOAD_2ADDR_B32 : DS_Real_Renamed_gfx11_gfx12<0x037, DS_READ2_B32, "ds_load_2addr_b32">;
+defm DS_LOAD_2ADDR_STRIDE64_B32 : DS_Real_Renamed_gfx11_gfx12<0x038, DS_READ2ST64_B32, "ds_load_2addr_stride64_b32">;
+defm DS_LOAD_I8 : DS_Real_Renamed_gfx11_gfx12<0x039, DS_READ_I8, "ds_load_i8">;
+defm DS_LOAD_U8 : DS_Real_Renamed_gfx11_gfx12<0x03a, DS_READ_U8, "ds_load_u8">;
+defm DS_LOAD_I16 : DS_Real_Renamed_gfx11_gfx12<0x03b, DS_READ_I16, "ds_load_i16">;
+defm DS_LOAD_U16 : DS_Real_Renamed_gfx11_gfx12<0x03c, DS_READ_U16, "ds_load_u16">;
+defm DS_STORE_B64 : DS_Real_Renamed_gfx11_gfx12<0x04d, DS_WRITE_B64, "ds_store_b64">;
+defm DS_STORE_2ADDR_B64 : DS_Real_Renamed_gfx11_gfx12<0x04e, DS_WRITE2_B64, "ds_store_2addr_b64">;
+defm DS_STORE_2ADDR_STRIDE64_B64 : DS_Real_Renamed_gfx11_gfx12<0x04f, DS_WRITE2ST64_B64, "ds_store_2addr_stride64_b64">;
+defm DS_STOREXCHG_RTN_B64 : DS_Real_Renamed_gfx11_gfx12<0x06d, DS_WRXCHG_RTN_B64, "ds_storexchg_rtn_b64">;
+defm DS_STOREXCHG_2ADDR_RTN_B64 : DS_Real_Renamed_gfx11_gfx12<0x06e, DS_WRXCHG2_RTN_B64, "ds_storexchg_2addr_rtn_b64">;
+defm DS_STOREXCHG_2ADDR_STRIDE64_RTN_B64 : DS_Real_Renamed_gfx11_gfx12<0x06f, DS_WRXCHG2ST64_RTN_B64, "ds_storexchg_2addr_stride64_rtn_b64">;
+defm DS_LOAD_B64 : DS_Real_Renamed_gfx11_gfx12<0x076, DS_READ_B64, "ds_load_b64">;
+defm DS_LOAD_2ADDR_B64 : DS_Real_Renamed_gfx11_gfx12<0x077, DS_READ2_B64, "ds_load_2addr_b64">;
+defm DS_LOAD_2ADDR_STRIDE64_B64 : DS_Real_Renamed_gfx11_gfx12<0x078, DS_READ2ST64_B64, "ds_load_2addr_stride64_b64">;
+defm DS_STORE_B8_D16_HI : DS_Real_Renamed_gfx11_gfx12<0x0a0, DS_WRITE_B8_D16_HI, "ds_store_b8_d16_hi">;
+defm DS_STORE_B16_D16_HI : DS_Real_Renamed_gfx11_gfx12<0x0a1, DS_WRITE_B16_D16_HI, "ds_store_b16_d16_hi">;
+defm DS_LOAD_U8_D16 : DS_Real_Renamed_gfx11_gfx12<0x0a2, DS_READ_U8_D16, "ds_load_u8_d16">;
+defm DS_LOAD_U8_D16_HI : DS_Real_Renamed_gfx11_gfx12<0x0a3, DS_READ_U8_D16_HI, "ds_load_u8_d16_hi">;
+defm DS_LOAD_I8_D16 : DS_Real_Renamed_gfx11_gfx12<0x0a4, DS_READ_I8_D16, "ds_load_i8_d16">;
+defm DS_LOAD_I8_D16_HI : DS_Real_Renamed_gfx11_gfx12<0x0a5, DS_READ_I8_D16_HI, "ds_load_i8_d16_hi">;
+defm DS_LOAD_U16_D16 : DS_Real_Renamed_gfx11_gfx12<0x0a6, DS_READ_U16_D16, "ds_load_u16_d16">;
+defm DS_LOAD_U16_D16_HI : DS_Real_Renamed_gfx11_gfx12<0x0a7, DS_READ_U16_D16_HI, "ds_load_u16_d16_hi">;
+defm DS_STORE_ADDTID_B32 : DS_Real_Renamed_gfx11_gfx12<0x0b0, DS_WRITE_ADDTID_B32, "ds_store_addtid_b32">;
+defm DS_LOAD_ADDTID_B32 : DS_Real_Renamed_gfx11_gfx12<0x0b1, DS_READ_ADDTID_B32, "ds_load_addtid_b32">;
+defm DS_STORE_B96 : DS_Real_Renamed_gfx11_gfx12<0x0de, DS_WRITE_B96, "ds_store_b96">;
+defm DS_STORE_B128 : DS_Real_Renamed_gfx11_gfx12<0x0df, DS_WRITE_B128, "ds_store_b128">;
+defm DS_LOAD_B96 : DS_Real_Renamed_gfx11_gfx12<0x0fe, DS_READ_B96, "ds_load_b96">;
+defm DS_LOAD_B128 : DS_Real_Renamed_gfx11_gfx12<0x0ff, DS_READ_B128, "ds_load_b128">;
// DS_CMPST_* are renamed to DS_CMPSTORE_* in GFX11, but also the data operands (src and cmp) are swapped
// comparing to pre-GFX11.
// Note: the mnemonic alias is not generated to avoid a potential ambiguity due to the semantics change.
-defm DS_CMPSTORE_B32 : DS_Real_gfx11<0x010>;
+defm DS_CMPSTORE_B32 : DS_Real_gfx11_gfx12<0x010>;
defm DS_CMPSTORE_F32 : DS_Real_gfx11<0x011>;
-defm DS_CMPSTORE_RTN_B32 : DS_Real_gfx11<0x030>;
+defm DS_CMPSTORE_RTN_B32 : DS_Real_gfx11_gfx12<0x030>;
defm DS_CMPSTORE_RTN_F32 : DS_Real_gfx11<0x031>;
-defm DS_CMPSTORE_B64 : DS_Real_gfx11<0x050>;
+defm DS_CMPSTORE_B64 : DS_Real_gfx11_gfx12<0x050>;
defm DS_CMPSTORE_F64 : DS_Real_gfx11<0x051>;
-defm DS_CMPSTORE_RTN_B64 : DS_Real_gfx11<0x070>;
+defm DS_CMPSTORE_RTN_B64 : DS_Real_gfx11_gfx12<0x070>;
defm DS_CMPSTORE_RTN_F64 : DS_Real_gfx11<0x071>;
-defm DS_ADD_RTN_F32 : DS_Real_gfx11<0x079>;
+defm DS_ADD_RTN_F32 : DS_Real_gfx11_gfx12<0x079>;
defm DS_ADD_GS_REG_RTN : DS_Real_gfx11<0x07a>;
defm DS_SUB_GS_REG_RTN : DS_Real_gfx11<0x07b>;
defm DS_BVH_STACK_RTN_B32 : DS_Real_gfx11<0x0ad>;
@@ -1265,8 +1325,8 @@ defm DS_BVH_STACK_RTN_B32 : DS_Real_gfx11<0x0ad>;
let AssemblerPredicate = isGFX10Only, DecoderNamespace = "GFX10" in {
multiclass DS_Real_gfx10<bits<8> op> {
- def _gfx10 : Base_DS_Real_gfx6_gfx7_gfx10_gfx11<op, !cast<DS_Pseudo>(NAME),
- SIEncodingFamily.GFX10>;
+ def _gfx10 : Base_DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<op,
+ !cast<DS_Pseudo>(NAME), SIEncodingFamily.GFX10>;
}
} // End AssemblerPredicate = isGFX10Only, DecoderNamespace = "GFX10"
@@ -1283,28 +1343,34 @@ defm DS_WRITE_ADDTID_B32 : DS_Real_gfx10<0x0b0>;
defm DS_READ_ADDTID_B32 : DS_Real_gfx10<0x0b1>;
//===----------------------------------------------------------------------===//
-// GFX10, GFX11.
+// GFX10, GFX11, GFX12.
//===----------------------------------------------------------------------===//
+multiclass DS_Real_gfx10_gfx11_gfx12<bits<8> op> :
+ DS_Real_gfx10<op>, DS_Real_gfx11<op>, DS_Real_gfx12<op>;
+
multiclass DS_Real_gfx10_gfx11<bits<8> op> :
DS_Real_gfx10<op>, DS_Real_gfx11<op>;
-defm DS_ADD_F32 : DS_Real_gfx10_gfx11<0x015>;
+defm DS_ADD_F32 : DS_Real_gfx10_gfx11_gfx12<0x015>;
defm DS_ADD_SRC2_F32 : DS_Real_gfx10<0x095>;
-defm DS_PERMUTE_B32 : DS_Real_gfx10_gfx11<0x0b2>;
-defm DS_BPERMUTE_B32 : DS_Real_gfx10_gfx11<0x0b3>;
+defm DS_PERMUTE_B32 : DS_Real_gfx10_gfx11_gfx12<0x0b2>;
+defm DS_BPERMUTE_B32 : DS_Real_gfx10_gfx11_gfx12<0x0b3>;
//===----------------------------------------------------------------------===//
-// GFX7, GFX10, GFX11.
+// GFX7, GFX10, GFX11, GFX12.
//===----------------------------------------------------------------------===//
let AssemblerPredicate = isGFX7Only, DecoderNamespace = "GFX7" in {
multiclass DS_Real_gfx7<bits<8> op> {
- def _gfx7 : Base_DS_Real_gfx6_gfx7_gfx10_gfx11<op, !cast<DS_Pseudo>(NAME),
- SIEncodingFamily.SI>;
+ def _gfx7 : Base_DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<op,
+ !cast<DS_Pseudo>(NAME), SIEncodingFamily.SI>;
}
} // End AssemblerPredicate = isGFX7Only, DecoderNamespace = "GFX7"
+multiclass DS_Real_gfx7_gfx10_gfx11_gfx12<bits<8> op> :
+ DS_Real_gfx7<op>, DS_Real_gfx10_gfx11_gfx12<op>;
+
multiclass DS_Real_gfx7_gfx10_gfx11<bits<8> op> :
DS_Real_gfx7<op>, DS_Real_gfx10_gfx11<op>;
@@ -1314,7 +1380,7 @@ multiclass DS_Real_gfx7_gfx10<bits<8> op> :
// FIXME-GFX7: Add tests when upstreaming this part.
defm DS_GWS_SEMA_RELEASE_ALL : DS_Real_gfx7_gfx10_gfx11<0x018>;
defm DS_WRAP_RTN_B32 : DS_Real_gfx7_gfx10_gfx11<0x034>;
-defm DS_CONDXCHG32_RTN_B64 : DS_Real_gfx7_gfx10_gfx11<0x07e>;
+defm DS_CONDXCHG32_RTN_B64 : DS_Real_gfx7_gfx10_gfx11_gfx12<0x07e>;
defm DS_WRITE_B96 : DS_Real_gfx7_gfx10<0x0de>;
defm DS_WRITE_B128 : DS_Real_gfx7_gfx10<0x0df>;
defm DS_READ_B96 : DS_Real_gfx7_gfx10<0x0fe>;
@@ -1326,30 +1392,33 @@ defm DS_READ_B128 : DS_Real_gfx7_gfx10<0x0ff>;
let AssemblerPredicate = isGFX6GFX7, DecoderNamespace = "GFX6GFX7" in {
multiclass DS_Real_gfx6_gfx7<bits<8> op> {
- def _gfx6_gfx7 : Base_DS_Real_gfx6_gfx7_gfx10_gfx11<op, !cast<DS_Pseudo>(NAME),
- SIEncodingFamily.SI>;
+ def _gfx6_gfx7 : Base_DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<op,
+ !cast<DS_Pseudo>(NAME), SIEncodingFamily.SI>;
}
} // End AssemblerPredicate = isGFX6GFX7, DecoderNamespace = "GFX6GFX7"
+multiclass DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<bits<8> op> :
+ DS_Real_gfx6_gfx7<op>, DS_Real_gfx10_gfx11_gfx12<op>;
+
multiclass DS_Real_gfx6_gfx7_gfx10_gfx11<bits<8> op> :
DS_Real_gfx6_gfx7<op>, DS_Real_gfx10_gfx11<op>;
multiclass DS_Real_gfx6_gfx7_gfx10<bits<8> op> :
DS_Real_gfx6_gfx7<op>, DS_Real_gfx10<op>;
-defm DS_ADD_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x000>;
-defm DS_SUB_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x001>;
-defm DS_RSUB_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x002>;
-defm DS_INC_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x003>;
-defm DS_DEC_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x004>;
-defm DS_MIN_I32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x005>;
-defm DS_MAX_I32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x006>;
-defm DS_MIN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x007>;
-defm DS_MAX_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x008>;
-defm DS_AND_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x009>;
-defm DS_OR_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x00a>;
-defm DS_XOR_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x00b>;
-defm DS_MSKOR_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x00c>;
+defm DS_ADD_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x000>;
+defm DS_SUB_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x001>;
+defm DS_RSUB_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x002>;
+defm DS_INC_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x003>;
+defm DS_DEC_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x004>;
+defm DS_MIN_I32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x005>;
+defm DS_MAX_I32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x006>;
+defm DS_MIN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x007>;
+defm DS_MAX_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x008>;
+defm DS_AND_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x009>;
+defm DS_OR_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x00a>;
+defm DS_XOR_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x00b>;
+defm DS_MSKOR_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x00c>;
defm DS_WRITE_B32 : DS_Real_gfx6_gfx7_gfx10<0x00d>;
defm DS_WRITE2_B32 : DS_Real_gfx6_gfx7_gfx10<0x00e>;
@@ -1359,7 +1428,7 @@ defm DS_CMPST_F32 : DS_Real_gfx6_gfx7_gfx10<0x011>;
defm DS_MIN_F32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x012>;
defm DS_MAX_F32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x013>;
-defm DS_NOP : DS_Real_gfx6_gfx7_gfx10_gfx11<0x014>;
+defm DS_NOP : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x014>;
defm DS_GWS_INIT : DS_Real_gfx6_gfx7_gfx10_gfx11<0x019>;
defm DS_GWS_SEMA_V : DS_Real_gfx6_gfx7_gfx10_gfx11<0x01a>;
defm DS_GWS_SEMA_BR : DS_Real_gfx6_gfx7_gfx10_gfx11<0x01b>;
@@ -1369,19 +1438,19 @@ defm DS_GWS_BARRIER : DS_Real_gfx6_gfx7_gfx10_gfx11<0x01d>;
defm DS_WRITE_B8 : DS_Real_gfx6_gfx7_gfx10<0x01e>;
defm DS_WRITE_B16 : DS_Real_gfx6_gfx7_gfx10<0x01f>;
-defm DS_ADD_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x020>;
-defm DS_SUB_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x021>;
-defm DS_RSUB_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x022>;
-defm DS_INC_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x023>;
-defm DS_DEC_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x024>;
-defm DS_MIN_RTN_I32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x025>;
-defm DS_MAX_RTN_I32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x026>;
-defm DS_MIN_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x027>;
-defm DS_MAX_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x028>;
-defm DS_AND_RTN_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x029>;
-defm DS_OR_RTN_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x02a>;
-defm DS_XOR_RTN_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x02b>;
-defm DS_MSKOR_RTN_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x02c>;
+defm DS_ADD_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x020>;
+defm DS_SUB_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x021>;
+defm DS_RSUB_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x022>;
+defm DS_INC_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x023>;
+defm DS_DEC_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x024>;
+defm DS_MIN_RTN_I32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x025>;
+defm DS_MAX_RTN_I32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x026>;
+defm DS_MIN_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x027>;
+defm DS_MAX_RTN_U32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x028>;
+defm DS_AND_RTN_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x029>;
+defm DS_OR_RTN_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x02a>;
+defm DS_XOR_RTN_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x02b>;
+defm DS_MSKOR_RTN_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x02c>;
defm DS_WRXCHG_RTN_B32 : DS_Real_gfx6_gfx7_gfx10<0x02d>;
defm DS_WRXCHG2_RTN_B32 : DS_Real_gfx6_gfx7_gfx10<0x02e>;
@@ -1391,7 +1460,7 @@ defm DS_CMPST_RTN_F32 : DS_Real_gfx6_gfx7_gfx10<0x031>;
defm DS_MIN_RTN_F32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x032>;
defm DS_MAX_RTN_F32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x033>;
-defm DS_SWIZZLE_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x035>;
+defm DS_SWIZZLE_B32 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x035>;
defm DS_READ_B32 : DS_Real_gfx6_gfx7_gfx10<0x036>;
defm DS_READ2_B32 : DS_Real_gfx6_gfx7_gfx10<0x037>;
@@ -1401,22 +1470,22 @@ defm DS_READ_U8 : DS_Real_gfx6_gfx7_gfx10<0x03a>;
defm DS_READ_I16 : DS_Real_gfx6_gfx7_gfx10<0x03b>;
defm DS_READ_U16 : DS_Real_gfx6_gfx7_gfx10<0x03c>;
-defm DS_CONSUME : DS_Real_gfx6_gfx7_gfx10_gfx11<0x03d>;
-defm DS_APPEND : DS_Real_gfx6_gfx7_gfx10_gfx11<0x03e>;
+defm DS_CONSUME : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x03d>;
+defm DS_APPEND : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x03e>;
defm DS_ORDERED_COUNT : DS_Real_gfx6_gfx7_gfx10_gfx11<0x03f>;
-defm DS_ADD_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x040>;
-defm DS_SUB_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x041>;
-defm DS_RSUB_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x042>;
-defm DS_INC_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x043>;
-defm DS_DEC_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x044>;
-defm DS_MIN_I64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x045>;
-defm DS_MAX_I64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x046>;
-defm DS_MIN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x047>;
-defm DS_MAX_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x048>;
-defm DS_AND_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x049>;
-defm DS_OR_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x04a>;
-defm DS_XOR_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x04b>;
-defm DS_MSKOR_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x04c>;
+defm DS_ADD_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x040>;
+defm DS_SUB_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x041>;
+defm DS_RSUB_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x042>;
+defm DS_INC_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x043>;
+defm DS_DEC_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x044>;
+defm DS_MIN_I64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x045>;
+defm DS_MAX_I64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x046>;
+defm DS_MIN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x047>;
+defm DS_MAX_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x048>;
+defm DS_AND_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x049>;
+defm DS_OR_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x04a>;
+defm DS_XOR_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x04b>;
+defm DS_MSKOR_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x04c>;
defm DS_WRITE_B64 : DS_Real_gfx6_gfx7_gfx10<0x04d>;
defm DS_WRITE2_B64 : DS_Real_gfx6_gfx7_gfx10<0x04e>;
@@ -1426,19 +1495,19 @@ defm DS_CMPST_F64 : DS_Real_gfx6_gfx7_gfx10<0x051>;
defm DS_MIN_F64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x052>;
defm DS_MAX_F64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x053>;
-defm DS_ADD_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x060>;
-defm DS_SUB_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x061>;
-defm DS_RSUB_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x062>;
-defm DS_INC_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x063>;
-defm DS_DEC_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x064>;
-defm DS_MIN_RTN_I64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x065>;
-defm DS_MAX_RTN_I64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x066>;
-defm DS_MIN_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x067>;
-defm DS_MAX_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x068>;
-defm DS_AND_RTN_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x069>;
-defm DS_OR_RTN_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x06a>;
-defm DS_XOR_RTN_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x06b>;
-defm DS_MSKOR_RTN_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11<0x06c>;
+defm DS_ADD_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x060>;
+defm DS_SUB_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x061>;
+defm DS_RSUB_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x062>;
+defm DS_INC_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x063>;
+defm DS_DEC_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x064>;
+defm DS_MIN_RTN_I64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x065>;
+defm DS_MAX_RTN_I64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x066>;
+defm DS_MIN_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x067>;
+defm DS_MAX_RTN_U64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x068>;
+defm DS_AND_RTN_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x069>;
+defm DS_OR_RTN_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x06a>;
+defm DS_XOR_RTN_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x06b>;
+defm DS_MSKOR_RTN_B64 : DS_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x06c>;
defm DS_WRXCHG_RTN_B64 : DS_Real_gfx6_gfx7_gfx10<0x06d>;
defm DS_WRXCHG2_RTN_B64 : DS_Real_gfx6_gfx7_gfx10<0x06e>;
diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
index 1f11beb71101..ed2e7e4f189e 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
@@ -107,6 +107,13 @@ static DecodeStatus decodeBoolReg(MCInst &Inst, unsigned Val, uint64_t Addr,
return addOperand(Inst, DAsm->decodeBoolReg(Val));
}
+static DecodeStatus decodeSplitBarrier(MCInst &Inst, unsigned Val,
+ uint64_t Addr,
+ const MCDisassembler *Decoder) {
+ auto DAsm = static_cast<const AMDGPUDisassembler *>(Decoder);
+ return addOperand(Inst, DAsm->decodeSplitBarrier(Val));
+}
+
#define DECODE_OPERAND(StaticDecoderName, DecoderName) \
static DecodeStatus StaticDecoderName(MCInst &Inst, unsigned Imm, \
uint64_t /*Addr*/, \
@@ -202,10 +209,12 @@ DECODE_OPERAND_REG_8(VReg_512)
DECODE_OPERAND_REG_8(VReg_1024)
DECODE_OPERAND_REG_7(SReg_32, OPW32)
+DECODE_OPERAND_REG_7(SReg_32_XEXEC, OPW32)
DECODE_OPERAND_REG_7(SReg_32_XM0_XEXEC, OPW32)
DECODE_OPERAND_REG_7(SReg_32_XEXEC_HI, OPW32)
DECODE_OPERAND_REG_7(SReg_64, OPW64)
DECODE_OPERAND_REG_7(SReg_64_XEXEC, OPW64)
+DECODE_OPERAND_REG_7(SReg_96, OPW96)
DECODE_OPERAND_REG_7(SReg_128, OPW128)
DECODE_OPERAND_REG_7(SReg_256, OPW256)
DECODE_OPERAND_REG_7(SReg_512, OPW512)
@@ -493,17 +502,33 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
if (Res && convertDPP8Inst(MI) == MCDisassembler::Success)
break;
MI = MCInst(); // clear
- Res = tryDecodeInst(DecoderTableDPPGFX1196, DecoderTableDPPGFX11_FAKE1696,
- MI, DecW, Address, CS);
- if (Res) {
- if (MCII->get(MI.getOpcode()).TSFlags & SIInstrFlags::VOP3P)
+ Res =
+ tryDecodeInst(DecoderTableDPP8GFX1296, DecoderTableDPP8GFX12_FAKE1696,
+ MI, DecW, Address, CS);
+ if (Res && convertDPP8Inst(MI) == MCDisassembler::Success)
+ break;
+ MI = MCInst(); // clear
+
+ const auto convertVOPDPP = [&]() {
+ if (MCII->get(MI.getOpcode()).TSFlags & SIInstrFlags::VOP3P) {
convertVOP3PDPPInst(MI);
- else if (AMDGPU::isVOPC64DPP(MI.getOpcode()))
+ } else if (AMDGPU::isVOPC64DPP(MI.getOpcode())) {
convertVOPCDPPInst(MI); // Special VOP3 case
- else {
+ } else {
assert(MCII->get(MI.getOpcode()).TSFlags & SIInstrFlags::VOP3);
convertVOP3DPPInst(MI); // Regular VOP3 case
}
+ };
+ Res = tryDecodeInst(DecoderTableDPPGFX1196, DecoderTableDPPGFX11_FAKE1696,
+ MI, DecW, Address, CS);
+ if (Res) {
+ convertVOPDPP();
+ break;
+ }
+ Res = tryDecodeInst(DecoderTableDPPGFX1296, DecoderTableDPPGFX12_FAKE1696,
+ MI, DecW, Address, CS);
+ if (Res) {
+ convertVOPDPP();
break;
}
Res = tryDecodeInst(DecoderTableGFX1196, MI, DecW, Address, CS);
@@ -543,6 +568,12 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
break;
MI = MCInst(); // clear
+ Res = tryDecodeInst(DecoderTableDPP8GFX1264,
+ DecoderTableDPP8GFX12_FAKE1664, MI, QW, Address, CS);
+ if (Res && convertDPP8Inst(MI) == MCDisassembler::Success)
+ break;
+ MI = MCInst(); // clear
+
Res = tryDecodeInst(DecoderTableDPP64, MI, QW, Address, CS);
if (Res) break;
@@ -554,6 +585,14 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
break;
}
+ Res = tryDecodeInst(DecoderTableDPPGFX1264, DecoderTableDPPGFX12_FAKE1664,
+ MI, QW, Address, CS);
+ if (Res) {
+ if (MCII->get(MI.getOpcode()).TSFlags & SIInstrFlags::VOPC)
+ convertVOPCDPPInst(MI);
+ break;
+ }
+
Res = tryDecodeInst(DecoderTableSDWA64, MI, QW, Address, CS);
if (Res) { IsSDWA = true; break; }
@@ -612,7 +651,8 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
Address, CS);
if (Res) break;
- Res = tryDecodeInst(DecoderTableGFX1232, MI, DW, Address, CS);
+ Res = tryDecodeInst(DecoderTableGFX1232, DecoderTableGFX12_FAKE1632, MI, DW,
+ Address, CS);
if (Res)
break;
@@ -643,7 +683,8 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
Res = tryDecodeInst(DecoderTableGFX1064, MI, QW, Address, CS);
if (Res) break;
- Res = tryDecodeInst(DecoderTableGFX1264, MI, QW, Address, CS);
+ Res = tryDecodeInst(DecoderTableGFX1264, DecoderTableGFX12_FAKE1664, MI, QW,
+ Address, CS);
if (Res)
break;
@@ -1200,6 +1241,8 @@ MCOperand AMDGPUDisassembler::createSRegOperand(unsigned SRegClassID,
case AMDGPU::TTMP_64RegClassID:
shift = 1;
break;
+ case AMDGPU::SGPR_96RegClassID:
+ case AMDGPU::TTMP_96RegClassID:
case AMDGPU::SGPR_128RegClassID:
case AMDGPU::TTMP_128RegClassID:
// ToDo: unclear if s[100:104] is available on VI. Can we use VCC as SGPR in
@@ -1715,6 +1758,10 @@ MCOperand AMDGPUDisassembler::decodeBoolReg(unsigned Val) const {
: decodeSrcOp(OPW32, Val);
}
+MCOperand AMDGPUDisassembler::decodeSplitBarrier(unsigned Val) const {
+ return decodeSrcOp(OPW32, Val);
+}
+
bool AMDGPUDisassembler::isVI() const {
return STI.hasFeature(AMDGPU::FeatureVolcanicIslands);
}
@@ -1836,12 +1883,16 @@ MCDisassembler::DecodeStatus AMDGPUDisassembler::decodeCOMPUTE_PGM_RSRC1(
if (FourByteBuffer & COMPUTE_PGM_RSRC1_PRIV)
return MCDisassembler::Fail;
- PRINT_DIRECTIVE(".amdhsa_dx10_clamp", COMPUTE_PGM_RSRC1_ENABLE_DX10_CLAMP);
+ if (!isGFX12Plus())
+ PRINT_DIRECTIVE(".amdhsa_dx10_clamp",
+ COMPUTE_PGM_RSRC1_GFX6_GFX11_ENABLE_DX10_CLAMP);
if (FourByteBuffer & COMPUTE_PGM_RSRC1_DEBUG_MODE)
return MCDisassembler::Fail;
- PRINT_DIRECTIVE(".amdhsa_ieee_mode", COMPUTE_PGM_RSRC1_ENABLE_IEEE_MODE);
+ if (!isGFX12Plus())
+ PRINT_DIRECTIVE(".amdhsa_ieee_mode",
+ COMPUTE_PGM_RSRC1_GFX6_GFX11_ENABLE_IEEE_MODE);
if (FourByteBuffer & COMPUTE_PGM_RSRC1_BULKY)
return MCDisassembler::Fail;
@@ -1867,6 +1918,11 @@ MCDisassembler::DecodeStatus AMDGPUDisassembler::decodeCOMPUTE_PGM_RSRC1(
PRINT_DIRECTIVE(".amdhsa_memory_ordered", COMPUTE_PGM_RSRC1_GFX10_PLUS_MEM_ORDERED);
PRINT_DIRECTIVE(".amdhsa_forward_progress", COMPUTE_PGM_RSRC1_GFX10_PLUS_FWD_PROGRESS);
}
+
+ if (isGFX12Plus())
+ PRINT_DIRECTIVE(".amdhsa_round_robin_scheduling",
+ COMPUTE_PGM_RSRC1_GFX12_PLUS_ENABLE_WG_RR_EN);
+
return MCDisassembler::Success;
}
@@ -2184,7 +2240,7 @@ AMDGPUDisassembler::onSymbolStart(SymbolInfoTy &Symbol, uint64_t &Size,
// Code Object V3 kernel descriptors.
StringRef Name = Symbol.Name;
- if (Symbol.Type == ELF::STT_OBJECT && Name.endswith(StringRef(".kd"))) {
+ if (Symbol.Type == ELF::STT_OBJECT && Name.ends_with(StringRef(".kd"))) {
Size = 64; // Size = 64 regardless of success or failure.
return decodeKernelDescriptor(Name.drop_back(3), Bytes, Address);
}
diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
index 7e233dcb54ea..233581949d71 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
@@ -251,6 +251,7 @@ public:
MCOperand decodeSDWAVopcDst(unsigned Val) const;
MCOperand decodeBoolReg(unsigned Val) const;
+ MCOperand decodeSplitBarrier(unsigned Val) const;
int getTTmpIdx(unsigned Val) const;
diff --git a/llvm/lib/Target/AMDGPU/FLATInstructions.td b/llvm/lib/Target/AMDGPU/FLATInstructions.td
index c0251164faee..0dd2b3f5c2c9 100644
--- a/llvm/lib/Target/AMDGPU/FLATInstructions.td
+++ b/llvm/lib/Target/AMDGPU/FLATInstructions.td
@@ -144,6 +144,47 @@ class FLAT_Real <bits<7> op, FLAT_Pseudo ps, string opName = ps.Mnemonic> :
let Inst{63-56} = !if(ps.has_vdst, vdst{7-0}, ?);
}
+class VFLAT_Real <bits<8> op, FLAT_Pseudo ps, string opName = ps.Mnemonic> :
+ InstSI <ps.OutOperandList, ps.InOperandList, opName # ps.AsmOperands, []>,
+ Enc96 {
+
+ let FLAT = 1;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let OtherPredicates = ps.OtherPredicates;
+ let TSFlags = ps.TSFlags;
+ let UseNamedOperandTable = ps.UseNamedOperandTable;
+ let SchedRW = ps.SchedRW;
+ let mayLoad = ps.mayLoad;
+ let mayStore = ps.mayStore;
+ let IsAtomicRet = ps.IsAtomicRet;
+ let IsAtomicNoRet = ps.IsAtomicNoRet;
+ let VM_CNT = ps.VM_CNT;
+ let LGKM_CNT = ps.LGKM_CNT;
+ let VALU = ps.VALU;
+
+ bits<7> saddr;
+ bits<8> vdst;
+ bits<6> cpol;
+ bits<8> vdata; // vsrc
+ bits<8> vaddr;
+ bits<24> offset;
+
+ let Inst{6-0} = !if(ps.has_saddr, !if(ps.enabled_saddr, saddr, 0x7f), 0);
+ let Inst{21-14} = op;
+ let Inst{31-26} = 0x3b;
+ let Inst{39-32} = !if(ps.has_vdst, vdst, ?);
+ let Inst{49} = ps.sve;
+ let Inst{54-53} = cpol{2-1}; // th{2-1}
+ let Inst{52} = !if(ps.IsAtomicRet, 1, cpol{0}); // th{0}
+ let Inst{51-50} = cpol{4-3}; // scope
+ let Inst{62-55} = !if(ps.has_data, vdata{7-0}, ?);
+ let Inst{71-64} = !if(ps.has_vaddr, vaddr, ?);
+ let Inst{95-72} = offset;
+}
+
class GlobalSaddrTable <bit is_saddr, string Name = ""> {
bit IsSaddr = is_saddr;
string SaddrOp = Name;
@@ -758,6 +799,10 @@ let SubtargetPredicate = HasFlatAtomicFaddF32Inst in {
defm FLAT_ATOMIC_ADD_F32 : FLAT_Atomic_Pseudo<"flat_atomic_add_f32", VGPR_32, f32>;
} // End SubtargetPredicate = HasFlatAtomicFaddF32Inst
+let SubtargetPredicate = isGFX12Plus in {
+ defm FLAT_ATOMIC_CSUB_U32 : FLAT_Atomic_Pseudo <"flat_atomic_csub_u32", VGPR_32, i32>;
+} // End SubtargetPredicate = isGFX12Plus
+
defm GLOBAL_LOAD_UBYTE : FLAT_Global_Load_Pseudo <"global_load_ubyte", VGPR_32>;
defm GLOBAL_LOAD_SBYTE : FLAT_Global_Load_Pseudo <"global_load_sbyte", VGPR_32>;
defm GLOBAL_LOAD_USHORT : FLAT_Global_Load_Pseudo <"global_load_ushort", VGPR_32>;
@@ -1027,19 +1072,43 @@ class FlatStoreSignedAtomicPat <FLAT_Pseudo inst, SDPatternOperator node,
(inst $vaddr, getVregSrcForVT<data_vt>.ret:$data, $offset)
>;
-multiclass FlatAtomicPat <string inst, string node, ValueType vt,
- ValueType data_vt = vt> {
- defvar rtnNode = !cast<PatFrags>(node#"_"#vt.Size);
- defvar noRtnNode = !cast<PatFrags>(node#"_noret_"#vt.Size);
-
- def : GCNPat <(vt (rtnNode (FlatOffset i64:$vaddr, i32:$offset), data_vt:$data)),
- (!cast<FLAT_Pseudo>(inst#"_RTN") VReg_64:$vaddr, getVregSrcForVT<data_vt>.ret:$data, $offset)>;
+multiclass FlatAtomicNoRtnPat <string inst, string node, ValueType vt,
+ ValueType data_vt = vt, bit isIntr = 0> {
+ defvar noRtnNode = !cast<PatFrags>(node # "_noret" # !if(isIntr, "", "_"#vt.Size));
let AddedComplexity = 1 in
def : GCNPat <(vt (noRtnNode (FlatOffset i64:$vaddr, i32:$offset), data_vt:$data)),
(!cast<FLAT_Pseudo>(inst) VReg_64:$vaddr, getVregSrcForVT<data_vt>.ret:$data, $offset)>;
}
+multiclass FlatAtomicRtnPat <string inst, string node, ValueType vt,
+ ValueType data_vt = vt, bit isIntr = 0> {
+ defvar rtnNode = !cast<SDPatternOperator>(node # !if(isIntr, "", "_"#vt.Size));
+
+ def : GCNPat <(vt (rtnNode (FlatOffset i64:$vaddr, i32:$offset), data_vt:$data)),
+ (!cast<FLAT_Pseudo>(inst#"_RTN") VReg_64:$vaddr, getVregSrcForVT<data_vt>.ret:$data, $offset)>;
+}
+
+multiclass FlatAtomicPat <string inst, string node, ValueType vt,
+ ValueType data_vt = vt, bit isIntr = 0> :
+ FlatAtomicRtnPat<inst, node, vt, data_vt, isIntr>,
+ FlatAtomicNoRtnPat<inst, node, vt, data_vt, isIntr>;
+
+multiclass FlatAtomicIntrNoRtnPat <string inst, string node, ValueType vt,
+ ValueType data_vt = vt> {
+ defm : FlatAtomicNoRtnPat<inst, node, vt, data_vt, /* isIntr */ 1>;
+}
+
+multiclass FlatAtomicIntrRtnPat <string inst, string node, ValueType vt,
+ ValueType data_vt = vt> {
+ defm : FlatAtomicRtnPat<inst, node, vt, data_vt, /* isIntr */ 1>;
+}
+
+multiclass FlatAtomicIntrPat <string inst, string node, ValueType vt,
+ ValueType data_vt = vt> :
+ FlatAtomicRtnPat<inst, node, vt, data_vt, /* isIntr */ 1>,
+ FlatAtomicNoRtnPat<inst, node, vt, data_vt, /* isIntr */ 1>;
+
class FlatSignedAtomicPatBase <FLAT_Pseudo inst, SDPatternOperator node,
ValueType vt, ValueType data_vt = vt> : GCNPat <
(vt (node (GlobalOffset i64:$vaddr, i32:$offset), data_vt:$data)),
@@ -1260,10 +1329,10 @@ multiclass GlobalFLATStorePats<FLAT_Pseudo inst, SDPatternOperator node,
multiclass GlobalFLATAtomicPatsNoRtnBase<string inst, string node, ValueType vt,
ValueType data_vt = vt> {
let AddedComplexity = 11 in
- def : FlatSignedAtomicPatBase<!cast<FLAT_Pseudo>(inst), !cast<PatFrags>(node), vt, data_vt>;
+ def : FlatSignedAtomicPatBase<!cast<FLAT_Pseudo>(inst), !cast<SDPatternOperator>(node), vt, data_vt>;
let AddedComplexity = 13 in
- def : GlobalAtomicSaddrPat<!cast<FLAT_Pseudo>(inst#"_SADDR"), !cast<PatFrags>(node), vt, data_vt>;
+ def : GlobalAtomicSaddrPat<!cast<FLAT_Pseudo>(inst#"_SADDR"), !cast<SDPatternOperator>(node), vt, data_vt>;
}
multiclass GlobalFLATAtomicPatsRtnBase<string inst, string node, ValueType vt,
@@ -1463,10 +1532,14 @@ defm : GlobalFLATAtomicPats <"GLOBAL_ATOMIC_XOR_X2", "atomic_load_xor_global", i
let OtherPredicates = [isGFX10Plus] in {
defm : GlobalFLATAtomicPats <"GLOBAL_ATOMIC_FMIN", "atomic_load_fmin_global", f32>;
defm : GlobalFLATAtomicPats <"GLOBAL_ATOMIC_FMAX", "atomic_load_fmax_global", f32>;
-defm : GlobalFLATAtomicIntrPats <"GLOBAL_ATOMIC_FMIN", "int_amdgcn_global_atomic_fmin", f32>;
-defm : GlobalFLATAtomicIntrPats <"GLOBAL_ATOMIC_FMAX", "int_amdgcn_global_atomic_fmax", f32>;
defm : FlatSignedAtomicPat <"FLAT_ATOMIC_FMIN", "atomic_load_fmin_flat", f32>;
defm : FlatSignedAtomicPat <"FLAT_ATOMIC_FMAX", "atomic_load_fmax_flat", f32>;
+}
+
+let OtherPredicates = [isGFX10GFX11] in {
+defm : GlobalFLATAtomicIntrPats <"GLOBAL_ATOMIC_FMIN", "int_amdgcn_global_atomic_fmin", f32>;
+defm : GlobalFLATAtomicIntrPats <"GLOBAL_ATOMIC_FMAX", "int_amdgcn_global_atomic_fmax", f32>;
+
defm : FlatSignedAtomicIntrPat <"FLAT_ATOMIC_FMIN", "int_amdgcn_flat_atomic_fmin", f32>;
defm : FlatSignedAtomicIntrPat <"FLAT_ATOMIC_FMAX", "int_amdgcn_flat_atomic_fmax", f32>;
}
@@ -1482,6 +1555,13 @@ defm : FlatSignedAtomicIntrPat <"FLAT_ATOMIC_FMIN_X2", "int_amdgcn_flat_atomic_f
defm : FlatSignedAtomicIntrPat <"FLAT_ATOMIC_FMAX_X2", "int_amdgcn_flat_atomic_fmax", f64>;
}
+let OtherPredicates = [isGFX12Only] in {
+ defm : GlobalFLATAtomicIntrPats <"GLOBAL_ATOMIC_FMIN", "int_amdgcn_global_atomic_fmin_num", f32>;
+ defm : GlobalFLATAtomicIntrPats <"GLOBAL_ATOMIC_FMAX", "int_amdgcn_global_atomic_fmax_num", f32>;
+ defm : FlatSignedAtomicIntrPat <"FLAT_ATOMIC_FMIN", "int_amdgcn_flat_atomic_fmin_num", f32>;
+ defm : FlatSignedAtomicIntrPat <"FLAT_ATOMIC_FMAX", "int_amdgcn_flat_atomic_fmax_num", f32>;
+}
+
let OtherPredicates = [HasAtomicFaddNoRtnInsts] in {
defm : GlobalFLATAtomicPatsNoRtn <"GLOBAL_ATOMIC_ADD_F32", "atomic_load_fadd_global", f32>;
defm : GlobalFLATAtomicPatsNoRtnWithAddrSpace <"GLOBAL_ATOMIC_ADD_F32", "int_amdgcn_flat_atomic_fadd", "global_addrspace", f32>;
@@ -2181,7 +2261,7 @@ defm SCRATCH_LOAD_LDS_DWORD : FLAT_Real_ScratchAllAddr_LDS_gfx10 <0x00c>;
class FLAT_Real_gfx11 <bits<7> op, FLAT_Pseudo ps, string opName = ps.Mnemonic> :
FLAT_Real <op, ps, opName>,
SIMCInstr <ps.PseudoInstr, SIEncodingFamily.GFX11> {
- let AssemblerPredicate = isGFX11Plus;
+ let AssemblerPredicate = isGFX11Only;
let DecoderNamespace = "GFX11";
let Inst{13} = !if(ps.has_dlc, cpol{CPolBit.DLC}, ps.dlcValue);
@@ -2193,7 +2273,7 @@ class FLAT_Real_gfx11 <bits<7> op, FLAT_Pseudo ps, string opName = ps.Mnemonic>
multiclass FLAT_Aliases_gfx11<string ps, string opName, int renamed> {
if renamed then
- def _renamed_gfx11 : MnemonicAlias<!cast<FLAT_Pseudo>(ps).Mnemonic, opName>, Requires<[isGFX11Plus]>;
+ def _renamed_gfx11 : MnemonicAlias<!cast<FLAT_Pseudo>(ps).Mnemonic, opName>, Requires<[isGFX11Only]>;
}
multiclass FLAT_Real_Base_gfx11<bits<7> op, string ps, string opName, int renamed = false> :
@@ -2388,3 +2468,213 @@ defm SCRATCH_LOAD_D16_HI_I8 : FLAT_Real_ScratchAllAddr_gfx11<0x22, "SCRATCH_
defm SCRATCH_LOAD_D16_HI_B16 : FLAT_Real_ScratchAllAddr_gfx11<0x23, "SCRATCH_LOAD_SHORT_D16_HI", "scratch_load_d16_hi_b16">;
defm SCRATCH_STORE_D16_HI_B8 : FLAT_Real_ScratchAllAddr_gfx11<0x24, "SCRATCH_STORE_BYTE_D16_HI", "scratch_store_d16_hi_b8">;
defm SCRATCH_STORE_D16_HI_B16 : FLAT_Real_ScratchAllAddr_gfx11<0x25, "SCRATCH_STORE_SHORT_D16_HI", "scratch_store_d16_hi_b16">;
+
+//===----------------------------------------------------------------------===//
+// GFX12
+//===----------------------------------------------------------------------===//
+
+class VFLAT_Real_gfx12 <bits<8> op, FLAT_Pseudo ps,
+ string opName = ps.Mnemonic> :
+ VFLAT_Real <op, ps, opName>,
+ SIMCInstr <ps.PseudoInstr, SIEncodingFamily.GFX12> {
+ let AssemblerPredicate = isGFX12Plus;
+ let DecoderNamespace = "GFX12";
+
+ let Inst{25-24} = !if(ps.is_flat_scratch, 0b01,
+ !if(ps.is_flat_global, 0b10, 0b00));
+}
+
+multiclass VFLAT_Aliases_gfx12<string ps, string opName, int renamed, string alias> {
+ if renamed then
+ def _renamed_gfx12 : MnemonicAlias<!cast<FLAT_Pseudo>(ps).Mnemonic, opName>, Requires<[isGFX12Plus]>;
+ if !not(!empty(alias)) then
+ def _alias_gfx12 : MnemonicAlias<alias, opName>, Requires<[isGFX12Plus]>;
+}
+
+multiclass VFLAT_Real_Base_gfx12<bits<8> op, string ps, string opName, int renamed = false, string alias = ""> :
+ VFLAT_Aliases_gfx12<ps, opName, renamed, alias> {
+ def _gfx12 : VFLAT_Real_gfx12<op, !cast<FLAT_Pseudo>(ps), opName> {
+ let Inst{6-0} = !cast<int>(SGPR_NULL_gfx11plus.HWEncoding);
+ }
+}
+
+multiclass VFLAT_Real_RTN_gfx12<bits<8> op, string ps, string opName> {
+ def _RTN_gfx12 : VFLAT_Real_gfx12<op, !cast<FLAT_Pseudo>(ps#"_RTN"), opName> {
+ let Inst{6-0} = !cast<int>(SGPR_NULL_gfx11plus.HWEncoding);
+ }
+}
+
+multiclass VFLAT_Real_SADDR_gfx12<bits<8> op, string ps, string opName> {
+ def _SADDR_gfx12 : VFLAT_Real_gfx12<op, !cast<FLAT_Pseudo>(ps#"_SADDR"), opName>;
+}
+
+multiclass VFLAT_Real_SADDR_RTN_gfx12<bits<8> op, string ps, string opName> {
+ def _SADDR_RTN_gfx12 : VFLAT_Real_gfx12<op, !cast<FLAT_Pseudo>(ps#"_SADDR_RTN"), opName>;
+}
+
+multiclass VFLAT_Real_ST_gfx12<bits<8> op, string ps, string opName> {
+ def _ST_gfx12 : VFLAT_Real_gfx12<op, !cast<FLAT_Pseudo>(ps#"_ST"), opName> {
+ let Inst{6-0} = !cast<int>(SGPR_NULL_gfx11plus.HWEncoding);
+ let OtherPredicates = [HasFlatScratchSTMode];
+ }
+}
+
+multiclass VFLAT_Real_SVS_gfx12<bits<8> op, string ps, string opName> {
+ def _SVS_gfx12 : VFLAT_Real_gfx12<op, !cast<FLAT_Pseudo>(ps#"_SVS"), opName> {
+ let OtherPredicates = [HasFlatScratchSVSMode];
+ }
+}
+
+multiclass VFLAT_Real_Atomics_gfx12<bits<8> op, string ps, string opName, int renamed = false, string alias = ""> :
+ VFLAT_Real_Base_gfx12<op, ps, opName, renamed, alias>,
+ VFLAT_Real_RTN_gfx12<op, ps, opName>;
+
+multiclass VGLOBAL_Real_AllAddr_gfx12<bits<8> op, string ps, string opName, int renamed = false, string alias = ""> :
+ VFLAT_Real_Base_gfx12<op, ps, opName, renamed, alias>,
+ VFLAT_Real_SADDR_gfx12<op, ps, opName>;
+
+multiclass VGLOBAL_Real_Atomics_gfx12<bits<8> op, string ps, string opName, int renamed = false, string alias = ""> :
+ VGLOBAL_Real_AllAddr_gfx12<op, ps, opName, renamed, alias>,
+ VFLAT_Real_RTN_gfx12<op, ps, opName>,
+ VFLAT_Real_SADDR_RTN_gfx12<op, ps, opName>;
+
+multiclass VSCRATCH_Real_AllAddr_gfx12<bits<8> op, string ps, string opName, int renamed = false> :
+ VFLAT_Real_Base_gfx12<op, ps, opName, renamed>,
+ VFLAT_Real_SADDR_gfx12<op, ps, opName>,
+ VFLAT_Real_ST_gfx12<op, ps, opName>,
+ VFLAT_Real_SVS_gfx12<op, ps, opName>;
+
+// ENC_VFLAT.
+defm FLAT_LOAD_U8 : VFLAT_Real_Base_gfx12<0x010, "FLAT_LOAD_UBYTE", "flat_load_u8", true>;
+defm FLAT_LOAD_I8 : VFLAT_Real_Base_gfx12<0x011, "FLAT_LOAD_SBYTE", "flat_load_i8", true>;
+defm FLAT_LOAD_U16 : VFLAT_Real_Base_gfx12<0x012, "FLAT_LOAD_USHORT", "flat_load_u16", true>;
+defm FLAT_LOAD_I16 : VFLAT_Real_Base_gfx12<0x013, "FLAT_LOAD_SSHORT", "flat_load_i16", true>;
+defm FLAT_LOAD_B32 : VFLAT_Real_Base_gfx12<0x014, "FLAT_LOAD_DWORD", "flat_load_b32", true>;
+defm FLAT_LOAD_B64 : VFLAT_Real_Base_gfx12<0x015, "FLAT_LOAD_DWORDX2", "flat_load_b64", true>;
+defm FLAT_LOAD_B96 : VFLAT_Real_Base_gfx12<0x016, "FLAT_LOAD_DWORDX3", "flat_load_b96", true>;
+defm FLAT_LOAD_B128 : VFLAT_Real_Base_gfx12<0x017, "FLAT_LOAD_DWORDX4", "flat_load_b128", true>;
+defm FLAT_STORE_B8 : VFLAT_Real_Base_gfx12<0x018, "FLAT_STORE_BYTE", "flat_store_b8", true>;
+defm FLAT_STORE_B16 : VFLAT_Real_Base_gfx12<0x019, "FLAT_STORE_SHORT", "flat_store_b16", true>;
+defm FLAT_STORE_B32 : VFLAT_Real_Base_gfx12<0x01a, "FLAT_STORE_DWORD", "flat_store_b32", true>;
+defm FLAT_STORE_B64 : VFLAT_Real_Base_gfx12<0x01b, "FLAT_STORE_DWORDX2", "flat_store_b64", true>;
+defm FLAT_STORE_B96 : VFLAT_Real_Base_gfx12<0x01c, "FLAT_STORE_DWORDX3", "flat_store_b96", true>;
+defm FLAT_STORE_B128 : VFLAT_Real_Base_gfx12<0x01d, "FLAT_STORE_DWORDX4", "flat_store_b128", true>;
+defm FLAT_LOAD_D16_U8 : VFLAT_Real_Base_gfx12<0x01e, "FLAT_LOAD_UBYTE_D16", "flat_load_d16_u8">;
+defm FLAT_LOAD_D16_I8 : VFLAT_Real_Base_gfx12<0x01f, "FLAT_LOAD_SBYTE_D16", "flat_load_d16_i8">;
+defm FLAT_LOAD_D16_B16 : VFLAT_Real_Base_gfx12<0x020, "FLAT_LOAD_SHORT_D16", "flat_load_d16_b16">;
+defm FLAT_LOAD_D16_HI_U8 : VFLAT_Real_Base_gfx12<0x021, "FLAT_LOAD_UBYTE_D16_HI", "flat_load_d16_hi_u8">;
+defm FLAT_LOAD_D16_HI_I8 : VFLAT_Real_Base_gfx12<0x022, "FLAT_LOAD_SBYTE_D16_HI", "flat_load_d16_hi_i8">;
+defm FLAT_LOAD_D16_HI_B16 : VFLAT_Real_Base_gfx12<0x023, "FLAT_LOAD_SHORT_D16_HI", "flat_load_d16_hi_b16">;
+defm FLAT_STORE_D16_HI_B8 : VFLAT_Real_Base_gfx12<0x024, "FLAT_STORE_BYTE_D16_HI", "flat_store_d16_hi_b8">;
+defm FLAT_STORE_D16_HI_B16 : VFLAT_Real_Base_gfx12<0x025, "FLAT_STORE_SHORT_D16_HI", "flat_store_d16_hi_b16">;
+defm FLAT_ATOMIC_SWAP_B32 : VFLAT_Real_Atomics_gfx12<0x033, "FLAT_ATOMIC_SWAP", "flat_atomic_swap_b32", true>;
+defm FLAT_ATOMIC_CMPSWAP_B32 : VFLAT_Real_Atomics_gfx12<0x034, "FLAT_ATOMIC_CMPSWAP", "flat_atomic_cmpswap_b32", true>;
+defm FLAT_ATOMIC_ADD_U32 : VFLAT_Real_Atomics_gfx12<0x035, "FLAT_ATOMIC_ADD", "flat_atomic_add_u32", true>;
+defm FLAT_ATOMIC_SUB_U32 : VFLAT_Real_Atomics_gfx12<0x036, "FLAT_ATOMIC_SUB", "flat_atomic_sub_u32", true>;
+defm FLAT_ATOMIC_SUB_CLAMP_U32 : VFLAT_Real_Atomics_gfx12<0x037, "FLAT_ATOMIC_CSUB_U32", "flat_atomic_sub_clamp_u32", true>;
+defm FLAT_ATOMIC_MIN_I32 : VFLAT_Real_Atomics_gfx12<0x038, "FLAT_ATOMIC_SMIN", "flat_atomic_min_i32", true>;
+defm FLAT_ATOMIC_MIN_U32 : VFLAT_Real_Atomics_gfx12<0x039, "FLAT_ATOMIC_UMIN", "flat_atomic_min_u32", true>;
+defm FLAT_ATOMIC_MAX_I32 : VFLAT_Real_Atomics_gfx12<0x03a, "FLAT_ATOMIC_SMAX", "flat_atomic_max_i32", true>;
+defm FLAT_ATOMIC_MAX_U32 : VFLAT_Real_Atomics_gfx12<0x03b, "FLAT_ATOMIC_UMAX", "flat_atomic_max_u32", true>;
+defm FLAT_ATOMIC_AND_B32 : VFLAT_Real_Atomics_gfx12<0x03c, "FLAT_ATOMIC_AND", "flat_atomic_and_b32", true>;
+defm FLAT_ATOMIC_OR_B32 : VFLAT_Real_Atomics_gfx12<0x03d, "FLAT_ATOMIC_OR", "flat_atomic_or_b32", true>;
+defm FLAT_ATOMIC_XOR_B32 : VFLAT_Real_Atomics_gfx12<0x03e, "FLAT_ATOMIC_XOR", "flat_atomic_xor_b32", true>;
+defm FLAT_ATOMIC_INC_U32 : VFLAT_Real_Atomics_gfx12<0x03f, "FLAT_ATOMIC_INC", "flat_atomic_inc_u32", true>;
+defm FLAT_ATOMIC_DEC_U32 : VFLAT_Real_Atomics_gfx12<0x040, "FLAT_ATOMIC_DEC", "flat_atomic_dec_u32", true>;
+defm FLAT_ATOMIC_SWAP_B64 : VFLAT_Real_Atomics_gfx12<0x041, "FLAT_ATOMIC_SWAP_X2", "flat_atomic_swap_b64", true>;
+defm FLAT_ATOMIC_CMPSWAP_B64 : VFLAT_Real_Atomics_gfx12<0x042, "FLAT_ATOMIC_CMPSWAP_X2", "flat_atomic_cmpswap_b64", true>;
+defm FLAT_ATOMIC_ADD_U64 : VFLAT_Real_Atomics_gfx12<0x043, "FLAT_ATOMIC_ADD_X2", "flat_atomic_add_u64", true>;
+defm FLAT_ATOMIC_SUB_U64 : VFLAT_Real_Atomics_gfx12<0x044, "FLAT_ATOMIC_SUB_X2", "flat_atomic_sub_u64", true>;
+defm FLAT_ATOMIC_MIN_I64 : VFLAT_Real_Atomics_gfx12<0x045, "FLAT_ATOMIC_SMIN_X2", "flat_atomic_min_i64", true>;
+defm FLAT_ATOMIC_MIN_U64 : VFLAT_Real_Atomics_gfx12<0x046, "FLAT_ATOMIC_UMIN_X2", "flat_atomic_min_u64", true>;
+defm FLAT_ATOMIC_MAX_I64 : VFLAT_Real_Atomics_gfx12<0x047, "FLAT_ATOMIC_SMAX_X2", "flat_atomic_max_i64", true>;
+defm FLAT_ATOMIC_MAX_U64 : VFLAT_Real_Atomics_gfx12<0x048, "FLAT_ATOMIC_UMAX_X2", "flat_atomic_max_u64", true>;
+defm FLAT_ATOMIC_AND_B64 : VFLAT_Real_Atomics_gfx12<0x049, "FLAT_ATOMIC_AND_X2", "flat_atomic_and_b64", true>;
+defm FLAT_ATOMIC_OR_B64 : VFLAT_Real_Atomics_gfx12<0x04a, "FLAT_ATOMIC_OR_X2", "flat_atomic_or_b64", true>;
+defm FLAT_ATOMIC_XOR_B64 : VFLAT_Real_Atomics_gfx12<0x04b, "FLAT_ATOMIC_XOR_X2", "flat_atomic_xor_b64", true>;
+defm FLAT_ATOMIC_INC_U64 : VFLAT_Real_Atomics_gfx12<0x04c, "FLAT_ATOMIC_INC_X2", "flat_atomic_inc_u64", true>;
+defm FLAT_ATOMIC_DEC_U64 : VFLAT_Real_Atomics_gfx12<0x04d, "FLAT_ATOMIC_DEC_X2", "flat_atomic_dec_u64", true>;
+defm FLAT_ATOMIC_MIN_NUM_F32 : VFLAT_Real_Atomics_gfx12<0x051, "FLAT_ATOMIC_FMIN", "flat_atomic_min_num_f32", true, "flat_atomic_min_f32">;
+defm FLAT_ATOMIC_MAX_NUM_F32 : VFLAT_Real_Atomics_gfx12<0x052, "FLAT_ATOMIC_FMAX", "flat_atomic_max_num_f32", true, "flat_atomic_max_f32">;
+defm FLAT_ATOMIC_ADD_F32 : VFLAT_Real_Atomics_gfx12<0x056, "FLAT_ATOMIC_ADD_F32", "flat_atomic_add_f32">;
+
+// ENC_VGLOBAL.
+defm GLOBAL_LOAD_U8 : VGLOBAL_Real_AllAddr_gfx12<0x010, "GLOBAL_LOAD_UBYTE", "global_load_u8", true>;
+defm GLOBAL_LOAD_I8 : VGLOBAL_Real_AllAddr_gfx12<0x011, "GLOBAL_LOAD_SBYTE", "global_load_i8", true>;
+defm GLOBAL_LOAD_U16 : VGLOBAL_Real_AllAddr_gfx12<0x012, "GLOBAL_LOAD_USHORT", "global_load_u16", true>;
+defm GLOBAL_LOAD_I16 : VGLOBAL_Real_AllAddr_gfx12<0x013, "GLOBAL_LOAD_SSHORT", "global_load_i16", true>;
+defm GLOBAL_LOAD_B32 : VGLOBAL_Real_AllAddr_gfx12<0x014, "GLOBAL_LOAD_DWORD", "global_load_b32", true>;
+defm GLOBAL_LOAD_B64 : VGLOBAL_Real_AllAddr_gfx12<0x015, "GLOBAL_LOAD_DWORDX2", "global_load_b64", true>;
+defm GLOBAL_LOAD_B96 : VGLOBAL_Real_AllAddr_gfx12<0x016, "GLOBAL_LOAD_DWORDX3", "global_load_b96", true>;
+defm GLOBAL_LOAD_B128 : VGLOBAL_Real_AllAddr_gfx12<0x017, "GLOBAL_LOAD_DWORDX4", "global_load_b128", true>;
+defm GLOBAL_STORE_B8 : VGLOBAL_Real_AllAddr_gfx12<0x018, "GLOBAL_STORE_BYTE", "global_store_b8", true>;
+defm GLOBAL_STORE_B16 : VGLOBAL_Real_AllAddr_gfx12<0x019, "GLOBAL_STORE_SHORT", "global_store_b16", true>;
+defm GLOBAL_STORE_B32 : VGLOBAL_Real_AllAddr_gfx12<0x01a, "GLOBAL_STORE_DWORD", "global_store_b32", true>;
+defm GLOBAL_STORE_B64 : VGLOBAL_Real_AllAddr_gfx12<0x01b, "GLOBAL_STORE_DWORDX2", "global_store_b64", true>;
+defm GLOBAL_STORE_B96 : VGLOBAL_Real_AllAddr_gfx12<0x01c, "GLOBAL_STORE_DWORDX3", "global_store_b96", true>;
+defm GLOBAL_STORE_B128 : VGLOBAL_Real_AllAddr_gfx12<0x01d, "GLOBAL_STORE_DWORDX4", "global_store_b128", true>;
+defm GLOBAL_LOAD_D16_U8 : VGLOBAL_Real_AllAddr_gfx12<0x01e, "GLOBAL_LOAD_UBYTE_D16", "global_load_d16_u8">;
+defm GLOBAL_LOAD_D16_I8 : VGLOBAL_Real_AllAddr_gfx12<0x01f, "GLOBAL_LOAD_SBYTE_D16", "global_load_d16_i8">;
+defm GLOBAL_LOAD_D16_B16 : VGLOBAL_Real_AllAddr_gfx12<0x020, "GLOBAL_LOAD_SHORT_D16", "global_load_d16_b16">;
+defm GLOBAL_LOAD_D16_HI_U8 : VGLOBAL_Real_AllAddr_gfx12<0x021, "GLOBAL_LOAD_UBYTE_D16_HI", "global_load_d16_hi_u8">;
+defm GLOBAL_LOAD_D16_HI_I8 : VGLOBAL_Real_AllAddr_gfx12<0x022, "GLOBAL_LOAD_SBYTE_D16_HI", "global_load_d16_hi_i8">;
+defm GLOBAL_LOAD_D16_HI_B16 : VGLOBAL_Real_AllAddr_gfx12<0x023, "GLOBAL_LOAD_SHORT_D16_HI", "global_load_d16_hi_b16">;
+defm GLOBAL_STORE_D16_HI_B8 : VGLOBAL_Real_AllAddr_gfx12<0x024, "GLOBAL_STORE_BYTE_D16_HI", "global_store_d16_hi_b8">;
+defm GLOBAL_STORE_D16_HI_B16 : VGLOBAL_Real_AllAddr_gfx12<0x025, "GLOBAL_STORE_SHORT_D16_HI", "global_store_d16_hi_b16">;
+defm GLOBAL_LOAD_ADDTID_B32 : VGLOBAL_Real_AllAddr_gfx12<0x028, "GLOBAL_LOAD_DWORD_ADDTID", "global_load_addtid_b32">;
+defm GLOBAL_STORE_ADDTID_B32 : VGLOBAL_Real_AllAddr_gfx12<0x029, "GLOBAL_STORE_DWORD_ADDTID", "global_store_addtid_b32">;
+
+defm GLOBAL_ATOMIC_SWAP_B32 : VGLOBAL_Real_Atomics_gfx12<0x033, "GLOBAL_ATOMIC_SWAP", "global_atomic_swap_b32", true>;
+defm GLOBAL_ATOMIC_CMPSWAP_B32 : VGLOBAL_Real_Atomics_gfx12<0x034, "GLOBAL_ATOMIC_CMPSWAP", "global_atomic_cmpswap_b32", true>;
+defm GLOBAL_ATOMIC_ADD_U32 : VGLOBAL_Real_Atomics_gfx12<0x035, "GLOBAL_ATOMIC_ADD", "global_atomic_add_u32", true>;
+defm GLOBAL_ATOMIC_SUB_U32 : VGLOBAL_Real_Atomics_gfx12<0x036, "GLOBAL_ATOMIC_SUB", "global_atomic_sub_u32", true>;
+defm GLOBAL_ATOMIC_SUB_CLAMP_U32 : VGLOBAL_Real_Atomics_gfx12<0x037, "GLOBAL_ATOMIC_CSUB", "global_atomic_sub_clamp_u32", true, "global_atomic_csub_u32">;
+defm GLOBAL_ATOMIC_MIN_I32 : VGLOBAL_Real_Atomics_gfx12<0x038, "GLOBAL_ATOMIC_SMIN", "global_atomic_min_i32", true>;
+defm GLOBAL_ATOMIC_MIN_U32 : VGLOBAL_Real_Atomics_gfx12<0x039, "GLOBAL_ATOMIC_UMIN", "global_atomic_min_u32", true>;
+defm GLOBAL_ATOMIC_MAX_I32 : VGLOBAL_Real_Atomics_gfx12<0x03a, "GLOBAL_ATOMIC_SMAX", "global_atomic_max_i32", true>;
+defm GLOBAL_ATOMIC_MAX_U32 : VGLOBAL_Real_Atomics_gfx12<0x03b, "GLOBAL_ATOMIC_UMAX", "global_atomic_max_u32", true>;
+defm GLOBAL_ATOMIC_AND_B32 : VGLOBAL_Real_Atomics_gfx12<0x03c, "GLOBAL_ATOMIC_AND", "global_atomic_and_b32", true>;
+defm GLOBAL_ATOMIC_OR_B32 : VGLOBAL_Real_Atomics_gfx12<0x03d, "GLOBAL_ATOMIC_OR", "global_atomic_or_b32", true>;
+defm GLOBAL_ATOMIC_XOR_B32 : VGLOBAL_Real_Atomics_gfx12<0x03e, "GLOBAL_ATOMIC_XOR", "global_atomic_xor_b32", true>;
+defm GLOBAL_ATOMIC_INC_U32 : VGLOBAL_Real_Atomics_gfx12<0x03f, "GLOBAL_ATOMIC_INC", "global_atomic_inc_u32", true>;
+defm GLOBAL_ATOMIC_DEC_U32 : VGLOBAL_Real_Atomics_gfx12<0x040, "GLOBAL_ATOMIC_DEC", "global_atomic_dec_u32", true>;
+defm GLOBAL_ATOMIC_SWAP_B64 : VGLOBAL_Real_Atomics_gfx12<0x041, "GLOBAL_ATOMIC_SWAP_X2", "global_atomic_swap_b64", true>;
+defm GLOBAL_ATOMIC_CMPSWAP_B64 : VGLOBAL_Real_Atomics_gfx12<0x042, "GLOBAL_ATOMIC_CMPSWAP_X2", "global_atomic_cmpswap_b64", true>;
+defm GLOBAL_ATOMIC_ADD_U64 : VGLOBAL_Real_Atomics_gfx12<0x043, "GLOBAL_ATOMIC_ADD_X2", "global_atomic_add_u64", true>;
+defm GLOBAL_ATOMIC_SUB_U64 : VGLOBAL_Real_Atomics_gfx12<0x044, "GLOBAL_ATOMIC_SUB_X2", "global_atomic_sub_u64", true>;
+defm GLOBAL_ATOMIC_MIN_I64 : VGLOBAL_Real_Atomics_gfx12<0x045, "GLOBAL_ATOMIC_SMIN_X2", "global_atomic_min_i64", true>;
+defm GLOBAL_ATOMIC_MIN_U64 : VGLOBAL_Real_Atomics_gfx12<0x046, "GLOBAL_ATOMIC_UMIN_X2", "global_atomic_min_u64", true>;
+defm GLOBAL_ATOMIC_MAX_I64 : VGLOBAL_Real_Atomics_gfx12<0x047, "GLOBAL_ATOMIC_SMAX_X2", "global_atomic_max_i64", true>;
+defm GLOBAL_ATOMIC_MAX_U64 : VGLOBAL_Real_Atomics_gfx12<0x048, "GLOBAL_ATOMIC_UMAX_X2", "global_atomic_max_u64", true>;
+defm GLOBAL_ATOMIC_AND_B64 : VGLOBAL_Real_Atomics_gfx12<0x049, "GLOBAL_ATOMIC_AND_X2", "global_atomic_and_b64", true>;
+defm GLOBAL_ATOMIC_OR_B64 : VGLOBAL_Real_Atomics_gfx12<0x04a, "GLOBAL_ATOMIC_OR_X2", "global_atomic_or_b64", true>;
+defm GLOBAL_ATOMIC_XOR_B64 : VGLOBAL_Real_Atomics_gfx12<0x04b, "GLOBAL_ATOMIC_XOR_X2", "global_atomic_xor_b64", true>;
+defm GLOBAL_ATOMIC_INC_U64 : VGLOBAL_Real_Atomics_gfx12<0x04c, "GLOBAL_ATOMIC_INC_X2", "global_atomic_inc_u64", true>;
+defm GLOBAL_ATOMIC_DEC_U64 : VGLOBAL_Real_Atomics_gfx12<0x04d, "GLOBAL_ATOMIC_DEC_X2", "global_atomic_dec_u64", true>;
+defm GLOBAL_ATOMIC_MIN_NUM_F32 : VGLOBAL_Real_Atomics_gfx12<0x051, "GLOBAL_ATOMIC_FMIN", "global_atomic_min_num_f32", true, "global_atomic_min_f32">;
+defm GLOBAL_ATOMIC_MAX_NUM_F32 : VGLOBAL_Real_Atomics_gfx12<0x052, "GLOBAL_ATOMIC_FMAX", "global_atomic_max_num_f32", true, "global_atomic_max_f32">;
+defm GLOBAL_ATOMIC_ADD_F32 : VGLOBAL_Real_Atomics_gfx12<0x056, "GLOBAL_ATOMIC_ADD_F32", "global_atomic_add_f32">;
+
+// ENC_VSCRATCH.
+defm SCRATCH_LOAD_U8 : VSCRATCH_Real_AllAddr_gfx12<0x10, "SCRATCH_LOAD_UBYTE", "scratch_load_u8", true>;
+defm SCRATCH_LOAD_I8 : VSCRATCH_Real_AllAddr_gfx12<0x11, "SCRATCH_LOAD_SBYTE", "scratch_load_i8", true>;
+defm SCRATCH_LOAD_U16 : VSCRATCH_Real_AllAddr_gfx12<0x12, "SCRATCH_LOAD_USHORT", "scratch_load_u16", true>;
+defm SCRATCH_LOAD_I16 : VSCRATCH_Real_AllAddr_gfx12<0x13, "SCRATCH_LOAD_SSHORT", "scratch_load_i16", true>;
+defm SCRATCH_LOAD_B32 : VSCRATCH_Real_AllAddr_gfx12<0x14, "SCRATCH_LOAD_DWORD", "scratch_load_b32", true>;
+defm SCRATCH_LOAD_B64 : VSCRATCH_Real_AllAddr_gfx12<0x15, "SCRATCH_LOAD_DWORDX2", "scratch_load_b64", true>;
+defm SCRATCH_LOAD_B96 : VSCRATCH_Real_AllAddr_gfx12<0x16, "SCRATCH_LOAD_DWORDX3", "scratch_load_b96", true>;
+defm SCRATCH_LOAD_B128 : VSCRATCH_Real_AllAddr_gfx12<0x17, "SCRATCH_LOAD_DWORDX4", "scratch_load_b128", true>;
+defm SCRATCH_STORE_B8 : VSCRATCH_Real_AllAddr_gfx12<0x18, "SCRATCH_STORE_BYTE", "scratch_store_b8", true>;
+defm SCRATCH_STORE_B16 : VSCRATCH_Real_AllAddr_gfx12<0x19, "SCRATCH_STORE_SHORT", "scratch_store_b16", true>;
+defm SCRATCH_STORE_B32 : VSCRATCH_Real_AllAddr_gfx12<0x1a, "SCRATCH_STORE_DWORD", "scratch_store_b32", true>;
+defm SCRATCH_STORE_B64 : VSCRATCH_Real_AllAddr_gfx12<0x1b, "SCRATCH_STORE_DWORDX2", "scratch_store_b64", true>;
+defm SCRATCH_STORE_B96 : VSCRATCH_Real_AllAddr_gfx12<0x1c, "SCRATCH_STORE_DWORDX3", "scratch_store_b96", true>;
+defm SCRATCH_STORE_B128 : VSCRATCH_Real_AllAddr_gfx12<0x1d, "SCRATCH_STORE_DWORDX4", "scratch_store_b128", true>;
+defm SCRATCH_LOAD_D16_U8 : VSCRATCH_Real_AllAddr_gfx12<0x1e, "SCRATCH_LOAD_UBYTE_D16", "scratch_load_d16_u8">;
+defm SCRATCH_LOAD_D16_I8 : VSCRATCH_Real_AllAddr_gfx12<0x1f, "SCRATCH_LOAD_SBYTE_D16", "scratch_load_d16_i8">;
+defm SCRATCH_LOAD_D16_B16 : VSCRATCH_Real_AllAddr_gfx12<0x20, "SCRATCH_LOAD_SHORT_D16", "scratch_load_d16_b16">;
+defm SCRATCH_LOAD_D16_HI_U8 : VSCRATCH_Real_AllAddr_gfx12<0x21, "SCRATCH_LOAD_UBYTE_D16_HI", "scratch_load_d16_hi_u8">;
+defm SCRATCH_LOAD_D16_HI_I8 : VSCRATCH_Real_AllAddr_gfx12<0x22, "SCRATCH_LOAD_SBYTE_D16_HI", "scratch_load_d16_hi_i8">;
+defm SCRATCH_LOAD_D16_HI_B16 : VSCRATCH_Real_AllAddr_gfx12<0x23, "SCRATCH_LOAD_SHORT_D16_HI", "scratch_load_d16_hi_b16">;
+defm SCRATCH_STORE_D16_HI_B8 : VSCRATCH_Real_AllAddr_gfx12<0x24, "SCRATCH_STORE_BYTE_D16_HI", "scratch_store_d16_hi_b8">;
+defm SCRATCH_STORE_D16_HI_B16 : VSCRATCH_Real_AllAddr_gfx12<0x25, "SCRATCH_STORE_SHORT_D16_HI", "scratch_store_d16_hi_b16">;
diff --git a/llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp b/llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp
index 982367f8f934..05e10a95b157 100644
--- a/llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp
@@ -71,8 +71,11 @@ public:
auto *SecondMI = CI.SecondMI;
unsigned Opc1 = FirstMI->getOpcode();
unsigned Opc2 = SecondMI->getOpcode();
- int NewOpcode = AMDGPU::getVOPDFull(AMDGPU::getVOPDOpcode(Opc1),
- AMDGPU::getVOPDOpcode(Opc2));
+ unsigned EncodingFamily =
+ AMDGPU::getVOPDEncodingFamily(SII->getSubtarget());
+ int NewOpcode =
+ AMDGPU::getVOPDFull(AMDGPU::getVOPDOpcode(Opc1),
+ AMDGPU::getVOPDOpcode(Opc2), EncodingFamily);
assert(NewOpcode != -1 &&
"Should have previously determined this as a possible VOPD\n");
diff --git a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp
index 3af71727c5b7..a7d8ff0242b8 100644
--- a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp
@@ -163,7 +163,9 @@ static bool isSendMsgTraceDataOrGDS(const SIInstrInfo &TII,
static bool isPermlane(const MachineInstr &MI) {
unsigned Opcode = MI.getOpcode();
return Opcode == AMDGPU::V_PERMLANE16_B32_e64 ||
- Opcode == AMDGPU::V_PERMLANEX16_B32_e64;
+ Opcode == AMDGPU::V_PERMLANEX16_B32_e64 ||
+ Opcode == AMDGPU::V_PERMLANE16_VAR_B32_e64 ||
+ Opcode == AMDGPU::V_PERMLANEX16_VAR_B32_e64;
}
static bool isLdsDma(const MachineInstr &MI) {
diff --git a/llvm/lib/Target/AMDGPU/GCNProcessors.td b/llvm/lib/Target/AMDGPU/GCNProcessors.td
index 80669c04f2c6..96af1a6aab3d 100644
--- a/llvm/lib/Target/AMDGPU/GCNProcessors.td
+++ b/llvm/lib/Target/AMDGPU/GCNProcessors.td
@@ -284,10 +284,10 @@ def : ProcessorModel<"gfx1151", GFX11SpeedModel,
// GCN GFX12.
//===----------------------------------------------------------------------===//
-def : ProcessorModel<"gfx1200", GFX11SpeedModel,
+def : ProcessorModel<"gfx1200", GFX12SpeedModel,
FeatureISAVersion12.Features
>;
-def : ProcessorModel<"gfx1201", GFX11SpeedModel,
+def : ProcessorModel<"gfx1201", GFX12SpeedModel,
FeatureISAVersion12.Features
>;
diff --git a/llvm/lib/Target/AMDGPU/GCNSubtarget.h b/llvm/lib/Target/AMDGPU/GCNSubtarget.h
index 94b9e49b765a..91a709303269 100644
--- a/llvm/lib/Target/AMDGPU/GCNSubtarget.h
+++ b/llvm/lib/Target/AMDGPU/GCNSubtarget.h
@@ -119,6 +119,7 @@ protected:
bool HasFmaMixInsts = false;
bool HasMovrel = false;
bool HasVGPRIndexMode = false;
+ bool HasScalarDwordx3Loads = false;
bool HasScalarStores = false;
bool HasScalarAtomics = false;
bool HasSDWAOmod = false;
@@ -197,6 +198,8 @@ protected:
bool ScalarizeGlobal = false;
bool HasSALUFloatInsts = false;
bool HasVGPRSingleUseHintInsts = false;
+ bool HasPseudoScalarTrans = false;
+ bool HasRestrictedSOffset = false;
bool HasVcmpxPermlaneHazard = false;
bool HasVMEMtoScalarWriteHazard = false;
@@ -677,6 +680,8 @@ public:
return AddNoCarryInsts;
}
+ bool hasScalarAddSub64() const { return getGeneration() >= GFX12; }
+
bool hasUnpackedD16VMem() const {
return HasUnpackedD16VMem;
}
@@ -828,6 +833,11 @@ public:
bool hasInstPrefetch() const { return getGeneration() >= GFX10; }
+ bool hasPrefetch() const { return GFX12Insts; }
+
+ // Has s_cmpk_* instructions.
+ bool hasSCmpK() const { return getGeneration() < GFX12; }
+
// Scratch is allocated in 256 dword per wave blocks for the entire
// wavefront. When viewed from the perspective of an arbitrary workitem, this
// is 4-byte aligned.
@@ -884,6 +894,8 @@ public:
return getGeneration() >= VOLCANIC_ISLANDS;
}
+ bool hasScalarDwordx3Loads() const { return HasScalarDwordx3Loads; }
+
bool hasScalarStores() const {
return HasScalarStores;
}
@@ -1152,6 +1164,10 @@ public:
bool hasVGPRSingleUseHintInsts() const { return HasVGPRSingleUseHintInsts; }
+ bool hasPseudoScalarTrans() const { return HasPseudoScalarTrans; }
+
+ bool hasRestrictedSOffset() const { return HasRestrictedSOffset; }
+
/// Return the maximum number of waves per SIMD for kernels using \p SGPRs
/// SGPRs
unsigned getOccupancyWithNumSGPRs(unsigned SGPRs) const;
@@ -1204,12 +1220,28 @@ public:
return hasKernargPreload() && !hasGFX940Insts();
}
+ // \returns true if the target has split barriers feature
+ bool hasSplitBarriers() const { return getGeneration() >= GFX12; }
+
// \returns true if FP8/BF8 VOP1 form of conversion to F32 is unreliable.
bool hasCvtFP8VOP1Bug() const { return true; }
- // \returns true is CSUB atomics support a no-return form.
+ // \returns true if CSUB (a.k.a. SUB_CLAMP on GFX12) atomics support a
+ // no-return form.
bool hasAtomicCSubNoRtnInsts() const { return HasAtomicCSubNoRtnInsts; }
+ // \returns true if the target has DX10_CLAMP kernel descriptor mode bit
+ bool hasDX10ClampMode() const { return getGeneration() < GFX12; }
+
+ // \returns true if the target has IEEE kernel descriptor mode bit
+ bool hasIEEEMode() const { return getGeneration() < GFX12; }
+
+ // \returns true if the target has IEEE fminimum/fmaximum instructions
+ bool hasIEEEMinMax() const { return getGeneration() >= GFX12; }
+
+ // \returns true if the target has WG_RR_MODE kernel descriptor mode bit
+ bool hasRrWGMode() const { return getGeneration() >= GFX12; }
+
/// \returns SGPR allocation granularity supported by the subtarget.
unsigned getSGPRAllocGranule() const {
return AMDGPU::IsaInfo::getSGPRAllocGranule(this);
diff --git a/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp b/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp
index 29c9b9ccf276..33c208495c50 100644
--- a/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp
@@ -103,7 +103,13 @@ bool llvm::checkVOPDRegConstraints(const SIInstrInfo &TII,
return false;
if ((UniqueLiterals.size() + UniqueScalarRegs.size()) > 2)
return false;
- if (InstInfo.hasInvalidOperand(getVRegIdx))
+
+ // On GFX12 if both OpX and OpY are V_MOV_B32 then OPY uses SRC2 source-cache.
+ bool SkipSrc = ST.getGeneration() >= AMDGPUSubtarget::GFX12 &&
+ FirstMI.getOpcode() == AMDGPU::V_MOV_B32_e32 &&
+ SecondMI.getOpcode() == AMDGPU::V_MOV_B32_e32;
+
+ if (InstInfo.hasInvalidOperand(getVRegIdx, SkipSrc))
return false;
LLVM_DEBUG(dbgs() << "VOPD Reg Constraints Passed\n\tX: " << FirstMI
@@ -142,10 +148,10 @@ namespace {
/// be turned into VOPD instructions
/// Greedily pairs instruction candidates. O(n^2) algorithm.
struct VOPDPairingMutation : ScheduleDAGMutation {
- ShouldSchedulePredTy shouldScheduleAdjacent; // NOLINT: function pointer
+ MacroFusionPredTy shouldScheduleAdjacent; // NOLINT: function pointer
VOPDPairingMutation(
- ShouldSchedulePredTy shouldScheduleAdjacent) // NOLINT: function pointer
+ MacroFusionPredTy shouldScheduleAdjacent) // NOLINT: function pointer
: shouldScheduleAdjacent(shouldScheduleAdjacent) {}
void apply(ScheduleDAGInstrs *DAG) override {
diff --git a/llvm/lib/Target/AMDGPU/MCA/AMDGPUCustomBehaviour.cpp b/llvm/lib/Target/AMDGPU/MCA/AMDGPUCustomBehaviour.cpp
index bf65be3fe903..c8ce1903d315 100644
--- a/llvm/lib/Target/AMDGPU/MCA/AMDGPUCustomBehaviour.cpp
+++ b/llvm/lib/Target/AMDGPU/MCA/AMDGPUCustomBehaviour.cpp
@@ -25,10 +25,12 @@ void AMDGPUInstrPostProcess::postProcessInstruction(
std::unique_ptr<Instruction> &Inst, const MCInst &MCI) {
switch (MCI.getOpcode()) {
case AMDGPU::S_WAITCNT:
+ case AMDGPU::S_WAITCNT_soft:
case AMDGPU::S_WAITCNT_EXPCNT:
case AMDGPU::S_WAITCNT_LGKMCNT:
case AMDGPU::S_WAITCNT_VMCNT:
case AMDGPU::S_WAITCNT_VSCNT:
+ case AMDGPU::S_WAITCNT_VSCNT_soft:
case AMDGPU::S_WAITCNT_EXPCNT_gfx10:
case AMDGPU::S_WAITCNT_LGKMCNT_gfx10:
case AMDGPU::S_WAITCNT_VMCNT_gfx10:
@@ -77,10 +79,12 @@ unsigned AMDGPUCustomBehaviour::checkCustomHazard(ArrayRef<InstRef> IssuedInst,
default:
return 0;
case AMDGPU::S_WAITCNT: // This instruction
+ case AMDGPU::S_WAITCNT_soft:
case AMDGPU::S_WAITCNT_EXPCNT:
case AMDGPU::S_WAITCNT_LGKMCNT:
case AMDGPU::S_WAITCNT_VMCNT:
- case AMDGPU::S_WAITCNT_VSCNT: // to this instruction are all pseudo.
+ case AMDGPU::S_WAITCNT_VSCNT:
+ case AMDGPU::S_WAITCNT_VSCNT_soft: // to this instruction are all pseudo.
case AMDGPU::S_WAITCNT_EXPCNT_gfx10:
case AMDGPU::S_WAITCNT_LGKMCNT_gfx10:
case AMDGPU::S_WAITCNT_VMCNT_gfx10:
diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
index 7ba015cdea24..edc244db613d 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
@@ -97,28 +97,36 @@ void AMDGPUInstPrinter::printNamedBit(const MCInst *MI, unsigned OpNo,
void AMDGPUInstPrinter::printOffset(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
- uint16_t Imm = MI->getOperand(OpNo).getImm();
+ uint32_t Imm = MI->getOperand(OpNo).getImm();
if (Imm != 0) {
O << " offset:";
- printU16ImmDecOperand(MI, OpNo, O);
+
+ // GFX12 uses a 24-bit signed offset for VBUFFER.
+ const MCInstrDesc &Desc = MII.get(MI->getOpcode());
+ bool IsVBuffer = Desc.TSFlags & (SIInstrFlags::MUBUF | SIInstrFlags::MTBUF);
+ if (AMDGPU::isGFX12(STI) && IsVBuffer)
+ O << formatDec(SignExtend32<24>(Imm));
+ else
+ printU16ImmDecOperand(MI, OpNo, O);
}
}
void AMDGPUInstPrinter::printFlatOffset(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
- uint16_t Imm = MI->getOperand(OpNo).getImm();
+ uint32_t Imm = MI->getOperand(OpNo).getImm();
if (Imm != 0) {
O << " offset:";
const MCInstrDesc &Desc = MII.get(MI->getOpcode());
- bool IsFlatSeg = !(Desc.TSFlags &
- (SIInstrFlags::FlatGlobal | SIInstrFlags::FlatScratch));
+ bool AllowNegative = (Desc.TSFlags & (SIInstrFlags::FlatGlobal |
+ SIInstrFlags::FlatScratch)) ||
+ AMDGPU::isGFX12(STI);
- if (IsFlatSeg) // Unsigned offset
- printU16ImmDecOperand(MI, OpNo, O);
- else // Signed offset
+ if (AllowNegative) // Signed offset
O << formatDec(SignExtend32(Imm, AMDGPU::getNumFlatOffsetBits(STI)));
+ else // Unsigned offset
+ printU16ImmDecOperand(MI, OpNo, O);
}
}
@@ -416,6 +424,15 @@ void AMDGPUInstPrinter::printVOPDst(const MCInst *MI, unsigned OpNo,
case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx11:
case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx11:
case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx11:
+ case AMDGPU::V_ADD_CO_CI_U32_e32_gfx12:
+ case AMDGPU::V_SUB_CO_CI_U32_e32_gfx12:
+ case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx12:
+ case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx12:
+ case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx12:
+ case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx12:
+ case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx12:
+ case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx12:
+ case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx12:
printDefaultVccOperand(false, STI, O);
break;
}
@@ -699,6 +716,7 @@ void AMDGPUInstPrinter::printRegularOperand(const MCInst *MI, unsigned OpNo,
case AMDGPU::OPERAND_REG_INLINE_C_V2INT32:
case AMDGPU::OPERAND_REG_INLINE_C_V2FP32:
case MCOI::OPERAND_IMMEDIATE:
+ case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32:
printImmediate32(Op.getImm(), STI, O);
break;
case AMDGPU::OPERAND_REG_IMM_INT64:
@@ -807,6 +825,18 @@ void AMDGPUInstPrinter::printRegularOperand(const MCInst *MI, unsigned OpNo,
case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx11:
case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx11:
case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx11:
+ case AMDGPU::V_CNDMASK_B32_e32_gfx12:
+ case AMDGPU::V_ADD_CO_CI_U32_e32_gfx12:
+ case AMDGPU::V_SUB_CO_CI_U32_e32_gfx12:
+ case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx12:
+ case AMDGPU::V_CNDMASK_B32_dpp_gfx12:
+ case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx12:
+ case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx12:
+ case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx12:
+ case AMDGPU::V_CNDMASK_B32_dpp8_gfx12:
+ case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx12:
+ case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx12:
+ case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx12:
case AMDGPU::V_CNDMASK_B32_e32_gfx6_gfx7:
case AMDGPU::V_CNDMASK_B32_e32_vi:
diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp
index 80e7ca2b39d1..b403d69d9ff1 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp
@@ -262,6 +262,7 @@ AMDGPUMCCodeEmitter::getLitEncoding(const MCOperand &MO,
case AMDGPU::OPERAND_REG_IMM_V2FP32:
case AMDGPU::OPERAND_REG_INLINE_C_V2INT32:
case AMDGPU::OPERAND_REG_INLINE_C_V2FP32:
+ case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32:
return getLit32Encoding(static_cast<uint32_t>(Imm), STI);
case AMDGPU::OPERAND_REG_IMM_INT64:
diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
index eba8e49a46f8..a855cf585205 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
@@ -451,12 +451,12 @@ void AMDGPUTargetAsmStreamer::EmitAmdhsaKernelDescriptor(
PRINT_FIELD(OS, ".amdhsa_float_denorm_mode_16_64", KD,
compute_pgm_rsrc1,
amdhsa::COMPUTE_PGM_RSRC1_FLOAT_DENORM_MODE_16_64);
- PRINT_FIELD(OS, ".amdhsa_dx10_clamp", KD,
- compute_pgm_rsrc1,
- amdhsa::COMPUTE_PGM_RSRC1_ENABLE_DX10_CLAMP);
- PRINT_FIELD(OS, ".amdhsa_ieee_mode", KD,
- compute_pgm_rsrc1,
- amdhsa::COMPUTE_PGM_RSRC1_ENABLE_IEEE_MODE);
+ if (IVersion.Major < 12) {
+ PRINT_FIELD(OS, ".amdhsa_dx10_clamp", KD, compute_pgm_rsrc1,
+ amdhsa::COMPUTE_PGM_RSRC1_GFX6_GFX11_ENABLE_DX10_CLAMP);
+ PRINT_FIELD(OS, ".amdhsa_ieee_mode", KD, compute_pgm_rsrc1,
+ amdhsa::COMPUTE_PGM_RSRC1_GFX6_GFX11_ENABLE_IEEE_MODE);
+ }
if (IVersion.Major >= 9)
PRINT_FIELD(OS, ".amdhsa_fp16_overflow", KD,
compute_pgm_rsrc1,
@@ -478,6 +478,9 @@ void AMDGPUTargetAsmStreamer::EmitAmdhsaKernelDescriptor(
PRINT_FIELD(OS, ".amdhsa_shared_vgpr_count", KD, compute_pgm_rsrc3,
amdhsa::COMPUTE_PGM_RSRC3_GFX10_PLUS_SHARED_VGPR_COUNT);
}
+ if (IVersion.Major >= 12)
+ PRINT_FIELD(OS, ".amdhsa_round_robin_scheduling", KD, compute_pgm_rsrc1,
+ amdhsa::COMPUTE_PGM_RSRC1_GFX12_PLUS_ENABLE_WG_RR_EN);
PRINT_FIELD(
OS, ".amdhsa_exception_fp_ieee_invalid_op", KD,
compute_pgm_rsrc2,
diff --git a/llvm/lib/Target/AMDGPU/R600OpenCLImageTypeLoweringPass.cpp b/llvm/lib/Target/AMDGPU/R600OpenCLImageTypeLoweringPass.cpp
index 2a15c0123b74..195dc4f9a0f4 100644
--- a/llvm/lib/Target/AMDGPU/R600OpenCLImageTypeLoweringPass.cpp
+++ b/llvm/lib/Target/AMDGPU/R600OpenCLImageTypeLoweringPass.cpp
@@ -163,11 +163,11 @@ class R600OpenCLImageTypeLoweringPass : public ModulePass {
Value *Replacement = nullptr;
StringRef Name = F->getName();
- if (Name.startswith(GetImageResourceIDFunc)) {
+ if (Name.starts_with(GetImageResourceIDFunc)) {
Replacement = ConstantInt::get(Int32Type, ResourceID);
- } else if (Name.startswith(GetImageSizeFunc)) {
+ } else if (Name.starts_with(GetImageSizeFunc)) {
Replacement = &ImageSizeArg;
- } else if (Name.startswith(GetImageFormatFunc)) {
+ } else if (Name.starts_with(GetImageFormatFunc)) {
Replacement = &ImageFormatArg;
} else {
continue;
diff --git a/llvm/lib/Target/AMDGPU/SIDefines.h b/llvm/lib/Target/AMDGPU/SIDefines.h
index 47dc59e77dc4..b291400a947c 100644
--- a/llvm/lib/Target/AMDGPU/SIDefines.h
+++ b/llvm/lib/Target/AMDGPU/SIDefines.h
@@ -213,6 +213,9 @@ enum OperandType : unsigned {
OPERAND_REG_INLINE_C_V2INT32,
OPERAND_REG_INLINE_C_V2FP32,
+ // Operand for split barrier inline constant
+ OPERAND_INLINE_SPLIT_BARRIER_INT32,
+
/// Operand with 32-bit immediate that uses the constant bus.
OPERAND_KIMM32,
OPERAND_KIMM16,
@@ -413,8 +416,8 @@ enum Id { // Message ID, width(4) [3:0].
ID_DEALLOC_VGPRS_GFX11Plus = 3, // reused in GFX11
ID_SAVEWAVE = 4, // added in GFX8, removed in GFX11
- ID_STALL_WAVE_GEN = 5, // added in GFX9
- ID_HALT_WAVES = 6, // added in GFX9
+ ID_STALL_WAVE_GEN = 5, // added in GFX9, removed in GFX12
+ ID_HALT_WAVES = 6, // added in GFX9, removed in GFX12
ID_ORDERED_PS_DONE = 7, // added in GFX9, removed in GFX11
ID_EARLY_PRIM_DEALLOC = 8, // added in GFX9, removed in GFX10
ID_GS_ALLOC_REQ = 9, // added in GFX9
@@ -428,6 +431,7 @@ enum Id { // Message ID, width(4) [3:0].
ID_RTN_GET_REALTIME = 131,
ID_RTN_SAVE_WAVE = 132,
ID_RTN_GET_TBA = 133,
+ ID_RTN_GET_SE_AID_ID = 134,
ID_MASK_PreGFX11_ = 0xF,
ID_MASK_GFX11Plus_ = 0xFF
@@ -1025,6 +1029,14 @@ enum Register_Flag : uint8_t {
} // namespace AMDGPU
+namespace AMDGPU {
+namespace Barrier {
+enum Type { TRAP = -2, WORKGROUP = -1 };
+} // namespace Barrier
+} // namespace AMDGPU
+
+// clang-format off
+
#define R_00B028_SPI_SHADER_PGM_RSRC1_PS 0x00B028
#define S_00B028_VGPRS(x) (((x) & 0x3F) << 0)
#define S_00B028_SGPRS(x) (((x) & 0x0F) << 6)
@@ -1117,6 +1129,9 @@ enum Register_Flag : uint8_t {
#define S_00B848_DX10_CLAMP(x) (((x) & 0x1) << 21)
#define G_00B848_DX10_CLAMP(x) (((x) >> 21) & 0x1)
#define C_00B848_DX10_CLAMP 0xFFDFFFFF
+#define S_00B848_RR_WG_MODE(x) (((x) & 0x1) << 21)
+#define G_00B848_RR_WG_MODE(x) (((x) >> 21) & 0x1)
+#define C_00B848_RR_WG_MODE 0xFFDFFFFF
#define S_00B848_DEBUG_MODE(x) (((x) & 0x1) << 22)
#define G_00B848_DEBUG_MODE(x) (((x) >> 22) & 0x1)
#define C_00B848_DEBUG_MODE 0xFFBFFFFF
@@ -1133,7 +1148,6 @@ enum Register_Flag : uint8_t {
#define G_00B848_FWD_PROGRESS(x) (((x) >> 31) & 0x1)
#define C_00B848_FWD_PROGRESS 0x7FFFFFFF
-
// Helpers for setting FLOAT_MODE
#define FP_ROUND_ROUND_TO_NEAREST 0
#define FP_ROUND_ROUND_TO_INF 1
@@ -1175,6 +1189,9 @@ enum Register_Flag : uint8_t {
#define R_SPILLED_SGPRS 0x4
#define R_SPILLED_VGPRS 0x8
+
+// clang-format on
+
} // End namespace llvm
#endif
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
index e842b0524b51..0f89df144486 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
@@ -1723,6 +1723,7 @@ bool SIFrameLowering::allocateScavengingFrameIndexesNearIncomingSP(
const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
const MachineFrameInfo &MFI = MF.getFrameInfo();
+ const SIInstrInfo *TII = ST.getInstrInfo();
uint64_t EstStackSize = MFI.estimateStackSize(MF);
uint64_t MaxOffset = EstStackSize - 1;
@@ -1734,12 +1735,11 @@ bool SIFrameLowering::allocateScavengingFrameIndexesNearIncomingSP(
// rather than allocating as close to possible. This could save a lot of space
// on frames with alignment requirements.
if (ST.enableFlatScratch()) {
- const SIInstrInfo *TII = ST.getInstrInfo();
if (TII->isLegalFLATOffset(MaxOffset, AMDGPUAS::PRIVATE_ADDRESS,
SIInstrFlags::FlatScratch))
return false;
} else {
- if (SIInstrInfo::isLegalMUBUFImmOffset(MaxOffset))
+ if (TII->isLegalMUBUFImmOffset(MaxOffset))
return false;
}
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index a7f4d63229b7..34826809c1a6 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -763,6 +763,13 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
if (Subtarget->hasMad64_32())
setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, MVT::i32, Custom);
+ if (Subtarget->hasPrefetch())
+ setOperationAction(ISD::PREFETCH, MVT::Other, Custom);
+
+ if (Subtarget->hasIEEEMinMax())
+ setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM},
+ {MVT::f16, MVT::f32, MVT::f64, MVT::v2f16}, Legal);
+
setOperationAction(ISD::INTRINSIC_WO_CHAIN,
{MVT::Other, MVT::f32, MVT::v4f32, MVT::i16, MVT::f16,
MVT::v2i16, MVT::v2f16, MVT::i128},
@@ -800,6 +807,8 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
ISD::FMAXNUM,
ISD::FMINNUM_IEEE,
ISD::FMAXNUM_IEEE,
+ ISD::FMINIMUM,
+ ISD::FMAXIMUM,
ISD::FMA,
ISD::SMIN,
ISD::SMAX,
@@ -1040,12 +1049,20 @@ static EVT memVTFromLoadIntrReturn(Type *Ty, unsigned MaxNumLanes) {
MVT SITargetLowering::getPointerTy(const DataLayout &DL, unsigned AS) const {
if (AMDGPUAS::BUFFER_FAT_POINTER == AS && DL.getPointerSizeInBits(AS) == 160)
return MVT::v5i32;
+ if (AMDGPUAS::BUFFER_STRIDED_POINTER == AS &&
+ DL.getPointerSizeInBits(AS) == 192)
+ return MVT::v6i32;
return AMDGPUTargetLowering::getPointerTy(DL, AS);
}
/// Similarly, the in-memory representation of a p7 is {p8, i32}, aka
/// v8i32 when padding is added.
+/// The in-memory representation of a p9 is {p8, i32, i32}, which is
+/// also v8i32 with padding.
MVT SITargetLowering::getPointerMemTy(const DataLayout &DL, unsigned AS) const {
- if (AMDGPUAS::BUFFER_FAT_POINTER == AS && DL.getPointerSizeInBits(AS) == 160)
+ if ((AMDGPUAS::BUFFER_FAT_POINTER == AS &&
+ DL.getPointerSizeInBits(AS) == 160) ||
+ (AMDGPUAS::BUFFER_STRIDED_POINTER == AS &&
+ DL.getPointerSizeInBits(AS) == 192))
return MVT::v8i32;
return AMDGPUTargetLowering::getPointerMemTy(DL, AS);
}
@@ -1224,9 +1241,13 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
case Intrinsic::amdgcn_global_atomic_fadd:
case Intrinsic::amdgcn_global_atomic_fmin:
case Intrinsic::amdgcn_global_atomic_fmax:
+ case Intrinsic::amdgcn_global_atomic_fmin_num:
+ case Intrinsic::amdgcn_global_atomic_fmax_num:
case Intrinsic::amdgcn_flat_atomic_fadd:
case Intrinsic::amdgcn_flat_atomic_fmin:
case Intrinsic::amdgcn_flat_atomic_fmax:
+ case Intrinsic::amdgcn_flat_atomic_fmin_num:
+ case Intrinsic::amdgcn_flat_atomic_fmax_num:
case Intrinsic::amdgcn_global_atomic_fadd_v2bf16:
case Intrinsic::amdgcn_flat_atomic_fadd_v2bf16: {
Info.opc = ISD::INTRINSIC_W_CHAIN;
@@ -1309,6 +1330,8 @@ bool SITargetLowering::getAddrModeArguments(IntrinsicInst *II,
case Intrinsic::amdgcn_flat_atomic_fadd:
case Intrinsic::amdgcn_flat_atomic_fmin:
case Intrinsic::amdgcn_flat_atomic_fmax:
+ case Intrinsic::amdgcn_flat_atomic_fmin_num:
+ case Intrinsic::amdgcn_flat_atomic_fmax_num:
case Intrinsic::amdgcn_global_atomic_fadd_v2bf16:
case Intrinsic::amdgcn_flat_atomic_fadd_v2bf16:
case Intrinsic::amdgcn_global_atomic_csub: {
@@ -1368,7 +1391,8 @@ bool SITargetLowering::isLegalMUBUFAddressingMode(const AddrMode &AM) const {
// assume those use MUBUF instructions. Scratch loads / stores are currently
// implemented as mubuf instructions with offen bit set, so slightly
// different than the normal addr64.
- if (!SIInstrInfo::isLegalMUBUFImmOffset(AM.BaseOffs))
+ const SIInstrInfo *TII = Subtarget->getInstrInfo();
+ if (!TII->isLegalMUBUFImmOffset(AM.BaseOffs))
return false;
// FIXME: Since we can split immediate into soffset and immediate offset,
@@ -1405,7 +1429,8 @@ bool SITargetLowering::isLegalAddressingMode(const DataLayout &DL,
if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT ||
- AS == AMDGPUAS::BUFFER_FAT_POINTER || AS == AMDGPUAS::BUFFER_RESOURCE) {
+ AS == AMDGPUAS::BUFFER_FAT_POINTER || AS == AMDGPUAS::BUFFER_RESOURCE ||
+ AS == AMDGPUAS::BUFFER_STRIDED_POINTER) {
// If the offset isn't a multiple of 4, it probably isn't going to be
// correctly aligned.
// FIXME: Can we get the real alignment here?
@@ -1432,11 +1457,15 @@ bool SITargetLowering::isLegalAddressingMode(const DataLayout &DL,
// On VI, these use the SMEM format and the offset is 20-bit in bytes.
if (!isUInt<20>(AM.BaseOffs))
return false;
- } else {
+ } else if (Subtarget->getGeneration() < AMDGPUSubtarget::GFX12) {
// On GFX9 the offset is signed 21-bit in bytes (but must not be negative
// for S_BUFFER_* instructions).
if (!isInt<21>(AM.BaseOffs))
return false;
+ } else {
+ // On GFX12, all offsets are signed 24-bit in bytes.
+ if (!isInt<24>(AM.BaseOffs))
+ return false;
}
if (AM.Scale == 0) // r + i or just i, depending on HasBaseReg.
@@ -1791,7 +1820,7 @@ SDValue SITargetLowering::lowerKernArgParameterPtr(SelectionDAG &DAG,
// We may not have the kernarg segment argument if we have no kernel
// arguments.
if (!InputPtrReg)
- return DAG.getConstant(0, SL, PtrVT);
+ return DAG.getConstant(Offset, SL, PtrVT);
MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();
SDValue BasePtr = DAG.getCopyFromReg(Chain, SL,
@@ -3858,6 +3887,23 @@ SDValue SITargetLowering::lowerGET_ROUNDING(SDValue Op,
return DAG.getMergeValues({Result, GetReg.getValue(1)}, SL);
}
+SDValue SITargetLowering::lowerPREFETCH(SDValue Op, SelectionDAG &DAG) const {
+ if (Op->isDivergent())
+ return SDValue();
+
+ switch (cast<MemSDNode>(Op)->getAddressSpace()) {
+ case AMDGPUAS::FLAT_ADDRESS:
+ case AMDGPUAS::GLOBAL_ADDRESS:
+ case AMDGPUAS::CONSTANT_ADDRESS:
+ case AMDGPUAS::CONSTANT_ADDRESS_32BIT:
+ break;
+ default:
+ return SDValue();
+ }
+
+ return Op;
+}
+
Register SITargetLowering::getRegisterByName(const char* RegName, LLT VT,
const MachineFunction &MF) const {
Register Reg = StringSwitch<Register>(RegName)
@@ -4555,40 +4601,51 @@ MachineBasicBlock *SITargetLowering::EmitInstrWithCustomInserter(
}
case AMDGPU::S_ADD_U64_PSEUDO:
case AMDGPU::S_SUB_U64_PSEUDO: {
- MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
+ // For targets older than GFX12, we emit a sequence of 32-bit operations.
+ // For GFX12, we emit s_add_u64 and s_sub_u64.
const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>();
- const SIRegisterInfo *TRI = ST.getRegisterInfo();
- const TargetRegisterClass *BoolRC = TRI->getBoolRC();
+ MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
const DebugLoc &DL = MI.getDebugLoc();
-
MachineOperand &Dest = MI.getOperand(0);
MachineOperand &Src0 = MI.getOperand(1);
MachineOperand &Src1 = MI.getOperand(2);
-
- Register DestSub0 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
- Register DestSub1 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
-
- MachineOperand Src0Sub0 = TII->buildExtractSubRegOrImm(
- MI, MRI, Src0, BoolRC, AMDGPU::sub0, &AMDGPU::SReg_32RegClass);
- MachineOperand Src0Sub1 = TII->buildExtractSubRegOrImm(
- MI, MRI, Src0, BoolRC, AMDGPU::sub1, &AMDGPU::SReg_32RegClass);
-
- MachineOperand Src1Sub0 = TII->buildExtractSubRegOrImm(
- MI, MRI, Src1, BoolRC, AMDGPU::sub0, &AMDGPU::SReg_32RegClass);
- MachineOperand Src1Sub1 = TII->buildExtractSubRegOrImm(
- MI, MRI, Src1, BoolRC, AMDGPU::sub1, &AMDGPU::SReg_32RegClass);
-
bool IsAdd = (MI.getOpcode() == AMDGPU::S_ADD_U64_PSEUDO);
-
- unsigned LoOpc = IsAdd ? AMDGPU::S_ADD_U32 : AMDGPU::S_SUB_U32;
- unsigned HiOpc = IsAdd ? AMDGPU::S_ADDC_U32 : AMDGPU::S_SUBB_U32;
- BuildMI(*BB, MI, DL, TII->get(LoOpc), DestSub0).add(Src0Sub0).add(Src1Sub0);
- BuildMI(*BB, MI, DL, TII->get(HiOpc), DestSub1).add(Src0Sub1).add(Src1Sub1);
- BuildMI(*BB, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), Dest.getReg())
- .addReg(DestSub0)
- .addImm(AMDGPU::sub0)
- .addReg(DestSub1)
- .addImm(AMDGPU::sub1);
+ if (Subtarget->hasScalarAddSub64()) {
+ unsigned Opc = IsAdd ? AMDGPU::S_ADD_U64 : AMDGPU::S_SUB_U64;
+ BuildMI(*BB, MI, DL, TII->get(Opc), Dest.getReg())
+ .addReg(Src0.getReg())
+ .addReg(Src1.getReg());
+ } else {
+ const SIRegisterInfo *TRI = ST.getRegisterInfo();
+ const TargetRegisterClass *BoolRC = TRI->getBoolRC();
+
+ Register DestSub0 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
+ Register DestSub1 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
+
+ MachineOperand Src0Sub0 = TII->buildExtractSubRegOrImm(
+ MI, MRI, Src0, BoolRC, AMDGPU::sub0, &AMDGPU::SReg_32RegClass);
+ MachineOperand Src0Sub1 = TII->buildExtractSubRegOrImm(
+ MI, MRI, Src0, BoolRC, AMDGPU::sub1, &AMDGPU::SReg_32RegClass);
+
+ MachineOperand Src1Sub0 = TII->buildExtractSubRegOrImm(
+ MI, MRI, Src1, BoolRC, AMDGPU::sub0, &AMDGPU::SReg_32RegClass);
+ MachineOperand Src1Sub1 = TII->buildExtractSubRegOrImm(
+ MI, MRI, Src1, BoolRC, AMDGPU::sub1, &AMDGPU::SReg_32RegClass);
+
+ unsigned LoOpc = IsAdd ? AMDGPU::S_ADD_U32 : AMDGPU::S_SUB_U32;
+ unsigned HiOpc = IsAdd ? AMDGPU::S_ADDC_U32 : AMDGPU::S_SUBB_U32;
+ BuildMI(*BB, MI, DL, TII->get(LoOpc), DestSub0)
+ .add(Src0Sub0)
+ .add(Src1Sub0);
+ BuildMI(*BB, MI, DL, TII->get(HiOpc), DestSub1)
+ .add(Src0Sub1)
+ .add(Src1Sub1);
+ BuildMI(*BB, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), Dest.getReg())
+ .addReg(DestSub0)
+ .addImm(AMDGPU::sub0)
+ .addReg(DestSub1)
+ .addImm(AMDGPU::sub1);
+ }
MI.eraseFromParent();
return BB;
}
@@ -5395,6 +5452,8 @@ SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
return LowerSTACKSAVE(Op, DAG);
case ISD::GET_ROUNDING:
return lowerGET_ROUNDING(Op, DAG);
+ case ISD::PREFETCH:
+ return lowerPREFETCH(Op, DAG);
}
return SDValue();
}
@@ -7108,6 +7167,7 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
unsigned IntrOpcode = Intr->BaseOpcode;
bool IsGFX10Plus = AMDGPU::isGFX10Plus(*Subtarget);
bool IsGFX11Plus = AMDGPU::isGFX11Plus(*Subtarget);
+ bool IsGFX12Plus = AMDGPU::isGFX12Plus(*Subtarget);
SmallVector<EVT, 3> ResultTypes(Op->values());
SmallVector<EVT, 3> OrigResultTypes(Op->values());
@@ -7127,7 +7187,7 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
if (BaseOpcode->Atomic) {
VData = Op.getOperand(2);
- bool Is64Bit = VData.getValueType() == MVT::i64;
+ bool Is64Bit = VData.getValueSizeInBits() == 64;
if (BaseOpcode->AtomicX2) {
SDValue VData2 = Op.getOperand(3);
VData = DAG.getBuildVector(Is64Bit ? MVT::v2i64 : MVT::v2i32, DL,
@@ -7287,9 +7347,9 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
// SIShrinkInstructions will convert NSA encodings to non-NSA after register
// allocation when possible.
//
- // Partial NSA is allowed on GFX11 where the final register is a contiguous
+ // Partial NSA is allowed on GFX11+ where the final register is a contiguous
// set of the remaining addresses.
- const unsigned NSAMaxSize = ST->getNSAMaxSize();
+ const unsigned NSAMaxSize = ST->getNSAMaxSize(BaseOpcode->Sampler);
const bool HasPartialNSAEncoding = ST->hasPartialNSAEncoding();
const bool UseNSA = ST->hasNSAEncoding() &&
VAddrs.size() >= ST->getNSAThreshold(MF) &&
@@ -7366,7 +7426,7 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
Op.getOperand(ArgOffset + Intr->CachePolicyIndex))->getZExtValue();
if (BaseOpcode->Atomic)
CPol |= AMDGPU::CPol::GLC; // TODO no-return optimization
- if (CPol & ~AMDGPU::CPol::ALL)
+ if (CPol & ~(IsGFX12Plus ? AMDGPU::CPol::ALL : AMDGPU::CPol::ALL_pregfx12))
return Op;
SmallVector<SDValue, 26> Ops;
@@ -7386,7 +7446,8 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
Ops.push_back(DAG.getTargetConstant(DMask, DL, MVT::i32));
if (IsGFX10Plus)
Ops.push_back(DAG.getTargetConstant(DimInfo->Encoding, DL, MVT::i32));
- Ops.push_back(Unorm);
+ if (!IsGFX12Plus || BaseOpcode->Sampler || BaseOpcode->MSAA)
+ Ops.push_back(Unorm);
Ops.push_back(DAG.getTargetConstant(CPol, DL, MVT::i32));
Ops.push_back(IsA16 && // r128, a16 for gfx9
ST->hasFeature(AMDGPU::FeatureR128A16) ? True : False);
@@ -7397,7 +7458,8 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
} else if (cast<ConstantSDNode>(TFE)->getZExtValue()) {
report_fatal_error("TFE is not supported on this GPU");
}
- Ops.push_back(LWE); // lwe
+ if (!IsGFX12Plus || BaseOpcode->Sampler || BaseOpcode->MSAA)
+ Ops.push_back(LWE); // lwe
if (!IsGFX10Plus)
Ops.push_back(DimInfo->DA ? True : False);
if (BaseOpcode->HasD16)
@@ -7409,7 +7471,10 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
UseNSA ? VAddrs.size() : VAddr.getValueType().getSizeInBits() / 32;
int Opcode = -1;
- if (IsGFX11Plus) {
+ if (IsGFX12Plus) {
+ Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx12,
+ NumVDataDwords, NumVAddrDwords);
+ } else if (IsGFX11Plus) {
Opcode = AMDGPU::getMIMGOpcode(IntrOpcode,
UseNSA ? AMDGPU::MIMGEncGfx11NSA
: AMDGPU::MIMGEncGfx11Default,
@@ -7480,7 +7545,8 @@ SDValue SITargetLowering::lowerSBuffer(EVT VT, SDLoc DL, SDValue Rsrc,
};
// Widen vec3 load to vec4.
- if (VT.isVector() && VT.getVectorNumElements() == 3) {
+ if (VT.isVector() && VT.getVectorNumElements() == 3 &&
+ !Subtarget->hasScalarDwordx3Loads()) {
EVT WidenedVT =
EVT::getVectorVT(*DAG.getContext(), VT.getVectorElementType(), 4);
auto WidenedOp = DAG.getMemIntrinsicNode(
@@ -7726,7 +7792,9 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
SDLoc(Op), MVT::i32);
case Intrinsic::amdgcn_s_buffer_load: {
unsigned CPol = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
- if (CPol & ~AMDGPU::CPol::ALL)
+ if (CPol & ~((Subtarget->getGeneration() >= AMDGPUSubtarget::GFX12)
+ ? AMDGPU::CPol::ALL
+ : AMDGPU::CPol::ALL_pregfx12))
return Op;
return lowerSBuffer(VT, DL, Op.getOperand(1), Op.getOperand(2), Op.getOperand(3),
DAG);
@@ -7896,6 +7964,19 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
}
}
+// On targets not supporting constant in soffset field, turn zero to
+// SGPR_NULL to avoid generating an extra s_mov with zero.
+static SDValue selectSOffset(SDValue SOffset, SelectionDAG &DAG,
+ const GCNSubtarget *Subtarget) {
+ if (Subtarget->hasRestrictedSOffset())
+ if (auto SOffsetConst = dyn_cast<ConstantSDNode>(SOffset)) {
+ if (SOffsetConst->isZero()) {
+ return DAG.getRegister(AMDGPU::SGPR_NULL, MVT::i32);
+ }
+ }
+ return SOffset;
+}
+
SDValue SITargetLowering::lowerRawBufferAtomicIntrin(SDValue Op,
SelectionDAG &DAG,
unsigned NewOpcode) const {
@@ -7904,13 +7985,14 @@ SDValue SITargetLowering::lowerRawBufferAtomicIntrin(SDValue Op,
SDValue VData = Op.getOperand(2);
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(4), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);
SDValue Ops[] = {
Op.getOperand(0), // Chain
VData, // vdata
Rsrc, // rsrc
DAG.getConstant(0, DL, MVT::i32), // vindex
Offsets.first, // voffset
- Op.getOperand(5), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(6), // cachepolicy
DAG.getTargetConstant(0, DL, MVT::i1), // idxen
@@ -7937,13 +8019,14 @@ SITargetLowering::lowerStructBufferAtomicIntrin(SDValue Op, SelectionDAG &DAG,
SDValue VData = Op.getOperand(2);
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(5), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(6), DAG, Subtarget);
SDValue Ops[] = {
Op.getOperand(0), // Chain
VData, // vdata
Rsrc, // rsrc
Op.getOperand(4), // vindex
Offsets.first, // voffset
- Op.getOperand(6), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(7), // cachepolicy
DAG.getTargetConstant(1, DL, MVT::i1), // idxen
@@ -8099,12 +8182,13 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(2), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(3), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(4), DAG, Subtarget);
SDValue Ops[] = {
Op.getOperand(0), // Chain
Rsrc, // rsrc
DAG.getConstant(0, DL, MVT::i32), // vindex
Offsets.first, // voffset
- Op.getOperand(4), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(5), // cachepolicy, swizzled buffer
DAG.getTargetConstant(0, DL, MVT::i1), // idxen
@@ -8123,12 +8207,13 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(2), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(4), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);
SDValue Ops[] = {
Op.getOperand(0), // Chain
Rsrc, // rsrc
Op.getOperand(3), // vindex
Offsets.first, // voffset
- Op.getOperand(5), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(6), // cachepolicy, swizzled buffer
DAG.getTargetConstant(1, DL, MVT::i1), // idxen
@@ -8140,21 +8225,22 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
MemSDNode *M = cast<MemSDNode>(Op);
EVT LoadVT = Op.getValueType();
+ auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);
unsigned Dfmt = cast<ConstantSDNode>(Op.getOperand(7))->getZExtValue();
unsigned Nfmt = cast<ConstantSDNode>(Op.getOperand(8))->getZExtValue();
unsigned Glc = cast<ConstantSDNode>(Op.getOperand(9))->getZExtValue();
unsigned Slc = cast<ConstantSDNode>(Op.getOperand(10))->getZExtValue();
unsigned IdxEn = getIdxEn(Op.getOperand(3));
SDValue Ops[] = {
- Op.getOperand(0), // Chain
- Op.getOperand(2), // rsrc
- Op.getOperand(3), // vindex
- Op.getOperand(4), // voffset
- Op.getOperand(5), // soffset
- Op.getOperand(6), // offset
- DAG.getTargetConstant(Dfmt | (Nfmt << 4), DL, MVT::i32), // format
- DAG.getTargetConstant(Glc | (Slc << 1), DL, MVT::i32), // cachepolicy
- DAG.getTargetConstant(IdxEn, DL, MVT::i1) // idxen
+ Op.getOperand(0), // Chain
+ Op.getOperand(2), // rsrc
+ Op.getOperand(3), // vindex
+ Op.getOperand(4), // voffset
+ SOffset, // soffset
+ Op.getOperand(6), // offset
+ DAG.getTargetConstant(Dfmt | (Nfmt << 4), DL, MVT::i32), // format
+ DAG.getTargetConstant(Glc | (Slc << 1), DL, MVT::i32), // cachepolicy
+ DAG.getTargetConstant(IdxEn, DL, MVT::i1) // idxen
};
if (LoadVT.getScalarType() == MVT::f16)
@@ -8170,13 +8256,14 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
EVT LoadVT = Op.getValueType();
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(2), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(3), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(4), DAG, Subtarget);
SDValue Ops[] = {
Op.getOperand(0), // Chain
Rsrc, // rsrc
DAG.getConstant(0, DL, MVT::i32), // vindex
Offsets.first, // voffset
- Op.getOperand(4), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(5), // format
Op.getOperand(6), // cachepolicy, swizzled buffer
@@ -8196,13 +8283,14 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
EVT LoadVT = Op.getValueType();
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(2), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(4), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);
SDValue Ops[] = {
Op.getOperand(0), // Chain
Rsrc, // rsrc
Op.getOperand(3), // vindex
Offsets.first, // voffset
- Op.getOperand(5), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(6), // format
Op.getOperand(7), // cachepolicy, swizzled buffer
@@ -8415,6 +8503,7 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap: {
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(4), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(5), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(6), DAG, Subtarget);
SDValue Ops[] = {
Op.getOperand(0), // Chain
Op.getOperand(2), // src
@@ -8422,7 +8511,7 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
Rsrc, // rsrc
DAG.getConstant(0, DL, MVT::i32), // vindex
Offsets.first, // voffset
- Op.getOperand(6), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(7), // cachepolicy
DAG.getTargetConstant(0, DL, MVT::i1), // idxen
@@ -8437,6 +8526,7 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap: {
SDValue Rsrc = bufferRsrcPtrToVector(Op->getOperand(4), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(6), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(7), DAG, Subtarget);
SDValue Ops[] = {
Op.getOperand(0), // Chain
Op.getOperand(2), // src
@@ -8444,7 +8534,7 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
Rsrc, // rsrc
Op.getOperand(5), // vindex
Offsets.first, // voffset
- Op.getOperand(7), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(8), // cachepolicy
DAG.getTargetConstant(1, DL, MVT::i1), // idxen
@@ -8474,14 +8564,17 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
return SDValue();
}
+ const bool IsGFX11 = AMDGPU::isGFX11(*Subtarget);
const bool IsGFX11Plus = AMDGPU::isGFX11Plus(*Subtarget);
+ const bool IsGFX12Plus = AMDGPU::isGFX12Plus(*Subtarget);
const bool IsA16 = RayDir.getValueType().getVectorElementType() == MVT::f16;
const bool Is64 = NodePtr.getValueType() == MVT::i64;
const unsigned NumVDataDwords = 4;
const unsigned NumVAddrDwords = IsA16 ? (Is64 ? 9 : 8) : (Is64 ? 12 : 11);
const unsigned NumVAddrs = IsGFX11Plus ? (IsA16 ? 4 : 5) : NumVAddrDwords;
- const bool UseNSA =
- Subtarget->hasNSAEncoding() && NumVAddrs <= Subtarget->getNSAMaxSize();
+ const bool UseNSA = (Subtarget->hasNSAEncoding() &&
+ NumVAddrs <= Subtarget->getNSAMaxSize()) ||
+ IsGFX12Plus;
const unsigned BaseOpcodes[2][2] = {
{AMDGPU::IMAGE_BVH_INTERSECT_RAY, AMDGPU::IMAGE_BVH_INTERSECT_RAY_a16},
{AMDGPU::IMAGE_BVH64_INTERSECT_RAY,
@@ -8489,15 +8582,16 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
int Opcode;
if (UseNSA) {
Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
- IsGFX11Plus ? AMDGPU::MIMGEncGfx11NSA
+ IsGFX12Plus ? AMDGPU::MIMGEncGfx12
+ : IsGFX11 ? AMDGPU::MIMGEncGfx11NSA
: AMDGPU::MIMGEncGfx10NSA,
NumVDataDwords, NumVAddrDwords);
} else {
- Opcode =
- AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
- IsGFX11Plus ? AMDGPU::MIMGEncGfx11Default
- : AMDGPU::MIMGEncGfx10Default,
- NumVDataDwords, NumVAddrDwords);
+ assert(!IsGFX12Plus);
+ Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
+ IsGFX11 ? AMDGPU::MIMGEncGfx11Default
+ : AMDGPU::MIMGEncGfx10Default,
+ NumVDataDwords, NumVAddrDwords);
}
assert(Opcode != -1);
@@ -8585,8 +8679,12 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
}
case Intrinsic::amdgcn_global_atomic_fmin:
case Intrinsic::amdgcn_global_atomic_fmax:
+ case Intrinsic::amdgcn_global_atomic_fmin_num:
+ case Intrinsic::amdgcn_global_atomic_fmax_num:
case Intrinsic::amdgcn_flat_atomic_fmin:
- case Intrinsic::amdgcn_flat_atomic_fmax: {
+ case Intrinsic::amdgcn_flat_atomic_fmax:
+ case Intrinsic::amdgcn_flat_atomic_fmin_num:
+ case Intrinsic::amdgcn_flat_atomic_fmax_num: {
MemSDNode *M = cast<MemSDNode>(Op);
SDValue Ops[] = {
M->getOperand(0), // Chain
@@ -8596,12 +8694,16 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
unsigned Opcode = 0;
switch (IntrID) {
case Intrinsic::amdgcn_global_atomic_fmin:
- case Intrinsic::amdgcn_flat_atomic_fmin: {
+ case Intrinsic::amdgcn_global_atomic_fmin_num:
+ case Intrinsic::amdgcn_flat_atomic_fmin:
+ case Intrinsic::amdgcn_flat_atomic_fmin_num: {
Opcode = AMDGPUISD::ATOMIC_LOAD_FMIN;
break;
}
case Intrinsic::amdgcn_global_atomic_fmax:
- case Intrinsic::amdgcn_flat_atomic_fmax: {
+ case Intrinsic::amdgcn_global_atomic_fmax_num:
+ case Intrinsic::amdgcn_flat_atomic_fmax:
+ case Intrinsic::amdgcn_flat_atomic_fmax_num: {
Opcode = AMDGPUISD::ATOMIC_LOAD_FMAX;
break;
}
@@ -8612,6 +8714,31 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
M->getVTList(), Ops, M->getMemoryVT(),
M->getMemOperand());
}
+ case Intrinsic::amdgcn_s_get_barrier_state: {
+ SDValue Chain = Op->getOperand(0);
+ SmallVector<SDValue, 2> Ops;
+ unsigned Opc;
+ bool IsInlinableBarID = false;
+ int64_t BarID;
+
+ if (isa<ConstantSDNode>(Op->getOperand(2))) {
+ BarID = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
+ IsInlinableBarID = AMDGPU::isInlinableIntLiteral(BarID);
+ }
+
+ if (IsInlinableBarID) {
+ Opc = AMDGPU::S_GET_BARRIER_STATE_IMM;
+ SDValue K = DAG.getTargetConstant(BarID, DL, MVT::i32);
+ Ops.push_back(K);
+ } else {
+ Opc = AMDGPU::S_GET_BARRIER_STATE_M0;
+ SDValue M0Val = copyToM0(DAG, Chain, DL, Op.getOperand(2));
+ Ops.push_back(M0Val.getValue(0));
+ }
+
+ auto NewMI = DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops);
+ return SDValue(NewMI, 0);
+ }
default:
if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr =
@@ -8789,13 +8916,29 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
return SDValue(DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops), 0);
}
case Intrinsic::amdgcn_s_barrier: {
+ const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
if (getTargetMachine().getOptLevel() > CodeGenOptLevel::None) {
- const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
unsigned WGSize = ST.getFlatWorkGroupSizes(MF.getFunction()).second;
if (WGSize <= ST.getWavefrontSize())
return SDValue(DAG.getMachineNode(AMDGPU::WAVE_BARRIER, DL, MVT::Other,
Op.getOperand(0)), 0);
}
+
+ // On GFX12 lower s_barrier into s_barrier_signal_imm and s_barrier_wait
+ if (ST.hasSplitBarriers()) {
+ SDValue K =
+ DAG.getTargetConstant(AMDGPU::Barrier::WORKGROUP, DL, MVT::i32);
+ SDValue BarSignal =
+ SDValue(DAG.getMachineNode(AMDGPU::S_BARRIER_SIGNAL_IMM, DL,
+ MVT::Other, K, Op.getOperand(0)),
+ 0);
+ SDValue BarWait =
+ SDValue(DAG.getMachineNode(AMDGPU::S_BARRIER_WAIT, DL, MVT::Other, K,
+ BarSignal.getValue(0)),
+ 0);
+ return BarWait;
+ }
+
return SDValue();
};
case Intrinsic::amdgcn_tbuffer_store: {
@@ -8835,13 +8978,14 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
VData = handleD16VData(VData, DAG);
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(5), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(6), DAG, Subtarget);
SDValue Ops[] = {
Chain,
VData, // vdata
Rsrc, // rsrc
Op.getOperand(4), // vindex
Offsets.first, // voffset
- Op.getOperand(6), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(7), // format
Op.getOperand(8), // cachepolicy, swizzled buffer
@@ -8862,13 +9006,14 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
VData = handleD16VData(VData, DAG);
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(4), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);
SDValue Ops[] = {
Chain,
VData, // vdata
Rsrc, // rsrc
DAG.getConstant(0, DL, MVT::i32), // vindex
Offsets.first, // voffset
- Op.getOperand(5), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(6), // format
Op.getOperand(7), // cachepolicy, swizzled buffer
@@ -8942,13 +9087,14 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(4), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);
SDValue Ops[] = {
Chain,
VData,
Rsrc,
DAG.getConstant(0, DL, MVT::i32), // vindex
Offsets.first, // voffset
- Op.getOperand(5), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(6), // cachepolicy, swizzled buffer
DAG.getTargetConstant(0, DL, MVT::i1), // idxen
@@ -8992,13 +9138,14 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
auto Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);
auto Offsets = splitBufferOffsets(Op.getOperand(5), DAG);
+ auto SOffset = selectSOffset(Op.getOperand(6), DAG, Subtarget);
SDValue Ops[] = {
Chain,
VData,
Rsrc,
Op.getOperand(4), // vindex
Offsets.first, // voffset
- Op.getOperand(6), // soffset
+ SOffset, // soffset
Offsets.second, // offset
Op.getOperand(7), // cachepolicy, swizzled buffer
DAG.getTargetConstant(1, DL, MVT::i1), // idxen
@@ -9181,7 +9328,76 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
case Intrinsic::amdgcn_end_cf:
return SDValue(DAG.getMachineNode(AMDGPU::SI_END_CF, DL, MVT::Other,
Op->getOperand(2), Chain), 0);
+ case Intrinsic::amdgcn_s_barrier_init:
+ case Intrinsic::amdgcn_s_barrier_join:
+ case Intrinsic::amdgcn_s_wakeup_barrier: {
+ SDValue Chain = Op->getOperand(0);
+ SmallVector<SDValue, 2> Ops;
+ SDValue BarOp = Op->getOperand(2);
+ unsigned Opc;
+ bool IsInlinableBarID = false;
+ int64_t BarVal;
+
+ if (isa<ConstantSDNode>(BarOp)) {
+ BarVal = cast<ConstantSDNode>(BarOp)->getSExtValue();
+ IsInlinableBarID = AMDGPU::isInlinableIntLiteral(BarVal);
+ }
+
+ if (IsInlinableBarID) {
+ switch (IntrinsicID) {
+ default:
+ return SDValue();
+ case Intrinsic::amdgcn_s_barrier_init:
+ Opc = AMDGPU::S_BARRIER_INIT_IMM;
+ break;
+ case Intrinsic::amdgcn_s_barrier_join:
+ Opc = AMDGPU::S_BARRIER_JOIN_IMM;
+ break;
+ case Intrinsic::amdgcn_s_wakeup_barrier:
+ Opc = AMDGPU::S_WAKEUP_BARRIER_IMM;
+ break;
+ }
+ SDValue K = DAG.getTargetConstant(BarVal, DL, MVT::i32);
+ Ops.push_back(K);
+ } else {
+ switch (IntrinsicID) {
+ default:
+ return SDValue();
+ case Intrinsic::amdgcn_s_barrier_init:
+ Opc = AMDGPU::S_BARRIER_INIT_M0;
+ break;
+ case Intrinsic::amdgcn_s_barrier_join:
+ Opc = AMDGPU::S_BARRIER_JOIN_M0;
+ break;
+ case Intrinsic::amdgcn_s_wakeup_barrier:
+ Opc = AMDGPU::S_WAKEUP_BARRIER_M0;
+ break;
+ }
+ }
+
+ if (IntrinsicID == Intrinsic::amdgcn_s_barrier_init) {
+ SDValue M0Val;
+ // Member count will be read from M0[16:22]
+ M0Val = DAG.getNode(ISD::SHL, DL, MVT::i32, Op.getOperand(3),
+ DAG.getShiftAmountConstant(16, MVT::i32, DL));
+
+ if (!IsInlinableBarID) {
+ // If reference to barrier id is not an inline constant then it must be
+ // referenced with M0[4:0]. Perform an OR with the member count to
+ // include it in M0.
+ M0Val = SDValue(DAG.getMachineNode(AMDGPU::S_OR_B32, DL, MVT::i32,
+ Op.getOperand(2), M0Val),
+ 0);
+ }
+ Ops.push_back(copyToM0(DAG, Chain, DL, M0Val).getValue(0));
+ } else if (!IsInlinableBarID) {
+ Ops.push_back(copyToM0(DAG, Chain, DL, BarOp).getValue(0));
+ }
+
+ auto NewMI = DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops);
+ return SDValue(NewMI, 0);
+ }
default: {
if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr =
AMDGPU::getImageDimIntrinsicInfo(IntrinsicID))
@@ -9201,7 +9417,7 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
std::pair<SDValue, SDValue> SITargetLowering::splitBufferOffsets(
SDValue Offset, SelectionDAG &DAG) const {
SDLoc DL(Offset);
- const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset();
+ const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset(*Subtarget);
SDValue N0 = Offset;
ConstantSDNode *C1 = nullptr;
@@ -9277,8 +9493,13 @@ void SITargetLowering::setBufferOffsets(SDValue CombinedOffset,
return;
}
}
+
+ SDValue SOffsetZero = Subtarget->hasRestrictedSOffset()
+ ? DAG.getRegister(AMDGPU::SGPR_NULL, MVT::i32)
+ : DAG.getConstant(0, DL, MVT::i32);
+
Offsets[0] = CombinedOffset;
- Offsets[1] = DAG.getConstant(0, DL, MVT::i32);
+ Offsets[1] = SOffsetZero;
Offsets[2] = DAG.getTargetConstant(0, DL, MVT::i32);
}
@@ -9536,7 +9757,8 @@ SDValue SITargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) {
if (!Op->isDivergent() && Alignment >= Align(4) && NumElements < 32) {
- if (MemVT.isPow2VectorType())
+ if (MemVT.isPow2VectorType() ||
+ (Subtarget->hasScalarDwordx3Loads() && NumElements == 3))
return SDValue();
return WidenOrSplitVectorLoad(Op, DAG);
}
@@ -9552,7 +9774,8 @@ SDValue SITargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
if (Subtarget->getScalarizeGlobalBehavior() && !Op->isDivergent() &&
Load->isSimple() && isMemOpHasNoClobberedMemOperand(Load) &&
Alignment >= Align(4) && NumElements < 32) {
- if (MemVT.isPow2VectorType())
+ if (MemVT.isPow2VectorType() ||
+ (Subtarget->hasScalarDwordx3Loads() && NumElements == 3))
return SDValue();
return WidenOrSplitVectorLoad(Op, DAG);
}
@@ -11775,10 +11998,14 @@ bool SITargetLowering::isCanonicalized(SelectionDAG &DAG, SDValue Op,
case ISD::FMAXNUM:
case ISD::FMINNUM_IEEE:
case ISD::FMAXNUM_IEEE:
+ case ISD::FMINIMUM:
+ case ISD::FMAXIMUM:
case AMDGPUISD::CLAMP:
case AMDGPUISD::FMED3:
case AMDGPUISD::FMAX3:
- case AMDGPUISD::FMIN3: {
+ case AMDGPUISD::FMIN3:
+ case AMDGPUISD::FMAXIMUM3:
+ case AMDGPUISD::FMINIMUM3: {
// FIXME: Shouldn't treat the generic operations different based these.
// However, we aren't really required to flush the result from
// minnum/maxnum..
@@ -11932,7 +12159,9 @@ bool SITargetLowering::isCanonicalized(Register Reg, MachineFunction &MF,
case AMDGPU::G_FMINNUM:
case AMDGPU::G_FMAXNUM:
case AMDGPU::G_FMINNUM_IEEE:
- case AMDGPU::G_FMAXNUM_IEEE: {
+ case AMDGPU::G_FMAXNUM_IEEE:
+ case AMDGPU::G_FMINIMUM:
+ case AMDGPU::G_FMAXIMUM: {
if (Subtarget->supportsMinMaxDenormModes() ||
// FIXME: denormalsEnabledForType is broken for dynamic
denormalsEnabledForType(MRI.getType(Reg), MF))
@@ -12120,6 +12349,8 @@ static unsigned minMaxOpcToMin3Max3Opc(unsigned Opc) {
case ISD::FMAXNUM:
case ISD::FMAXNUM_IEEE:
return AMDGPUISD::FMAX3;
+ case ISD::FMAXIMUM:
+ return AMDGPUISD::FMAXIMUM3;
case ISD::SMAX:
return AMDGPUISD::SMAX3;
case ISD::UMAX:
@@ -12127,6 +12358,8 @@ static unsigned minMaxOpcToMin3Max3Opc(unsigned Opc) {
case ISD::FMINNUM:
case ISD::FMINNUM_IEEE:
return AMDGPUISD::FMIN3;
+ case ISD::FMINIMUM:
+ return AMDGPUISD::FMINIMUM3;
case ISD::SMIN:
return AMDGPUISD::SMIN3;
case ISD::UMIN:
@@ -12486,7 +12719,9 @@ SDValue SITargetLowering::performExtractVectorEltCombine(
case ISD::FMAXNUM:
case ISD::FMINNUM:
case ISD::FMAXNUM_IEEE:
- case ISD::FMINNUM_IEEE: {
+ case ISD::FMINNUM_IEEE:
+ case ISD::FMAXIMUM:
+ case ISD::FMINIMUM: {
SDValue Elt0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, ResVT,
Vec.getOperand(0), Idx);
SDValue Elt1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, ResVT,
@@ -13748,6 +13983,8 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
case ISD::FMINNUM:
case ISD::FMAXNUM_IEEE:
case ISD::FMINNUM_IEEE:
+ case ISD::FMAXIMUM:
+ case ISD::FMINIMUM:
case ISD::SMAX:
case ISD::SMIN:
case ISD::UMAX:
@@ -13863,7 +14100,7 @@ static unsigned SubIdx2Lane(unsigned Idx) {
}
}
-/// Adjust the writemask of MIMG instructions
+/// Adjust the writemask of MIMG, VIMAGE or VSAMPLE instructions
SDNode *SITargetLowering::adjustWritemask(MachineSDNode *&Node,
SelectionDAG &DAG) const {
unsigned Opcode = Node->getMachineOpcode();
@@ -13881,7 +14118,7 @@ SDNode *SITargetLowering::adjustWritemask(MachineSDNode *&Node,
unsigned TFEIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::tfe) - 1;
unsigned LWEIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::lwe) - 1;
bool UsesTFC = ((int(TFEIdx) >= 0 && Node->getConstantOperandVal(TFEIdx)) ||
- Node->getConstantOperandVal(LWEIdx))
+ (int(LWEIdx) >= 0 && Node->getConstantOperandVal(LWEIdx)))
? true
: false;
unsigned TFCLane = 0;
@@ -14093,7 +14330,7 @@ SDNode *SITargetLowering::PostISelFolding(MachineSDNode *Node,
const SIInstrInfo *TII = getSubtarget()->getInstrInfo();
unsigned Opcode = Node->getMachineOpcode();
- if (TII->isMIMG(Opcode) && !TII->get(Opcode).mayStore() &&
+ if (TII->isImage(Opcode) && !TII->get(Opcode).mayStore() &&
!TII->isGather4(Opcode) &&
AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::dmask)) {
return adjustWritemask(Node, DAG);
@@ -14180,7 +14417,7 @@ void SITargetLowering::AddIMGInit(MachineInstr &MI) const {
return;
unsigned TFEVal = TFE ? TFE->getImm() : 0;
- unsigned LWEVal = LWE->getImm();
+ unsigned LWEVal = LWE ? LWE->getImm() : 0;
unsigned D16Val = D16 ? D16->getImm() : 0;
if (!TFEVal && !LWEVal)
@@ -14317,7 +14554,7 @@ void SITargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI,
return;
}
- if (TII->isMIMG(MI)) {
+ if (TII->isImage(MI)) {
if (!MI.mayStore())
AddIMGInit(MI);
TII->enforceOperandRCAlignment(MI, AMDGPU::OpName::vaddr);
@@ -14461,7 +14698,7 @@ SITargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI_,
return std::pair(0U, RC);
}
- if (Constraint.startswith("{") && Constraint.endswith("}")) {
+ if (Constraint.starts_with("{") && Constraint.ends_with("}")) {
StringRef RegName(Constraint.data() + 1, Constraint.size() - 2);
if (RegName.consume_front("v")) {
RC = &AMDGPU::VGPR_32RegClass;
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index c9cc149218a9..5bc091d6e84d 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -416,6 +416,8 @@ public:
SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerGET_ROUNDING(SDValue Op, SelectionDAG &DAG) const;
+ SDValue lowerPREFETCH(SDValue Op, SelectionDAG &DAG) const;
+
Register getRegisterByName(const char* RegName, LLT VT,
const MachineFunction &MF) const override;
diff --git a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
index ede4841b8a5f..8415a3d77d3b 100644
--- a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
@@ -292,6 +292,11 @@ public:
VgprVmemTypes[GprNo] = 0;
}
+ void setNonKernelFunctionInitialState() {
+ setScoreUB(VS_CNT, getWaitCountMax(VS_CNT));
+ PendingEvents |= WaitEventMaskForInst[VS_CNT];
+ }
+
void print(raw_ostream &);
void dump() { print(dbgs()); }
@@ -364,7 +369,6 @@ private:
const MachineRegisterInfo *MRI = nullptr;
AMDGPU::IsaVersion IV;
- DenseSet<MachineInstr *> TrackedWaitcntSet;
DenseMap<const Value *, MachineBasicBlock *> SLoadAddresses;
DenseMap<MachineBasicBlock *, bool> PreheadersToFlush;
MachineLoopInfo *MLI;
@@ -452,7 +456,9 @@ public:
// FLAT instruction.
WaitEventType getVmemWaitEventType(const MachineInstr &Inst) const {
assert(SIInstrInfo::isVMEM(Inst) || SIInstrInfo::isFLAT(Inst));
- if (!ST->hasVscnt())
+ // LDS DMA loads are also stores, but on the LDS side. On the VMEM side
+ // these should use VM_CNT.
+ if (!ST->hasVscnt() || SIInstrInfo::mayWriteLDSThroughDMA(Inst))
return VMEM_ACCESS;
if (Inst.mayStore() && !SIInstrInfo::isAtomicRet(Inst)) {
// FLAT and SCRATCH instructions may access scratch. Other VMEM
@@ -486,6 +492,9 @@ public:
MachineInstr &OldWaitcntInstr,
AMDGPU::Waitcnt &Wait,
MachineBasicBlock::instr_iterator It) const;
+
+ // Transform a soft waitcnt into a normal one.
+ bool promoteSoftWaitCnt(MachineInstr *Waitcnt) const;
};
} // end anonymous namespace
@@ -544,14 +553,6 @@ void WaitcntBrackets::setExpScore(const MachineInstr *MI,
}
}
-// MUBUF and FLAT LDS DMA operations need a wait on vmcnt before LDS written
-// can be accessed. A load from LDS to VMEM does not need a wait.
-static bool mayWriteLDSThroughDMA(const MachineInstr &MI) {
- return SIInstrInfo::isVALU(MI) &&
- (SIInstrInfo::isMUBUF(MI) || SIInstrInfo::isFLAT(MI)) &&
- MI.getOpcode() != AMDGPU::BUFFER_STORE_LDS_DWORD;
-}
-
void WaitcntBrackets::updateByEvent(const SIInstrInfo *TII,
const SIRegisterInfo *TRI,
const MachineRegisterInfo *MRI,
@@ -703,7 +704,10 @@ void WaitcntBrackets::updateByEvent(const SIInstrInfo *TII,
setRegScore(RegNo, T, CurrScore);
}
}
- if (Inst.mayStore() && (TII->isDS(Inst) || mayWriteLDSThroughDMA(Inst))) {
+ if (Inst.mayStore() &&
+ (TII->isDS(Inst) || TII->mayWriteLDSThroughDMA(Inst))) {
+ // MUBUF and FLAT LDS DMA operations need a wait on vmcnt before LDS
+ // written can be accessed. A load from LDS to VMEM does not need a wait.
setRegScore(SQ_MAX_PGM_VGPRS + EXTRA_VGPR_LDS, T, CurrScore);
}
}
@@ -870,6 +874,15 @@ static bool updateOperandIfDifferent(MachineInstr &MI, uint16_t OpName,
return true;
}
+bool SIInsertWaitcnts::promoteSoftWaitCnt(MachineInstr *Waitcnt) const {
+ unsigned Opcode = Waitcnt->getOpcode();
+ if (!SIInstrInfo::isSoftWaitcnt(Opcode))
+ return false;
+
+ Waitcnt->setDesc(TII->get(SIInstrInfo::getNonSoftWaitcntOpcode(Opcode)));
+ return true;
+}
+
/// Combine consecutive waitcnt instructions that precede \p It and follow
/// \p OldWaitcntInstr and apply any extra wait from waitcnt that were added
/// by previous passes. Currently this pass conservatively assumes that these
@@ -886,86 +899,77 @@ bool SIInsertWaitcnts::applyPreexistingWaitcnt(
if (II.isMetaInstruction())
continue;
- if (II.getOpcode() == AMDGPU::S_WAITCNT) {
- // Conservatively update required wait if this waitcnt was added in an
- // earlier pass. In this case it will not exist in the tracked waitcnt
- // set.
- if (!TrackedWaitcntSet.count(&II)) {
- unsigned IEnc = II.getOperand(0).getImm();
- AMDGPU::Waitcnt OldWait = AMDGPU::decodeWaitcnt(IV, IEnc);
- Wait = Wait.combined(OldWait);
- }
+ unsigned Opcode = II.getOpcode();
+ bool IsSoft = SIInstrInfo::isSoftWaitcnt(Opcode);
+
+ if (SIInstrInfo::isWaitcnt(Opcode)) {
+ // Update required wait count. If this is a soft waitcnt (= it was added
+ // by an earlier pass), it may be entirely removed.
+ unsigned IEnc = II.getOperand(0).getImm();
+ AMDGPU::Waitcnt OldWait = AMDGPU::decodeWaitcnt(IV, IEnc);
+ if (IsSoft)
+ ScoreBrackets.simplifyWaitcnt(OldWait);
+ Wait = Wait.combined(OldWait);
// Merge consecutive waitcnt of the same type by erasing multiples.
- if (!WaitcntInstr) {
- WaitcntInstr = &II;
- } else {
+ if (WaitcntInstr || (!Wait.hasWaitExceptVsCnt() && IsSoft)) {
II.eraseFromParent();
Modified = true;
- }
+ } else
+ WaitcntInstr = &II;
} else {
- assert(II.getOpcode() == AMDGPU::S_WAITCNT_VSCNT);
+ assert(SIInstrInfo::isWaitcntVsCnt(Opcode));
assert(II.getOperand(0).getReg() == AMDGPU::SGPR_NULL);
- if (!TrackedWaitcntSet.count(&II)) {
- unsigned OldVSCnt =
- TII->getNamedOperand(II, AMDGPU::OpName::simm16)->getImm();
- Wait.VsCnt = std::min(Wait.VsCnt, OldVSCnt);
- }
- if (!WaitcntVsCntInstr) {
- WaitcntVsCntInstr = &II;
- } else {
+ unsigned OldVSCnt =
+ TII->getNamedOperand(II, AMDGPU::OpName::simm16)->getImm();
+ if (IsSoft)
+ ScoreBrackets.simplifyWaitcnt(InstCounterType::VS_CNT, OldVSCnt);
+ Wait.VsCnt = std::min(Wait.VsCnt, OldVSCnt);
+
+ if (WaitcntVsCntInstr || (!Wait.hasWaitVsCnt() && IsSoft)) {
II.eraseFromParent();
Modified = true;
- }
+ } else
+ WaitcntVsCntInstr = &II;
}
}
// Updated encoding of merged waitcnt with the required wait.
if (WaitcntInstr) {
- if (Wait.hasWaitExceptVsCnt()) {
- Modified |=
- updateOperandIfDifferent(*WaitcntInstr, AMDGPU::OpName::simm16,
- AMDGPU::encodeWaitcnt(IV, Wait));
- ScoreBrackets.applyWaitcnt(Wait);
- Wait.VmCnt = ~0u;
- Wait.LgkmCnt = ~0u;
- Wait.ExpCnt = ~0u;
-
- LLVM_DEBUG(It == OldWaitcntInstr.getParent()->end()
- ? dbgs() << "applyPreexistingWaitcnt\n"
- << "New Instr at block end: " << *WaitcntInstr
- << '\n'
- : dbgs() << "applyPreexistingWaitcnt\n"
- << "Old Instr: " << *It
- << "New Instr: " << *WaitcntInstr << '\n');
+ Modified |= updateOperandIfDifferent(*WaitcntInstr, AMDGPU::OpName::simm16,
+ AMDGPU::encodeWaitcnt(IV, Wait));
+ Modified |= promoteSoftWaitCnt(WaitcntInstr);
- } else {
- WaitcntInstr->eraseFromParent();
- Modified = true;
- }
+ ScoreBrackets.applyWaitcnt(Wait);
+ Wait.VmCnt = ~0u;
+ Wait.LgkmCnt = ~0u;
+ Wait.ExpCnt = ~0u;
+
+ LLVM_DEBUG(It == OldWaitcntInstr.getParent()->end()
+ ? dbgs()
+ << "applyPreexistingWaitcnt\n"
+ << "New Instr at block end: " << *WaitcntInstr << '\n'
+ : dbgs() << "applyPreexistingWaitcnt\n"
+ << "Old Instr: " << *It
+ << "New Instr: " << *WaitcntInstr << '\n');
}
if (WaitcntVsCntInstr) {
- if (Wait.hasWaitVsCnt()) {
- assert(ST->hasVscnt());
- Modified |= updateOperandIfDifferent(*WaitcntVsCntInstr,
- AMDGPU::OpName::simm16, Wait.VsCnt);
- ScoreBrackets.applyWaitcnt(Wait);
- Wait.VsCnt = ~0u;
-
- LLVM_DEBUG(It == OldWaitcntInstr.getParent()->end()
- ? dbgs() << "applyPreexistingWaitcnt\n"
- << "New Instr at block end: "
- << *WaitcntVsCntInstr << '\n'
- : dbgs() << "applyPreexistingWaitcnt\n"
- << "Old Instr: " << *It
- << "New Instr: " << *WaitcntVsCntInstr << '\n');
- } else {
- WaitcntVsCntInstr->eraseFromParent();
- Modified = true;
- }
+ Modified |= updateOperandIfDifferent(*WaitcntVsCntInstr,
+ AMDGPU::OpName::simm16, Wait.VsCnt);
+ Modified |= promoteSoftWaitCnt(WaitcntVsCntInstr);
+ ScoreBrackets.applyWaitcnt(Wait);
+ Wait.VsCnt = ~0u;
+
+ LLVM_DEBUG(It == OldWaitcntInstr.getParent()->end()
+ ? dbgs() << "applyPreexistingWaitcnt\n"
+ << "New Instr at block end: " << *WaitcntVsCntInstr
+ << '\n'
+ : dbgs() << "applyPreexistingWaitcnt\n"
+ << "Old Instr: " << *It
+ << "New Instr: " << *WaitcntVsCntInstr << '\n');
}
return Modified;
@@ -1178,7 +1182,7 @@ bool SIInsertWaitcnts::generateWaitcntInstBefore(MachineInstr &MI,
if (AS != AMDGPUAS::LOCAL_ADDRESS && AS != AMDGPUAS::FLAT_ADDRESS)
continue;
// No need to wait before load from VMEM to LDS.
- if (mayWriteLDSThroughDMA(MI))
+ if (TII->mayWriteLDSThroughDMA(MI))
continue;
unsigned RegNo = SQ_MAX_PGM_VGPRS + EXTRA_VGPR_LDS;
// VM_CNT is only relevant to vgpr or LDS.
@@ -1315,9 +1319,8 @@ bool SIInsertWaitcnts::generateWaitcnt(AMDGPU::Waitcnt Wait,
// instruction was modified to handle the required wait.
if (Wait.hasWaitExceptVsCnt()) {
unsigned Enc = AMDGPU::encodeWaitcnt(IV, Wait);
- auto SWaitInst =
+ [[maybe_unused]] auto SWaitInst =
BuildMI(Block, It, DL, TII->get(AMDGPU::S_WAITCNT)).addImm(Enc);
- TrackedWaitcntSet.insert(SWaitInst);
Modified = true;
LLVM_DEBUG(dbgs() << "generateWaitcnt\n";
@@ -1328,10 +1331,9 @@ bool SIInsertWaitcnts::generateWaitcnt(AMDGPU::Waitcnt Wait,
if (Wait.hasWaitVsCnt()) {
assert(ST->hasVscnt());
- auto SWaitInst = BuildMI(Block, It, DL, TII->get(AMDGPU::S_WAITCNT_VSCNT))
+ [[maybe_unused]] auto SWaitInst = BuildMI(Block, It, DL, TII->get(AMDGPU::S_WAITCNT_VSCNT))
.addReg(AMDGPU::SGPR_NULL, RegState::Undef)
.addImm(Wait.VsCnt);
- TrackedWaitcntSet.insert(SWaitInst);
Modified = true;
LLVM_DEBUG(dbgs() << "generateWaitcnt\n";
@@ -1504,6 +1506,11 @@ void SIInsertWaitcnts::updateEventWaitcntAfter(MachineInstr &Inst,
break;
case AMDGPU::S_MEMTIME:
case AMDGPU::S_MEMREALTIME:
+ case AMDGPU::S_BARRIER_SIGNAL_ISFIRST_M0:
+ case AMDGPU::S_BARRIER_SIGNAL_ISFIRST_IMM:
+ case AMDGPU::S_BARRIER_LEAVE:
+ case AMDGPU::S_GET_BARRIER_STATE_M0:
+ case AMDGPU::S_GET_BARRIER_STATE_IMM:
ScoreBrackets->updateByEvent(TII, TRI, MRI, SMEM_ACCESS, Inst);
break;
}
@@ -1574,9 +1581,9 @@ bool WaitcntBrackets::merge(const WaitcntBrackets &Other) {
}
static bool isWaitInstr(MachineInstr &Inst) {
- return Inst.getOpcode() == AMDGPU::S_WAITCNT ||
- (Inst.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
- Inst.getOperand(0).isReg() &&
+ auto Opcode = Inst.getOpcode();
+ return SIInstrInfo::isWaitcnt(Opcode) ||
+ (SIInstrInfo::isWaitcntVsCnt(Opcode) && Inst.getOperand(0).isReg() &&
Inst.getOperand(0).getReg() == AMDGPU::SGPR_NULL);
}
@@ -1845,7 +1852,6 @@ bool SIInsertWaitcnts::runOnMachineFunction(MachineFunction &MF) {
TRI->getEncodingValue(AMDGPU::SGPR0) & AMDGPU::HWEncoding::REG_IDX_MASK;
Encoding.SGPRL = Encoding.SGPR0 + NumSGPRsMax - 1;
- TrackedWaitcntSet.clear();
BlockInfos.clear();
bool Modified = false;
@@ -1863,6 +1869,11 @@ bool SIInsertWaitcnts::runOnMachineFunction(MachineFunction &MF) {
;
BuildMI(EntryBB, I, DebugLoc(), TII->get(AMDGPU::S_WAITCNT)).addImm(0);
+ auto NonKernelInitialState =
+ std::make_unique<WaitcntBrackets>(ST, Limits, Encoding);
+ NonKernelInitialState->setNonKernelFunctionInitialState();
+ BlockInfos[&EntryBB].Incoming = std::move(NonKernelInitialState);
+
Modified = true;
}
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
index 0a06fa88b6b1..70ef1fff274a 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
@@ -17,6 +17,7 @@
#include "GCNHazardRecognizer.h"
#include "GCNSubtarget.h"
#include "SIMachineFunctionInfo.h"
+#include "Utils/AMDGPUBaseInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
#include "llvm/CodeGen/LiveIntervals.h"
@@ -483,6 +484,8 @@ bool SIInstrInfo::getMemOperandsWithOffsetWidth(
Offset = OffsetOp ? OffsetOp->getImm() : 0;
// Get appropriate operand, and compute width accordingly.
DataOpIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::sdst);
+ if (DataOpIdx == -1)
+ return false;
Width = getOpSize(LdSt, DataOpIdx);
return true;
}
@@ -4118,7 +4121,8 @@ bool SIInstrInfo::isInlineConstant(const MachineOperand &MO,
case AMDGPU::OPERAND_REG_IMM_V2INT32:
case AMDGPU::OPERAND_REG_INLINE_C_V2INT32:
case AMDGPU::OPERAND_REG_INLINE_AC_INT32:
- case AMDGPU::OPERAND_REG_INLINE_AC_FP32: {
+ case AMDGPU::OPERAND_REG_INLINE_AC_FP32:
+ case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32: {
int32_t Trunc = static_cast<int32_t>(Imm);
return AMDGPU::isInlinableLiteral32(Trunc, ST.hasInv2PiInlineImm());
}
@@ -4514,8 +4518,8 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
return true;
}
- if (isMIMG(MI) && MI.memoperands_empty() && MI.mayLoadOrStore()) {
- ErrInfo = "missing memory operand from MIMG instruction.";
+ if (isImage(MI) && MI.memoperands_empty() && MI.mayLoadOrStore()) {
+ ErrInfo = "missing memory operand from image instruction.";
return false;
}
@@ -4559,6 +4563,12 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
}
break;
}
+ case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32:
+ if (!MI.getOperand(i).isImm() || !isInlineConstant(MI, i)) {
+ ErrInfo = "Expected inline constant for operand.";
+ return false;
+ }
+ break;
case MCOI::OPERAND_IMMEDIATE:
case AMDGPU::OPERAND_KIMM32:
// Check if this operand is an immediate.
@@ -4701,8 +4711,8 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
}
}
- // Verify MIMG
- if (isMIMG(MI.getOpcode()) && !MI.mayStore()) {
+ // Verify MIMG / VIMAGE / VSAMPLE
+ if (isImage(MI.getOpcode()) && !MI.mayStore()) {
// Ensure that the return type used is large enough for all the options
// being used TFE/LWE require an extra result register.
const MachineOperand *DMask = getNamedOperand(MI, AMDGPU::OpName::dmask);
@@ -4966,12 +4976,14 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
}
}
- if (isMIMG(MI)) {
+ if (isImage(MI)) {
const MachineOperand *DimOp = getNamedOperand(MI, AMDGPU::OpName::dim);
if (DimOp) {
int VAddr0Idx = AMDGPU::getNamedOperandIdx(Opcode,
AMDGPU::OpName::vaddr0);
- int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
+ int RSrcOpName =
+ isMIMG(MI) ? AMDGPU::OpName::srsrc : AMDGPU::OpName::rsrc;
+ int RsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, RSrcOpName);
const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(Opcode);
const AMDGPU::MIMGBaseOpcodeInfo *BaseOpcode =
AMDGPU::getMIMGBaseOpcodeInfo(Info->BaseOpcode);
@@ -4992,16 +5004,17 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
IsA16 = A16->getImm() != 0;
}
- bool IsNSA = SRsrcIdx - VAddr0Idx > 1;
+ bool IsNSA = RsrcIdx - VAddr0Idx > 1;
unsigned AddrWords =
AMDGPU::getAddrSizeMIMGOp(BaseOpcode, Dim, IsA16, ST.hasG16());
unsigned VAddrWords;
if (IsNSA) {
- VAddrWords = SRsrcIdx - VAddr0Idx;
- if (ST.hasPartialNSAEncoding() && AddrWords > ST.getNSAMaxSize()) {
- unsigned LastVAddrIdx = SRsrcIdx - 1;
+ VAddrWords = RsrcIdx - VAddr0Idx;
+ if (ST.hasPartialNSAEncoding() &&
+ AddrWords > ST.getNSAMaxSize(isVSAMPLE(MI))) {
+ unsigned LastVAddrIdx = RsrcIdx - 1;
VAddrWords += getOpSize(MI, LastVAddrIdx) / 4 - 1;
}
} else {
@@ -5157,6 +5170,9 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
return true;
}
+// It is more readable to list mapped opcodes on the same line.
+// clang-format off
+
unsigned SIInstrInfo::getVALUOp(const MachineInstr &MI) const {
switch (MI.getOpcode()) {
default: return AMDGPU::INSTRUCTION_LIST_END;
@@ -5252,11 +5268,15 @@ unsigned SIInstrInfo::getVALUOp(const MachineInstr &MI) const {
case AMDGPU::S_SUB_F32: return AMDGPU::V_SUB_F32_e64;
case AMDGPU::S_MIN_F32: return AMDGPU::V_MIN_F32_e64;
case AMDGPU::S_MAX_F32: return AMDGPU::V_MAX_F32_e64;
+ case AMDGPU::S_MINIMUM_F32: return AMDGPU::V_MINIMUM_F32_e64;
+ case AMDGPU::S_MAXIMUM_F32: return AMDGPU::V_MAXIMUM_F32_e64;
case AMDGPU::S_MUL_F32: return AMDGPU::V_MUL_F32_e64;
case AMDGPU::S_ADD_F16: return AMDGPU::V_ADD_F16_fake16_e64;
case AMDGPU::S_SUB_F16: return AMDGPU::V_SUB_F16_fake16_e64;
case AMDGPU::S_MIN_F16: return AMDGPU::V_MIN_F16_fake16_e64;
case AMDGPU::S_MAX_F16: return AMDGPU::V_MAX_F16_fake16_e64;
+ case AMDGPU::S_MINIMUM_F16: return AMDGPU::V_MINIMUM_F16_e64;
+ case AMDGPU::S_MAXIMUM_F16: return AMDGPU::V_MAXIMUM_F16_e64;
case AMDGPU::S_MUL_F16: return AMDGPU::V_MUL_F16_fake16_e64;
case AMDGPU::S_CVT_PK_RTZ_F16_F32: return AMDGPU::V_CVT_PKRTZ_F16_F32_e64;
case AMDGPU::S_FMAC_F32: return AMDGPU::V_FMAC_F32_e64;
@@ -5291,11 +5311,23 @@ unsigned SIInstrInfo::getVALUOp(const MachineInstr &MI) const {
case AMDGPU::S_CMP_NLE_F16: return AMDGPU::V_CMP_NLE_F16_t16_e64;
case AMDGPU::S_CMP_NEQ_F16: return AMDGPU::V_CMP_NEQ_F16_t16_e64;
case AMDGPU::S_CMP_NLT_F16: return AMDGPU::V_CMP_NLT_F16_t16_e64;
+ case AMDGPU::V_S_EXP_F32_e64: return AMDGPU::V_EXP_F32_e64;
+ case AMDGPU::V_S_EXP_F16_e64: return AMDGPU::V_EXP_F16_t16_e64;
+ case AMDGPU::V_S_LOG_F32_e64: return AMDGPU::V_LOG_F32_e64;
+ case AMDGPU::V_S_LOG_F16_e64: return AMDGPU::V_LOG_F16_t16_e64;
+ case AMDGPU::V_S_RCP_F32_e64: return AMDGPU::V_RCP_F32_e64;
+ case AMDGPU::V_S_RCP_F16_e64: return AMDGPU::V_RCP_F16_t16_e64;
+ case AMDGPU::V_S_RSQ_F32_e64: return AMDGPU::V_RSQ_F32_e64;
+ case AMDGPU::V_S_RSQ_F16_e64: return AMDGPU::V_RSQ_F16_t16_e64;
+ case AMDGPU::V_S_SQRT_F32_e64: return AMDGPU::V_SQRT_F32_e64;
+ case AMDGPU::V_S_SQRT_F16_e64: return AMDGPU::V_SQRT_F16_t16_e64;
}
llvm_unreachable(
"Unexpected scalar opcode without corresponding vector one!");
}
+// clang-format on
+
void SIInstrInfo::insertScratchExecCopy(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
@@ -6502,18 +6534,21 @@ SIInstrInfo::legalizeOperands(MachineInstr &MI,
return CreatedBB;
}
- // Legalize MIMG and MUBUF/MTBUF for shaders.
+ // Legalize MIMG/VIMAGE/VSAMPLE and MUBUF/MTBUF for shaders.
//
// Shaders only generate MUBUF/MTBUF instructions via intrinsics or via
// scratch memory access. In both cases, the legalization never involves
// conversion to the addr64 form.
- if (isMIMG(MI) || (AMDGPU::isGraphics(MF.getFunction().getCallingConv()) &&
- (isMUBUF(MI) || isMTBUF(MI)))) {
- MachineOperand *SRsrc = getNamedOperand(MI, AMDGPU::OpName::srsrc);
+ if (isImage(MI) || (AMDGPU::isGraphics(MF.getFunction().getCallingConv()) &&
+ (isMUBUF(MI) || isMTBUF(MI)))) {
+ int RSrcOpName = (isVIMAGE(MI) || isVSAMPLE(MI)) ? AMDGPU::OpName::rsrc
+ : AMDGPU::OpName::srsrc;
+ MachineOperand *SRsrc = getNamedOperand(MI, RSrcOpName);
if (SRsrc && !RI.isSGPRClass(MRI.getRegClass(SRsrc->getReg())))
CreatedBB = loadMBUFScalarOperandsFromVGPR(*this, MI, {SRsrc}, MDT);
- MachineOperand *SSamp = getNamedOperand(MI, AMDGPU::OpName::ssamp);
+ int SampOpName = isMIMG(MI) ? AMDGPU::OpName::ssamp : AMDGPU::OpName::samp;
+ MachineOperand *SSamp = getNamedOperand(MI, SampOpName);
if (SSamp && !RI.isSGPRClass(MRI.getRegClass(SSamp->getReg())))
CreatedBB = loadMBUFScalarOperandsFromVGPR(*this, MI, {SSamp}, MDT);
@@ -6548,13 +6583,26 @@ SIInstrInfo::legalizeOperands(MachineInstr &MI,
}
}
+ // Legalize s_sleep_var.
+ if (MI.getOpcode() == AMDGPU::S_SLEEP_VAR) {
+ const DebugLoc &DL = MI.getDebugLoc();
+ Register Reg = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);
+ int Src0Idx =
+ AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src0);
+ MachineOperand &Src0 = MI.getOperand(Src0Idx);
+ BuildMI(*MI.getParent(), MI, DL, get(AMDGPU::V_READFIRSTLANE_B32), Reg)
+ .add(Src0);
+ Src0.ChangeToRegister(Reg, false);
+ return nullptr;
+ }
+
// Legalize MUBUF instructions.
bool isSoffsetLegal = true;
int SoffsetIdx =
AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::soffset);
if (SoffsetIdx != -1) {
MachineOperand *Soffset = &MI.getOperand(SoffsetIdx);
- if (Soffset->isReg() &&
+ if (Soffset->isReg() && Soffset->getReg().isVirtual() &&
!RI.isSGPRClass(MRI.getRegClass(Soffset->getReg()))) {
isSoffsetLegal = false;
}
@@ -6869,7 +6917,9 @@ void SIInstrInfo::moveToVALUImpl(SIInstrWorklist &Worklist,
break;
case AMDGPU::S_LSHL_B64:
if (ST.hasOnlyRevVALUShifts()) {
- NewOpcode = AMDGPU::V_LSHLREV_B64_e64;
+ NewOpcode = ST.getGeneration() >= AMDGPUSubtarget::GFX12
+ ? AMDGPU::V_LSHLREV_B64_pseudo_e64
+ : AMDGPU::V_LSHLREV_B64_e64;
swapOperands(Inst);
}
break;
@@ -7094,6 +7144,26 @@ void SIInstrInfo::moveToVALUImpl(SIInstrWorklist &Worklist,
Inst.eraseFromParent();
return;
}
+ case AMDGPU::S_MINIMUM_F32:
+ case AMDGPU::S_MAXIMUM_F32:
+ case AMDGPU::S_MINIMUM_F16:
+ case AMDGPU::S_MAXIMUM_F16: {
+ const DebugLoc &DL = Inst.getDebugLoc();
+ Register NewDst = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+ MachineInstr *NewInstr = BuildMI(*MBB, Inst, DL, get(NewOpcode), NewDst)
+ .addImm(0) // src0_modifiers
+ .add(Inst.getOperand(1))
+ .addImm(0) // src1_modifiers
+ .add(Inst.getOperand(2))
+ .addImm(0) // clamp
+ .addImm(0); // omod
+ MRI.replaceRegWith(Inst.getOperand(0).getReg(), NewDst);
+
+ legalizeOperands(*NewInstr, MDT);
+ addUsersToMoveToVALUWorklist(NewDst, MRI, Worklist);
+ Inst.eraseFromParent();
+ return;
+ }
}
if (NewOpcode == AMDGPU::INSTRUCTION_LIST_END) {
@@ -7138,7 +7208,7 @@ void SIInstrInfo::moveToVALUImpl(SIInstrWorklist &Worklist,
// Use the new VALU Opcode.
auto NewInstr = BuildMI(*MBB, Inst, Inst.getDebugLoc(), get(NewOpcode))
.setMIFlags(Inst.getFlags());
- if (isVOP3(NewOpcode)) {
+ if (isVOP3(NewOpcode) && !isVOP3(Opcode)) {
// Intersperse VOP3 modifiers among the SALU operands.
NewInstr->addOperand(Inst.getOperand(0));
if (AMDGPU::getNamedOperandIdx(NewOpcode,
@@ -7552,80 +7622,6 @@ void SIInstrInfo::splitScalar64BitUnaryOp(SIInstrWorklist &Worklist,
addUsersToMoveToVALUWorklist(FullDestReg, MRI, Worklist);
}
-void SIInstrInfo::splitScalar64BitAddSub(SIInstrWorklist &Worklist,
- MachineInstr &Inst,
- MachineDominatorTree *MDT) const {
- bool IsAdd = (Inst.getOpcode() == AMDGPU::S_ADD_U64_PSEUDO);
-
- MachineBasicBlock &MBB = *Inst.getParent();
- MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
- const auto *CarryRC = RI.getRegClass(AMDGPU::SReg_1_XEXECRegClassID);
-
- Register FullDestReg = MRI.createVirtualRegister(&AMDGPU::VReg_64RegClass);
- Register DestSub0 = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
- Register DestSub1 = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
-
- Register CarryReg = MRI.createVirtualRegister(CarryRC);
- Register DeadCarryReg = MRI.createVirtualRegister(CarryRC);
-
- MachineOperand &Dest = Inst.getOperand(0);
- MachineOperand &Src0 = Inst.getOperand(1);
- MachineOperand &Src1 = Inst.getOperand(2);
- const DebugLoc &DL = Inst.getDebugLoc();
- MachineBasicBlock::iterator MII = Inst;
-
- const TargetRegisterClass *Src0RC = MRI.getRegClass(Src0.getReg());
- const TargetRegisterClass *Src1RC = MRI.getRegClass(Src1.getReg());
- const TargetRegisterClass *Src0SubRC =
- RI.getSubRegisterClass(Src0RC, AMDGPU::sub0);
- const TargetRegisterClass *Src1SubRC =
- RI.getSubRegisterClass(Src1RC, AMDGPU::sub0);
-
- MachineOperand SrcReg0Sub0 = buildExtractSubRegOrImm(MII, MRI, Src0, Src0RC,
- AMDGPU::sub0, Src0SubRC);
- MachineOperand SrcReg1Sub0 = buildExtractSubRegOrImm(MII, MRI, Src1, Src1RC,
- AMDGPU::sub0, Src1SubRC);
-
-
- MachineOperand SrcReg0Sub1 = buildExtractSubRegOrImm(MII, MRI, Src0, Src0RC,
- AMDGPU::sub1, Src0SubRC);
- MachineOperand SrcReg1Sub1 = buildExtractSubRegOrImm(MII, MRI, Src1, Src1RC,
- AMDGPU::sub1, Src1SubRC);
-
- unsigned LoOpc = IsAdd ? AMDGPU::V_ADD_CO_U32_e64 : AMDGPU::V_SUB_CO_U32_e64;
- MachineInstr *LoHalf =
- BuildMI(MBB, MII, DL, get(LoOpc), DestSub0)
- .addReg(CarryReg, RegState::Define)
- .add(SrcReg0Sub0)
- .add(SrcReg1Sub0)
- .addImm(0); // clamp bit
-
- unsigned HiOpc = IsAdd ? AMDGPU::V_ADDC_U32_e64 : AMDGPU::V_SUBB_U32_e64;
- MachineInstr *HiHalf =
- BuildMI(MBB, MII, DL, get(HiOpc), DestSub1)
- .addReg(DeadCarryReg, RegState::Define | RegState::Dead)
- .add(SrcReg0Sub1)
- .add(SrcReg1Sub1)
- .addReg(CarryReg, RegState::Kill)
- .addImm(0); // clamp bit
-
- BuildMI(MBB, MII, DL, get(TargetOpcode::REG_SEQUENCE), FullDestReg)
- .addReg(DestSub0)
- .addImm(AMDGPU::sub0)
- .addReg(DestSub1)
- .addImm(AMDGPU::sub1);
-
- MRI.replaceRegWith(Dest.getReg(), FullDestReg);
-
- // Try to legalize the operands in case we need to swap the order to keep it
- // valid.
- legalizeOperands(*LoHalf, MDT);
- legalizeOperands(*HiHalf, MDT);
-
- // Move all users of this moved value.
- addUsersToMoveToVALUWorklist(FullDestReg, MRI, Worklist);
-}
-
void SIInstrInfo::splitScalar64BitBinaryOp(SIInstrWorklist &Worklist,
MachineInstr &Inst, unsigned Opcode,
MachineDominatorTree *MDT) const {
@@ -8565,7 +8561,16 @@ const MCInstrDesc &SIInstrInfo::getKillTerminatorFromPseudo(unsigned Opcode) con
}
}
-unsigned SIInstrInfo::getMaxMUBUFImmOffset() { return (1 << 12) - 1; }
+bool SIInstrInfo::isLegalMUBUFImmOffset(unsigned Imm) const {
+ return Imm <= getMaxMUBUFImmOffset(ST);
+}
+
+unsigned SIInstrInfo::getMaxMUBUFImmOffset(const GCNSubtarget &ST) {
+ // GFX12 field is non-negative 24-bit signed byte offset.
+ const unsigned OffsetBits =
+ ST.getGeneration() >= AMDGPUSubtarget::GFX12 ? 23 : 12;
+ return (1 << OffsetBits) - 1;
+}
void SIInstrInfo::fixImplicitOperands(MachineInstr &MI) const {
if (!ST.isWave32())
@@ -8602,7 +8607,7 @@ bool SIInstrInfo::isBufferSMRD(const MachineInstr &MI) const {
// offsets within the given alignment can be added to the resulting ImmOffset.
bool SIInstrInfo::splitMUBUFOffset(uint32_t Imm, uint32_t &SOffset,
uint32_t &ImmOffset, Align Alignment) const {
- const uint32_t MaxOffset = SIInstrInfo::getMaxMUBUFImmOffset();
+ const uint32_t MaxOffset = SIInstrInfo::getMaxMUBUFImmOffset(ST);
const uint32_t MaxImm = alignDown(MaxOffset, Alignment.value());
uint32_t Overflow = 0;
@@ -8628,11 +8633,17 @@ bool SIInstrInfo::splitMUBUFOffset(uint32_t Imm, uint32_t &SOffset,
}
}
- // There is a hardware bug in SI and CI which prevents address clamping in
- // MUBUF instructions from working correctly with SOffsets. The immediate
- // offset is unaffected.
- if (Overflow > 0 && ST.getGeneration() <= AMDGPUSubtarget::SEA_ISLANDS)
- return false;
+ if (Overflow > 0) {
+ // There is a hardware bug in SI and CI which prevents address clamping in
+ // MUBUF instructions from working correctly with SOffsets. The immediate
+ // offset is unaffected.
+ if (ST.getGeneration() <= AMDGPUSubtarget::SEA_ISLANDS)
+ return false;
+
+ // It is not possible to set immediate in SOffset field on some targets.
+ if (ST.hasRestrictedSOffset())
+ return false;
+ }
ImmOffset = Imm;
SOffset = Overflow;
@@ -8680,16 +8691,13 @@ bool SIInstrInfo::isLegalFLATOffset(int64_t Offset, unsigned AddrSpace,
AddrSpace == AMDGPUAS::GLOBAL_ADDRESS))
return false;
- bool AllowNegative = FlatVariant != SIInstrFlags::FLAT;
- if (ST.hasNegativeScratchOffsetBug() &&
- FlatVariant == SIInstrFlags::FlatScratch)
- AllowNegative = false;
if (ST.hasNegativeUnalignedScratchOffsetBug() &&
FlatVariant == SIInstrFlags::FlatScratch && Offset < 0 &&
(Offset % 4) != 0) {
return false;
}
+ bool AllowNegative = allowNegativeFlatOffset(FlatVariant);
unsigned N = AMDGPU::getNumFlatOffsetBits(ST);
return isIntN(N, Offset) && (AllowNegative || Offset >= 0);
}
@@ -8700,12 +8708,10 @@ SIInstrInfo::splitFlatOffset(int64_t COffsetVal, unsigned AddrSpace,
uint64_t FlatVariant) const {
int64_t RemainderOffset = COffsetVal;
int64_t ImmField = 0;
- bool AllowNegative = FlatVariant != SIInstrFlags::FLAT;
- if (ST.hasNegativeScratchOffsetBug() &&
- FlatVariant == SIInstrFlags::FlatScratch)
- AllowNegative = false;
+ bool AllowNegative = allowNegativeFlatOffset(FlatVariant);
const unsigned NumBits = AMDGPU::getNumFlatOffsetBits(ST) - 1;
+
if (AllowNegative) {
// Use signed division by a power of two to truncate towards 0.
int64_t D = 1LL << NumBits;
@@ -8729,6 +8735,14 @@ SIInstrInfo::splitFlatOffset(int64_t COffsetVal, unsigned AddrSpace,
return {ImmField, RemainderOffset};
}
+bool SIInstrInfo::allowNegativeFlatOffset(uint64_t FlatVariant) const {
+ if (ST.hasNegativeScratchOffsetBug() &&
+ FlatVariant == SIInstrFlags::FlatScratch)
+ return false;
+
+ return FlatVariant != SIInstrFlags::FLAT || AMDGPU::isGFX12Plus(ST);
+}
+
static unsigned subtargetEncodingFamily(const GCNSubtarget &ST) {
switch (ST.getGeneration()) {
default:
@@ -8770,6 +8784,9 @@ bool SIInstrInfo::isAsmOnlyOpcode(int MCOp) const {
}
int SIInstrInfo::pseudoToMCOpcode(int Opcode) const {
+ if (SIInstrInfo::isSoftWaitcnt(Opcode))
+ Opcode = SIInstrInfo::getNonSoftWaitcntOpcode(Opcode);
+
unsigned Gen = subtargetEncodingFamily(ST);
if ((get(Opcode).TSFlags & SIInstrFlags::renamedInGFX9) != 0 &&
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.h b/llvm/lib/Target/AMDGPU/SIInstrInfo.h
index 0ce31ac6d54e..affe52046752 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.h
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.h
@@ -134,9 +134,6 @@ private:
void splitScalar64BitUnaryOp(SIInstrWorklist &Worklist, MachineInstr &Inst,
unsigned Opcode, bool Swap = false) const;
- void splitScalar64BitAddSub(SIInstrWorklist &Worklist, MachineInstr &Inst,
- MachineDominatorTree *MDT = nullptr) const;
-
void splitScalar64BitBinaryOp(SIInstrWorklist &Worklist, MachineInstr &Inst,
unsigned Opcode,
MachineDominatorTree *MDT = nullptr) const;
@@ -549,6 +546,14 @@ public:
return get(Opcode).TSFlags & SIInstrFlags::DS;
}
+ static bool isLDSDMA(const MachineInstr &MI) {
+ return isVALU(MI) && (isMUBUF(MI) || isFLAT(MI));
+ }
+
+ bool isLDSDMA(uint16_t Opcode) {
+ return isVALU(Opcode) && (isMUBUF(Opcode) || isFLAT(Opcode));
+ }
+
static bool isGWS(const MachineInstr &MI) {
return MI.getDesc().TSFlags & SIInstrFlags::GWS;
}
@@ -670,6 +675,10 @@ public:
SIInstrFlags::IsAtomicNoRet);
}
+ static bool mayWriteLDSThroughDMA(const MachineInstr &MI) {
+ return isLDSDMA(MI) && MI.getOpcode() != AMDGPU::BUFFER_STORE_LDS_DWORD;
+ }
+
static bool isWQM(const MachineInstr &MI) {
return MI.getDesc().TSFlags & SIInstrFlags::WQM;
}
@@ -886,6 +895,32 @@ public:
return get(Opcode).TSFlags & SIInstrFlags::TiedSourceNotRead;
}
+ static unsigned getNonSoftWaitcntOpcode(unsigned Opcode) {
+ if (isWaitcnt(Opcode))
+ return AMDGPU::S_WAITCNT;
+
+ if (isWaitcntVsCnt(Opcode))
+ return AMDGPU::S_WAITCNT_VSCNT;
+
+ llvm_unreachable("Expected opcode S_WAITCNT/S_WAITCNT_VSCNT");
+ }
+
+ static bool isWaitcnt(unsigned Opcode) {
+ return Opcode == AMDGPU::S_WAITCNT || Opcode == AMDGPU::S_WAITCNT_soft;
+ }
+
+ static bool isWaitcntVsCnt(unsigned Opcode) {
+ return Opcode == AMDGPU::S_WAITCNT_VSCNT ||
+ Opcode == AMDGPU::S_WAITCNT_VSCNT_soft;
+ }
+
+ // "Soft" waitcnt instructions can be relaxed/optimized out by
+ // SIInsertWaitcnts.
+ static bool isSoftWaitcnt(unsigned Opcode) {
+ return Opcode == AMDGPU::S_WAITCNT_soft ||
+ Opcode == AMDGPU::S_WAITCNT_VSCNT_soft;
+ }
+
bool isVGPRCopy(const MachineInstr &MI) const {
assert(isCopyInstr(MI));
Register Dest = MI.getOperand(0).getReg();
@@ -1240,11 +1275,9 @@ public:
static bool isKillTerminator(unsigned Opcode);
const MCInstrDesc &getKillTerminatorFromPseudo(unsigned Opcode) const;
- static bool isLegalMUBUFImmOffset(unsigned Imm) {
- return isUInt<12>(Imm);
- }
+ bool isLegalMUBUFImmOffset(unsigned Imm) const;
- static unsigned getMaxMUBUFImmOffset();
+ static unsigned getMaxMUBUFImmOffset(const GCNSubtarget &ST);
bool splitMUBUFOffset(uint32_t Imm, uint32_t &SOffset, uint32_t &ImmOffset,
Align Alignment = Align(4)) const;
@@ -1261,6 +1294,9 @@ public:
unsigned AddrSpace,
uint64_t FlatVariant) const;
+ /// Returns true if negative offsets are allowed for the given \p FlatVariant.
+ bool allowNegativeFlatOffset(uint64_t FlatVariant) const;
+
/// \brief Return a target-specific opcode if Opcode is a pseudo instruction.
/// Return -1 if the target-specific opcode for the pseudo instruction does
/// not exist. If Opcode is not a pseudo instruction, this is identity.
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
index 091b40eefa55..173c877b8d29 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
@@ -887,11 +887,19 @@ def fp16_zeros_high_16bits : PatLeaf<(f16 VGPR_32:$src), [{
//===----------------------------------------------------------------------===//
def extract_cpol : SDNodeXForm<timm, [{
- return CurDAG->getTargetConstant(N->getZExtValue() & AMDGPU::CPol::ALL, SDLoc(N), MVT::i8);
+ return CurDAG->getTargetConstant(
+ N->getZExtValue() & (Subtarget->getGeneration() >= AMDGPUSubtarget::GFX12
+ ? AMDGPU::CPol::ALL
+ : AMDGPU::CPol::ALL_pregfx12),
+ SDLoc(N), MVT::i8);
}]>;
def extract_swz : SDNodeXForm<timm, [{
- return CurDAG->getTargetConstant((N->getZExtValue() >> 3) & 1, SDLoc(N), MVT::i8);
+ const bool Swizzle =
+ N->getZExtValue() & (Subtarget->getGeneration() >= AMDGPUSubtarget::GFX12
+ ? AMDGPU::CPol::SWZ
+ : AMDGPU::CPol::SWZ_pregfx12);
+ return CurDAG->getTargetConstant(Swizzle, SDLoc(N), MVT::i8);
}]>;
def set_glc : SDNodeXForm<timm, [{
@@ -919,6 +927,13 @@ def InterpAttr : CustomOperand<i32>;
def InterpAttrChan : ImmOperand<i32>;
+def SplitBarrier : ImmOperand<i32> {
+ let OperandNamespace = "AMDGPU";
+ let OperandType = "OPERAND_INLINE_SPLIT_BARRIER_INT32";
+ let DecoderMethod = "decodeSplitBarrier";
+ let PrintMethod = "printOperand";
+}
+
def VReg32OrOffClass : AsmOperandClass {
let Name = "VReg32OrOff";
let ParserMethod = "parseVReg32OrOff";
@@ -2898,14 +2913,14 @@ def getVOPDBaseFromComponent : SearchIndex {
def VOPDPairs : GenericTable {
let FilterClass = "VOPD_Base";
let CppTypeName = "VOPDInfo";
- let Fields = ["Opcode", "OpX", "OpY"];
+ let Fields = ["Opcode", "OpX", "OpY", "SubTgt"];
let PrimaryKey = ["Opcode"];
let PrimaryKeyName = "getVOPDOpcodeHelper";
}
def getVOPDInfoFromComponentOpcodes : SearchIndex {
let Table = VOPDPairs;
- let Key = ["OpX", "OpY"];
+ let Key = ["OpX", "OpY", "SubTgt"];
}
include "SIInstructions.td"
diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td
index 9362fe5d9678..f9bc623abcd0 100644
--- a/llvm/lib/Target/AMDGPU/SIInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SIInstructions.td
@@ -3441,6 +3441,12 @@ defm : Int16Med3Pat<V_MED3_I16_e64, smin, smax>;
defm : Int16Med3Pat<V_MED3_U16_e64, umin, umax>;
} // End Predicates = [isGFX9Plus]
+let OtherPredicates = [isGFX12Plus] in {
+def : FPMinMaxPat<V_MINIMUMMAXIMUM_F32_e64, f32, DivergentBinFrag<fmaximum>, fminimum_oneuse>;
+def : FPMinMaxPat<V_MAXIMUMMINIMUM_F32_e64, f32, DivergentBinFrag<fminimum>, fmaximum_oneuse>;
+def : FPMinMaxPat<V_MINIMUMMAXIMUM_F16_e64, f16, DivergentBinFrag<fmaximum>, fminimum_oneuse>;
+def : FPMinMaxPat<V_MAXIMUMMINIMUM_F16_e64, f16, DivergentBinFrag<fminimum>, fmaximum_oneuse>;
+}
// Convert a floating-point power of 2 to the integer exponent.
def FPPow2ToExponentXForm : SDNodeXForm<fpimm, [{
diff --git a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
index 17105965471f..9c85ff3c43e2 100644
--- a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
@@ -161,8 +161,10 @@ class SILoadStoreOptimizer : public MachineFunctionPass {
if (!AddrOp->isReg())
return false;
- // TODO: We should be able to merge physical reg addresses.
- if (AddrOp->getReg().isPhysical())
+ // TODO: We should be able to merge instructions with other physical reg
+ // addresses too.
+ if (AddrOp->getReg().isPhysical() &&
+ AddrOp->getReg() != AMDGPU::SGPR_NULL)
return false;
// If an address has only one use then there will be no other
@@ -320,7 +322,7 @@ static unsigned getOpcodeWidth(const MachineInstr &MI, const SIInstrInfo &TII) {
// FIXME: Handle d16 correctly
return AMDGPU::getMUBUFElements(Opc);
}
- if (TII.isMIMG(MI)) {
+ if (TII.isImage(MI)) {
uint64_t DMaskImm =
TII.getNamedOperand(MI, AMDGPU::OpName::dmask)->getImm();
return llvm::popcount(DMaskImm);
@@ -350,6 +352,9 @@ static unsigned getOpcodeWidth(const MachineInstr &MI, const SIInstrInfo &TII) {
case AMDGPU::FLAT_LOAD_DWORDX2:
case AMDGPU::FLAT_STORE_DWORDX2:
return 2;
+ case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
+ case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
+ case AMDGPU::S_LOAD_DWORDX3_IMM:
case AMDGPU::GLOBAL_LOAD_DWORDX3:
case AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR:
case AMDGPU::GLOBAL_STORE_DWORDX3:
@@ -398,15 +403,23 @@ static InstClassEnum getInstClass(unsigned Opc, const SIInstrInfo &TII) {
case AMDGPU::BUFFER_LOAD_DWORD_OFFEN_exact:
case AMDGPU::BUFFER_LOAD_DWORD_OFFSET:
case AMDGPU::BUFFER_LOAD_DWORD_OFFSET_exact:
+ case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFEN:
+ case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFEN_exact:
+ case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFSET:
+ case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFSET_exact:
return BUFFER_LOAD;
case AMDGPU::BUFFER_STORE_DWORD_OFFEN:
case AMDGPU::BUFFER_STORE_DWORD_OFFEN_exact:
case AMDGPU::BUFFER_STORE_DWORD_OFFSET:
case AMDGPU::BUFFER_STORE_DWORD_OFFSET_exact:
+ case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFEN:
+ case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFEN_exact:
+ case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFSET:
+ case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFSET_exact:
return BUFFER_STORE;
}
}
- if (TII.isMIMG(Opc)) {
+ if (TII.isImage(Opc)) {
// Ignore instructions encoded without vaddr.
if (!AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::vaddr) &&
!AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::vaddr0))
@@ -424,35 +437,50 @@ static InstClassEnum getInstClass(unsigned Opc, const SIInstrInfo &TII) {
switch (AMDGPU::getMTBUFBaseOpcode(Opc)) {
default:
return UNKNOWN;
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_BOTHEN:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_BOTHEN_exact:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_IDXEN:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_IDXEN_exact:
case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFEN:
case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFEN_exact:
case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFSET:
case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFSET_exact:
- case AMDGPU::TBUFFER_LOAD_FORMAT_X_IDXEN:
- case AMDGPU::TBUFFER_LOAD_FORMAT_X_IDXEN_exact:
- case AMDGPU::TBUFFER_LOAD_FORMAT_X_BOTHEN:
- case AMDGPU::TBUFFER_LOAD_FORMAT_X_BOTHEN_exact:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_BOTHEN:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_BOTHEN_exact:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_IDXEN:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_IDXEN_exact:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFEN:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFEN_exact:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFSET:
+ case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFSET_exact:
return TBUFFER_LOAD;
case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFEN:
case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFEN_exact:
case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFSET:
case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFSET_exact:
+ case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFEN:
+ case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFEN_exact:
+ case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFSET:
+ case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFSET_exact:
return TBUFFER_STORE;
}
}
return UNKNOWN;
case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
+ case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
return S_BUFFER_LOAD_IMM;
case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
+ case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
return S_BUFFER_LOAD_SGPR_IMM;
case AMDGPU::S_LOAD_DWORD_IMM:
case AMDGPU::S_LOAD_DWORDX2_IMM:
+ case AMDGPU::S_LOAD_DWORDX3_IMM:
case AMDGPU::S_LOAD_DWORDX4_IMM:
case AMDGPU::S_LOAD_DWORDX8_IMM:
return S_LOAD_IMM;
@@ -505,7 +533,7 @@ static unsigned getInstSubclass(unsigned Opc, const SIInstrInfo &TII) {
default:
if (TII.isMUBUF(Opc))
return AMDGPU::getMUBUFBaseOpcode(Opc);
- if (TII.isMIMG(Opc)) {
+ if (TII.isImage(Opc)) {
const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(Opc);
assert(Info);
return Info->BaseOpcode;
@@ -524,16 +552,19 @@ static unsigned getInstSubclass(unsigned Opc, const SIInstrInfo &TII) {
return Opc;
case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
+ case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
return AMDGPU::S_BUFFER_LOAD_DWORD_IMM;
case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
+ case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
return AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM;
case AMDGPU::S_LOAD_DWORD_IMM:
case AMDGPU::S_LOAD_DWORDX2_IMM:
+ case AMDGPU::S_LOAD_DWORDX3_IMM:
case AMDGPU::S_LOAD_DWORDX4_IMM:
case AMDGPU::S_LOAD_DWORDX8_IMM:
return AMDGPU::S_LOAD_DWORD_IMM;
@@ -600,11 +631,13 @@ static AddressRegs getRegs(unsigned Opc, const SIInstrInfo &TII) {
return Result;
}
- if (TII.isMIMG(Opc)) {
+ if (TII.isImage(Opc)) {
int VAddr0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vaddr0);
if (VAddr0Idx >= 0) {
- int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::srsrc);
- Result.NumVAddrs = SRsrcIdx - VAddr0Idx;
+ int RsrcName =
+ TII.isMIMG(Opc) ? AMDGPU::OpName::srsrc : AMDGPU::OpName::rsrc;
+ int RsrcIdx = AMDGPU::getNamedOperandIdx(Opc, RsrcName);
+ Result.NumVAddrs = RsrcIdx - VAddr0Idx;
} else {
Result.VAddr = true;
}
@@ -631,16 +664,19 @@ static AddressRegs getRegs(unsigned Opc, const SIInstrInfo &TII) {
return Result;
case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
+ case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
Result.SOffset = true;
[[fallthrough]];
case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
+ case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
case AMDGPU::S_LOAD_DWORD_IMM:
case AMDGPU::S_LOAD_DWORDX2_IMM:
+ case AMDGPU::S_LOAD_DWORDX3_IMM:
case AMDGPU::S_LOAD_DWORDX4_IMM:
case AMDGPU::S_LOAD_DWORDX8_IMM:
Result.SBase = true;
@@ -739,6 +775,7 @@ void SILoadStoreOptimizer::CombineInfo::setMI(MachineBasicBlock::iterator MI,
}
AddressRegs Regs = getRegs(Opc, *LSO.TII);
+ bool isVIMAGEorVSAMPLE = LSO.TII->isVIMAGE(*I) || LSO.TII->isVSAMPLE(*I);
NumAddresses = 0;
for (unsigned J = 0; J < Regs.NumVAddrs; J++)
@@ -751,8 +788,8 @@ void SILoadStoreOptimizer::CombineInfo::setMI(MachineBasicBlock::iterator MI,
AddrIdx[NumAddresses++] =
AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::sbase);
if (Regs.SRsrc)
- AddrIdx[NumAddresses++] =
- AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::srsrc);
+ AddrIdx[NumAddresses++] = AMDGPU::getNamedOperandIdx(
+ Opc, isVIMAGEorVSAMPLE ? AMDGPU::OpName::rsrc : AMDGPU::OpName::srsrc);
if (Regs.SOffset)
AddrIdx[NumAddresses++] =
AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::soffset);
@@ -763,8 +800,8 @@ void SILoadStoreOptimizer::CombineInfo::setMI(MachineBasicBlock::iterator MI,
AddrIdx[NumAddresses++] =
AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vaddr);
if (Regs.SSamp)
- AddrIdx[NumAddresses++] =
- AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::ssamp);
+ AddrIdx[NumAddresses++] = AMDGPU::getNamedOperandIdx(
+ Opc, isVIMAGEorVSAMPLE ? AMDGPU::OpName::samp : AMDGPU::OpName::ssamp);
assert(NumAddresses <= MaxAddressRegs);
for (unsigned J = 0; J < NumAddresses; J++)
@@ -967,6 +1004,17 @@ bool SILoadStoreOptimizer::offsetsCanBeCombined(CombineInfo &CI,
return false;
if (CI.CPol != Paired.CPol)
return false;
+ if (CI.InstClass == S_LOAD_IMM || CI.InstClass == S_BUFFER_LOAD_IMM ||
+ CI.InstClass == S_BUFFER_LOAD_SGPR_IMM) {
+ // Reject cases like:
+ // dword + dwordx2 -> dwordx3
+ // dword + dwordx3 -> dwordx4
+ // If we tried to combine these cases, we would fail to extract a subreg
+ // for the result of the second load due to SGPR alignment requirements.
+ if (CI.Width != Paired.Width &&
+ (CI.Width < Paired.Width) == (CI.Offset < Paired.Offset))
+ return false;
+ }
return true;
}
@@ -1046,6 +1094,8 @@ bool SILoadStoreOptimizer::widthsFit(const GCNSubtarget &STM,
case 4:
case 8:
return true;
+ case 3:
+ return STM.hasScalarDwordx3Loads();
}
}
}
@@ -1674,6 +1724,8 @@ unsigned SILoadStoreOptimizer::getNewOpcode(const CombineInfo &CI,
return 0;
case 2:
return AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM;
+ case 3:
+ return AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM;
case 4:
return AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM;
case 8:
@@ -1685,6 +1737,8 @@ unsigned SILoadStoreOptimizer::getNewOpcode(const CombineInfo &CI,
return 0;
case 2:
return AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM;
+ case 3:
+ return AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM;
case 4:
return AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM;
case 8:
@@ -1696,6 +1750,8 @@ unsigned SILoadStoreOptimizer::getNewOpcode(const CombineInfo &CI,
return 0;
case 2:
return AMDGPU::S_LOAD_DWORDX2_IMM;
+ case 3:
+ return AMDGPU::S_LOAD_DWORDX3_IMM;
case 4:
return AMDGPU::S_LOAD_DWORDX4_IMM;
case 8:
@@ -1817,6 +1873,8 @@ SILoadStoreOptimizer::getTargetRegisterClass(const CombineInfo &CI,
return nullptr;
case 2:
return &AMDGPU::SReg_64_XEXECRegClass;
+ case 3:
+ return &AMDGPU::SGPR_96RegClass;
case 4:
return &AMDGPU::SGPR_128RegClass;
case 8:
diff --git a/llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp b/llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp
index 68c8f4024e73..cfa0c21def79 100644
--- a/llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp
@@ -21,57 +21,26 @@
//
//===----------------------------------------------------------------------===//
+#include "SILowerI1Copies.h"
#include "AMDGPU.h"
-#include "GCNSubtarget.h"
-#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
-#include "llvm/CodeGen/MachineDominators.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachinePostDominators.h"
#include "llvm/CodeGen/MachineSSAUpdater.h"
#include "llvm/InitializePasses.h"
+#include "llvm/Target/CGPassBuilderOption.h"
#define DEBUG_TYPE "si-i1-copies"
using namespace llvm;
-static unsigned createLaneMaskReg(MachineFunction &MF);
-static unsigned insertUndefLaneMask(MachineBasicBlock &MBB);
+static Register insertUndefLaneMask(MachineBasicBlock *MBB,
+ MachineRegisterInfo *MRI,
+ Register LaneMaskRegAttrs);
namespace {
-struct Incoming {
- Register Reg;
- MachineBasicBlock *Block;
- Register UpdatedReg;
-
- Incoming(Register Reg, MachineBasicBlock *Block, Register UpdatedReg)
- : Reg(Reg), Block(Block), UpdatedReg(UpdatedReg) {}
-};
-
class SILowerI1Copies : public MachineFunctionPass {
public:
static char ID;
-private:
- bool IsWave32 = false;
- MachineFunction *MF = nullptr;
- MachineDominatorTree *DT = nullptr;
- MachinePostDominatorTree *PDT = nullptr;
- MachineRegisterInfo *MRI = nullptr;
- const GCNSubtarget *ST = nullptr;
- const SIInstrInfo *TII = nullptr;
-
- unsigned ExecReg;
- unsigned MovOp;
- unsigned AndOp;
- unsigned OrOp;
- unsigned XorOp;
- unsigned AndN2Op;
- unsigned OrN2Op;
-
- DenseSet<unsigned> ConstrainRegs;
-
-public:
SILowerI1Copies() : MachineFunctionPass(ID) {
initializeSILowerI1CopiesPass(*PassRegistry::getPassRegistry());
}
@@ -86,29 +55,53 @@ public:
AU.addRequired<MachinePostDominatorTree>();
MachineFunctionPass::getAnalysisUsage(AU);
}
+};
+
+class Vreg1LoweringHelper : public PhiLoweringHelper {
+public:
+ Vreg1LoweringHelper(MachineFunction *MF, MachineDominatorTree *DT,
+ MachinePostDominatorTree *PDT);
private:
- bool lowerCopiesFromI1();
- bool lowerPhis();
- bool lowerCopiesToI1();
- bool isConstantLaneMask(Register Reg, bool &Val) const;
+ DenseSet<Register> ConstrainRegs;
+
+public:
+ void markAsLaneMask(Register DstReg) const override;
+ void getCandidatesForLowering(
+ SmallVectorImpl<MachineInstr *> &Vreg1Phis) const override;
+ void collectIncomingValuesFromPhi(
+ const MachineInstr *MI,
+ SmallVectorImpl<Incoming> &Incomings) const override;
+ void replaceDstReg(Register NewReg, Register OldReg,
+ MachineBasicBlock *MBB) override;
void buildMergeLaneMasks(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I, const DebugLoc &DL,
- unsigned DstReg, unsigned PrevReg, unsigned CurReg);
- MachineBasicBlock::iterator
- getSaluInsertionAtEnd(MachineBasicBlock &MBB) const;
+ Register DstReg, Register PrevReg,
+ Register CurReg) override;
+ void constrainIncomingRegisterTakenAsIs(Incoming &In) override;
+ bool lowerCopiesFromI1();
+ bool lowerCopiesToI1();
+ bool cleanConstrainRegs(bool Changed);
bool isVreg1(Register Reg) const {
return Reg.isVirtual() && MRI->getRegClass(Reg) == &AMDGPU::VReg_1RegClass;
}
-
- bool isLaneMaskReg(unsigned Reg) const {
- return TII->getRegisterInfo().isSGPRReg(*MRI, Reg) &&
- TII->getRegisterInfo().getRegSizeInBits(Reg, *MRI) ==
- ST->getWavefrontSize();
- }
};
+Vreg1LoweringHelper::Vreg1LoweringHelper(MachineFunction *MF,
+ MachineDominatorTree *DT,
+ MachinePostDominatorTree *PDT)
+ : PhiLoweringHelper(MF, DT, PDT) {}
+
+bool Vreg1LoweringHelper::cleanConstrainRegs(bool Changed) {
+ assert(Changed || ConstrainRegs.empty());
+ for (Register Reg : ConstrainRegs)
+ MRI->constrainRegClass(Reg, &AMDGPU::SReg_1_XEXECRegClass);
+ ConstrainRegs.clear();
+
+ return Changed;
+}
+
/// Helper class that determines the relationship between incoming values of a
/// phi in the control flow graph to determine where an incoming value can
/// simply be taken as a scalar lane mask as-is, and where it needs to be
@@ -311,6 +304,7 @@ public:
/// blocks, so that the SSA updater doesn't have to search all the way to the
/// function entry.
void addLoopEntries(unsigned LoopLevel, MachineSSAUpdater &SSAUpdater,
+ MachineRegisterInfo &MRI, Register LaneMaskRegAttrs,
ArrayRef<Incoming> Incomings = {}) {
assert(LoopLevel < CommonDominators.size());
@@ -319,13 +313,15 @@ public:
Dom = DT.findNearestCommonDominator(Dom, Incoming.Block);
if (!inLoopLevel(*Dom, LoopLevel, Incomings)) {
- SSAUpdater.AddAvailableValue(Dom, insertUndefLaneMask(*Dom));
+ SSAUpdater.AddAvailableValue(
+ Dom, insertUndefLaneMask(Dom, &MRI, LaneMaskRegAttrs));
} else {
// The dominator is part of the loop or the given blocks, so add the
// undef value to unreachable predecessors instead.
for (MachineBasicBlock *Pred : Dom->predecessors()) {
if (!inLoopLevel(*Pred, LoopLevel, Incomings))
- SSAUpdater.AddAvailableValue(Pred, insertUndefLaneMask(*Pred));
+ SSAUpdater.AddAvailableValue(
+ Pred, insertUndefLaneMask(Pred, &MRI, LaneMaskRegAttrs));
}
}
}
@@ -415,19 +411,19 @@ FunctionPass *llvm::createSILowerI1CopiesPass() {
return new SILowerI1Copies();
}
-static unsigned createLaneMaskReg(MachineFunction &MF) {
- const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
- MachineRegisterInfo &MRI = MF.getRegInfo();
- return MRI.createVirtualRegister(ST.isWave32() ? &AMDGPU::SReg_32RegClass
- : &AMDGPU::SReg_64RegClass);
+Register llvm::createLaneMaskReg(MachineRegisterInfo *MRI,
+ Register LaneMaskRegAttrs) {
+ return MRI->cloneVirtualRegister(LaneMaskRegAttrs);
}
-static unsigned insertUndefLaneMask(MachineBasicBlock &MBB) {
- MachineFunction &MF = *MBB.getParent();
+static Register insertUndefLaneMask(MachineBasicBlock *MBB,
+ MachineRegisterInfo *MRI,
+ Register LaneMaskRegAttrs) {
+ MachineFunction &MF = *MBB->getParent();
const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
const SIInstrInfo *TII = ST.getInstrInfo();
- unsigned UndefReg = createLaneMaskReg(MF);
- BuildMI(MBB, MBB.getFirstTerminator(), {}, TII->get(AMDGPU::IMPLICIT_DEF),
+ Register UndefReg = createLaneMaskReg(MRI, LaneMaskRegAttrs);
+ BuildMI(*MBB, MBB->getFirstTerminator(), {}, TII->get(AMDGPU::IMPLICIT_DEF),
UndefReg);
return UndefReg;
}
@@ -444,47 +440,17 @@ static unsigned insertUndefLaneMask(MachineBasicBlock &MBB) {
bool SILowerI1Copies::runOnMachineFunction(MachineFunction &TheMF) {
// Only need to run this in SelectionDAG path.
if (TheMF.getProperties().hasProperty(
- MachineFunctionProperties::Property::Selected))
+ MachineFunctionProperties::Property::Selected))
return false;
- MF = &TheMF;
- MRI = &MF->getRegInfo();
- DT = &getAnalysis<MachineDominatorTree>();
- PDT = &getAnalysis<MachinePostDominatorTree>();
-
- ST = &MF->getSubtarget<GCNSubtarget>();
- TII = ST->getInstrInfo();
- IsWave32 = ST->isWave32();
-
- if (IsWave32) {
- ExecReg = AMDGPU::EXEC_LO;
- MovOp = AMDGPU::S_MOV_B32;
- AndOp = AMDGPU::S_AND_B32;
- OrOp = AMDGPU::S_OR_B32;
- XorOp = AMDGPU::S_XOR_B32;
- AndN2Op = AMDGPU::S_ANDN2_B32;
- OrN2Op = AMDGPU::S_ORN2_B32;
- } else {
- ExecReg = AMDGPU::EXEC;
- MovOp = AMDGPU::S_MOV_B64;
- AndOp = AMDGPU::S_AND_B64;
- OrOp = AMDGPU::S_OR_B64;
- XorOp = AMDGPU::S_XOR_B64;
- AndN2Op = AMDGPU::S_ANDN2_B64;
- OrN2Op = AMDGPU::S_ORN2_B64;
- }
+ Vreg1LoweringHelper Helper(&TheMF, &getAnalysis<MachineDominatorTree>(),
+ &getAnalysis<MachinePostDominatorTree>());
bool Changed = false;
- Changed |= lowerCopiesFromI1();
- Changed |= lowerPhis();
- Changed |= lowerCopiesToI1();
-
- assert(Changed || ConstrainRegs.empty());
- for (unsigned Reg : ConstrainRegs)
- MRI->constrainRegClass(Reg, &AMDGPU::SReg_1_XEXECRegClass);
- ConstrainRegs.clear();
-
- return Changed;
+ Changed |= Helper.lowerCopiesFromI1();
+ Changed |= Helper.lowerPhis();
+ Changed |= Helper.lowerCopiesToI1();
+ return Helper.cleanConstrainRegs(Changed);
}
#ifndef NDEBUG
@@ -496,7 +462,7 @@ static bool isVRegCompatibleReg(const SIRegisterInfo &TRI,
}
#endif
-bool SILowerI1Copies::lowerCopiesFromI1() {
+bool Vreg1LoweringHelper::lowerCopiesFromI1() {
bool Changed = false;
SmallVector<MachineInstr *, 4> DeadCopies;
@@ -539,23 +505,43 @@ bool SILowerI1Copies::lowerCopiesFromI1() {
return Changed;
}
-bool SILowerI1Copies::lowerPhis() {
+PhiLoweringHelper::PhiLoweringHelper(MachineFunction *MF,
+ MachineDominatorTree *DT,
+ MachinePostDominatorTree *PDT)
+ : MF(MF), DT(DT), PDT(PDT) {
+ MRI = &MF->getRegInfo();
+
+ ST = &MF->getSubtarget<GCNSubtarget>();
+ TII = ST->getInstrInfo();
+ IsWave32 = ST->isWave32();
+
+ if (IsWave32) {
+ ExecReg = AMDGPU::EXEC_LO;
+ MovOp = AMDGPU::S_MOV_B32;
+ AndOp = AMDGPU::S_AND_B32;
+ OrOp = AMDGPU::S_OR_B32;
+ XorOp = AMDGPU::S_XOR_B32;
+ AndN2Op = AMDGPU::S_ANDN2_B32;
+ OrN2Op = AMDGPU::S_ORN2_B32;
+ } else {
+ ExecReg = AMDGPU::EXEC;
+ MovOp = AMDGPU::S_MOV_B64;
+ AndOp = AMDGPU::S_AND_B64;
+ OrOp = AMDGPU::S_OR_B64;
+ XorOp = AMDGPU::S_XOR_B64;
+ AndN2Op = AMDGPU::S_ANDN2_B64;
+ OrN2Op = AMDGPU::S_ORN2_B64;
+ }
+}
+
+bool PhiLoweringHelper::lowerPhis() {
MachineSSAUpdater SSAUpdater(*MF);
LoopFinder LF(*DT, *PDT);
PhiIncomingAnalysis PIA(*PDT, TII);
SmallVector<MachineInstr *, 4> Vreg1Phis;
SmallVector<Incoming, 4> Incomings;
-#ifndef NDEBUG
- DenseSet<unsigned> PhiRegisters;
-#endif
-
- for (MachineBasicBlock &MBB : *MF) {
- for (MachineInstr &MI : MBB.phis()) {
- if (isVreg1(MI.getOperand(0).getReg()))
- Vreg1Phis.push_back(&MI);
- }
- }
+ getCandidatesForLowering(Vreg1Phis);
if (Vreg1Phis.empty())
return false;
@@ -571,28 +557,10 @@ bool SILowerI1Copies::lowerPhis() {
LLVM_DEBUG(dbgs() << "Lower PHI: " << *MI);
Register DstReg = MI->getOperand(0).getReg();
- MRI->setRegClass(DstReg, IsWave32 ? &AMDGPU::SReg_32RegClass
- : &AMDGPU::SReg_64RegClass);
-
- // Collect incoming values.
- for (unsigned i = 1; i < MI->getNumOperands(); i += 2) {
- assert(i + 1 < MI->getNumOperands());
- Register IncomingReg = MI->getOperand(i).getReg();
- MachineBasicBlock *IncomingMBB = MI->getOperand(i + 1).getMBB();
- MachineInstr *IncomingDef = MRI->getUniqueVRegDef(IncomingReg);
-
- if (IncomingDef->getOpcode() == AMDGPU::COPY) {
- IncomingReg = IncomingDef->getOperand(1).getReg();
- assert(isLaneMaskReg(IncomingReg) || isVreg1(IncomingReg));
- assert(!IncomingDef->getOperand(1).getSubReg());
- } else if (IncomingDef->getOpcode() == AMDGPU::IMPLICIT_DEF) {
- continue;
- } else {
- assert(IncomingDef->isPHI() || PhiRegisters.count(IncomingReg));
- }
+ markAsLaneMask(DstReg);
+ initializeLaneMaskRegisterAttributes(DstReg);
- Incomings.emplace_back(IncomingReg, IncomingMBB, Register{});
- }
+ collectIncomingValuesFromPhi(MI, Incomings);
// Sort the incomings such that incoming values that dominate other incoming
// values are sorted earlier. This allows us to do some amount of on-the-fly
@@ -625,10 +593,11 @@ bool SILowerI1Copies::lowerPhis() {
SSAUpdater.Initialize(DstReg);
if (FoundLoopLevel) {
- LF.addLoopEntries(FoundLoopLevel, SSAUpdater, Incomings);
+ LF.addLoopEntries(FoundLoopLevel, SSAUpdater, *MRI, LaneMaskRegAttrs,
+ Incomings);
for (auto &Incoming : Incomings) {
- Incoming.UpdatedReg = createLaneMaskReg(*MF);
+ Incoming.UpdatedReg = createLaneMaskReg(MRI, LaneMaskRegAttrs);
SSAUpdater.AddAvailableValue(Incoming.Block, Incoming.UpdatedReg);
}
@@ -644,14 +613,16 @@ bool SILowerI1Copies::lowerPhis() {
PIA.analyze(MBB, Incomings);
for (MachineBasicBlock *MBB : PIA.predecessors())
- SSAUpdater.AddAvailableValue(MBB, insertUndefLaneMask(*MBB));
+ SSAUpdater.AddAvailableValue(
+ MBB, insertUndefLaneMask(MBB, MRI, LaneMaskRegAttrs));
for (auto &Incoming : Incomings) {
MachineBasicBlock &IMBB = *Incoming.Block;
if (PIA.isSource(IMBB)) {
+ constrainIncomingRegisterTakenAsIs(Incoming);
SSAUpdater.AddAvailableValue(&IMBB, Incoming.Reg);
} else {
- Incoming.UpdatedReg = createLaneMaskReg(*MF);
+ Incoming.UpdatedReg = createLaneMaskReg(MRI, LaneMaskRegAttrs);
SSAUpdater.AddAvailableValue(&IMBB, Incoming.UpdatedReg);
}
}
@@ -669,7 +640,7 @@ bool SILowerI1Copies::lowerPhis() {
Register NewReg = SSAUpdater.GetValueInMiddleOfBlock(&MBB);
if (NewReg != DstReg) {
- MRI->replaceRegWith(NewReg, DstReg);
+ replaceDstReg(NewReg, DstReg, &MBB);
MI->eraseFromParent();
}
@@ -678,7 +649,7 @@ bool SILowerI1Copies::lowerPhis() {
return true;
}
-bool SILowerI1Copies::lowerCopiesToI1() {
+bool Vreg1LoweringHelper::lowerCopiesToI1() {
bool Changed = false;
MachineSSAUpdater SSAUpdater(*MF);
LoopFinder LF(*DT, *PDT);
@@ -705,8 +676,9 @@ bool SILowerI1Copies::lowerCopiesToI1() {
LLVM_DEBUG(dbgs() << "Lower Other: " << MI);
- MRI->setRegClass(DstReg, IsWave32 ? &AMDGPU::SReg_32RegClass
- : &AMDGPU::SReg_64RegClass);
+ markAsLaneMask(DstReg);
+ initializeLaneMaskRegisterAttributes(DstReg);
+
if (MI.getOpcode() == AMDGPU::IMPLICIT_DEF)
continue;
@@ -716,7 +688,7 @@ bool SILowerI1Copies::lowerCopiesToI1() {
if (!SrcReg.isVirtual() || (!isLaneMaskReg(SrcReg) && !isVreg1(SrcReg))) {
assert(TII->getRegisterInfo().getRegSizeInBits(SrcReg, *MRI) == 32);
- unsigned TmpReg = createLaneMaskReg(*MF);
+ Register TmpReg = createLaneMaskReg(MRI, LaneMaskRegAttrs);
BuildMI(MBB, MI, DL, TII->get(AMDGPU::V_CMP_NE_U32_e64), TmpReg)
.addReg(SrcReg)
.addImm(0);
@@ -739,7 +711,7 @@ bool SILowerI1Copies::lowerCopiesToI1() {
if (FoundLoopLevel) {
SSAUpdater.Initialize(DstReg);
SSAUpdater.AddAvailableValue(&MBB, DstReg);
- LF.addLoopEntries(FoundLoopLevel, SSAUpdater);
+ LF.addLoopEntries(FoundLoopLevel, SSAUpdater, *MRI, LaneMaskRegAttrs);
buildMergeLaneMasks(MBB, MI, DL, DstReg,
SSAUpdater.GetValueInMiddleOfBlock(&MBB), SrcReg);
@@ -754,7 +726,7 @@ bool SILowerI1Copies::lowerCopiesToI1() {
return Changed;
}
-bool SILowerI1Copies::isConstantLaneMask(Register Reg, bool &Val) const {
+bool PhiLoweringHelper::isConstantLaneMask(Register Reg, bool &Val) const {
const MachineInstr *MI;
for (;;) {
MI = MRI->getUniqueVRegDef(Reg);
@@ -807,7 +779,7 @@ static void instrDefsUsesSCC(const MachineInstr &MI, bool &Def, bool &Use) {
/// Return a point at the end of the given \p MBB to insert SALU instructions
/// for lane mask calculation. Take terminators and SCC into account.
MachineBasicBlock::iterator
-SILowerI1Copies::getSaluInsertionAtEnd(MachineBasicBlock &MBB) const {
+PhiLoweringHelper::getSaluInsertionAtEnd(MachineBasicBlock &MBB) const {
auto InsertionPt = MBB.getFirstTerminator();
bool TerminatorsUseSCC = false;
for (auto I = InsertionPt, E = MBB.end(); I != E; ++I) {
@@ -833,10 +805,53 @@ SILowerI1Copies::getSaluInsertionAtEnd(MachineBasicBlock &MBB) const {
llvm_unreachable("SCC used by terminator but no def in block");
}
-void SILowerI1Copies::buildMergeLaneMasks(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator I,
- const DebugLoc &DL, unsigned DstReg,
- unsigned PrevReg, unsigned CurReg) {
+// VReg_1 -> SReg_32 or SReg_64
+void Vreg1LoweringHelper::markAsLaneMask(Register DstReg) const {
+ MRI->setRegClass(DstReg, ST->getBoolRC());
+}
+
+void Vreg1LoweringHelper::getCandidatesForLowering(
+ SmallVectorImpl<MachineInstr *> &Vreg1Phis) const {
+ for (MachineBasicBlock &MBB : *MF) {
+ for (MachineInstr &MI : MBB.phis()) {
+ if (isVreg1(MI.getOperand(0).getReg()))
+ Vreg1Phis.push_back(&MI);
+ }
+ }
+}
+
+void Vreg1LoweringHelper::collectIncomingValuesFromPhi(
+ const MachineInstr *MI, SmallVectorImpl<Incoming> &Incomings) const {
+ for (unsigned i = 1; i < MI->getNumOperands(); i += 2) {
+ assert(i + 1 < MI->getNumOperands());
+ Register IncomingReg = MI->getOperand(i).getReg();
+ MachineBasicBlock *IncomingMBB = MI->getOperand(i + 1).getMBB();
+ MachineInstr *IncomingDef = MRI->getUniqueVRegDef(IncomingReg);
+
+ if (IncomingDef->getOpcode() == AMDGPU::COPY) {
+ IncomingReg = IncomingDef->getOperand(1).getReg();
+ assert(isLaneMaskReg(IncomingReg) || isVreg1(IncomingReg));
+ assert(!IncomingDef->getOperand(1).getSubReg());
+ } else if (IncomingDef->getOpcode() == AMDGPU::IMPLICIT_DEF) {
+ continue;
+ } else {
+ assert(IncomingDef->isPHI() || PhiRegisters.count(IncomingReg));
+ }
+
+ Incomings.emplace_back(IncomingReg, IncomingMBB, Register());
+ }
+}
+
+void Vreg1LoweringHelper::replaceDstReg(Register NewReg, Register OldReg,
+ MachineBasicBlock *MBB) {
+ MRI->replaceRegWith(NewReg, OldReg);
+}
+
+void Vreg1LoweringHelper::buildMergeLaneMasks(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ const DebugLoc &DL,
+ Register DstReg, Register PrevReg,
+ Register CurReg) {
bool PrevVal = false;
bool PrevConstant = isConstantLaneMask(PrevReg, PrevVal);
bool CurVal = false;
@@ -855,13 +870,13 @@ void SILowerI1Copies::buildMergeLaneMasks(MachineBasicBlock &MBB,
return;
}
- unsigned PrevMaskedReg = 0;
- unsigned CurMaskedReg = 0;
+ Register PrevMaskedReg;
+ Register CurMaskedReg;
if (!PrevConstant) {
if (CurConstant && CurVal) {
PrevMaskedReg = PrevReg;
} else {
- PrevMaskedReg = createLaneMaskReg(*MF);
+ PrevMaskedReg = createLaneMaskReg(MRI, LaneMaskRegAttrs);
BuildMI(MBB, I, DL, TII->get(AndN2Op), PrevMaskedReg)
.addReg(PrevReg)
.addReg(ExecReg);
@@ -872,7 +887,7 @@ void SILowerI1Copies::buildMergeLaneMasks(MachineBasicBlock &MBB,
if (PrevConstant && PrevVal) {
CurMaskedReg = CurReg;
} else {
- CurMaskedReg = createLaneMaskReg(*MF);
+ CurMaskedReg = createLaneMaskReg(MRI, LaneMaskRegAttrs);
BuildMI(MBB, I, DL, TII->get(AndOp), CurMaskedReg)
.addReg(CurReg)
.addReg(ExecReg);
@@ -895,3 +910,7 @@ void SILowerI1Copies::buildMergeLaneMasks(MachineBasicBlock &MBB,
.addReg(CurMaskedReg ? CurMaskedReg : ExecReg);
}
}
+
+void Vreg1LoweringHelper::constrainIncomingRegisterTakenAsIs(Incoming &In) {
+ return;
+}
diff --git a/llvm/lib/Target/AMDGPU/SILowerI1Copies.h b/llvm/lib/Target/AMDGPU/SILowerI1Copies.h
new file mode 100644
index 000000000000..5099d39c2d14
--- /dev/null
+++ b/llvm/lib/Target/AMDGPU/SILowerI1Copies.h
@@ -0,0 +1,97 @@
+//===-- SILowerI1Copies.h --------------------------------------*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Interface definition of the PhiLoweringHelper class that implements lane
+/// mask merging algorithm for divergent i1 phis.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GCNSubtarget.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachinePostDominators.h"
+#include "llvm/CodeGen/MachineSSAUpdater.h"
+
+namespace llvm {
+
+/// Incoming for lane maks phi as machine instruction, incoming register \p Reg
+/// and incoming block \p Block are taken from machine instruction.
+/// \p UpdatedReg (if valid) is \p Reg lane mask merged with another lane mask.
+struct Incoming {
+ Register Reg;
+ MachineBasicBlock *Block;
+ Register UpdatedReg;
+
+ Incoming(Register Reg, MachineBasicBlock *Block, Register UpdatedReg)
+ : Reg(Reg), Block(Block), UpdatedReg(UpdatedReg) {}
+};
+
+Register createLaneMaskReg(MachineRegisterInfo *MRI, Register LaneMaskRegAttrs);
+
+class PhiLoweringHelper {
+public:
+ PhiLoweringHelper(MachineFunction *MF, MachineDominatorTree *DT,
+ MachinePostDominatorTree *PDT);
+ virtual ~PhiLoweringHelper() = default;
+
+protected:
+ bool IsWave32 = false;
+ MachineFunction *MF = nullptr;
+ MachineDominatorTree *DT = nullptr;
+ MachinePostDominatorTree *PDT = nullptr;
+ MachineRegisterInfo *MRI = nullptr;
+ const GCNSubtarget *ST = nullptr;
+ const SIInstrInfo *TII = nullptr;
+ Register LaneMaskRegAttrs;
+
+#ifndef NDEBUG
+ DenseSet<Register> PhiRegisters;
+#endif
+
+ Register ExecReg;
+ unsigned MovOp;
+ unsigned AndOp;
+ unsigned OrOp;
+ unsigned XorOp;
+ unsigned AndN2Op;
+ unsigned OrN2Op;
+
+public:
+ bool lowerPhis();
+ bool isConstantLaneMask(Register Reg, bool &Val) const;
+ MachineBasicBlock::iterator
+ getSaluInsertionAtEnd(MachineBasicBlock &MBB) const;
+
+ void initializeLaneMaskRegisterAttributes(Register LaneMask) {
+ LaneMaskRegAttrs = LaneMask;
+ }
+
+ bool isLaneMaskReg(Register Reg) const {
+ return TII->getRegisterInfo().isSGPRReg(*MRI, Reg) &&
+ TII->getRegisterInfo().getRegSizeInBits(Reg, *MRI) ==
+ ST->getWavefrontSize();
+ }
+
+ // Helpers from lowerPhis that are different between sdag and global-isel.
+
+ virtual void markAsLaneMask(Register DstReg) const = 0;
+ virtual void getCandidatesForLowering(
+ SmallVectorImpl<MachineInstr *> &Vreg1Phis) const = 0;
+ virtual void
+ collectIncomingValuesFromPhi(const MachineInstr *MI,
+ SmallVectorImpl<Incoming> &Incomings) const = 0;
+ virtual void replaceDstReg(Register NewReg, Register OldReg,
+ MachineBasicBlock *MBB) = 0;
+ virtual void buildMergeLaneMasks(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ const DebugLoc &DL, Register DstReg,
+ Register PrevReg, Register CurReg) = 0;
+ virtual void constrainIncomingRegisterTakenAsIs(Incoming &In) = 0;
+};
+
+} // end namespace llvm
diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
index f8eb67199f62..e8142244b7db 100644
--- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
@@ -37,7 +37,7 @@ const GCNTargetMachine &getTM(const GCNSubtarget *STI) {
SIMachineFunctionInfo::SIMachineFunctionInfo(const Function &F,
const GCNSubtarget *STI)
- : AMDGPUMachineFunction(F, *STI), Mode(F), GWSResourcePSV(getTM(STI)),
+ : AMDGPUMachineFunction(F, *STI), Mode(F, *STI), GWSResourcePSV(getTM(STI)),
UserSGPRInfo(F, *STI), WorkGroupIDX(false), WorkGroupIDY(false),
WorkGroupIDZ(false), WorkGroupInfo(false), LDSKernelId(false),
PrivateSegmentWaveByteOffset(false), WorkItemIDX(false),
@@ -349,8 +349,9 @@ bool SIMachineFunctionInfo::allocatePhysicalVGPRForSGPRSpills(
MBB.addLiveIn(LaneVGPR);
MBB.sortUniqueLiveIns();
}
+ SpillPhysVGPRs.push_back(LaneVGPR);
} else {
- LaneVGPR = WWMReservedRegs.back();
+ LaneVGPR = SpillPhysVGPRs.back();
}
SGPRSpillsToPhysicalVGPRLanes[FI].push_back(
@@ -728,7 +729,7 @@ bool SIMachineFunctionInfo::mayUseAGPRs(const Function &F) const {
for (const auto &CI : IA->ParseConstraints()) {
for (StringRef Code : CI.Codes) {
Code.consume_front("{");
- if (Code.startswith("a"))
+ if (Code.starts_with("a"))
return true;
}
}
diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h
index 7ff50c80081d..dc63ae44c528 100644
--- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h
+++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h
@@ -502,6 +502,7 @@ private:
unsigned NumVirtualVGPRSpillLanes = 0;
unsigned NumPhysicalVGPRSpillLanes = 0;
SmallVector<Register, 2> SpillVGPRs;
+ SmallVector<Register, 2> SpillPhysVGPRs;
using WWMSpillsMap = MapVector<Register, int>;
// To track the registers used in instructions that can potentially modify the
// inactive lanes. The WWM instructions and the writelane instructions for
diff --git a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
index bc48f7b76c6d..10ec54d3317f 100644
--- a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
@@ -1055,7 +1055,8 @@ bool SIGfx6CacheControl::insertWait(MachineBasicBlock::iterator &MI,
VMCnt ? 0 : getVmcntBitMask(IV),
getExpcntBitMask(IV),
LGKMCnt ? 0 : getLgkmcntBitMask(IV));
- BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT)).addImm(WaitCntImmediate);
+ BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT_soft))
+ .addImm(WaitCntImmediate);
Changed = true;
}
@@ -1963,14 +1964,15 @@ bool SIGfx10CacheControl::insertWait(MachineBasicBlock::iterator &MI,
VMCnt ? 0 : getVmcntBitMask(IV),
getExpcntBitMask(IV),
LGKMCnt ? 0 : getLgkmcntBitMask(IV));
- BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT)).addImm(WaitCntImmediate);
+ BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT_soft))
+ .addImm(WaitCntImmediate);
Changed = true;
}
if (VSCnt) {
- BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT_VSCNT))
- .addReg(AMDGPU::SGPR_NULL, RegState::Undef)
- .addImm(0);
+ BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT_VSCNT_soft))
+ .addReg(AMDGPU::SGPR_NULL, RegState::Undef)
+ .addImm(0);
Changed = true;
}
diff --git a/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.cpp b/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.cpp
index ffed268244ed..2684a1e3c335 100644
--- a/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.cpp
+++ b/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.cpp
@@ -7,20 +7,26 @@
//===----------------------------------------------------------------------===//
#include "SIModeRegisterDefaults.h"
+#include "GCNSubtarget.h"
using namespace llvm;
-SIModeRegisterDefaults::SIModeRegisterDefaults(const Function &F) {
+SIModeRegisterDefaults::SIModeRegisterDefaults(const Function &F,
+ const GCNSubtarget &ST) {
*this = getDefaultForCallingConv(F.getCallingConv());
- StringRef IEEEAttr = F.getFnAttribute("amdgpu-ieee").getValueAsString();
- if (!IEEEAttr.empty())
- IEEE = IEEEAttr == "true";
+ if (ST.hasIEEEMode()) {
+ StringRef IEEEAttr = F.getFnAttribute("amdgpu-ieee").getValueAsString();
+ if (!IEEEAttr.empty())
+ IEEE = IEEEAttr == "true";
+ }
- StringRef DX10ClampAttr =
- F.getFnAttribute("amdgpu-dx10-clamp").getValueAsString();
- if (!DX10ClampAttr.empty())
- DX10Clamp = DX10ClampAttr == "true";
+ if (ST.hasDX10ClampMode()) {
+ StringRef DX10ClampAttr =
+ F.getFnAttribute("amdgpu-dx10-clamp").getValueAsString();
+ if (!DX10ClampAttr.empty())
+ DX10Clamp = DX10ClampAttr == "true";
+ }
StringRef DenormF32Attr =
F.getFnAttribute("denormal-fp-math-f32").getValueAsString();
diff --git a/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h b/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h
index 58e2c67c248b..9fbd74c3eede 100644
--- a/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h
+++ b/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h
@@ -14,6 +14,8 @@
namespace llvm {
+class GCNSubtarget;
+
// Track defaults for fields in the MODE register.
struct SIModeRegisterDefaults {
/// Floating point opcodes that support exception flag gathering quiet and
@@ -40,7 +42,7 @@ struct SIModeRegisterDefaults {
FP32Denormals(DenormalMode::getIEEE()),
FP64FP16Denormals(DenormalMode::getIEEE()) {}
- SIModeRegisterDefaults(const Function &F);
+ SIModeRegisterDefaults(const Function &F, const GCNSubtarget &ST);
static SIModeRegisterDefaults getDefaultForCallingConv(CallingConv::ID CC) {
SIModeRegisterDefaults Mode;
diff --git a/llvm/lib/Target/AMDGPU/SIProgramInfo.cpp b/llvm/lib/Target/AMDGPU/SIProgramInfo.cpp
index b6839c8308d8..9ed7aacc0538 100644
--- a/llvm/lib/Target/AMDGPU/SIProgramInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIProgramInfo.cpp
@@ -15,27 +15,48 @@
//
#include "SIProgramInfo.h"
+#include "GCNSubtarget.h"
#include "SIDefines.h"
#include "Utils/AMDGPUBaseInfo.h"
using namespace llvm;
-uint64_t SIProgramInfo::getComputePGMRSrc1() const {
- return S_00B848_VGPRS(VGPRBlocks) | S_00B848_SGPRS(SGPRBlocks) |
- S_00B848_PRIORITY(Priority) | S_00B848_FLOAT_MODE(FloatMode) |
- S_00B848_PRIV(Priv) | S_00B848_DX10_CLAMP(DX10Clamp) |
- S_00B848_DEBUG_MODE(DebugMode) | S_00B848_IEEE_MODE(IEEEMode) |
- S_00B848_WGP_MODE(WgpMode) | S_00B848_MEM_ORDERED(MemOrdered);
+uint64_t SIProgramInfo::getComputePGMRSrc1(const GCNSubtarget &ST) const {
+ uint64_t Reg = S_00B848_VGPRS(VGPRBlocks) | S_00B848_SGPRS(SGPRBlocks) |
+ S_00B848_PRIORITY(Priority) | S_00B848_FLOAT_MODE(FloatMode) |
+ S_00B848_PRIV(Priv) | S_00B848_DEBUG_MODE(DebugMode) |
+ S_00B848_WGP_MODE(WgpMode) | S_00B848_MEM_ORDERED(MemOrdered);
+
+ if (ST.hasDX10ClampMode())
+ Reg |= S_00B848_DX10_CLAMP(DX10Clamp);
+
+ if (ST.hasIEEEMode())
+ Reg |= S_00B848_IEEE_MODE(IEEEMode);
+
+ if (ST.hasRrWGMode())
+ Reg |= S_00B848_RR_WG_MODE(RrWgMode);
+
+ return Reg;
}
-uint64_t SIProgramInfo::getPGMRSrc1(CallingConv::ID CC) const {
+uint64_t SIProgramInfo::getPGMRSrc1(CallingConv::ID CC,
+ const GCNSubtarget &ST) const {
if (AMDGPU::isCompute(CC)) {
- return getComputePGMRSrc1();
+ return getComputePGMRSrc1(ST);
}
uint64_t Reg = S_00B848_VGPRS(VGPRBlocks) | S_00B848_SGPRS(SGPRBlocks) |
S_00B848_PRIORITY(Priority) | S_00B848_FLOAT_MODE(FloatMode) |
- S_00B848_PRIV(Priv) | S_00B848_DX10_CLAMP(DX10Clamp) |
- S_00B848_DEBUG_MODE(DebugMode) | S_00B848_IEEE_MODE(IEEEMode);
+ S_00B848_PRIV(Priv) | S_00B848_DEBUG_MODE(DebugMode);
+
+ if (ST.hasDX10ClampMode())
+ Reg |= S_00B848_DX10_CLAMP(DX10Clamp);
+
+ if (ST.hasIEEEMode())
+ Reg |= S_00B848_IEEE_MODE(IEEEMode);
+
+ if (ST.hasRrWGMode())
+ Reg |= S_00B848_RR_WG_MODE(RrWgMode);
+
switch (CC) {
case CallingConv::AMDGPU_PS:
Reg |= S_00B028_MEM_ORDERED(MemOrdered);
diff --git a/llvm/lib/Target/AMDGPU/SIProgramInfo.h b/llvm/lib/Target/AMDGPU/SIProgramInfo.h
index aab127e49463..8c26789f936c 100644
--- a/llvm/lib/Target/AMDGPU/SIProgramInfo.h
+++ b/llvm/lib/Target/AMDGPU/SIProgramInfo.h
@@ -21,6 +21,8 @@
namespace llvm {
+class GCNSubtarget;
+
/// Track resource usage for kernels / entry functions.
struct SIProgramInfo {
// Fields set in PGM_RSRC1 pm4 packet.
@@ -34,6 +36,7 @@ struct SIProgramInfo {
uint32_t IEEEMode = 0;
uint32_t WgpMode = 0; // GFX10+
uint32_t MemOrdered = 0; // GFX10+
+ uint32_t RrWgMode = 0; // GFX12+
uint64_t ScratchSize = 0;
// State used to calculate fields set in PGM_RSRC2 pm4 packet.
@@ -85,8 +88,8 @@ struct SIProgramInfo {
SIProgramInfo() = default;
/// Compute the value of the ComputePGMRsrc1 register.
- uint64_t getComputePGMRSrc1() const;
- uint64_t getPGMRSrc1(CallingConv::ID CC) const;
+ uint64_t getComputePGMRSrc1(const GCNSubtarget &ST) const;
+ uint64_t getPGMRSrc1(CallingConv::ID CC, const GCNSubtarget &ST) const;
/// Compute the value of the ComputePGMRsrc2 register.
uint64_t getComputePGMRSrc2() const;
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
index 1ce596de0403..021d797344c5 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
@@ -804,10 +804,10 @@ bool SIRegisterInfo::needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const {
int64_t FullOffset = Offset + getScratchInstrOffset(MI);
+ const SIInstrInfo *TII = ST.getInstrInfo();
if (SIInstrInfo::isMUBUF(*MI))
- return !SIInstrInfo::isLegalMUBUFImmOffset(FullOffset);
+ return !TII->isLegalMUBUFImmOffset(FullOffset);
- const SIInstrInfo *TII = ST.getInstrInfo();
return !TII->isLegalFLATOffset(FullOffset, AMDGPUAS::PRIVATE_ADDRESS,
SIInstrFlags::FlatScratch);
}
@@ -905,8 +905,7 @@ void SIRegisterInfo::resolveFrameIndex(MachineInstr &MI, Register BaseReg,
assert(SOffset->isImm() && SOffset->getImm() == 0);
#endif
- assert(SIInstrInfo::isLegalMUBUFImmOffset(NewOffset) &&
- "offset should be legal");
+ assert(TII->isLegalMUBUFImmOffset(NewOffset) && "offset should be legal");
FIOp->ChangeToRegister(BaseReg, false);
OffsetOp->setImm(NewOffset);
@@ -920,10 +919,10 @@ bool SIRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI,
int64_t NewOffset = Offset + getScratchInstrOffset(MI);
+ const SIInstrInfo *TII = ST.getInstrInfo();
if (SIInstrInfo::isMUBUF(*MI))
- return SIInstrInfo::isLegalMUBUFImmOffset(NewOffset);
+ return TII->isLegalMUBUFImmOffset(NewOffset);
- const SIInstrInfo *TII = ST.getInstrInfo();
return TII->isLegalFLATOffset(NewOffset, AMDGPUAS::PRIVATE_ADDRESS,
SIInstrFlags::FlatScratch);
}
@@ -1404,7 +1403,7 @@ void SIRegisterInfo::buildSpillLoadStore(
bool IsOffsetLegal =
IsFlat ? TII->isLegalFLATOffset(MaxOffset, AMDGPUAS::PRIVATE_ADDRESS,
SIInstrFlags::FlatScratch)
- : SIInstrInfo::isLegalMUBUFImmOffset(MaxOffset);
+ : TII->isLegalMUBUFImmOffset(MaxOffset);
if (!IsOffsetLegal || (IsFlat && !SOffset && !ST.hasFlatScratchSTMode())) {
SOffset = MCRegister();
@@ -2562,7 +2561,7 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
= TII->getNamedOperand(*MI, AMDGPU::OpName::offset)->getImm();
int64_t NewOffset = OldImm + Offset;
- if (SIInstrInfo::isLegalMUBUFImmOffset(NewOffset) &&
+ if (TII->isLegalMUBUFImmOffset(NewOffset) &&
buildMUBUFOffsetLoadStore(ST, FrameInfo, MI, Index, NewOffset)) {
MI->eraseFromParent();
return true;
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
index 7ea2280c474b..981da13fe089 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
@@ -414,7 +414,7 @@ def SGPR_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32,
// SGPR 64-bit registers
def SGPR_64Regs : SIRegisterTuples<getSubRegs<2>.ret, SGPR_32, 105, 2, 2, "s">;
-// SGPR 96-bit registers. No operations use these, but for symmetry with 96-bit VGPRs.
+// SGPR 96-bit registers.
def SGPR_96Regs : SIRegisterTuples<getSubRegs<3>.ret, SGPR_32, 105, 4, 3, "s">;
// SGPR 128-bit registers
diff --git a/llvm/lib/Target/AMDGPU/SISchedule.td b/llvm/lib/Target/AMDGPU/SISchedule.td
index c67e647a7e7c..b0e8e4112254 100644
--- a/llvm/lib/Target/AMDGPU/SISchedule.td
+++ b/llvm/lib/Target/AMDGPU/SISchedule.td
@@ -68,6 +68,9 @@ def Write8PassDGEMM : SchedWrite;
// Scalar float instructions
def WriteSFPU : SchedWrite;
+// F16 or F32 pseudo scalar transcendental instructions
+def WritePseudoScalarTrans : SchedWrite;
+
// FIXME: Should there be a class for instructions which are VALU
// instructions and have VALU rates, but write to the SALU (i.e. VOPC
// instructions)
@@ -93,6 +96,7 @@ def SIDPFullSpeedModel : SISchedMachineModel;
def SIDPGFX940FullSpeedModel : SISchedMachineModel;
def GFX10SpeedModel : SISchedMachineModel;
def GFX11SpeedModel : SISchedMachineModel;
+def GFX12SpeedModel : SISchedMachineModel;
// XXX: Are the resource counts correct?
def HWBranch : ProcResource<1> {
@@ -174,6 +178,7 @@ multiclass SICommonWriteRes {
def : HWWriteRes<Write16PassMAI, [HWXDL], 16>;
def : UnsupportedWriteRes<WriteSFPU>;
+ def : UnsupportedWriteRes<WritePseudoScalarTrans>;
} // End RetireOOO = 1
def : ReadAdvance<MIVGPRRead, -2>;
@@ -318,6 +323,7 @@ def : HWWriteRes<WriteVMEM, [HWVMEM, HWRC], 320>;
def : HWWriteRes<WriteBarrier, [HWBranch], 2000>;
def : UnsupportedWriteRes<WriteSFPU>;
+def : UnsupportedWriteRes<WritePseudoScalarTrans>;
} // End RetireOOO = 1
def : InstRW<[WriteCopy], (instrs COPY)>;
@@ -351,6 +357,36 @@ def : HWWriteRes<WriteVMEM, [HWVMEM, HWRC], 320>;
def : HWWriteRes<WriteBarrier, [HWBranch], 2000>;
} // End RetireOOO = 1
+def : UnsupportedWriteRes<WritePseudoScalarTrans>;
+
def : InstRW<[WriteCopy], (instrs COPY)>;
} // End SchedModel = GFX11SpeedModel
+
+let SchedModel = GFX12SpeedModel in {
+
+def : HWWriteRes<Write32Bit, [HWVALU, HWRC], 5>;
+def : HWWriteRes<WriteFloatCvt, [HWVALU, HWRC], 5>;
+def : HWWriteRes<Write64Bit, [HWVALU, HWRC], 6>;
+def : HWWriteRes<WriteTrans32, [HWVALU, HWRC], 10>;
+def : HWWriteRes<WriteQuarterRate32, [HWVALU, HWRC], 8>;
+def : HWWriteRes<WriteFloatFMA, [HWVALU, HWRC], 5>;
+def : HWWriteRes<WriteDouble, [HWVALU, HWRC], 38>;
+def : HWWriteRes<WriteDoubleAdd, [HWVALU, HWRC], 38>;
+def : HWWriteRes<WriteDoubleCvt, [HWVALU, HWRC], 38>;
+def : HWWriteRes<WriteIntMul, [HWVALU, HWRC], 8>;
+def : HWWriteRes<WriteTrans64, [HWVALU, HWRC], 40>;
+def : HWWriteRes<WritePseudoScalarTrans, [HWVALU, HWRC], 7>;
+
+def : HWWriteRes<WriteBranch, [HWBranch], 32>;
+def : HWWriteRes<WriteExport, [HWExport, HWRC], 16>;
+def : HWWriteRes<WriteLDS, [HWLGKM, HWRC], 20>;
+def : HWWriteRes<WriteSALU, [HWSALU, HWRC], 2>;
+def : HWWriteRes<WriteSFPU, [HWSALU, HWRC], 4>;
+def : HWWriteRes<WriteSMEM, [HWLGKM, HWRC], 20>;
+def : HWWriteRes<WriteVMEM, [HWVMEM, HWRC], 320>;
+def : HWWriteRes<WriteBarrier, [HWBranch], 2000>;
+
+def : InstRW<[WriteCopy], (instrs COPY)>;
+
+} // End SchedModel = GFX12SpeedModel
diff --git a/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp b/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp
index 856121be7803..d290dd82b760 100644
--- a/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp
+++ b/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp
@@ -211,6 +211,9 @@ void SIShrinkInstructions::copyExtraImplicitOps(MachineInstr &NewMI,
}
void SIShrinkInstructions::shrinkScalarCompare(MachineInstr &MI) const {
+ if (!ST->hasSCmpK())
+ return;
+
// cmpk instructions do scc = dst <cc op> imm16, so commute the instruction to
// get constants on the RHS.
if (!MI.getOperand(0).isReg())
diff --git a/llvm/lib/Target/AMDGPU/SMInstructions.td b/llvm/lib/Target/AMDGPU/SMInstructions.td
index c18846483cf9..3297847b0360 100644
--- a/llvm/lib/Target/AMDGPU/SMInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SMInstructions.td
@@ -74,7 +74,7 @@ class SM_Real <SM_Pseudo ps, string opName = ps.Mnemonic>
bits<7> sdst;
bits<32> offset;
bits<8> soffset;
- bits<5> cpol;
+ bits<5> cpol;
}
class OffsetMode<bit hasOffset, bit hasSOffset, string variant,
@@ -300,6 +300,8 @@ multiclass SM_Pseudo_Atomics<RegisterClass baseClass,
// does sdst for SMRD on SI/CI?
defm S_LOAD_DWORD : SM_Pseudo_Loads <SReg_64, SReg_32_XM0_XEXEC>;
defm S_LOAD_DWORDX2 : SM_Pseudo_Loads <SReg_64, SReg_64_XEXEC>;
+let SubtargetPredicate = HasScalarDwordx3Loads in
+ defm S_LOAD_DWORDX3 : SM_Pseudo_Loads <SReg_64, SReg_96>;
defm S_LOAD_DWORDX4 : SM_Pseudo_Loads <SReg_64, SReg_128>;
defm S_LOAD_DWORDX8 : SM_Pseudo_Loads <SReg_64, SReg_256>;
defm S_LOAD_DWORDX16 : SM_Pseudo_Loads <SReg_64, SReg_512>;
@@ -309,6 +311,8 @@ defm S_BUFFER_LOAD_DWORD : SM_Pseudo_Loads <SReg_128, SReg_32_XM0_XEXEC>;
// FIXME: exec_lo/exec_hi appear to be allowed for SMRD loads on
// SI/CI, bit disallowed for SMEM on VI.
defm S_BUFFER_LOAD_DWORDX2 : SM_Pseudo_Loads <SReg_128, SReg_64_XEXEC>;
+let SubtargetPredicate = HasScalarDwordx3Loads in
+ defm S_BUFFER_LOAD_DWORDX3 : SM_Pseudo_Loads <SReg_128, SReg_96>;
defm S_BUFFER_LOAD_DWORDX4 : SM_Pseudo_Loads <SReg_128, SReg_128>;
defm S_BUFFER_LOAD_DWORDX8 : SM_Pseudo_Loads <SReg_128, SReg_256>;
defm S_BUFFER_LOAD_DWORDX16 : SM_Pseudo_Loads <SReg_128, SReg_512>;
@@ -814,6 +818,14 @@ def smrd_load : PatFrag <(ops node:$ptr), (load node:$ptr), [{ return isUniformL
}];
}
+def smrd_prefetch : PatFrag <(ops node:$ptr, node:$rw, node:$loc, node:$type),
+ (prefetch node:$ptr, node:$rw, node:$loc, node:$type),
+ [{ return !N->getOperand(1)->isDivergent();}]> {
+ let GISelPredicateCode = [{
+ return isInstrUniform(MI);
+ }];
+}
+
def SMRDImm : ComplexPattern<iPTR, 2, "SelectSMRDImm">;
def SMRDImm32 : ComplexPattern<iPTR, 2, "SelectSMRDImm32">;
def SMRDSgpr : ComplexPattern<iPTR, 2, "SelectSMRDSgpr">;
@@ -822,7 +834,7 @@ def SMRDBufferImm : ComplexPattern<iPTR, 1, "SelectSMRDBufferImm">;
def SMRDBufferImm32 : ComplexPattern<iPTR, 1, "SelectSMRDBufferImm32">;
def SMRDBufferSgprImm : ComplexPattern<iPTR, 2, "SelectSMRDBufferSgprImm">;
-multiclass SMRD_Pattern <string Instr, ValueType vt> {
+multiclass SMRD_Pattern <string Instr, ValueType vt, bit immci = true> {
// 1. IMM offset
def : GCNPat <
@@ -831,7 +843,7 @@ multiclass SMRD_Pattern <string Instr, ValueType vt> {
>;
// 2. 32-bit IMM offset on CI
- def : GCNPat <
+ if immci then def : GCNPat <
(smrd_load (SMRDImm32 i64:$sbase, i32:$offset)),
(vt (!cast<InstSI>(Instr#"_IMM_ci") $sbase, $offset, 0))> {
let OtherPredicates = [isGFX7Only];
@@ -863,7 +875,7 @@ multiclass SMRD_Pattern <string Instr, ValueType vt> {
>;
}
-multiclass SMLoad_Pattern <string Instr, ValueType vt> {
+multiclass SMLoad_Pattern <string Instr, ValueType vt, bit immci = true> {
// 1. Offset as an immediate
def : GCNPat <
(SIsbuffer_load v4i32:$sbase, (SMRDBufferImm i32:$offset), timm:$cachepolicy),
@@ -872,7 +884,7 @@ multiclass SMLoad_Pattern <string Instr, ValueType vt> {
}
// 2. 32-bit IMM offset on CI
- def : GCNPat <
+ if immci then def : GCNPat <
(vt (SIsbuffer_load v4i32:$sbase, (SMRDBufferImm32 i32:$offset), timm:$cachepolicy)),
(!cast<InstSI>(Instr#"_IMM_ci") SReg_128:$sbase, smrd_literal_offset:$offset,
(extract_cpol $cachepolicy))> {
@@ -915,6 +927,10 @@ foreach vt = SReg_64.RegTypes in {
defm : SMRD_Pattern <"S_LOAD_DWORDX2", vt>;
}
+foreach vt = SReg_96.RegTypes in {
+defm : SMRD_Pattern <"S_LOAD_DWORDX3", vt, false>;
+}
+
foreach vt = SReg_128.RegTypes in {
defm : SMRD_Pattern <"S_LOAD_DWORDX4", vt>;
}
@@ -931,12 +947,14 @@ defm : SMRD_Pattern <"S_LOAD_DWORDX16", vt>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORD", i32>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX2", v2i32>;
+defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX3", v3i32, false>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX4", v4i32>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX8", v8i32>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX16", v16i32>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORD", f32>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX2", v2f32>;
+defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX3", v3f32, false>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX4", v4f32>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX8", v8f32>;
defm : SMLoad_Pattern <"S_BUFFER_LOAD_DWORDX16", v16f32>;
@@ -959,6 +977,21 @@ def : GCNPat <
}
} // let OtherPredicates = [HasShaderCyclesRegister]
+multiclass SMPrefetchPat<string type, int cache_type> {
+ def : GCNPat <
+ (smrd_prefetch (SMRDImm i64:$sbase, i32:$offset), timm, timm, (i32 cache_type)),
+ (!cast<SM_Prefetch_Pseudo>("S_PREFETCH_"#type) $sbase, $offset, (i32 SGPR_NULL), (i8 0))
+ >;
+
+ def : GCNPat <
+ (smrd_prefetch (i64 SReg_64:$sbase), timm, timm, (i32 cache_type)),
+ (!cast<SM_Prefetch_Pseudo>("S_PREFETCH_"#type) $sbase, 0, (i32 SGPR_NULL), (i8 0))
+ >;
+}
+
+defm : SMPrefetchPat<"INST", 0>;
+defm : SMPrefetchPat<"DATA", 1>;
+
//===----------------------------------------------------------------------===//
// GFX10.
//===----------------------------------------------------------------------===//
@@ -1179,7 +1212,7 @@ def SMInfoTable : GenericTable {
class SMEM_Real_gfx11<bits<8> op, SM_Pseudo ps, string opName = ps.Mnemonic> :
SMEM_Real_10Plus_common<op, ps, opName, SIEncodingFamily.GFX11,
SGPR_NULL_gfx11plus> {
- let AssemblerPredicate = isGFX11Plus;
+ let AssemblerPredicate = isGFX11Only;
let DecoderNamespace = "GFX11";
let Inst{13} = !if(ps.has_dlc, cpol{CPolBit.DLC}, 0);
let Inst{14} = !if(ps.has_glc, cpol{CPolBit.GLC}, 0);
@@ -1235,19 +1268,30 @@ defm S_ATC_PROBE_BUFFER : SM_Real_Probe_gfx11 <0x23>;
// GFX12.
//===----------------------------------------------------------------------===//
-class SMEM_Real_gfx12<bits<8> op, SM_Pseudo ps, string opName = ps.Mnemonic> :
- SMEM_Real_10Plus_common<op, ps, opName, SIEncodingFamily.GFX12,
- SGPR_NULL_gfx11plus> {
+class SMEM_Real_gfx12Plus<bits<6> op, SM_Pseudo ps, string opName,
+ int subtarget, RegisterWithSubRegs sgpr_null> :
+ SM_Real<ps, opName>, SIMCInstr<ps.PseudoInstr, subtarget>, Enc64 {
+
+ let Inst{18-13} = op;
+ let Inst{31-26} = 0x3d;
+
+ let Inst{55-32} = !if(ps.has_offset, offset{23-0}, !if(ps.has_soffset, 0, ?));
+ let Inst{63-57} = !if(ps.has_soffset, soffset{6-0},
+ !if(ps.has_offset, sgpr_null.HWEncoding{6-0}, ?));
+}
+
+class SMEM_Real_gfx12<bits<6> op, SM_Pseudo ps, string opName = ps.Mnemonic> :
+ SMEM_Real_gfx12Plus<op, ps, opName, SIEncodingFamily.GFX12,
+ SGPR_NULL_gfx11plus> {
let AssemblerPredicate = isGFX12Plus;
let DecoderNamespace = "GFX12";
- let Inst{18-13} = op{5-0};
- let Inst{19} = !if(ps.has_dlc, cpol{CPolBit.DLC}, 0);
- let Inst{24-20} = ?; // TODO-GFX12: Add new bits {24-20}: TH, Scope, NV
- let Inst{25} = !if(ps.has_glc, cpol{CPolBit.GLC}, 0);
- let Inst{55-32} = offset{23-0};
+
+ let Inst{5-0} = !if(ps.has_sbase, sbase{6-1}, ?);
+ let Inst{12-6} = !if(ps.has_sdst, sdst{6-0}, ?);
}
-class SMEM_Real_Prefetch_gfx12 <bits<8> op, SM_Pseudo ps> : SMEM_Real_gfx12<op, ps> {
+class SMEM_Real_Prefetch_gfx12<bits<6> op, SM_Pseudo ps> :
+ SMEM_Real_gfx12<op, ps> {
bits<7> sdata; // Only 5 bits of sdata are supported.
let sdst = ?;
@@ -1255,8 +1299,48 @@ class SMEM_Real_Prefetch_gfx12 <bits<8> op, SM_Pseudo ps> : SMEM_Real_gfx12<op,
let Inst{10-6} = !if(ps.has_sdst, sdata{4-0}, ?);
}
+class SMEM_Real_Load_gfx12<bits<6> op, string ps, string opName, OffsetMode offsets> :
+ SMEM_Real_gfx12<op, !cast<SM_Pseudo>(ps # offsets.Variant), opName> {
+ RegisterClass BaseClass = !cast<SM_Load_Pseudo>(ps # offsets.Variant).BaseClass;
+ let InOperandList = !con((ins BaseClass:$sbase), offsets.Ins, (ins CPol:$cpol));
+
+ let Inst{22-21} = cpol{4-3}; // scope
+ let Inst{24-23} = cpol{1-0}; // th - only lower 2 bits are supported
+}
+
+multiclass SM_Real_Loads_gfx12<bits<6> op, string ps = NAME> {
+ defvar opName = !tolower(NAME);
+ def _IMM_gfx12 : SMEM_Real_Load_gfx12<op, ps, opName, IMM_Offset>;
+ def _SGPR_IMM_gfx12 : SMEM_Real_Load_gfx12<op, ps, opName, SGPR_IMM_Offset>;
+}
+
+defm S_LOAD_B32 : SM_Real_Loads_gfx12<0x00, "S_LOAD_DWORD">;
+defm S_LOAD_B64 : SM_Real_Loads_gfx12<0x01, "S_LOAD_DWORDX2">;
+defm S_LOAD_B96 : SM_Real_Loads_gfx12<0x05, "S_LOAD_DWORDX3">;
+defm S_LOAD_B128 : SM_Real_Loads_gfx12<0x02, "S_LOAD_DWORDX4">;
+defm S_LOAD_B256 : SM_Real_Loads_gfx12<0x03, "S_LOAD_DWORDX8">;
+defm S_LOAD_B512 : SM_Real_Loads_gfx12<0x04, "S_LOAD_DWORDX16">;
+
+defm S_BUFFER_LOAD_B32 : SM_Real_Loads_gfx12<0x10, "S_BUFFER_LOAD_DWORD">;
+defm S_BUFFER_LOAD_B64 : SM_Real_Loads_gfx12<0x11, "S_BUFFER_LOAD_DWORDX2">;
+defm S_BUFFER_LOAD_B96 : SM_Real_Loads_gfx12<0x15, "S_BUFFER_LOAD_DWORDX3">;
+defm S_BUFFER_LOAD_B128 : SM_Real_Loads_gfx12<0x12, "S_BUFFER_LOAD_DWORDX4">;
+defm S_BUFFER_LOAD_B256 : SM_Real_Loads_gfx12<0x13, "S_BUFFER_LOAD_DWORDX8">;
+defm S_BUFFER_LOAD_B512 : SM_Real_Loads_gfx12<0x14, "S_BUFFER_LOAD_DWORDX16">;
+
+def S_DCACHE_INV_gfx12 : SMEM_Real_gfx12<0x021, S_DCACHE_INV>;
+
def S_PREFETCH_INST_gfx12 : SMEM_Real_Prefetch_gfx12<0x24, S_PREFETCH_INST>;
def S_PREFETCH_INST_PC_REL_gfx12 : SMEM_Real_Prefetch_gfx12<0x25, S_PREFETCH_INST_PC_REL>;
def S_PREFETCH_DATA_gfx12 : SMEM_Real_Prefetch_gfx12<0x26, S_PREFETCH_DATA>;
def S_BUFFER_PREFETCH_DATA_gfx12 : SMEM_Real_Prefetch_gfx12<0x27, S_BUFFER_PREFETCH_DATA>;
def S_PREFETCH_DATA_PC_REL_gfx12 : SMEM_Real_Prefetch_gfx12<0x28, S_PREFETCH_DATA_PC_REL>;
+
+multiclass SMEM_Real_Probe_gfx12<bits<6> op> {
+ defvar ps = NAME;
+ def _IMM_gfx12 : SMEM_Real_Prefetch_gfx12<op, !cast<SM_Probe_Pseudo>(ps#_IMM)>;
+ def _SGPR_IMM_gfx12 : SMEM_Real_Prefetch_gfx12<op, !cast<SM_Probe_Pseudo>(ps#_SGPR_IMM)>;
+}
+
+defm S_ATC_PROBE : SMEM_Real_Probe_gfx12<0x22>;
+defm S_ATC_PROBE_BUFFER : SMEM_Real_Probe_gfx12<0x23>;
diff --git a/llvm/lib/Target/AMDGPU/SOPInstructions.td b/llvm/lib/Target/AMDGPU/SOPInstructions.td
index 9ff64968ef01..c9687ac368d3 100644
--- a/llvm/lib/Target/AMDGPU/SOPInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SOPInstructions.td
@@ -438,6 +438,89 @@ let SubtargetPredicate = HasSALUFloatInsts, Uses = [MODE],
} // End SubtargetPredicate = HasSALUFloatInsts, Uses = [MODE]
// SchedRW = [WriteSFPU], isReMaterializable = 1
+let hasSideEffects = 1 in {
+let has_sdst = 0 in {
+let Uses = [M0] in {
+def S_BARRIER_SIGNAL_M0 : SOP1_Pseudo <"s_barrier_signal m0", (outs), (ins),
+ "", [(int_amdgcn_s_barrier_signal_var M0)]>{
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_BARRIER_SIGNAL_ISFIRST_M0 : SOP1_Pseudo <"s_barrier_signal_isfirst m0", (outs), (ins),
+ "", [(set SCC, (int_amdgcn_s_barrier_signal_isfirst_var M0))]>{
+ let Defs = [SCC];
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_BARRIER_INIT_M0 : SOP1_Pseudo <"s_barrier_init m0", (outs), (ins),
+ "", []>{
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_BARRIER_INIT_IMM : SOP1_Pseudo <"s_barrier_init", (outs),
+ (ins SplitBarrier:$src0), "$src0", []>{
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_BARRIER_JOIN_M0 : SOP1_Pseudo <"s_barrier_join m0", (outs), (ins),
+ "", []>{
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_WAKEUP_BARRIER_M0 : SOP1_Pseudo <"s_wakeup_barrier m0", (outs), (ins),
+ "", []>{
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+} // End Uses = [M0]
+
+def S_BARRIER_SIGNAL_IMM : SOP1_Pseudo <"s_barrier_signal", (outs),
+ (ins SplitBarrier:$src0), "$src0", [(int_amdgcn_s_barrier_signal timm:$src0)]>{
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_BARRIER_SIGNAL_ISFIRST_IMM : SOP1_Pseudo <"s_barrier_signal_isfirst", (outs),
+ (ins SplitBarrier:$src0), "$src0", [(set SCC, (int_amdgcn_s_barrier_signal_isfirst timm:$src0))]>{
+ let Defs = [SCC];
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_BARRIER_JOIN_IMM : SOP1_Pseudo <"s_barrier_join", (outs),
+ (ins SplitBarrier:$src0), "$src0", []>{
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_WAKEUP_BARRIER_IMM : SOP1_Pseudo <"s_wakeup_barrier", (outs),
+ (ins SplitBarrier:$src0), "$src0", []>{
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+
+
+}
+} // End has_sdst = 0
+
+def S_GET_BARRIER_STATE_IMM : SOP1_Pseudo <"s_get_barrier_state", (outs SSrc_b32:$sdst),
+ (ins SplitBarrier:$src0), "$sdst, $src0", []>{
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_GET_BARRIER_STATE_M0 : SOP1_Pseudo <"s_get_barrier_state $sdst, m0", (outs SSrc_b32:$sdst),
+ (ins), "", []>{
+ let Uses = [M0];
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+} // End hasSideEffects = 1
+
//===----------------------------------------------------------------------===//
// SOP2 Instructions
//===----------------------------------------------------------------------===//
@@ -592,19 +675,8 @@ let SubtargetPredicate = isGFX12Plus in {
} // End SubtargetPredicate = isGFX12Plus
-def SelectPat : PatFrag <
- (ops node:$src1, node:$src2),
- (select SCC, $src1, $src2),
- [{ return !N->isDivergent(); }]
->;
-
let Uses = [SCC] in {
- let AddedComplexity = 20 in {
- def S_CSELECT_B32 : SOP2_32 <"s_cselect_b32",
- [(set i32:$sdst, (SelectPat i32:$src0, i32:$src1))]
- >;
- }
-
+ def S_CSELECT_B32 : SOP2_32 <"s_cselect_b32">;
def S_CSELECT_B64 : SOP2_64 <"s_cselect_b64">;
} // End Uses = [SCC]
@@ -847,6 +919,15 @@ let SubtargetPredicate = HasSALUFloatInsts, mayRaiseFPException = 1,
} // End SubtargetPredicate = HasSALUFloatInsts, mayRaiseFPException = 1,
// Uses = [MODE], SchedRW = [WriteSFPU]
+// On GFX12 MIN/MAX instructions do not read MODE register.
+let SubtargetPredicate = isGFX12Plus, mayRaiseFPException = 1, isCommutable = 1,
+ isReMaterializable = 1, SchedRW = [WriteSFPU] in {
+ def S_MINIMUM_F32 : SOP2_F32_Inst<"s_minimum_f32", fminimum>;
+ def S_MAXIMUM_F32 : SOP2_F32_Inst<"s_maximum_f32", fmaximum>;
+ def S_MINIMUM_F16 : SOP2_F16_Inst<"s_minimum_f16", fminimum>;
+ def S_MAXIMUM_F16 : SOP2_F16_Inst<"s_maximum_f16", fmaximum>;
+}
+
//===----------------------------------------------------------------------===//
// SOPK Instructions
//===----------------------------------------------------------------------===//
@@ -1473,6 +1554,21 @@ def S_BARRIER : SOPP_Pseudo <"s_barrier", (ins), "",
let isConvergent = 1;
}
+def S_BARRIER_WAIT : SOPP_Pseudo <"s_barrier_wait", (ins i16imm:$simm16), "$simm16",
+ [(int_amdgcn_s_barrier_wait timm:$simm16)]> {
+ let SchedRW = [WriteBarrier];
+ let isConvergent = 1;
+}
+
+def S_BARRIER_LEAVE : SOPP_Pseudo <"s_barrier_leave", (ins), "",
+ [(set SCC, (int_amdgcn_s_barrier_leave))]> {
+ let SchedRW = [WriteBarrier];
+ let simm16 = 0;
+ let fixed_imm = 1;
+ let isConvergent = 1;
+ let Defs = [SCC];
+}
+
def S_WAKEUP : SOPP_Pseudo <"s_wakeup", (ins) > {
let SubtargetPredicate = isGFX8Plus;
let simm16 = 0;
@@ -1483,6 +1579,17 @@ def S_WAKEUP : SOPP_Pseudo <"s_wakeup", (ins) > {
def S_WAITCNT : SOPP_Pseudo <"s_waitcnt" , (ins SWaitCnt:$simm16), "$simm16",
[(int_amdgcn_s_waitcnt timm:$simm16)]>;
+
+// "_soft" waitcnts are waitcnts that are either relaxed into their non-soft
+// counterpart, or completely removed.
+//
+// These are inserted by SIMemoryLegalizer to resolve memory dependencies
+// and later optimized by SIInsertWaitcnts
+// For example, a S_WAITCNT_soft 0 can be completely removed in a function
+// that doesn't access memory.
+def S_WAITCNT_soft : SOPP_Pseudo <"s_soft_waitcnt" , (ins SWaitCnt:$simm16), "$simm16">;
+def S_WAITCNT_VSCNT_soft : SOPK_WAITCNT<"s_soft_waitcnt_vscnt">;
+
def S_SETHALT : SOPP_Pseudo <"s_sethalt" , (ins i32imm:$simm16), "$simm16",
[(int_amdgcn_s_sethalt timm:$simm16)]>;
def S_SETKILL : SOPP_Pseudo <"s_setkill" , (ins i16imm:$simm16), "$simm16">;
@@ -1495,6 +1602,10 @@ def S_SLEEP : SOPP_Pseudo <"s_sleep", (ins i32imm:$simm16),
"$simm16", [(int_amdgcn_s_sleep timm:$simm16)]> {
}
+def S_SLEEP_VAR : SOP1_0_32 <"s_sleep_var", [(int_amdgcn_s_sleep_var SSrc_b32:$src0)]> {
+ let hasSideEffects = 1;
+}
+
def S_SETPRIO : SOPP_Pseudo <"s_setprio", (ins i16imm:$simm16), "$simm16",
[(int_amdgcn_s_setprio timm:$simm16)]> {
}
@@ -1697,6 +1808,27 @@ def : GetFPModePat<fpmode_mask_gfx6plus>;
// SOP2 Patterns
//===----------------------------------------------------------------------===//
+def UniformSelect : PatFrag<
+ (ops node:$src0, node:$src1),
+ (select SCC, $src0, $src1),
+ [{ return !N->isDivergent(); }]
+>;
+
+let AddedComplexity = 20 in {
+ def : GCNPat<
+ (i32 (UniformSelect i32:$src0, i32:$src1)),
+ (S_CSELECT_B32 SSrc_b32:$src0, SSrc_b32:$src1)
+ >;
+
+ // TODO: The predicate should not be necessary, but enabling this pattern for
+ // all subtargets generates worse code in some cases.
+ let OtherPredicates = [HasPseudoScalarTrans] in
+ def : GCNPat<
+ (f32 (UniformSelect f32:$src0, f32:$src1)),
+ (S_CSELECT_B32 SSrc_b32:$src0, SSrc_b32:$src1)
+ >;
+}
+
// V_ADD_I32_e32/S_ADD_U32 produces carry in VCC/SCC. For the vector
// case, the sgpr-copies pass will fix this to use the vector version.
def : GCNPat <
@@ -1878,6 +2010,19 @@ defm S_SWAPPC_B64 : SOP1_Real_gfx11_gfx12<0x049>;
defm S_RFE_B64 : SOP1_Real_gfx11_gfx12<0x04a>;
defm S_SENDMSG_RTN_B32 : SOP1_Real_gfx11_gfx12<0x04c>;
defm S_SENDMSG_RTN_B64 : SOP1_Real_gfx11_gfx12<0x04d>;
+defm S_BARRIER_SIGNAL_M0 : SOP1_M0_Real_gfx12<0x04e>;
+defm S_BARRIER_SIGNAL_ISFIRST_M0 : SOP1_M0_Real_gfx12<0x04f>;
+defm S_GET_BARRIER_STATE_M0 : SOP1_M0_Real_gfx12<0x050>;
+defm S_BARRIER_INIT_M0 : SOP1_M0_Real_gfx12<0x051>;
+defm S_BARRIER_JOIN_M0 : SOP1_M0_Real_gfx12<0x052>;
+defm S_WAKEUP_BARRIER_M0 : SOP1_M0_Real_gfx12<0x057>;
+defm S_BARRIER_SIGNAL_IMM : SOP1_Real_gfx12<0x04e>;
+defm S_BARRIER_SIGNAL_ISFIRST_IMM : SOP1_Real_gfx12<0x04f>;
+defm S_GET_BARRIER_STATE_IMM : SOP1_Real_gfx12<0x050>;
+defm S_BARRIER_INIT_IMM : SOP1_Real_gfx12<0x051>;
+defm S_BARRIER_JOIN_IMM : SOP1_Real_gfx12<0x052>;
+defm S_WAKEUP_BARRIER_IMM : SOP1_Real_gfx12<0x057>;
+defm S_SLEEP_VAR : SOP1_Real_gfx12<0x058>;
//===----------------------------------------------------------------------===//
// SOP1 - GFX1150, GFX12
@@ -2017,6 +2162,10 @@ defm S_MIN_NUM_F32 : SOP2_Real_Renamed_gfx12<0x042, S_MIN_F32, "s_min_num_f32">;
defm S_MAX_NUM_F32 : SOP2_Real_Renamed_gfx12<0x043, S_MAX_F32, "s_max_num_f32">;
defm S_MIN_NUM_F16 : SOP2_Real_Renamed_gfx12<0x04b, S_MIN_F16, "s_min_num_f16">;
defm S_MAX_NUM_F16 : SOP2_Real_Renamed_gfx12<0x04c, S_MAX_F16, "s_max_num_f16">;
+defm S_MINIMUM_F32 : SOP2_Real_gfx12<0x04f>;
+defm S_MAXIMUM_F32 : SOP2_Real_gfx12<0x050>;
+defm S_MINIMUM_F16 : SOP2_Real_gfx12<0x051>;
+defm S_MAXIMUM_F16 : SOP2_Real_gfx12<0x052>;
defm S_ADD_CO_U32 : SOP2_Real_Renamed_gfx12<0x000, S_ADD_U32, "s_add_co_u32">;
defm S_SUB_CO_U32 : SOP2_Real_Renamed_gfx12<0x001, S_SUB_U32, "s_sub_co_u32">;
@@ -2365,6 +2514,8 @@ multiclass SOPP_Real_32_Renamed_gfx12<bits<7> op, SOPP_Pseudo backing_pseudo, st
}
defm S_WAIT_ALU : SOPP_Real_32_Renamed_gfx12<0x008, S_WAITCNT_DEPCTR, "s_wait_alu">;
+defm S_BARRIER_WAIT : SOPP_Real_32_gfx12<0x014>;
+defm S_BARRIER_LEAVE : SOPP_Real_32_gfx12<0x015>;
//===----------------------------------------------------------------------===//
// SOPP - GFX11, GFX12.
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp
index 403efd6ffed3..23434d2de0fc 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp
@@ -36,14 +36,15 @@ namespace SendMsg {
// Disable lint checking for this block since it makes the table unreadable.
// NOLINTBEGIN
+// clang-format off
const CustomOperand<const MCSubtargetInfo &> Msg[] = {
{{""}},
{{"MSG_INTERRUPT"}, ID_INTERRUPT},
{{"MSG_GS"}, ID_GS_PreGFX11, isNotGFX11Plus},
{{"MSG_GS_DONE"}, ID_GS_DONE_PreGFX11, isNotGFX11Plus},
{{"MSG_SAVEWAVE"}, ID_SAVEWAVE, isGFX8_GFX9_GFX10},
- {{"MSG_STALL_WAVE_GEN"}, ID_STALL_WAVE_GEN, isGFX9Plus},
- {{"MSG_HALT_WAVES"}, ID_HALT_WAVES, isGFX9Plus},
+ {{"MSG_STALL_WAVE_GEN"}, ID_STALL_WAVE_GEN, isGFX9_GFX10_GFX11},
+ {{"MSG_HALT_WAVES"}, ID_HALT_WAVES, isGFX9_GFX10_GFX11},
{{"MSG_ORDERED_PS_DONE"}, ID_ORDERED_PS_DONE, isGFX9_GFX10},
{{"MSG_EARLY_PRIM_DEALLOC"}, ID_EARLY_PRIM_DEALLOC, isGFX9_GFX10},
{{"MSG_GS_ALLOC_REQ"}, ID_GS_ALLOC_REQ, isGFX9Plus},
@@ -59,7 +60,9 @@ const CustomOperand<const MCSubtargetInfo &> Msg[] = {
{{"MSG_RTN_GET_REALTIME"}, ID_RTN_GET_REALTIME, isGFX11Plus},
{{"MSG_RTN_SAVE_WAVE"}, ID_RTN_SAVE_WAVE, isGFX11Plus},
{{"MSG_RTN_GET_TBA"}, ID_RTN_GET_TBA, isGFX11Plus},
+ {{"MSG_RTN_GET_SE_AID_ID"}, ID_RTN_GET_SE_AID_ID, isGFX12Plus},
};
+// clang-format on
// NOLINTEND
const int MSG_SIZE = static_cast<int>(
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
index 68d561a0d9f7..0f92a56237ac 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
@@ -309,6 +309,7 @@ struct VOPDInfo {
uint16_t Opcode;
uint16_t OpX;
uint16_t OpY;
+ uint16_t Subtarget;
};
struct VOPTrue16Info {
@@ -443,6 +444,14 @@ bool getMAIIsGFX940XDL(unsigned Opc) {
return Info ? Info->is_gfx940_xdl : false;
}
+unsigned getVOPDEncodingFamily(const MCSubtargetInfo &ST) {
+ if (ST.hasFeature(AMDGPU::FeatureGFX12Insts))
+ return SIEncodingFamily::GFX12;
+ if (ST.hasFeature(AMDGPU::FeatureGFX11Insts))
+ return SIEncodingFamily::GFX11;
+ llvm_unreachable("Subtarget generation does not support VOPD!");
+}
+
CanBeVOPD getCanBeVOPD(unsigned Opc) {
const VOPDComponentInfo *Info = getVOPDComponentHelper(Opc);
if (Info)
@@ -470,11 +479,13 @@ bool isMAC(unsigned Opc) {
Opc == AMDGPU::V_FMAC_F64_e64_gfx90a ||
Opc == AMDGPU::V_FMAC_F32_e64_gfx10 ||
Opc == AMDGPU::V_FMAC_F32_e64_gfx11 ||
+ Opc == AMDGPU::V_FMAC_F32_e64_gfx12 ||
Opc == AMDGPU::V_FMAC_F32_e64_vi ||
Opc == AMDGPU::V_FMAC_LEGACY_F32_e64_gfx10 ||
Opc == AMDGPU::V_FMAC_DX9_ZERO_F32_e64_gfx11 ||
Opc == AMDGPU::V_FMAC_F16_e64_gfx10 ||
Opc == AMDGPU::V_FMAC_F16_t16_e64_gfx11 ||
+ Opc == AMDGPU::V_FMAC_F16_t16_e64_gfx12 ||
Opc == AMDGPU::V_DOT2C_F32_F16_e64_vi ||
Opc == AMDGPU::V_DOT2C_I32_I16_e64_vi ||
Opc == AMDGPU::V_DOT4C_I32_I8_e64_vi ||
@@ -485,7 +496,11 @@ bool isPermlane16(unsigned Opc) {
return Opc == AMDGPU::V_PERMLANE16_B32_gfx10 ||
Opc == AMDGPU::V_PERMLANEX16_B32_gfx10 ||
Opc == AMDGPU::V_PERMLANE16_B32_e64_gfx11 ||
- Opc == AMDGPU::V_PERMLANEX16_B32_e64_gfx11;
+ Opc == AMDGPU::V_PERMLANEX16_B32_e64_gfx11 ||
+ Opc == AMDGPU::V_PERMLANE16_B32_e64_gfx12 ||
+ Opc == AMDGPU::V_PERMLANEX16_B32_e64_gfx12 ||
+ Opc == AMDGPU::V_PERMLANE16_VAR_B32_e64_gfx12 ||
+ Opc == AMDGPU::V_PERMLANEX16_VAR_B32_e64_gfx12;
}
bool isGenericAtomic(unsigned Opc) {
@@ -532,8 +547,9 @@ int getMCOpcode(uint16_t Opcode, unsigned Gen) {
return getMCOpcodeGen(Opcode, static_cast<Subtarget>(Gen));
}
-int getVOPDFull(unsigned OpX, unsigned OpY) {
- const VOPDInfo *Info = getVOPDInfoFromComponentOpcodes(OpX, OpY);
+int getVOPDFull(unsigned OpX, unsigned OpY, unsigned EncodingFamily) {
+ const VOPDInfo *Info =
+ getVOPDInfoFromComponentOpcodes(OpX, OpY, EncodingFamily);
return Info ? Info->Opcode : -1;
}
@@ -585,13 +601,15 @@ unsigned ComponentInfo::getIndexInParsedOperands(unsigned CompOprIdx) const {
}
std::optional<unsigned> InstInfo::getInvalidCompOperandIndex(
- std::function<unsigned(unsigned, unsigned)> GetRegIdx) const {
+ std::function<unsigned(unsigned, unsigned)> GetRegIdx, bool SkipSrc) const {
auto OpXRegs = getRegIndices(ComponentIndex::X, GetRegIdx);
auto OpYRegs = getRegIndices(ComponentIndex::Y, GetRegIdx);
+ const unsigned CompOprNum =
+ SkipSrc ? Component::DST_NUM : Component::MAX_OPR_NUM;
unsigned CompOprIdx;
- for (CompOprIdx = 0; CompOprIdx < Component::MAX_OPR_NUM; ++CompOprIdx) {
+ for (CompOprIdx = 0; CompOprIdx < CompOprNum; ++CompOprIdx) {
unsigned BanksMasks = VOPD_VGPR_BANK_MASKS[CompOprIdx];
if (OpXRegs[CompOprIdx] && OpYRegs[CompOprIdx] &&
((OpXRegs[CompOprIdx] & BanksMasks) ==
@@ -716,9 +734,9 @@ void AMDGPUTargetID::setTargetIDFromFeaturesString(StringRef FS) {
static TargetIDSetting
getTargetIDSettingFromFeatureString(StringRef FeatureString) {
- if (FeatureString.endswith("-"))
+ if (FeatureString.ends_with("-"))
return TargetIDSetting::Off;
- if (FeatureString.endswith("+"))
+ if (FeatureString.ends_with("+"))
return TargetIDSetting::On;
llvm_unreachable("Malformed feature string");
@@ -729,9 +747,9 @@ void AMDGPUTargetID::setTargetIDFromTargetIDStream(StringRef TargetID) {
TargetID.split(TargetIDSplit, ':');
for (const auto &FeatureString : TargetIDSplit) {
- if (FeatureString.startswith("xnack"))
+ if (FeatureString.starts_with("xnack"))
XnackSetting = getTargetIDSettingFromFeatureString(FeatureString);
- if (FeatureString.startswith("sramecc"))
+ if (FeatureString.starts_with("sramecc"))
SramEccSetting = getTargetIDSettingFromFeatureString(FeatureString);
}
}
@@ -1131,10 +1149,17 @@ amdhsa::kernel_descriptor_t getDefaultAmdhsaKernelDescriptor(
AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
amdhsa::COMPUTE_PGM_RSRC1_FLOAT_DENORM_MODE_16_64,
amdhsa::FLOAT_DENORM_MODE_FLUSH_NONE);
- AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
- amdhsa::COMPUTE_PGM_RSRC1_ENABLE_DX10_CLAMP, 1);
- AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
- amdhsa::COMPUTE_PGM_RSRC1_ENABLE_IEEE_MODE, 1);
+ if (Version.Major >= 12) {
+ AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
+ amdhsa::COMPUTE_PGM_RSRC1_GFX12_PLUS_ENABLE_WG_RR_EN, 0);
+ AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
+ amdhsa::COMPUTE_PGM_RSRC1_GFX12_PLUS_DISABLE_PERF, 0);
+ } else {
+ AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
+ amdhsa::COMPUTE_PGM_RSRC1_GFX6_GFX11_ENABLE_DX10_CLAMP, 1);
+ AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
+ amdhsa::COMPUTE_PGM_RSRC1_GFX6_GFX11_ENABLE_IEEE_MODE, 1);
+ }
AMDHSA_BITS_SET(KD.compute_pgm_rsrc2,
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_ID_X, 1);
if (Version.Major >= 10) {
@@ -1578,7 +1603,7 @@ unsigned getTgtId(const StringRef Name) {
if (Val.MaxIndex == 0 && Name == Val.Name)
return Val.Tgt;
- if (Val.MaxIndex > 0 && Name.startswith(Val.Name)) {
+ if (Val.MaxIndex > 0 && Name.starts_with(Val.Name)) {
StringRef Suffix = Name.drop_front(Val.Name.size());
unsigned Id;
@@ -2668,10 +2693,11 @@ std::optional<int64_t> getSMRDEncodedLiteralOffset32(const MCSubtargetInfo &ST,
}
unsigned getNumFlatOffsetBits(const MCSubtargetInfo &ST) {
- // Address offset is 12-bit signed for GFX10, 13-bit for GFX9 and GFX11+.
if (AMDGPU::isGFX10(ST))
return 12;
+ if (AMDGPU::isGFX12(ST))
+ return 24;
return 13;
}
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
index 436a0ff5ce26..3c9f330cbcde 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
@@ -505,6 +505,10 @@ struct CanBeVOPD {
bool Y;
};
+/// \returns SIEncodingFamily used for VOPD encoding on a \p ST.
+LLVM_READONLY
+unsigned getVOPDEncodingFamily(const MCSubtargetInfo &ST);
+
LLVM_READONLY
CanBeVOPD getCanBeVOPD(unsigned Opc);
@@ -524,7 +528,7 @@ LLVM_READONLY
unsigned getVOPDOpcode(unsigned Opc);
LLVM_READONLY
-int getVOPDFull(unsigned OpX, unsigned OpY);
+int getVOPDFull(unsigned OpX, unsigned OpY, unsigned EncodingFamily);
LLVM_READONLY
bool isVOPD(unsigned Opc);
@@ -747,15 +751,20 @@ public:
// GetRegIdx(Component, MCOperandIdx) must return a VGPR register index
// for the specified component and MC operand. The callback must return 0
// if the operand is not a register or not a VGPR.
- bool hasInvalidOperand(
- std::function<unsigned(unsigned, unsigned)> GetRegIdx) const {
- return getInvalidCompOperandIndex(GetRegIdx).has_value();
+ // If \p SkipSrc is set to true then constraints for source operands are not
+ // checked.
+ bool hasInvalidOperand(std::function<unsigned(unsigned, unsigned)> GetRegIdx,
+ bool SkipSrc = false) const {
+ return getInvalidCompOperandIndex(GetRegIdx, SkipSrc).has_value();
}
// Check VOPD operands constraints.
// Return the index of an invalid component operand, if any.
+ // If \p SkipSrc is set to true then constraints for source operands are not
+ // checked.
std::optional<unsigned> getInvalidCompOperandIndex(
- std::function<unsigned(unsigned, unsigned)> GetRegIdx) const;
+ std::function<unsigned(unsigned, unsigned)> GetRegIdx,
+ bool SkipSrc = false) const;
private:
RegIndices
@@ -1229,6 +1238,7 @@ inline unsigned getOperandSize(const MCOperandInfo &OpInfo) {
case AMDGPU::OPERAND_REG_INLINE_C_V2FP32:
case AMDGPU::OPERAND_KIMM32:
case AMDGPU::OPERAND_KIMM16: // mandatory literal is always size 4
+ case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32:
return 4;
case AMDGPU::OPERAND_REG_IMM_INT64:
@@ -1324,7 +1334,7 @@ std::optional<int64_t> getSMRDEncodedOffset(const MCSubtargetInfo &ST,
std::optional<int64_t> getSMRDEncodedLiteralOffset32(const MCSubtargetInfo &ST,
int64_t ByteOffset);
-/// For FLAT segment the offset must be positive;
+/// For pre-GFX12 FLAT instructions the offset must be positive;
/// MSB is ignored and forced to zero.
///
/// \return The number of bits available for the signed offset field in flat
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.cpp
index cbdbf1c16f9f..25e628e5cbc5 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.cpp
@@ -74,6 +74,16 @@ bool isReallyAClobber(const Value *Ptr, MemoryDef *Def, AAResults *AA) {
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(DefInst)) {
switch (II->getIntrinsicID()) {
case Intrinsic::amdgcn_s_barrier:
+ case Intrinsic::amdgcn_s_barrier_signal:
+ case Intrinsic::amdgcn_s_barrier_signal_var:
+ case Intrinsic::amdgcn_s_barrier_signal_isfirst:
+ case Intrinsic::amdgcn_s_barrier_signal_isfirst_var:
+ case Intrinsic::amdgcn_s_barrier_init:
+ case Intrinsic::amdgcn_s_barrier_join:
+ case Intrinsic::amdgcn_s_barrier_wait:
+ case Intrinsic::amdgcn_s_barrier_leave:
+ case Intrinsic::amdgcn_s_get_barrier_state:
+ case Intrinsic::amdgcn_s_wakeup_barrier:
case Intrinsic::amdgcn_wave_barrier:
case Intrinsic::amdgcn_sched_barrier:
case Intrinsic::amdgcn_sched_group_barrier:
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.h
index 7c6ed01a1cd4..e42b27f8e09e 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.h
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUMemoryUtils.h
@@ -14,12 +14,10 @@ namespace llvm {
struct Align;
class AAResults;
class DataLayout;
-class Function;
class GlobalVariable;
class LoadInst;
class MemoryDef;
class MemorySSA;
-class Module;
class Value;
namespace AMDGPU {
diff --git a/llvm/lib/Target/AMDGPU/VOP1Instructions.td b/llvm/lib/Target/AMDGPU/VOP1Instructions.td
index 53b0513c85d8..27a7c29cb1ac 100644
--- a/llvm/lib/Target/AMDGPU/VOP1Instructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP1Instructions.td
@@ -88,6 +88,12 @@ class VOP1_Real <VOP1_Pseudo ps, int EncodingFamily, string real_name = ps.Mnemo
let TRANS = ps.TRANS;
}
+class VOP1_Real_Gen <VOP1_Pseudo ps, GFXGen Gen, string real_name = ps.Mnemonic> :
+ VOP1_Real <ps, Gen.Subtarget, real_name> {
+ let AssemblerPredicate = Gen.AssemblerPredicate;
+ let DecoderNamespace = Gen.DecoderNamespace;
+}
+
class VOP1_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
VOP_SDWA_Pseudo <OpName, P, pattern> {
let AsmMatchConverter = "cvtSdwaVOP1";
@@ -688,6 +694,13 @@ class VOP1_DPP16<bits<8> op, VOP1_DPP_Pseudo ps, int subtarget, VOPProfile p = p
let SubtargetPredicate = HasDPP16;
}
+class VOP1_DPP16_Gen<bits<8> op, VOP1_DPP_Pseudo ps, GFXGen Gen, VOPProfile p = ps.Pfl> :
+ VOP1_DPP16 <op, ps, Gen.Subtarget, p> {
+ let AssemblerPredicate = Gen.AssemblerPredicate;
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace;
+}
+
+
class VOP1_DPP8<bits<8> op, VOP1_Pseudo ps, VOPProfile p = ps.Pfl> :
VOP_DPP8<ps.OpName, p> {
let hasSideEffects = ps.hasSideEffects;
@@ -702,138 +715,173 @@ class VOP1_DPP8<bits<8> op, VOP1_Pseudo ps, VOPProfile p = ps.Pfl> :
let Inst{31-25} = 0x3f;
}
+class VOP1_DPP8_Gen<bits<8> op, VOP1_Pseudo ps, GFXGen Gen, VOPProfile p = ps.Pfl> :
+ VOP1_DPP8<op, ps, p> {
+ let AssemblerPredicate = Gen.AssemblerPredicate;
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace;
+}
+
//===----------------------------------------------------------------------===//
-// GFX11.
+// GFX11, GFX12
//===----------------------------------------------------------------------===//
-let AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11" in {
- multiclass VOP1Only_Real_gfx11<bits<9> op> {
- let IsSingle = 1 in
- def _gfx11 :
- VOP1_Real<!cast<VOP1_Pseudo>(NAME), SIEncodingFamily.GFX11>,
- VOP1e<op{7-0}, !cast<VOP1_Pseudo>(NAME).Pfl>;
- }
- multiclass VOP1_Real_e32_gfx11<bits<9> op, string opName = NAME> {
- defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
- def _e32_gfx11 :
- VOP1_Real<ps, SIEncodingFamily.GFX11>,
- VOP1e<op{7-0}, ps.Pfl>;
- }
- multiclass VOP1_Real_e32_with_name_gfx11<bits<9> op, string opName,
- string asmName> {
- defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
- let AsmString = asmName # ps.AsmOperands in {
- defm NAME : VOP1_Real_e32_gfx11<op, opName>;
- }
- }
- multiclass VOP1_Real_e64_gfx11<bits<9> op> {
- def _e64_gfx11 :
- VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.GFX11>,
- VOP3e_gfx11<{0, 1, 1, op{6-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
- }
- multiclass VOP1_Real_dpp_gfx11<bits<9> op, string opName = NAME> {
- defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
- def _dpp_gfx11 : VOP1_DPP16<op{7-0}, !cast<VOP1_DPP_Pseudo>(opName#"_dpp"), SIEncodingFamily.GFX11> {
- let DecoderNamespace = "DPPGFX11";
- }
- }
- multiclass VOP1_Real_dpp_with_name_gfx11<bits<9> op, string opName,
- string asmName> {
- defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
- let AsmString = asmName # ps.Pfl.AsmDPP16, DecoderNamespace = "DPPGFX11" in {
- defm NAME : VOP1_Real_dpp_gfx11<op, opName>;
- }
+multiclass VOP1Only_Real<GFXGen Gen, bits<9> op> {
+ let IsSingle = 1 in
+ def Gen.Suffix :
+ VOP1_Real_Gen<!cast<VOP1_Pseudo>(NAME), Gen>,
+ VOP1e<op{7-0}, !cast<VOP1_Pseudo>(NAME).Pfl>;
+}
+
+multiclass VOP1_Real_e32<GFXGen Gen, bits<9> op, string opName = NAME> {
+ defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
+ def _e32#Gen.Suffix :
+ VOP1_Real_Gen<ps, Gen>,
+ VOP1e<op{7-0}, ps.Pfl>;
+}
+
+multiclass VOP1_Real_e32_with_name<GFXGen Gen, bits<9> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
+ let AsmString = asmName # ps.AsmOperands in {
+ defm NAME : VOP1_Real_e32<Gen, op, opName>;
}
- multiclass VOP1_Real_dpp8_gfx11<bits<9> op, string opName = NAME> {
- defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
- def _dpp8_gfx11 : VOP1_DPP8<op{7-0}, ps> {
- let DecoderNamespace = "DPP8GFX11";
- }
+}
+
+multiclass VOP1_Real_e64<GFXGen Gen, bits<9> op> {
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<!cast<VOP3_Pseudo>(NAME#"_e64"), Gen>,
+ VOP3e_gfx11_gfx12<{0, 1, 1, op{6-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
+}
+
+multiclass VOP1_Real_dpp<GFXGen Gen, bits<9> op, string opName = NAME> {
+ defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
+ def _dpp#Gen.Suffix : VOP1_DPP16_Gen<op{7-0}, !cast<VOP1_DPP_Pseudo>(opName#"_dpp"), Gen>;
+}
+
+multiclass VOP1_Real_dpp_with_name<GFXGen Gen, bits<9> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
+ let AsmString = asmName # ps.Pfl.AsmDPP16 in {
+ defm NAME : VOP1_Real_dpp<Gen, op, opName>;
}
- multiclass VOP1_Real_dpp8_with_name_gfx11<bits<9> op, string opName,
- string asmName> {
- defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
- let AsmString = asmName # ps.Pfl.AsmDPP8, DecoderNamespace = "DPP8GFX11" in {
- defm NAME : VOP1_Real_dpp8_gfx11<op, opName>;
- }
+}
+
+multiclass VOP1_Real_dpp8<GFXGen Gen, bits<9> op, string opName = NAME> {
+ defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
+ def _dpp8#Gen.Suffix : VOP1_DPP8_Gen<op{7-0}, ps, Gen>;
+}
+
+multiclass VOP1_Real_dpp8_with_name<GFXGen Gen, bits<9> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
+ let AsmString = asmName # ps.Pfl.AsmDPP8 in {
+ defm NAME : VOP1_Real_dpp8<Gen, op, opName>;
}
-} // End AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11"
+}
-multiclass VOP1_Realtriple_e64_gfx11<bits<9> op> {
- defm NAME : VOP3_Realtriple_gfx11<{0, 1, 1, op{6-0}}, /*isSingle=*/ 0, NAME>;
+multiclass VOP1_Realtriple_e64<GFXGen Gen, bits<9> op> {
+ defm NAME : VOP3_Realtriple<Gen, {0, 1, 1, op{6-0}}, /*isSingle=*/ 0, NAME>;
}
-multiclass VOP1_Realtriple_e64_with_name_gfx11<bits<9> op, string opName,
+
+multiclass VOP1_Realtriple_e64_with_name<GFXGen Gen, bits<9> op, string opName,
string asmName> {
- defm NAME : VOP3_Realtriple_with_name_gfx11<{0, 1, 1, op{6-0}}, opName,
+ defm NAME : VOP3_Realtriple_with_name<Gen, {0, 1, 1, op{6-0}}, opName,
asmName>;
}
-multiclass VOP1_Real_FULL_gfx11<bits<9> op> :
- VOP1_Real_e32_gfx11<op>, VOP1_Realtriple_e64_gfx11<op>,
- VOP1_Real_dpp_gfx11<op>, VOP1_Real_dpp8_gfx11<op>;
+multiclass VOP1_Real_FULL<GFXGen Gen, bits<9> op> :
+ VOP1_Real_e32<Gen, op>, VOP1_Realtriple_e64<Gen, op>,
+ VOP1_Real_dpp<Gen, op>, VOP1_Real_dpp8<Gen, op>;
multiclass VOP1_Real_NO_VOP3_with_name_gfx11<bits<9> op, string opName,
- string asmName> {
- defm NAME : VOP1_Real_e32_with_name_gfx11<op, opName, asmName>,
- VOP1_Real_dpp_with_name_gfx11<op, opName, asmName>,
- VOP1_Real_dpp8_with_name_gfx11<op, opName, asmName>;
+ string asmName> {
+ defm NAME : VOP1_Real_e32_with_name<GFX11Gen, op, opName, asmName>,
+ VOP1_Real_dpp_with_name<GFX11Gen, op, opName, asmName>,
+ VOP1_Real_dpp8_with_name<GFX11Gen, op, opName, asmName>;
defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
def gfx11_alias : MnemonicAlias<ps.Mnemonic, asmName>,
Requires<[isGFX11Plus]>;
}
-multiclass VOP1_Real_FULL_with_name_gfx11<bits<9> op, string opName,
+multiclass VOP1_Real_NO_VOP3_with_name_gfx12<bits<9> op, string opName,
+ string asmName> {
+ defm NAME : VOP1_Real_e32_with_name<GFX12Gen, op, opName, asmName>,
+ VOP1_Real_dpp_with_name<GFX12Gen, op, opName, asmName>,
+ VOP1_Real_dpp8_with_name<GFX12Gen, op, opName, asmName>;
+}
+
+multiclass VOP1_Real_FULL_with_name<GFXGen Gen, bits<9> op, string opName,
string asmName> :
- VOP1_Real_NO_VOP3_with_name_gfx11<op, opName, asmName>,
- VOP1_Realtriple_e64_with_name_gfx11<op, opName, asmName>;
+ VOP1_Real_e32_with_name<Gen, op, opName, asmName>,
+ VOP1_Real_dpp_with_name<Gen, op, opName, asmName>,
+ VOP1_Real_dpp8_with_name<Gen, op, opName, asmName>,
+ VOP1_Realtriple_e64_with_name<Gen, op, opName, asmName>;
-multiclass VOP1_Real_FULL_t16_gfx11<bits<9> op, string asmName,
- string opName = NAME> :
- VOP1_Real_FULL_with_name_gfx11<op, opName, asmName>;
+multiclass VOP1_Real_NO_DPP<GFXGen Gen, bits<9> op> :
+ VOP1_Real_e32<Gen, op>, VOP1_Real_e64<Gen, op>;
-multiclass VOP1_Real_NO_DPP_gfx11<bits<9> op> :
- VOP1_Real_e32_gfx11<op>, VOP1_Real_e64_gfx11<op>;
+multiclass VOP1_Real_FULL_t16_gfx11_gfx12<bits<9> op, string asmName,
+ string opName = NAME> :
+ VOP1_Real_FULL_with_name<GFX11Gen, op, opName, asmName>,
+ VOP1_Real_FULL_with_name<GFX12Gen, op, opName, asmName>;
-defm V_CVT_NEAREST_I32_F32 : VOP1_Real_FULL_with_name_gfx11<0x00c,
+multiclass VOP1_Real_FULL_with_name_gfx11_gfx12<bits<9> op, string opName,
+ string asmName> :
+ VOP1_Real_FULL_with_name<GFX11Gen, op, opName, asmName>,
+ VOP1_Real_FULL_with_name<GFX12Gen, op, opName, asmName>;
+
+multiclass VOP1Only_Real_gfx11_gfx12<bits<9> op> :
+ VOP1Only_Real<GFX11Gen, op>, VOP1Only_Real<GFX12Gen, op>;
+
+multiclass VOP1_Real_FULL_gfx11_gfx12<bits<9> op> :
+ VOP1_Real_FULL<GFX11Gen, op>, VOP1_Real_FULL<GFX12Gen, op>;
+
+multiclass VOP1_Real_NO_DPP_OP_SEL_with_name<GFXGen Gen, bits<9> op,
+ string opName, string asmName> :
+ VOP1_Real_e32_with_name<Gen, op, opName, asmName>,
+ VOP3_Real_with_name<Gen, {0, 1, 1, op{6-0}}, opName, asmName>;
+
+
+defm V_CVT_NEAREST_I32_F32 : VOP1_Real_FULL_with_name_gfx11_gfx12<0x00c,
"V_CVT_RPI_I32_F32", "v_cvt_nearest_i32_f32">;
-defm V_CVT_FLOOR_I32_F32 : VOP1_Real_FULL_with_name_gfx11<0x00d,
+defm V_CVT_FLOOR_I32_F32 : VOP1_Real_FULL_with_name_gfx11_gfx12<0x00d,
"V_CVT_FLR_I32_F32", "v_cvt_floor_i32_f32">;
-defm V_CLZ_I32_U32 : VOP1_Real_FULL_with_name_gfx11<0x039,
+defm V_CLZ_I32_U32 : VOP1_Real_FULL_with_name_gfx11_gfx12<0x039,
"V_FFBH_U32", "v_clz_i32_u32">;
-defm V_CTZ_I32_B32 : VOP1_Real_FULL_with_name_gfx11<0x03a,
+defm V_CTZ_I32_B32 : VOP1_Real_FULL_with_name_gfx11_gfx12<0x03a,
"V_FFBL_B32", "v_ctz_i32_b32">;
-defm V_CLS_I32 : VOP1_Real_FULL_with_name_gfx11<0x03b,
+defm V_CLS_I32 : VOP1_Real_FULL_with_name_gfx11_gfx12<0x03b,
"V_FFBH_I32", "v_cls_i32">;
-defm V_PERMLANE64_B32 : VOP1Only_Real_gfx11<0x067>;
-defm V_MOV_B16_t16 : VOP1_Real_FULL_t16_gfx11<0x01c, "v_mov_b16">;
-defm V_NOT_B16_t16 : VOP1_Real_FULL_t16_gfx11<0x069, "v_not_b16">;
-defm V_CVT_I32_I16_t16 : VOP1_Real_FULL_t16_gfx11<0x06a, "v_cvt_i32_i16">;
-defm V_CVT_U32_U16_t16 : VOP1_Real_FULL_t16_gfx11<0x06b, "v_cvt_u32_u16">;
-
-defm V_CVT_F16_U16_t16 : VOP1_Real_FULL_t16_gfx11<0x050, "v_cvt_f16_u16">;
-defm V_CVT_F16_I16_t16 : VOP1_Real_FULL_t16_gfx11<0x051, "v_cvt_f16_i16">;
-defm V_CVT_U16_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x052, "v_cvt_u16_f16">;
-defm V_CVT_I16_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x053, "v_cvt_i16_f16">;
-defm V_RCP_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x054, "v_rcp_f16">;
-defm V_SQRT_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x055, "v_sqrt_f16">;
-defm V_RSQ_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x056, "v_rsq_f16">;
-defm V_LOG_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x057, "v_log_f16">;
-defm V_EXP_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x058, "v_exp_f16">;
-defm V_FREXP_MANT_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x059, "v_frexp_mant_f16">;
-defm V_FREXP_EXP_I16_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x05a, "v_frexp_exp_i16_f16">;
-defm V_FLOOR_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x05b, "v_floor_f16">;
-defm V_CEIL_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x05c, "v_ceil_f16">;
-defm V_TRUNC_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x05d, "v_trunc_f16">;
-defm V_RNDNE_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x05e, "v_rndne_f16">;
-defm V_FRACT_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x05f, "v_fract_f16">;
-defm V_SIN_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x060, "v_sin_f16">;
-defm V_COS_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x061, "v_cos_f16">;
-defm V_SAT_PK_U8_I16_t16 : VOP1_Real_FULL_t16_gfx11<0x062, "v_sat_pk_u8_i16">;
-defm V_CVT_NORM_I16_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x063, "v_cvt_norm_i16_f16">;
-defm V_CVT_NORM_U16_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x064, "v_cvt_norm_u16_f16">;
-
-defm V_CVT_F16_F32_t16 : VOP1_Real_FULL_t16_gfx11<0x00a, "v_cvt_f16_f32">;
-defm V_CVT_F32_F16_t16 : VOP1_Real_FULL_t16_gfx11<0x00b, "v_cvt_f32_f16">;
+defm V_PERMLANE64_B32 : VOP1Only_Real_gfx11_gfx12<0x067>;
+defm V_MOV_B16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x01c, "v_mov_b16">;
+defm V_NOT_B16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x069, "v_not_b16">;
+defm V_CVT_I32_I16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x06a, "v_cvt_i32_i16">;
+defm V_CVT_U32_U16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x06b, "v_cvt_u32_u16">;
+
+defm V_CVT_F16_U16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x050, "v_cvt_f16_u16">;
+defm V_CVT_F16_I16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x051, "v_cvt_f16_i16">;
+defm V_CVT_U16_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x052, "v_cvt_u16_f16">;
+defm V_CVT_I16_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x053, "v_cvt_i16_f16">;
+defm V_RCP_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x054, "v_rcp_f16">;
+defm V_SQRT_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x055, "v_sqrt_f16">;
+defm V_RSQ_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x056, "v_rsq_f16">;
+defm V_LOG_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x057, "v_log_f16">;
+defm V_EXP_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x058, "v_exp_f16">;
+defm V_FREXP_MANT_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x059, "v_frexp_mant_f16">;
+defm V_FREXP_EXP_I16_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x05a, "v_frexp_exp_i16_f16">;
+defm V_FLOOR_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x05b, "v_floor_f16">;
+defm V_CEIL_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x05c, "v_ceil_f16">;
+defm V_TRUNC_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x05d, "v_trunc_f16">;
+defm V_RNDNE_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x05e, "v_rndne_f16">;
+defm V_FRACT_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x05f, "v_fract_f16">;
+defm V_SIN_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x060, "v_sin_f16">;
+defm V_COS_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x061, "v_cos_f16">;
+defm V_SAT_PK_U8_I16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x062, "v_sat_pk_u8_i16">;
+defm V_CVT_NORM_I16_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x063, "v_cvt_norm_i16_f16">;
+defm V_CVT_NORM_U16_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x064, "v_cvt_norm_u16_f16">;
+
+defm V_CVT_F16_F32_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x00a, "v_cvt_f16_f32">;
+defm V_CVT_F32_F16_t16 : VOP1_Real_FULL_t16_gfx11_gfx12<0x00b, "v_cvt_f32_f16">;
//===----------------------------------------------------------------------===//
// GFX10.
@@ -882,17 +930,23 @@ multiclass VOP1_Real_gfx10<bits<9> op> :
VOP1_Real_sdwa_gfx10<op>, VOP1_Real_dpp_gfx10<op>,
VOP1_Real_dpp8_gfx10<op>;
-multiclass VOP1_Real_gfx10_FULL_gfx11<bits<9> op> :
- VOP1_Real_gfx10<op>, VOP1_Real_FULL_gfx11<op>;
+multiclass VOP1_Real_gfx10_FULL_gfx11_gfx12<bits<9> op> :
+ VOP1_Real_gfx10<op>,
+ VOP1_Real_FULL<GFX11Gen, op>,
+ VOP1_Real_FULL<GFX12Gen, op>;
-multiclass VOP1_Real_gfx10_NO_DPP_gfx11<bits<9> op> :
- VOP1_Real_gfx10<op>, VOP1_Real_NO_DPP_gfx11<op>;
+multiclass VOP1_Real_gfx10_NO_DPP_gfx11_gfx12<bits<9> op> :
+ VOP1_Real_gfx10<op>,
+ VOP1_Real_NO_DPP<GFX11Gen, op>,
+ VOP1_Real_NO_DPP<GFX12Gen, op>;
-multiclass VOP1Only_Real_gfx10_gfx11<bits<9> op> :
- VOP1Only_Real_gfx10<op>, VOP1Only_Real_gfx11<op>;
+multiclass VOP1Only_Real_gfx10_gfx11_gfx12<bits<9> op> :
+ VOP1Only_Real_gfx10<op>,
+ VOP1Only_Real<GFX11Gen, op>,
+ VOP1Only_Real<GFX12Gen, op>;
-defm V_PIPEFLUSH : VOP1_Real_gfx10_NO_DPP_gfx11<0x01b>;
-defm V_MOVRELSD_2_B32 : VOP1_Real_gfx10_FULL_gfx11<0x048>;
+defm V_PIPEFLUSH : VOP1_Real_gfx10_NO_DPP_gfx11_gfx12<0x01b>;
+defm V_MOVRELSD_2_B32 : VOP1_Real_gfx10_FULL_gfx11_gfx12<0x048>;
defm V_CVT_F16_U16 : VOP1_Real_gfx10<0x050>;
defm V_CVT_F16_I16 : VOP1_Real_gfx10<0x051>;
defm V_CVT_U16_F16 : VOP1_Real_gfx10<0x052>;
@@ -915,11 +969,11 @@ defm V_SAT_PK_U8_I16 : VOP1_Real_gfx10<0x062>;
defm V_CVT_NORM_I16_F16 : VOP1_Real_gfx10<0x063>;
defm V_CVT_NORM_U16_F16 : VOP1_Real_gfx10<0x064>;
-defm V_SWAP_B32 : VOP1Only_Real_gfx10_gfx11<0x065>;
-defm V_SWAPREL_B32 : VOP1Only_Real_gfx10_gfx11<0x068>;
+defm V_SWAP_B32 : VOP1Only_Real_gfx10_gfx11_gfx12<0x065>;
+defm V_SWAPREL_B32 : VOP1Only_Real_gfx10_gfx11_gfx12<0x068>;
//===----------------------------------------------------------------------===//
-// GFX7, GFX10.
+// GFX7, GFX10, GFX11, GFX12
//===----------------------------------------------------------------------===//
let AssemblerPredicate = isGFX7Only, DecoderNamespace = "GFX7" in {
@@ -938,22 +992,20 @@ let AssemblerPredicate = isGFX7Only, DecoderNamespace = "GFX7" in {
multiclass VOP1_Real_gfx7<bits<9> op> :
VOP1_Real_e32_gfx7<op>, VOP1_Real_e64_gfx7<op>;
-multiclass VOP1_Real_gfx7_gfx10<bits<9> op> :
- VOP1_Real_gfx7<op>, VOP1_Real_gfx10<op>;
-
-multiclass VOP1_Real_gfx7_gfx10_NO_DPP_gfx11<bits<9> op> :
- VOP1_Real_gfx7_gfx10<op>, VOP1_Real_NO_DPP_gfx11<op>;
+multiclass VOP1_Real_gfx7_gfx10_NO_DPP_gfx11_gfx12<bits<9> op> :
+ VOP1_Real_gfx7<op>, VOP1_Real_gfx10<op>, VOP1_Real_NO_DPP<GFX11Gen, op>,
+ VOP1_Real_NO_DPP<GFX12Gen, op>;
defm V_LOG_LEGACY_F32 : VOP1_Real_gfx7<0x045>;
defm V_EXP_LEGACY_F32 : VOP1_Real_gfx7<0x046>;
-defm V_TRUNC_F64 : VOP1_Real_gfx7_gfx10_NO_DPP_gfx11<0x017>;
-defm V_CEIL_F64 : VOP1_Real_gfx7_gfx10_NO_DPP_gfx11<0x018>;
-defm V_RNDNE_F64 : VOP1_Real_gfx7_gfx10_NO_DPP_gfx11<0x019>;
-defm V_FLOOR_F64 : VOP1_Real_gfx7_gfx10_NO_DPP_gfx11<0x01a>;
+defm V_TRUNC_F64 : VOP1_Real_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x017>;
+defm V_CEIL_F64 : VOP1_Real_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x018>;
+defm V_RNDNE_F64 : VOP1_Real_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x019>;
+defm V_FLOOR_F64 : VOP1_Real_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x01a>;
//===----------------------------------------------------------------------===//
-// GFX6, GFX7, GFX10, GFX11.
+// GFX6, GFX7, GFX10, GFX11, GFX12
//===----------------------------------------------------------------------===//
let AssemblerPredicate = isGFX6GFX7, DecoderNamespace = "GFX6GFX7" in {
@@ -975,11 +1027,13 @@ multiclass VOP1_Real_gfx6_gfx7<bits<9> op> :
multiclass VOP1_Real_gfx6_gfx7_gfx10<bits<9> op> :
VOP1_Real_gfx6_gfx7<op>, VOP1_Real_gfx10<op>;
-multiclass VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<bits<9> op> :
- VOP1_Real_gfx6_gfx7_gfx10<op>, VOP1_Real_FULL_gfx11<op>;
+multiclass VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<bits<9> op> :
+ VOP1_Real_gfx6_gfx7_gfx10<op>, VOP1_Real_FULL<GFX11Gen, op>,
+ VOP1_Real_FULL<GFX12Gen, op>;
-multiclass VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<bits<9> op> :
- VOP1_Real_gfx6_gfx7_gfx10<op>, VOP1_Real_NO_DPP_gfx11<op>;
+multiclass VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<bits<9> op> :
+ VOP1_Real_gfx6_gfx7_gfx10<op>, VOP1_Real_NO_DPP<GFX11Gen, op>,
+ VOP1_Real_NO_DPP<GFX12Gen, op>;
defm V_LOG_CLAMP_F32 : VOP1_Real_gfx6_gfx7<0x026>;
defm V_RCP_CLAMP_F32 : VOP1_Real_gfx6_gfx7<0x028>;
@@ -989,57 +1043,57 @@ defm V_RSQ_LEGACY_F32 : VOP1_Real_gfx6_gfx7<0x02d>;
defm V_RCP_CLAMP_F64 : VOP1_Real_gfx6_gfx7<0x030>;
defm V_RSQ_CLAMP_F64 : VOP1_Real_gfx6_gfx7<0x032>;
-defm V_NOP : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x000>;
-defm V_MOV_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x001>;
-defm V_CVT_I32_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x003>;
-defm V_CVT_F64_I32 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x004>;
-defm V_CVT_F32_I32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x005>;
-defm V_CVT_F32_U32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x006>;
-defm V_CVT_U32_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x007>;
-defm V_CVT_I32_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x008>;
+defm V_NOP : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x000>;
+defm V_MOV_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x001>;
+defm V_CVT_I32_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x003>;
+defm V_CVT_F64_I32 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x004>;
+defm V_CVT_F32_I32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x005>;
+defm V_CVT_F32_U32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x006>;
+defm V_CVT_U32_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x007>;
+defm V_CVT_I32_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x008>;
defm V_CVT_F16_F32 : VOP1_Real_gfx6_gfx7_gfx10<0x00a>;
defm V_CVT_F32_F16 : VOP1_Real_gfx6_gfx7_gfx10<0x00b>;
defm V_CVT_RPI_I32_F32 : VOP1_Real_gfx6_gfx7_gfx10<0x00c>;
defm V_CVT_FLR_I32_F32 : VOP1_Real_gfx6_gfx7_gfx10<0x00d>;
-defm V_CVT_OFF_F32_I4 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x00e>;
-defm V_CVT_F32_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x00f>;
-defm V_CVT_F64_F32 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x010>;
-defm V_CVT_F32_UBYTE0 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x011>;
-defm V_CVT_F32_UBYTE1 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x012>;
-defm V_CVT_F32_UBYTE2 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x013>;
-defm V_CVT_F32_UBYTE3 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x014>;
-defm V_CVT_U32_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x015>;
-defm V_CVT_F64_U32 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x016>;
-defm V_FRACT_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x020>;
-defm V_TRUNC_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x021>;
-defm V_CEIL_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x022>;
-defm V_RNDNE_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x023>;
-defm V_FLOOR_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x024>;
-defm V_EXP_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x025>;
-defm V_LOG_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x027>;
-defm V_RCP_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x02a>;
-defm V_RCP_IFLAG_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x02b>;
-defm V_RSQ_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x02e>;
-defm V_RCP_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x02f>;
-defm V_RSQ_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x031>;
-defm V_SQRT_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x033>;
-defm V_SQRT_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x034>;
-defm V_SIN_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x035>;
-defm V_COS_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x036>;
-defm V_NOT_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x037>;
-defm V_BFREV_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x038>;
+defm V_CVT_OFF_F32_I4 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x00e>;
+defm V_CVT_F32_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x00f>;
+defm V_CVT_F64_F32 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x010>;
+defm V_CVT_F32_UBYTE0 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x011>;
+defm V_CVT_F32_UBYTE1 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x012>;
+defm V_CVT_F32_UBYTE2 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x013>;
+defm V_CVT_F32_UBYTE3 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x014>;
+defm V_CVT_U32_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x015>;
+defm V_CVT_F64_U32 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x016>;
+defm V_FRACT_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x020>;
+defm V_TRUNC_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x021>;
+defm V_CEIL_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x022>;
+defm V_RNDNE_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x023>;
+defm V_FLOOR_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x024>;
+defm V_EXP_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x025>;
+defm V_LOG_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x027>;
+defm V_RCP_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x02a>;
+defm V_RCP_IFLAG_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x02b>;
+defm V_RSQ_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x02e>;
+defm V_RCP_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x02f>;
+defm V_RSQ_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x031>;
+defm V_SQRT_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x033>;
+defm V_SQRT_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x034>;
+defm V_SIN_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x035>;
+defm V_COS_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x036>;
+defm V_NOT_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x037>;
+defm V_BFREV_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x038>;
defm V_FFBH_U32 : VOP1_Real_gfx6_gfx7_gfx10<0x039>;
defm V_FFBL_B32 : VOP1_Real_gfx6_gfx7_gfx10<0x03a>;
defm V_FFBH_I32 : VOP1_Real_gfx6_gfx7_gfx10<0x03b>;
-defm V_FREXP_EXP_I32_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x03c>;
-defm V_FREXP_MANT_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x03d>;
-defm V_FRACT_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11<0x03e>;
-defm V_FREXP_EXP_I32_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x03f>;
-defm V_FREXP_MANT_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x040>;
+defm V_FREXP_EXP_I32_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x03c>;
+defm V_FREXP_MANT_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x03d>;
+defm V_FRACT_F64 : VOP1_Real_gfx6_gfx7_gfx10_NO_DPP_gfx11_gfx12<0x03e>;
+defm V_FREXP_EXP_I32_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x03f>;
+defm V_FREXP_MANT_F32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x040>;
defm V_CLREXCP : VOP1_Real_gfx6_gfx7_gfx10<0x041>;
-defm V_MOVRELD_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x042>;
-defm V_MOVRELS_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x043>;
-defm V_MOVRELSD_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11<0x044>;
+defm V_MOVRELD_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x042>;
+defm V_MOVRELS_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x043>;
+defm V_MOVRELSD_B32 : VOP1_Real_gfx6_gfx7_gfx10_FULL_gfx11_gfx12<0x044>;
//===----------------------------------------------------------------------===//
// GFX8, GFX9 (VI).
@@ -1320,3 +1374,15 @@ def : GCNPat <
(as_i32timm $dpp8), (i32 DPP8Mode.FI_0))
>;
} // End OtherPredicates = [isGFX11Only]
+
+//===----------------------------------------------------------------------===//
+// GFX12
+//===----------------------------------------------------------------------===//
+
+let OtherPredicates = [isGFX12Only] in {
+def : GCNPat <
+ (i32 (int_amdgcn_mov_dpp8 i32:$src, timm:$dpp8)),
+ (V_MOV_B32_dpp8_gfx12 VGPR_32:$src, VGPR_32:$src,
+ (as_i32timm $dpp8), (i32 DPP8Mode.FI_0))
+>;
+} // End OtherPredicates = [isGFX12Only]
diff --git a/llvm/lib/Target/AMDGPU/VOP2Instructions.td b/llvm/lib/Target/AMDGPU/VOP2Instructions.td
index 1917b24539d0..0aa62ea77b11 100644
--- a/llvm/lib/Target/AMDGPU/VOP2Instructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP2Instructions.td
@@ -109,6 +109,14 @@ class VOP2_Real <VOP2_Pseudo ps, int EncodingFamily, string real_name = ps.Mnemo
let mayStore = ps.mayStore;
}
+class VOP2_Real_Gen <VOP2_Pseudo ps, GFXGen Gen, string real_name = ps.Mnemonic> :
+ VOP2_Real <ps, Gen.Subtarget, real_name> {
+ let AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts,
+ Gen.AssemblerPredicate);
+ let DecoderNamespace = Gen.DecoderNamespace#
+ !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+}
+
class VOP2_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
VOP_SDWA_Pseudo <OpName, P, pattern> {
let AsmMatchConverter = "cvtSdwaVOP2";
@@ -1215,6 +1223,20 @@ def : VOPBinOpClampPat<uaddsat, V_ADD_U16_e64, i16>;
def : VOPBinOpClampPat<usubsat, V_SUB_U16_e64, i16>;
}
+let SubtargetPredicate = isGFX12Plus, isReMaterializable = 1 in {
+ let SchedRW = [WriteDoubleAdd], isCommutable = 1 in {
+ let FPDPRounding = 1 in {
+ defm V_ADD_F64_pseudo : VOP2Inst <"v_add_f64_pseudo", VOP_F64_F64_F64, any_fadd>;
+ defm V_MUL_F64_pseudo : VOP2Inst <"v_mul_f64_pseudo", VOP_F64_F64_F64, fmul>;
+ } // End FPDPRounding = 1
+ defm V_MIN_NUM_F64 : VOP2Inst <"v_min_num_f64", VOP_F64_F64_F64, fminnum_like>;
+ defm V_MAX_NUM_F64 : VOP2Inst <"v_max_num_f64", VOP_F64_F64_F64, fmaxnum_like>;
+ } // End SchedRW = [WriteDoubleAdd], isCommutable = 1
+ let SchedRW = [Write64Bit] in {
+ defm V_LSHLREV_B64_pseudo : VOP2Inst <"v_lshlrev_b64_pseudo", VOP_I64_I32_I64, clshl_rev_64>;
+ } // End SchedRW = [Write64Bit]
+} // End SubtargetPredicate = isGFX12Plus, isReMaterializable = 1
+
//===----------------------------------------------------------------------===//
// DPP Encodings
//===----------------------------------------------------------------------===//
@@ -1250,6 +1272,15 @@ class VOP2_DPP16<bits<6> op, VOP2_DPP_Pseudo ps, int subtarget,
Base_VOP2_DPP16<op, ps, opName, p>,
SIMCInstr <ps.PseudoInstr, subtarget>;
+class VOP2_DPP16_Gen<bits<6> op, VOP2_DPP_Pseudo ps, GFXGen Gen,
+ string opName = ps.OpName, VOPProfile p = ps.Pfl> :
+ VOP2_DPP16<op, ps, Gen.Subtarget, opName, p> {
+ let AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts,
+ Gen.AssemblerPredicate);
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace#
+ !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+}
+
class VOP2_DPP8<bits<6> op, VOP2_Pseudo ps,
VOPProfile p = ps.Pfl> :
VOP_DPP8<ps.OpName, p> {
@@ -1269,234 +1300,362 @@ class VOP2_DPP8<bits<6> op, VOP2_Pseudo ps,
let OtherPredicates = ps.OtherPredicates;
}
+
+class VOP2_DPP8_Gen<bits<6> op, VOP2_Pseudo ps, GFXGen Gen,
+ VOPProfile p = ps.Pfl> :
+ VOP2_DPP8<op, ps, p> {
+ let AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts,
+ Gen.AssemblerPredicate);
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace#
+ !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+}
//===----------------------------------------------------------------------===//
-// GFX11.
+// GFX11, GFX12
//===----------------------------------------------------------------------===//
-let AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11" in {
- //===------------------------------- VOP2 -------------------------------===//
- multiclass VOP2Only_Real_MADK_gfx11<bits<6> op> {
- def _gfx11 :
- VOP2_Real<!cast<VOP2_Pseudo>(NAME), SIEncodingFamily.GFX11>,
- VOP2_MADKe<op{5-0}, !cast<VOP2_Pseudo>(NAME).Pfl>;
+//===------------------------------- VOP2 -------------------------------===//
+multiclass VOP2Only_Real_MADK<GFXGen Gen, bits<6> op> {
+ def Gen.Suffix :
+ VOP2_Real_Gen<!cast<VOP2_Pseudo>(NAME), Gen>,
+ VOP2_MADKe<op{5-0}, !cast<VOP2_Pseudo>(NAME).Pfl>;
+}
+
+multiclass VOP2Only_Real_MADK_with_name<GFXGen Gen, bits<6> op, string asmName,
+ string opName = NAME> {
+ def Gen.Suffix :
+ VOP2_Real_Gen<!cast<VOP2_Pseudo>(opName), Gen>,
+ VOP2_MADKe<op{5-0}, !cast<VOP2_Pseudo>(opName).Pfl> {
+ VOP2_Pseudo ps = !cast<VOP2_Pseudo>(opName);
+ let AsmString = asmName # ps.AsmOperands;
}
- multiclass VOP2Only_Real_MADK_gfx11_with_name<bits<6> op, string asmName,
- string opName = NAME> {
- def _gfx11 :
- VOP2_Real<!cast<VOP2_Pseudo>(opName), SIEncodingFamily.GFX11>,
- VOP2_MADKe<op{5-0}, !cast<VOP2_Pseudo>(opName).Pfl> {
- VOP2_Pseudo ps = !cast<VOP2_Pseudo>(opName);
+}
+
+multiclass VOP2_Real_e32<GFXGen Gen, bits<6> op> {
+ def _e32#Gen.Suffix :
+ VOP2_Real_Gen<!cast<VOP2_Pseudo>(NAME#"_e32"), Gen>,
+ VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME#"_e32").Pfl>;
+}
+
+multiclass VOP2Only_Real_e32<GFXGen Gen, bits<6> op> {
+ let IsSingle = 1 in
+ defm NAME: VOP2_Real_e32<Gen, op>;
+}
+
+multiclass VOP2_Real_e64<GFXGen Gen, bits<6> op> {
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<!cast<VOP3_Pseudo>(NAME#"_e64"), Gen>,
+ VOP3e_gfx11_gfx12<{0, 1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
+}
+
+multiclass VOP2_Real_dpp<GFXGen Gen, bits<6> op> {
+ if !cast<VOP2_Pseudo>(NAME#"_e32").Pfl.HasExtDPP then
+ def _dpp#Gen.Suffix : VOP2_DPP16_Gen<op, !cast<VOP2_DPP_Pseudo>(NAME#"_dpp"), Gen>;
+}
+
+multiclass VOP2_Real_dpp8<GFXGen Gen, bits<6> op> {
+ if !cast<VOP2_Pseudo>(NAME#"_e32").Pfl.HasExtDPP then
+ def _dpp8#Gen.Suffix : VOP2_DPP8_Gen<op, !cast<VOP2_Pseudo>(NAME#"_e32"), Gen>;
+}
+
+//===------------------------- VOP2 (with name) -------------------------===//
+multiclass VOP2_Real_e32_with_name<GFXGen Gen, bits<6> op, string opName,
+ string asmName, bit single = 0> {
+ defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
+ def _e32#Gen.Suffix :
+ VOP2_Real_Gen<ps, Gen, asmName>,
+ VOP2e<op{5-0}, ps.Pfl> {
let AsmString = asmName # ps.AsmOperands;
+ let IsSingle = single;
}
- }
- multiclass VOP2_Real_e32_gfx11<bits<6> op> {
- def _e32_gfx11 :
- VOP2_Real<!cast<VOP2_Pseudo>(NAME#"_e32"), SIEncodingFamily.GFX11>,
- VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME#"_e32").Pfl>;
- }
- multiclass VOP2Only_Real_e32_gfx11<bits<6> op> {
- let IsSingle = 1 in
- defm NAME: VOP2_Real_e32_gfx11<op>;
- }
- multiclass VOP2_Real_e64_gfx11<bits<6> op> {
- def _e64_gfx11 :
- VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.GFX11>,
- VOP3e_gfx11<{0, 1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
- }
- multiclass VOP2_Real_dpp_gfx11<bits<6> op> {
- if !cast<VOP2_Pseudo>(NAME#"_e32").Pfl.HasExtDPP then
- def _dpp_gfx11 : VOP2_DPP16<op, !cast<VOP2_DPP_Pseudo>(NAME#"_dpp"), SIEncodingFamily.GFX11> {
- let DecoderNamespace = "DPPGFX11";
- }
- }
- multiclass VOP2_Real_dpp8_gfx11<bits<6> op> {
- if !cast<VOP2_Pseudo>(NAME#"_e32").Pfl.HasExtDPP then
- def _dpp8_gfx11 : VOP2_DPP8<op, !cast<VOP2_Pseudo>(NAME#"_e32")> {
- let DecoderNamespace = "DPP8GFX11";
+}
+multiclass VOP2_Real_e64_with_name<GFXGen Gen, bits<6> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<ps, Gen>,
+ VOP3e_gfx11_gfx12<{0, 1, 0, 0, op{5-0}}, ps.Pfl> {
+ let AsmString = asmName # ps.AsmOperands;
}
- }
+}
- //===------------------------- VOP2 (with name) -------------------------===//
- multiclass VOP2_Real_e32_with_name_gfx11<bits<6> op, string opName,
- string asmName, bit single = 0> {
- defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
- let DecoderNamespace = !if(ps.Pfl.IsRealTrue16, "GFX11", "GFX11_FAKE16"),
- AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, isGFX11Only) in
- def _e32_gfx11 :
- VOP2_Real<ps, SIEncodingFamily.GFX11, asmName>,
- VOP2e<op{5-0}, ps.Pfl> {
- let AsmString = asmName # ps.AsmOperands;
- let IsSingle = single;
- }
+multiclass VOP2_Real_dpp_with_name<GFXGen Gen, bits<6> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
+ if ps.Pfl.HasExtDPP then
+ def _dpp#Gen.Suffix : VOP2_DPP16_Gen<op, !cast<VOP2_DPP_Pseudo>(opName#"_dpp"), Gen> {
+ let AsmString = asmName # ps.Pfl.AsmDPP16;
}
- multiclass VOP2_Real_e64_with_name_gfx11<bits<6> op, string opName,
- string asmName> {
- defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
- def _e64_gfx11 :
- VOP3_Real<ps, SIEncodingFamily.GFX11>,
- VOP3e_gfx11<{0, 1, 0, 0, op{5-0}}, ps.Pfl> {
- let AsmString = asmName # ps.AsmOperands;
- }
+}
+multiclass VOP2_Real_dpp8_with_name<GFXGen Gen, bits<6> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
+ if ps.Pfl.HasExtDPP then
+ def _dpp8#Gen.Suffix : VOP2_DPP8_Gen<op, ps, Gen> {
+ let AsmString = asmName # ps.Pfl.AsmDPP8;
}
+}
- multiclass VOP2_Real_dpp_with_name_gfx11<bits<6> op, string opName,
- string asmName> {
- defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
- if ps.Pfl.HasExtDPP then
- def _dpp_gfx11 : VOP2_DPP16<op, !cast<VOP2_DPP_Pseudo>(opName#"_dpp"),
- SIEncodingFamily.GFX11> {
- let AsmString = asmName # ps.Pfl.AsmDPP16;
- let DecoderNamespace = !if(ps.Pfl.IsRealTrue16, "DPPGFX11", "DPPGFX11_FAKE16");
- let AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, isGFX11Only);
+//===------------------------------ VOP2be ------------------------------===//
+multiclass VOP2be_Real_e32<GFXGen Gen, bits<6> op, string opName, string asmName> {
+ defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
+ def _e32#Gen.Suffix :
+ VOP2_Real_Gen<ps, Gen>,
+ VOP2e<op{5-0}, ps.Pfl> {
+ let AsmString = asmName # !subst(", vcc", "", ps.AsmOperands);
}
- }
- multiclass VOP2_Real_dpp8_with_name_gfx11<bits<6> op, string opName,
- string asmName> {
- defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
- if ps.Pfl.HasExtDPP then
- def _dpp8_gfx11 : VOP2_DPP8<op, ps> {
- let AsmString = asmName # ps.Pfl.AsmDPP8;
- let DecoderNamespace = !if(ps.Pfl.IsRealTrue16, "DPP8GFX11", "DPP8GFX11_FAKE16");
- let AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, isGFX11Only);
+}
+multiclass VOP2be_Real_dpp<GFXGen Gen, bits<6> op, string opName, string asmName> {
+ if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
+ def _dpp#Gen.Suffix :
+ VOP2_DPP16_Gen<op, !cast<VOP2_DPP_Pseudo>(opName#"_dpp"), Gen, asmName> {
+ string AsmDPP = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP16;
+ let AsmString = asmName # !subst(", vcc", "", AsmDPP);
}
- }
-
- //===------------------------------ VOP2be ------------------------------===//
- multiclass VOP2be_Real_e32_gfx11<bits<6> op, string opName, string asmName> {
- defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
- def _e32_gfx11 :
- VOP2_Real<ps, SIEncodingFamily.GFX11>,
- VOP2e<op{5-0}, ps.Pfl> {
- let AsmString = asmName # !subst(", vcc", "", ps.AsmOperands);
- }
- }
- multiclass VOP2be_Real_dpp_gfx11<bits<6> op, string opName, string asmName> {
- if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
- def _dpp_gfx11 :
- VOP2_DPP16<op, !cast<VOP2_DPP_Pseudo>(opName#"_dpp"), SIEncodingFamily.GFX11, asmName> {
- string AsmDPP = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP16;
- let AsmString = asmName # !subst(", vcc", "", AsmDPP);
- let DecoderNamespace = "DPPGFX11";
- }
- if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
- def _dpp_w32_gfx11 :
- Base_VOP2_DPP16<op, !cast<VOP2_DPP_Pseudo>(opName#"_dpp"), asmName> {
- string AsmDPP = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP16;
- let AsmString = asmName # !subst("vcc", "vcc_lo", AsmDPP);
- let isAsmParserOnly = 1;
- let WaveSizePredicate = isWave32;
- }
- if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
- def _dpp_w64_gfx11 :
- Base_VOP2_DPP16<op, !cast<VOP2_DPP_Pseudo>(opName#"_dpp"), asmName> {
- string AsmDPP = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP16;
- let AsmString = asmName # AsmDPP;
- let isAsmParserOnly = 1;
- let WaveSizePredicate = isWave64;
- }
- }
- multiclass VOP2be_Real_dpp8_gfx11<bits<6> op, string opName, string asmName> {
- if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
- def _dpp8_gfx11 :
- VOP2_DPP8<op, !cast<VOP2_Pseudo>(opName#"_e32")> {
- string AsmDPP8 = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP8;
- let AsmString = asmName # !subst(", vcc", "", AsmDPP8);
- let DecoderNamespace = "DPP8GFX11";
- }
- if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
- def _dpp8_w32_gfx11 :
- VOP2_DPP8<op, !cast<VOP2_Pseudo>(opName#"_e32")> {
- string AsmDPP8 = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP8;
- let AsmString = asmName # !subst("vcc", "vcc_lo", AsmDPP8);
- let isAsmParserOnly = 1;
- let WaveSizePredicate = isWave32;
- }
- if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
- def _dpp8_w64_gfx11 :
- VOP2_DPP8<op, !cast<VOP2_Pseudo>(opName#"_e32")> {
- string AsmDPP8 = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP8;
- let AsmString = asmName # AsmDPP8;
- let isAsmParserOnly = 1;
- let WaveSizePredicate = isWave64;
- }
- }
-
-} // End AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11"
+ if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
+ def _dpp_w32#Gen.Suffix :
+ Base_VOP2_DPP16<op, !cast<VOP2_DPP_Pseudo>(opName#"_dpp"), asmName> {
+ string AsmDPP = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP16;
+ let AsmString = asmName # !subst("vcc", "vcc_lo", AsmDPP);
+ let isAsmParserOnly = 1;
+ let WaveSizePredicate = isWave32;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
+ let DecoderNamespace = Gen.DecoderNamespace;
+ }
+ if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
+ def _dpp_w64#Gen.Suffix :
+ Base_VOP2_DPP16<op, !cast<VOP2_DPP_Pseudo>(opName#"_dpp"), asmName> {
+ string AsmDPP = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP16;
+ let AsmString = asmName # AsmDPP;
+ let isAsmParserOnly = 1;
+ let WaveSizePredicate = isWave64;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
+ let DecoderNamespace = Gen.DecoderNamespace;
+ }
+}
+multiclass VOP2be_Real_dpp8<GFXGen Gen, bits<6> op, string opName, string asmName> {
+ if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
+ def _dpp8#Gen.Suffix :
+ VOP2_DPP8_Gen<op, !cast<VOP2_Pseudo>(opName#"_e32"), Gen> {
+ string AsmDPP8 = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP8;
+ let AsmString = asmName # !subst(", vcc", "", AsmDPP8);
+ }
+ if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
+ def _dpp8_w32#Gen.Suffix :
+ VOP2_DPP8<op, !cast<VOP2_Pseudo>(opName#"_e32")> {
+ string AsmDPP8 = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP8;
+ let AsmString = asmName # !subst("vcc", "vcc_lo", AsmDPP8);
+ let isAsmParserOnly = 1;
+ let WaveSizePredicate = isWave32;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
+ let DecoderNamespace = Gen.DecoderNamespace;
+ }
+ if !cast<VOP2_Pseudo>(opName#"_e32").Pfl.HasExtDPP then
+ def _dpp8_w64#Gen.Suffix :
+ VOP2_DPP8<op, !cast<VOP2_Pseudo>(opName#"_e32")> {
+ string AsmDPP8 = !cast<VOP2_Pseudo>(opName#"_e32").Pfl.AsmDPP8;
+ let AsmString = asmName # AsmDPP8;
+ let isAsmParserOnly = 1;
+ let WaveSizePredicate = isWave64;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
+ let DecoderNamespace = Gen.DecoderNamespace;
+ }
+}
// We don't want to override separate decoderNamespaces within these
-multiclass VOP2_Realtriple_e64_gfx11<bits<6> op> {
- defm NAME : VOP3_Realtriple_gfx11<{0, 1, 0, 0, op{5-0}}, /*isSingle=*/ 0, NAME> ;
+multiclass VOP2_Realtriple_e64<GFXGen Gen, bits<6> op> {
+ defm NAME : VOP3_Realtriple<Gen, {0, 1, 0, 0, op{5-0}}, /*isSingle=*/ 0, NAME> ;
}
-multiclass VOP2_Realtriple_e64_with_name_gfx11<bits<6> op, string opName,
+
+multiclass VOP2_Realtriple_e64_with_name<GFXGen Gen, bits<6> op, string opName,
string asmName> {
- defm NAME : VOP3_Realtriple_with_name_gfx11<{0, 1, 0, 0, op{5-0}}, opName, asmName> ;
+ defm NAME : VOP3_Realtriple_with_name<Gen, {0, 1, 0, 0, op{5-0}}, opName, asmName> ;
}
-multiclass VOP2be_Real_gfx11<bits<6> op, string opName, string asmName> :
- VOP2be_Real_e32_gfx11<op, opName, asmName>,
- VOP3be_Realtriple_gfx11<{0, 1, 0, 0, op{5-0}}, /*isSingle=*/ 0, opName, asmName>,
- VOP2be_Real_dpp_gfx11<op, opName, asmName>,
- VOP2be_Real_dpp8_gfx11<op, opName, asmName>;
+multiclass VOP2be_Real<GFXGen Gen, bits<6> op, string opName, string asmName> :
+ VOP2be_Real_e32<Gen, op, opName, asmName>,
+ VOP3be_Realtriple<Gen, {0, 1, 0, 0, op{5-0}}, /*isSingle=*/ 0, opName, asmName>,
+ VOP2be_Real_dpp<Gen, op, opName, asmName>,
+ VOP2be_Real_dpp8<Gen, op, opName, asmName>;
// Only for CNDMASK
-multiclass VOP2e_Real_gfx11<bits<6> op, string opName, string asmName> :
- VOP2_Real_e32_gfx11<op>,
- VOP2_Realtriple_e64_gfx11<op>,
- VOP2be_Real_dpp_gfx11<op, opName, asmName>,
- VOP2be_Real_dpp8_gfx11<op, opName, asmName>;
+multiclass VOP2e_Real<GFXGen Gen, bits<6> op, string opName, string asmName> :
+ VOP2_Real_e32<Gen, op>,
+ VOP2_Realtriple_e64<Gen, op>,
+ VOP2be_Real_dpp<Gen, op, opName, asmName>,
+ VOP2be_Real_dpp8<Gen, op, opName, asmName>;
+
+multiclass VOP2Only_Real<GFXGen Gen, bits<6> op> :
+ VOP2Only_Real_e32<Gen, op>,
+ VOP2_Real_dpp<Gen, op>,
+ VOP2_Real_dpp8<Gen, op>;
+
+multiclass VOP2_Real_FULL<GFXGen Gen, bits<6> op> :
+ VOP2_Realtriple_e64<Gen, op>,
+ VOP2_Real_e32<Gen, op>,
+ VOP2_Real_dpp<Gen, op>,
+ VOP2_Real_dpp8<Gen, op>;
+
+multiclass VOP2_Real_NO_VOP3_with_name<GFXGen Gen, bits<6> op, string opName,
+ string asmName, bit isSingle = 0> {
+ defm NAME : VOP2_Real_e32_with_name<Gen, op, opName, asmName, isSingle>,
+ VOP2_Real_dpp_with_name<Gen, op, opName, asmName>,
+ VOP2_Real_dpp8_with_name<Gen, op, opName, asmName>;
+ defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
+ def Gen.Suffix#"_alias" : MnemonicAlias<ps.Mnemonic, asmName>, Requires<[Gen.AssemblerPredicate]>;
+}
-multiclass VOP2Only_Real_gfx11<bits<6> op> :
- VOP2Only_Real_e32_gfx11<op>,
- VOP2_Real_dpp_gfx11<op>,
- VOP2_Real_dpp8_gfx11<op>;
+multiclass VOP2_Real_FULL_with_name<GFXGen Gen, bits<6> op, string opName,
+ string asmName> :
+ VOP2_Realtriple_e64_with_name<Gen, op, opName, asmName>,
+ VOP2_Real_NO_VOP3_with_name<Gen, op, opName, asmName>;
-multiclass VOP2_Real_NO_VOP3_gfx11<bits<6> op> :
- VOP2_Real_e32_gfx11<op>, VOP2_Real_dpp_gfx11<op>, VOP2_Real_dpp8_gfx11<op>;
+multiclass VOP2_Real_NO_DPP_with_name<GFXGen Gen, bits<6> op, string opName,
+ string asmName> {
+ defm NAME : VOP2_Real_e32_with_name<Gen, op, opName, asmName>,
+ VOP2_Real_e64_with_name<Gen, op, opName, asmName>;
+ defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
+ def Gen.Suffix#"_alias" : MnemonicAlias<ps.Mnemonic, asmName>, Requires<[Gen.AssemblerPredicate]>;
+}
-multiclass VOP2_Real_FULL_gfx11<bits<6> op> :
- VOP2_Realtriple_e64_gfx11<op>, VOP2_Real_NO_VOP3_gfx11<op>;
+multiclass VOP2_Real_NO_DPP_with_alias<GFXGen Gen, bits<6> op, string alias> {
+ defm NAME : VOP2_Real_e32<Gen, op>,
+ VOP2_Real_e64<Gen, op>;
+ def Gen.Suffix#"_alias" : MnemonicAlias<alias, NAME>, Requires<[Gen.AssemblerPredicate]>;
+}
-multiclass VOP2_Real_NO_VOP3_with_name_gfx11<bits<6> op, string opName,
- string asmName, bit isSingle = 0> {
+//===----------------------------------------------------------------------===//
+// GFX12.
+//===----------------------------------------------------------------------===//
- defm NAME : VOP2_Real_e32_with_name_gfx11<op, opName, asmName, isSingle>,
- VOP2_Real_dpp_with_name_gfx11<op, opName, asmName>,
- VOP2_Real_dpp8_with_name_gfx11<op, opName, asmName>;
- defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
- def _gfx11_alias : MnemonicAlias<ps.Mnemonic, asmName>, Requires<[isGFX11Plus]>;
+multiclass VOP2be_Real_gfx12<bits<6> op, string opName, string asmName> :
+ VOP2be_Real<GFX12Gen, op, opName, asmName>;
+
+// Only for CNDMASK
+multiclass VOP2e_Real_gfx12<bits<6> op, string opName, string asmName> :
+ VOP2e_Real<GFX12Gen, op, opName, asmName>;
+
+multiclass VOP2_Real_FULL_with_name_gfx12<bits<6> op, string opName,
+ string asmName> :
+ VOP2_Real_FULL_with_name<GFX12Gen, op, opName, asmName>;
+
+multiclass VOP2_Real_FULL_t16_with_name_gfx12<bits<6> op, string opName,
+ string asmName, string alias> {
+ defm NAME : VOP2_Real_FULL_with_name<GFX12Gen, op, opName, asmName>;
+ def _gfx12_2nd_alias : MnemonicAlias<alias, asmName>, Requires<[isGFX12Only]>;
}
-multiclass VOP2_Real_FULL_with_name_gfx11<bits<6> op, string opName,
- string asmName> :
- VOP2_Realtriple_e64_with_name_gfx11<op, opName, asmName>,
- VOP2_Real_NO_VOP3_with_name_gfx11<op, opName, asmName>;
+multiclass VOP2_Real_NO_DPP_with_name_gfx12<bits<6> op, string opName,
+ string asmName> :
+ VOP2_Real_NO_DPP_with_name<GFX12Gen, op, opName, asmName>;
-multiclass VOP2_Real_FULL_t16_gfx11<bits<6> op, string asmName, string opName = NAME>
- : VOP2_Real_FULL_with_name_gfx11<op, opName, asmName>;
+multiclass VOP2_Real_NO_DPP_with_alias_gfx12<bits<6> op, string alias> :
+ VOP2_Real_NO_DPP_with_alias<GFX12Gen, op, alias>;
-multiclass VOP2_Real_NO_DPP_gfx11<bits<6> op> :
- VOP2_Real_e32_gfx11<op>, VOP2_Real_e64_gfx11<op>;
+defm V_ADD_F64 : VOP2_Real_NO_DPP_with_name_gfx12<0x002, "V_ADD_F64_pseudo", "v_add_f64">;
+defm V_MUL_F64 : VOP2_Real_NO_DPP_with_name_gfx12<0x006, "V_MUL_F64_pseudo", "v_mul_f64">;
+defm V_LSHLREV_B64 : VOP2_Real_NO_DPP_with_name_gfx12<0x01f, "V_LSHLREV_B64_pseudo", "v_lshlrev_b64">;
+defm V_MIN_NUM_F64 : VOP2_Real_NO_DPP_with_alias_gfx12<0x00d, "v_min_f64">;
+defm V_MAX_NUM_F64 : VOP2_Real_NO_DPP_with_alias_gfx12<0x00e, "v_max_f64">;
-multiclass VOP2_Real_NO_DPP_with_name_gfx11<bits<6> op, string opName,
- string asmName> {
- defm NAME : VOP2_Real_e32_with_name_gfx11<op, opName, asmName>,
- VOP2_Real_e64_with_name_gfx11<op, opName, asmName>;
+defm V_CNDMASK_B32 : VOP2e_Real_gfx12<0x001, "V_CNDMASK_B32", "v_cndmask_b32">;
+defm V_ADD_CO_CI_U32 :
+ VOP2be_Real_gfx12<0x020, "V_ADDC_U32", "v_add_co_ci_u32">;
+defm V_SUB_CO_CI_U32 :
+ VOP2be_Real_gfx12<0x021, "V_SUBB_U32", "v_sub_co_ci_u32">;
+defm V_SUBREV_CO_CI_U32 :
+ VOP2be_Real_gfx12<0x022, "V_SUBBREV_U32", "v_subrev_co_ci_u32">;
+
+defm V_MIN_NUM_F32 : VOP2_Real_FULL_with_name_gfx12<0x015, "V_MIN_F32", "v_min_num_f32">;
+defm V_MAX_NUM_F32 : VOP2_Real_FULL_with_name_gfx12<0x016, "V_MAX_F32", "v_max_num_f32">;
+defm V_MIN_NUM_F16 : VOP2_Real_FULL_t16_with_name_gfx12<0x030, "V_MIN_F16_t16", "v_min_num_f16", "v_min_f16">;
+defm V_MIN_NUM_F16_fake16 : VOP2_Real_FULL_t16_with_name_gfx12<0x030, "V_MIN_F16_fake16", "v_min_num_f16", "v_min_f16">;
+defm V_MAX_NUM_F16 : VOP2_Real_FULL_t16_with_name_gfx12<0x031, "V_MAX_F16_t16", "v_max_num_f16", "v_max_f16">;
+defm V_MAX_NUM_F16_fake16 : VOP2_Real_FULL_t16_with_name_gfx12<0x031, "V_MAX_F16_fake16", "v_max_num_f16", "v_max_f16">;
+
+let SubtargetPredicate = isGFX12Plus in {
+ defm : VOP2eInstAliases<V_CNDMASK_B32_e32, V_CNDMASK_B32_e32_gfx12>;
+
+ defm : VOP2bInstAliases<
+ V_ADDC_U32_e32, V_ADD_CO_CI_U32_e32_gfx12, "v_add_co_ci_u32">;
+ defm : VOP2bInstAliases<
+ V_SUBB_U32_e32, V_SUB_CO_CI_U32_e32_gfx12, "v_sub_co_ci_u32">;
+ defm : VOP2bInstAliases<
+ V_SUBBREV_U32_e32, V_SUBREV_CO_CI_U32_e32_gfx12, "v_subrev_co_ci_u32">;
+} // End SubtargetPredicate = isGFX12Plus
+
+//===----------------------------------------------------------------------===//
+// GFX11.
+//===----------------------------------------------------------------------===//
+
+multiclass VOP2be_Real_gfx11<bits<6> op, string opName, string asmName> :
+ VOP2be_Real<GFX11Gen, op, opName, asmName>;
+
+// Only for CNDMASK
+multiclass VOP2e_Real_gfx11<bits<6> op, string opName, string asmName> :
+ VOP2e_Real<GFX11Gen, op, opName, asmName>;
+
+multiclass VOP2_Real_NO_VOP3_with_name_gfx11<bits<6> op, string opName,
+ string asmName, bit isSingle = 0> {
+ defm NAME : VOP2_Real_e32_with_name<GFX11Gen, op, opName, asmName, isSingle>,
+ VOP2_Real_dpp_with_name<GFX11Gen, op, opName, asmName>,
+ VOP2_Real_dpp8_with_name<GFX11Gen, op, opName, asmName>;
defvar ps = !cast<VOP2_Pseudo>(opName#"_e32");
- def _gfx11_alias : MnemonicAlias<ps.Mnemonic, asmName>, Requires<[isGFX11Plus]>;
+ def _gfx11_alias : MnemonicAlias<ps.Mnemonic, asmName>, Requires<[isGFX11Only]>;
}
+multiclass VOP2_Real_NO_DPP_with_name_gfx11<bits<6> op, string opName,
+ string asmName> :
+ VOP2_Real_NO_DPP_with_name<GFX11Gen, op, opName, asmName>;
+
+multiclass VOP2_Real_FULL_gfx11_gfx12<bits<6> op> :
+ VOP2_Real_FULL<GFX11Gen, op>, VOP2_Real_FULL<GFX12Gen, op>;
+
+multiclass VOP2_Real_FULL_with_name_gfx11_gfx12<bits<6> op, string opName,
+ string asmName> :
+ VOP2_Real_FULL_with_name<GFX11Gen, op, opName, asmName>,
+ VOP2_Real_FULL_with_name<GFX12Gen, op, opName, asmName>;
+
+multiclass VOP2_Real_e32_gfx11_gfx12<bits<6> op> :
+ VOP2Only_Real<GFX11Gen, op>, VOP2Only_Real<GFX12Gen, op>;
+
+multiclass VOP3Only_Realtriple_gfx11_gfx12<bits<10> op> :
+ VOP3Only_Realtriple<GFX11Gen, op>, VOP3Only_Realtriple<GFX12Gen, op>;
+
+multiclass VOP3Only_Realtriple_t16_gfx11_gfx12<bits<10> op, string asmName> :
+ VOP3Only_Realtriple_t16<GFX11Gen, op, asmName>,
+ VOP3Only_Realtriple_t16<GFX12Gen, op, asmName>;
+
+multiclass VOP3beOnly_Realtriple_gfx11_gfx12<bits<10> op> :
+ VOP3beOnly_Realtriple<GFX11Gen, op>, VOP3beOnly_Realtriple<GFX12Gen, op>;
+
+multiclass VOP2Only_Real_MADK_with_name_gfx11_gfx12<bits<6> op, string asmName,
+ string opName = NAME> :
+ VOP2Only_Real_MADK_with_name<GFX11Gen, op, asmName, opName>,
+ VOP2Only_Real_MADK_with_name<GFX12Gen, op, asmName, opName>;
+
+multiclass VOP2_Real_FULL_t16_gfx11<bits<6> op, string asmName,
+ string opName = NAME> :
+ VOP2_Real_FULL_with_name<GFX11Gen, op, opName, asmName>;
+
+multiclass VOP2_Real_FULL_t16_gfx11_gfx12<bits<6> op, string asmName,
+ string opName = NAME> :
+ VOP2_Real_FULL_with_name_gfx11_gfx12<op, opName, asmName>;
+
+multiclass VOP2_Real_FULL_gfx11<bits<6> op> :
+ VOP2_Real_FULL<GFX11Gen, op>;
+
defm V_CNDMASK_B32 : VOP2e_Real_gfx11<0x001, "V_CNDMASK_B32",
"v_cndmask_b32">;
defm V_DOT2ACC_F32_F16 : VOP2_Real_NO_VOP3_with_name_gfx11<0x002,
"V_DOT2C_F32_F16", "v_dot2acc_f32_f16", 1>;
defm V_FMAC_DX9_ZERO_F32 : VOP2_Real_NO_DPP_with_name_gfx11<0x006,
"V_FMAC_LEGACY_F32", "v_fmac_dx9_zero_f32">;
-defm V_MUL_DX9_ZERO_F32 : VOP2_Real_FULL_with_name_gfx11<0x007,
+defm V_MUL_DX9_ZERO_F32 : VOP2_Real_FULL_with_name_gfx11_gfx12<0x007,
"V_MUL_LEGACY_F32", "v_mul_dx9_zero_f32">;
-defm V_LSHLREV_B32 : VOP2_Real_FULL_gfx11<0x018>;
-defm V_LSHRREV_B32 : VOP2_Real_FULL_gfx11<0x019>;
-defm V_ASHRREV_I32 : VOP2_Real_FULL_gfx11<0x01a>;
+defm V_LSHLREV_B32 : VOP2_Real_FULL_gfx11_gfx12<0x018>;
+defm V_LSHRREV_B32 : VOP2_Real_FULL_gfx11_gfx12<0x019>;
+defm V_ASHRREV_I32 : VOP2_Real_FULL_gfx11_gfx12<0x01a>;
defm V_ADD_CO_CI_U32 :
VOP2be_Real_gfx11<0x020, "V_ADDC_U32", "v_add_co_ci_u32">;
defm V_SUB_CO_CI_U32 :
@@ -1504,43 +1663,43 @@ defm V_SUB_CO_CI_U32 :
defm V_SUBREV_CO_CI_U32 :
VOP2be_Real_gfx11<0x022, "V_SUBBREV_U32", "v_subrev_co_ci_u32">;
-defm V_CVT_PK_RTZ_F16_F32 : VOP2_Real_FULL_with_name_gfx11<0x02f,
+defm V_CVT_PK_RTZ_F16_F32 : VOP2_Real_FULL_with_name_gfx11_gfx12<0x02f,
"V_CVT_PKRTZ_F16_F32", "v_cvt_pk_rtz_f16_f32">;
-defm V_PK_FMAC_F16 : VOP2Only_Real_gfx11<0x03c>;
-
-defm V_ADD_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x032, "v_add_f16">;
-defm V_ADD_F16_fake16 : VOP2_Real_FULL_t16_gfx11<0x032, "v_add_f16">;
-defm V_SUB_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x033, "v_sub_f16">;
-defm V_SUB_F16_fake16 : VOP2_Real_FULL_t16_gfx11<0x033, "v_sub_f16">;
-defm V_SUBREV_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x034, "v_subrev_f16">;
-defm V_SUBREV_F16_fake16 : VOP2_Real_FULL_t16_gfx11<0x034, "v_subrev_f16">;
-defm V_MUL_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x035, "v_mul_f16">;
-defm V_MUL_F16_fake16 : VOP2_Real_FULL_t16_gfx11<0x035, "v_mul_f16">;
-defm V_FMAC_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x036, "v_fmac_f16">;
-defm V_LDEXP_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x03b, "v_ldexp_f16">;
+defm V_PK_FMAC_F16 : VOP2_Real_e32_gfx11_gfx12<0x03c>;
+
+defm V_ADD_F16_t16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x032, "v_add_f16">;
+defm V_ADD_F16_fake16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x032, "v_add_f16">;
+defm V_SUB_F16_t16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x033, "v_sub_f16">;
+defm V_SUB_F16_fake16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x033, "v_sub_f16">;
+defm V_SUBREV_F16_t16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x034, "v_subrev_f16">;
+defm V_SUBREV_F16_fake16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x034, "v_subrev_f16">;
+defm V_MUL_F16_t16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x035, "v_mul_f16">;
+defm V_MUL_F16_fake16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x035, "v_mul_f16">;
+defm V_FMAC_F16_t16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x036, "v_fmac_f16">;
+defm V_LDEXP_F16_t16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x03b, "v_ldexp_f16">;
defm V_MAX_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x039, "v_max_f16">;
defm V_MAX_F16_fake16 : VOP2_Real_FULL_t16_gfx11<0x039, "v_max_f16">;
defm V_MIN_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x03a, "v_min_f16">;
defm V_MIN_F16_fake16 : VOP2_Real_FULL_t16_gfx11<0x03a, "v_min_f16">;
-defm V_FMAMK_F16_t16 : VOP2Only_Real_MADK_gfx11_with_name<0x037, "v_fmamk_f16">;
-defm V_FMAAK_F16_t16 : VOP2Only_Real_MADK_gfx11_with_name<0x038, "v_fmaak_f16">;
+defm V_FMAMK_F16_t16 : VOP2Only_Real_MADK_with_name_gfx11_gfx12<0x037, "v_fmamk_f16">;
+defm V_FMAAK_F16_t16 : VOP2Only_Real_MADK_with_name_gfx11_gfx12<0x038, "v_fmaak_f16">;
// VOP3 only.
-defm V_CNDMASK_B16 : VOP3Only_Realtriple_gfx11<0x25d>;
-defm V_LDEXP_F32 : VOP3Only_Realtriple_gfx11<0x31c>;
-defm V_BFM_B32 : VOP3Only_Realtriple_gfx11<0x31d>;
-defm V_BCNT_U32_B32 : VOP3Only_Realtriple_gfx11<0x31e>;
-defm V_MBCNT_LO_U32_B32 : VOP3Only_Realtriple_gfx11<0x31f>;
-defm V_MBCNT_HI_U32_B32 : VOP3Only_Realtriple_gfx11<0x320>;
-defm V_CVT_PK_NORM_I16_F32 : VOP3Only_Realtriple_with_name_gfx11<0x321, "V_CVT_PKNORM_I16_F32", "v_cvt_pk_norm_i16_f32">;
-defm V_CVT_PK_NORM_U16_F32 : VOP3Only_Realtriple_with_name_gfx11<0x322, "V_CVT_PKNORM_U16_F32", "v_cvt_pk_norm_u16_f32">;
-defm V_CVT_PK_U16_U32 : VOP3Only_Realtriple_gfx11<0x323>;
-defm V_CVT_PK_I16_I32 : VOP3Only_Realtriple_gfx11<0x324>;
-defm V_ADD_CO_U32 : VOP3beOnly_Realtriple_gfx11<0x300>;
-defm V_SUB_CO_U32 : VOP3beOnly_Realtriple_gfx11<0x301>;
-defm V_SUBREV_CO_U32 : VOP3beOnly_Realtriple_gfx11<0x302>;
-
-let SubtargetPredicate = isGFX11Plus in {
+defm V_CNDMASK_B16 : VOP3Only_Realtriple_gfx11_gfx12<0x25d>;
+defm V_LDEXP_F32 : VOP3Only_Realtriple_gfx11_gfx12<0x31c>;
+defm V_BFM_B32 : VOP3Only_Realtriple_gfx11_gfx12<0x31d>;
+defm V_BCNT_U32_B32 : VOP3Only_Realtriple_gfx11_gfx12<0x31e>;
+defm V_MBCNT_LO_U32_B32 : VOP3Only_Realtriple_gfx11_gfx12<0x31f>;
+defm V_MBCNT_HI_U32_B32 : VOP3Only_Realtriple_gfx11_gfx12<0x320>;
+defm V_CVT_PK_NORM_I16_F32 : VOP3Only_Realtriple_with_name_gfx11_gfx12<0x321, "V_CVT_PKNORM_I16_F32", "v_cvt_pk_norm_i16_f32">;
+defm V_CVT_PK_NORM_U16_F32 : VOP3Only_Realtriple_with_name_gfx11_gfx12<0x322, "V_CVT_PKNORM_U16_F32", "v_cvt_pk_norm_u16_f32">;
+defm V_CVT_PK_U16_U32 : VOP3Only_Realtriple_gfx11_gfx12<0x323>;
+defm V_CVT_PK_I16_I32 : VOP3Only_Realtriple_gfx11_gfx12<0x324>;
+defm V_ADD_CO_U32 : VOP3beOnly_Realtriple_gfx11_gfx12<0x300>;
+defm V_SUB_CO_U32 : VOP3beOnly_Realtriple_gfx11_gfx12<0x301>;
+defm V_SUBREV_CO_U32 : VOP3beOnly_Realtriple_gfx11_gfx12<0x302>;
+
+let SubtargetPredicate = isGFX11Only in {
defm : VOP2eInstAliases<V_CNDMASK_B32_e32, V_CNDMASK_B32_e32_gfx11>;
defm : VOP2bInstAliases<
@@ -1549,7 +1708,7 @@ let SubtargetPredicate = isGFX11Plus in {
V_SUBB_U32_e32, V_SUB_CO_CI_U32_e32_gfx11, "v_sub_co_ci_u32">;
defm : VOP2bInstAliases<
V_SUBBREV_U32_e32, V_SUBREV_CO_CI_U32_e32_gfx11, "v_subrev_co_ci_u32">;
-} // End SubtargetPredicate = isGFX11Plus
+} // End SubtargetPredicate = isGFX11Only
//===----------------------------------------------------------------------===//
// GFX10.
@@ -1771,7 +1930,10 @@ let AssemblerPredicate = isGFX10Only, DecoderNamespace = "GFX10" in {
} // End AssemblerPredicate = isGFX10Only, DecoderNamespace = "GFX10"
multiclass VOP2Only_Real_MADK_gfx10_gfx11<bits<6> op> :
- VOP2Only_Real_MADK_gfx10<op>, VOP2Only_Real_MADK_gfx11<op>;
+ VOP2Only_Real_MADK_gfx10<op>, VOP2Only_Real_MADK<GFX11Gen, op>;
+
+multiclass VOP2Only_Real_MADK_gfx10_gfx11_gfx12<bits<6> op> :
+ VOP2Only_Real_MADK_gfx10_gfx11<op>, VOP2Only_Real_MADK<GFX12Gen, op>;
multiclass VOP2be_Real_gfx10<bits<6> op, string opName, string asmName> :
VOP2be_Real_e32_gfx10<op, opName, asmName>,
@@ -1792,7 +1954,10 @@ multiclass VOP2_Real_gfx10<bits<6> op> :
VOP2_Real_sdwa_gfx10<op>, VOP2_Real_dpp_gfx10<op>, VOP2_Real_dpp8_gfx10<op>;
multiclass VOP2_Real_gfx10_gfx11<bits<6> op> :
- VOP2_Real_gfx10<op>, VOP2_Real_FULL_gfx11<op>;
+ VOP2_Real_gfx10<op>, VOP2_Real_FULL<GFX11Gen, op>;
+
+multiclass VOP2_Real_gfx10_gfx11_gfx12<bits<6> op> :
+ VOP2_Real_gfx10_gfx11<op>, VOP2_Real_FULL<GFX12Gen, op>;
multiclass VOP2_Real_with_name_gfx10<bits<6> op, string opName,
string asmName> :
@@ -1802,19 +1967,20 @@ multiclass VOP2_Real_with_name_gfx10<bits<6> op, string opName,
VOP2_Real_dpp_gfx10_with_name<op, opName, asmName>,
VOP2_Real_dpp8_gfx10_with_name<op, opName, asmName>;
-multiclass VOP2_Real_with_name_gfx10_gfx11<bits<6> op, string opName,
- string asmName> :
+multiclass VOP2_Real_with_name_gfx10_gfx11_gfx12<bits<6> op, string opName,
+ string asmName> :
VOP2_Real_with_name_gfx10<op, opName, asmName>,
- VOP2_Real_FULL_with_name_gfx11<op, opName, asmName>;
+ VOP2_Real_FULL_with_name<GFX11Gen, op, opName, asmName>,
+ VOP2_Real_FULL_with_name<GFX12Gen, op, opName, asmName>;
// NB: Same opcode as v_mac_legacy_f32
let DecoderNamespace = "GFX10_B" in
defm V_FMAC_LEGACY_F32 : VOP2_Real_gfx10<0x006>;
-defm V_XNOR_B32 : VOP2_Real_gfx10_gfx11<0x01e>;
-defm V_FMAC_F32 : VOP2_Real_gfx10_gfx11<0x02b>;
-defm V_FMAMK_F32 : VOP2Only_Real_MADK_gfx10_gfx11<0x02c>;
-defm V_FMAAK_F32 : VOP2Only_Real_MADK_gfx10_gfx11<0x02d>;
+defm V_XNOR_B32 : VOP2_Real_gfx10_gfx11_gfx12<0x01e>;
+defm V_FMAC_F32 : VOP2_Real_gfx10_gfx11_gfx12<0x02b>;
+defm V_FMAMK_F32 : VOP2Only_Real_MADK_gfx10_gfx11_gfx12<0x02c>;
+defm V_FMAAK_F32 : VOP2Only_Real_MADK_gfx10_gfx11_gfx12<0x02d>;
defm V_ADD_F16 : VOP2_Real_gfx10<0x032>;
defm V_SUB_F16 : VOP2_Real_gfx10<0x033>;
defm V_SUBREV_F16 : VOP2_Real_gfx10<0x034>;
@@ -1832,11 +1998,11 @@ let IsSingle = 1 in {
// VOP2 no carry-in, carry-out.
defm V_ADD_NC_U32 :
- VOP2_Real_with_name_gfx10_gfx11<0x025, "V_ADD_U32", "v_add_nc_u32">;
+ VOP2_Real_with_name_gfx10_gfx11_gfx12<0x025, "V_ADD_U32", "v_add_nc_u32">;
defm V_SUB_NC_U32 :
- VOP2_Real_with_name_gfx10_gfx11<0x026, "V_SUB_U32", "v_sub_nc_u32">;
+ VOP2_Real_with_name_gfx10_gfx11_gfx12<0x026, "V_SUB_U32", "v_sub_nc_u32">;
defm V_SUBREV_NC_U32 :
- VOP2_Real_with_name_gfx10_gfx11<0x027, "V_SUBREV_U32", "v_subrev_nc_u32">;
+ VOP2_Real_with_name_gfx10_gfx11_gfx12<0x027, "V_SUBREV_U32", "v_subrev_nc_u32">;
// VOP2 carry-in, carry-out.
defm V_ADD_CO_CI_U32 :
@@ -1929,7 +2095,10 @@ multiclass VOP2_Real_gfx6_gfx7_gfx10<bits<6> op> :
VOP2_Real_gfx6_gfx7<op>, VOP2_Real_gfx10<op>;
multiclass VOP2_Real_gfx6_gfx7_gfx10_gfx11<bits<6> op> :
- VOP2_Real_gfx6_gfx7_gfx10<op>, VOP2_Real_FULL_gfx11<op>;
+ VOP2_Real_gfx6_gfx7_gfx10<op>, VOP2_Real_FULL<GFX11Gen, op>;
+
+multiclass VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<bits<6> op> :
+ VOP2_Real_gfx6_gfx7_gfx10_gfx11<op>, VOP2_Real_FULL<GFX12Gen, op>;
multiclass VOP2be_Real_gfx6_gfx7<bits<6> op> :
VOP2_Real_e32_gfx6_gfx7<op>, VOP2be_Real_e64_gfx6_gfx7<op>;
@@ -1991,28 +2160,28 @@ let SubtargetPredicate = isGFX6GFX7 in {
def : VOP2e64InstAlias<V_SUBREV_CO_U32_e64, V_SUBREV_I32_e64_gfx6_gfx7>;
} // End SubtargetPredicate = isGFX6GFX7
-defm V_ADD_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x003>;
-defm V_SUB_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x004>;
-defm V_SUBREV_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x005>;
+defm V_ADD_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x003>;
+defm V_SUB_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x004>;
+defm V_SUBREV_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x005>;
defm V_MAC_LEGACY_F32 : VOP2_Real_gfx6_gfx7_gfx10<0x006>;
defm V_MUL_LEGACY_F32 : VOP2_Real_gfx6_gfx7_gfx10<0x007>;
-defm V_MUL_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x008>;
-defm V_MUL_I32_I24 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x009>;
-defm V_MUL_HI_I32_I24 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x00a>;
-defm V_MUL_U32_U24 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x00b>;
-defm V_MUL_HI_U32_U24 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x00c>;
+defm V_MUL_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x008>;
+defm V_MUL_I32_I24 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x009>;
+defm V_MUL_HI_I32_I24 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x00a>;
+defm V_MUL_U32_U24 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x00b>;
+defm V_MUL_HI_U32_U24 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x00c>;
defm V_MIN_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x00f>;
defm V_MAX_F32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x010>;
-defm V_MIN_I32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x011>;
-defm V_MAX_I32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x012>;
-defm V_MIN_U32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x013>;
-defm V_MAX_U32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x014>;
+defm V_MIN_I32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x011>;
+defm V_MAX_I32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x012>;
+defm V_MIN_U32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x013>;
+defm V_MAX_U32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x014>;
defm V_LSHRREV_B32 : VOP2_Real_gfx6_gfx7_gfx10<0x016>;
defm V_ASHRREV_I32 : VOP2_Real_gfx6_gfx7_gfx10<0x018>;
defm V_LSHLREV_B32 : VOP2_Real_gfx6_gfx7_gfx10<0x01a>;
-defm V_AND_B32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x01b>;
-defm V_OR_B32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x01c>;
-defm V_XOR_B32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11<0x01d>;
+defm V_AND_B32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x01b>;
+defm V_OR_B32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x01c>;
+defm V_XOR_B32 : VOP2_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x01d>;
defm V_MAC_F32 : VOP2_Real_gfx6_gfx7_gfx10<0x01f>;
defm V_CVT_PKRTZ_F16_F32 : VOP2_Real_gfx6_gfx7_gfx10<0x02f>;
defm V_MADMK_F32 : VOP2Only_Real_MADK_gfx6_gfx7_gfx10<0x020>;
diff --git a/llvm/lib/Target/AMDGPU/VOP3Instructions.td b/llvm/lib/Target/AMDGPU/VOP3Instructions.td
index 114d33b07786..eebd323210f9 100644
--- a/llvm/lib/Target/AMDGPU/VOP3Instructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP3Instructions.td
@@ -144,11 +144,15 @@ defm V_LERP_U8 : VOP3Inst <"v_lerp_u8", VOP3_Profile<VOP_I32_I32_I32_I32>, int_a
let SchedRW = [WriteDoubleAdd] in {
let FPDPRounding = 1 in {
defm V_FMA_F64 : VOP3Inst <"v_fma_f64", VOP3_Profile<VOP_F64_F64_F64_F64>, any_fma>;
+let SubtargetPredicate = isNotGFX12Plus in {
defm V_ADD_F64 : VOP3Inst <"v_add_f64", VOP3_Profile<VOP_F64_F64_F64>, any_fadd>;
defm V_MUL_F64 : VOP3Inst <"v_mul_f64", VOP3_Profile<VOP_F64_F64_F64>, any_fmul>;
+} // End SubtargetPredicate = isNotGFX12Plus
} // End FPDPRounding = 1
+let SubtargetPredicate = isNotGFX12Plus in {
defm V_MIN_F64 : VOP3Inst <"v_min_f64", VOP3_Profile<VOP_F64_F64_F64>, fminnum_like>;
defm V_MAX_F64 : VOP3Inst <"v_max_f64", VOP3_Profile<VOP_F64_F64_F64>, fmaxnum_like>;
+} // End SubtargetPredicate = isNotGFX12Plus
} // End SchedRW = [WriteDoubleAdd]
let SchedRW = [WriteIntMul] in {
@@ -157,6 +161,19 @@ defm V_MUL_HI_U32 : VOP3Inst <"v_mul_hi_u32", V_MUL_PROF<VOP_I32_I32_I32>, mulhu
defm V_MUL_LO_I32 : VOP3Inst <"v_mul_lo_i32", V_MUL_PROF<VOP_I32_I32_I32>>;
defm V_MUL_HI_I32 : VOP3Inst <"v_mul_hi_i32", V_MUL_PROF<VOP_I32_I32_I32>, mulhs>;
} // End SchedRW = [WriteIntMul]
+
+let SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0 in {
+defm V_MINIMUM_F32 : VOP3Inst <"v_minimum_f32", VOP3_Profile<VOP_F32_F32_F32>, DivergentBinFrag<fminimum>>;
+defm V_MAXIMUM_F32 : VOP3Inst <"v_maximum_f32", VOP3_Profile<VOP_F32_F32_F32>, DivergentBinFrag<fmaximum>>;
+defm V_MINIMUM_F16 : VOP3Inst <"v_minimum_f16", VOP3_Profile<VOP_F16_F16_F16>, DivergentBinFrag<fminimum>>;
+defm V_MAXIMUM_F16 : VOP3Inst <"v_maximum_f16", VOP3_Profile<VOP_F16_F16_F16>, DivergentBinFrag<fmaximum>>;
+
+let SchedRW = [WriteDoubleAdd] in {
+defm V_MINIMUM_F64 : VOP3Inst <"v_minimum_f64", VOP3_Profile<VOP_F64_F64_F64>, fminimum>;
+defm V_MAXIMUM_F64 : VOP3Inst <"v_maximum_f64", VOP3_Profile<VOP_F64_F64_F64>, fmaximum>;
+} // End SchedRW = [WriteDoubleAdd]
+} // End SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0
+
} // End isReMaterializable = 1
let Uses = [MODE, VCC, EXEC] in {
@@ -207,6 +224,11 @@ let mayRaiseFPException = 0 in {
defm V_MED3_F32 : VOP3Inst <"v_med3_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, AMDGPUfmed3>;
} // End mayRaiseFPException = 0
+let SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0 in {
+ defm V_MINIMUM3_F32 : VOP3Inst <"v_minimum3_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, AMDGPUfminimum3>;
+ defm V_MAXIMUM3_F32 : VOP3Inst <"v_maximum3_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, AMDGPUfmaximum3>;
+} // End SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0
+
let isCommutable = 1 in {
defm V_SAD_U8 : VOP3Inst <"v_sad_u8", VOP3_Profile<VOP_I32_I32_I32_I32, VOP3_CLAMP>>;
defm V_SAD_HI_U8 : VOP3Inst <"v_sad_hi_u8", VOP3_Profile<VOP_I32_I32_I32_I32, VOP3_CLAMP>>;
@@ -254,10 +276,13 @@ let SchedRW = [Write64Bit] in {
} // End SubtargetPredicate = isGFX6GFX7
let SubtargetPredicate = isGFX8Plus in {
- defm V_LSHLREV_B64 : VOP3Inst <"v_lshlrev_b64", VOP3_Profile<VOP_I64_I32_I64>, clshl_rev_64>;
defm V_LSHRREV_B64 : VOP3Inst <"v_lshrrev_b64", VOP3_Profile<VOP_I64_I32_I64>, clshr_rev_64>;
defm V_ASHRREV_I64 : VOP3Inst <"v_ashrrev_i64", VOP3_Profile<VOP_I64_I32_I64>, cashr_rev_64>;
} // End SubtargetPredicate = isGFX8Plus
+
+ let SubtargetPredicate = isGFX8GFX9GFX10GFX11 in {
+ defm V_LSHLREV_B64 : VOP3Inst <"v_lshlrev_b64", VOP3_Profile<VOP_I64_I32_I64>, clshl_rev_64>;
+ } // End SubtargetPredicate = isGFX8GFX9GFX10GFX11
} // End SchedRW = [Write64Bit]
} // End isReMaterializable = 1
@@ -548,6 +573,11 @@ defm V_MAX3_F16 : VOP3Inst <"v_max3_f16", VOP3_Profile<VOP_F16_F16_F16_F16, VOP3
defm V_MAX3_I16 : VOP3Inst <"v_max3_i16", VOP3_Profile<VOP_I16_I16_I16_I16, VOP3_OPSEL>, AMDGPUsmax3>;
defm V_MAX3_U16 : VOP3Inst <"v_max3_u16", VOP3_Profile<VOP_I16_I16_I16_I16, VOP3_OPSEL>, AMDGPUumax3>;
+let SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0 in {
+ defm V_MINIMUM3_F16 : VOP3Inst <"v_minimum3_f16", VOP3_Profile<VOP_F16_F16_F16_F16, VOP3_OPSEL>, AMDGPUfminimum3>;
+ defm V_MAXIMUM3_F16 : VOP3Inst <"v_maximum3_f16", VOP3_Profile<VOP_F16_F16_F16_F16, VOP3_OPSEL>, AMDGPUfmaximum3>;
+} // End SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0
+
defm V_ADD_I16 : VOP3Inst <"v_add_i16", VOP3_Profile<VOP_I16_I16_I16, VOP3_OPSEL>>;
defm V_SUB_I16 : VOP3Inst <"v_sub_i16", VOP3_Profile<VOP_I16_I16_I16, VOP3_OPSEL>>;
@@ -678,11 +708,22 @@ multiclass IMAD32_Pats <VOP3_Pseudo inst> {
>;
}
+// Handle cases where amdgpu-codegenprepare-mul24 made a mul24 instead of a normal mul.
+// We need to separate this because otherwise OtherPredicates would be overriden.
+class IMAD32_Mul24_Pat<VOP3_Pseudo inst>: GCNPat <
+ (i64 (add (i64 (AMDGPUmul_u24 i32:$src0, i32:$src1)), i64:$src2)),
+ (inst $src0, $src1, $src2, 0 /* clamp */)
+ >;
+
// exclude pre-GFX9 where it was slow
-let OtherPredicates = [HasNotMADIntraFwdBug], SubtargetPredicate = isGFX9Plus in
+let OtherPredicates = [HasNotMADIntraFwdBug], SubtargetPredicate = isGFX9Plus in {
defm : IMAD32_Pats<V_MAD_U64_U32_e64>;
-let OtherPredicates = [HasMADIntraFwdBug], SubtargetPredicate = isGFX11Only in
+ def : IMAD32_Mul24_Pat<V_MAD_U64_U32_e64>;
+}
+let OtherPredicates = [HasMADIntraFwdBug], SubtargetPredicate = isGFX11Only in {
defm : IMAD32_Pats<V_MAD_U64_U32_gfx11_e64>;
+ def : IMAD32_Mul24_Pat<V_MAD_U64_U32_gfx11_e64>;
+}
def VOP3_PERMLANE_Profile : VOP3_Profile<VOPProfile <[i32, i32, i32, i32]>, VOP3_OPSEL> {
let InsVOP3OpSel = (ins IntOpSelMods:$src0_modifiers, VRegSrc_32:$src0,
@@ -694,6 +735,15 @@ def VOP3_PERMLANE_Profile : VOP3_Profile<VOPProfile <[i32, i32, i32, i32]>, VOP3
let HasExtDPP = 0;
}
+def VOP3_PERMLANE_VAR_Profile : VOP3_Profile<VOPProfile <[i32, i32, i32, untyped]>, VOP3_OPSEL> {
+ let InsVOP3OpSel = (ins IntOpSelMods:$src0_modifiers, VRegSrc_32:$src0,
+ IntOpSelMods:$src1_modifiers, VRegSrc_32:$src1,
+ VGPR_32:$vdst_in, op_sel0:$op_sel);
+ let HasClamp = 0;
+ let HasExtVOP3DPP = 0;
+ let HasExtDPP = 0;
+}
+
def opsel_i1timm : SDNodeXForm<timm, [{
return CurDAG->getTargetConstant(
N->getZExtValue() ? SISrcMods::OP_SEL_0 : SISrcMods::NONE,
@@ -710,6 +760,13 @@ class PermlanePat<SDPatternOperator permlane,
SCSrc_b32:$src1, 0, SCSrc_b32:$src2, VGPR_32:$vdst_in)
>;
+class PermlaneVarPat<SDPatternOperator permlane,
+ Instruction inst> : GCNPat<
+ (permlane i32:$vdst_in, i32:$src0, i32:$src1,
+ timm:$fi, timm:$bc),
+ (inst (opsel_i1timm $fi), VGPR_32:$src0, (opsel_i1timm $bc),
+ VGPR_32:$src1, VGPR_32:$vdst_in)
+>;
let SubtargetPredicate = isGFX10Plus in {
let isCommutable = 1, isReMaterializable = 1 in {
@@ -740,6 +797,17 @@ let SubtargetPredicate = isGFX10Plus in {
} // End SubtargetPredicate = isGFX10Plus
+let SubtargetPredicate = isGFX12Plus in {
+ let Constraints = "$vdst = $vdst_in", DisableEncoding="$vdst_in" in {
+ defm V_PERMLANE16_VAR_B32 : VOP3Inst<"v_permlane16_var_b32", VOP3_PERMLANE_VAR_Profile>;
+ defm V_PERMLANEX16_VAR_B32 : VOP3Inst<"v_permlanex16_var_b32", VOP3_PERMLANE_VAR_Profile>;
+ } // End $vdst = $vdst_in, DisableEncoding $vdst_in
+
+ def : PermlaneVarPat<int_amdgcn_permlane16_var, V_PERMLANE16_VAR_B32_e64>;
+ def : PermlaneVarPat<int_amdgcn_permlanex16_var, V_PERMLANEX16_VAR_B32_e64>;
+
+} // End SubtargetPredicate = isGFX12Plus
+
class DivFmasPat<ValueType vt, Instruction inst, Register CondReg> : GCNPat<
(AMDGPUdiv_fmas (vt (VOP3Mods vt:$src0, i32:$src0_modifiers)),
(vt (VOP3Mods vt:$src1, i32:$src1_modifiers)),
@@ -787,11 +855,61 @@ let SubtargetPredicate = isGFX11Plus in {
defm V_CVT_PK_U16_F32 : VOP3Inst<"v_cvt_pk_u16_f32", VOP3_Profile<VOP_V2I16_F32_F32>>;
} // End SubtargetPredicate = isGFX11Plus
+let SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0 in {
+ defm V_MAXIMUMMINIMUM_F32 : VOP3Inst<"v_maximumminimum_f32", VOP3_Profile<VOP_F32_F32_F32_F32>>;
+ defm V_MINIMUMMAXIMUM_F32 : VOP3Inst<"v_minimummaximum_f32", VOP3_Profile<VOP_F32_F32_F32_F32>>;
+ defm V_MAXIMUMMINIMUM_F16 : VOP3Inst<"v_maximumminimum_f16", VOP3_Profile<VOP_F16_F16_F16_F16, VOP3_OPSEL>>;
+ defm V_MINIMUMMAXIMUM_F16 : VOP3Inst<"v_minimummaximum_f16", VOP3_Profile<VOP_F16_F16_F16_F16, VOP3_OPSEL>>;
+} // End SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0
+
let SubtargetPredicate = HasDot9Insts, IsDOT=1 in {
defm V_DOT2_F16_F16 : VOP3Inst<"v_dot2_f16_f16", VOP3_DOT_Profile<VOP_F16_V2F16_V2F16_F16>, int_amdgcn_fdot2_f16_f16>;
defm V_DOT2_BF16_BF16 : VOP3Inst<"v_dot2_bf16_bf16", VOP3_DOT_Profile<VOP_I16_V2I16_V2I16_I16>, int_amdgcn_fdot2_bf16_bf16>;
}
+class VOP_Pseudo_Scalar<RegisterClass Dst, RegisterOperand SrcOp,
+ ValueType dstVt, ValueType srcVt = dstVt>
+ : VOPProfile<[dstVt, srcVt, untyped, untyped]> {
+ let DstRC = VOPDstOperand<Dst>;
+ let Src0RC64 = SrcOp;
+
+ let HasOMod = 1;
+ let HasModifiers = 1;
+}
+
+def VOP_Pseudo_Scalar_F32 : VOP_Pseudo_Scalar<SReg_32_XEXEC, SSrc_f32, f32>;
+def VOP_Pseudo_Scalar_F16 : VOP_Pseudo_Scalar<SReg_32_XEXEC, SSrc_f16, f32, f16>;
+
+let SubtargetPredicate = HasPseudoScalarTrans, TRANS = 1,
+ isReMaterializable = 1, SchedRW = [WritePseudoScalarTrans] in {
+ defm V_S_EXP_F32 : VOP3PseudoScalarInst<"v_s_exp_f32", VOP_Pseudo_Scalar_F32, AMDGPUexp>;
+ defm V_S_EXP_F16 : VOP3PseudoScalarInst<"v_s_exp_f16", VOP_Pseudo_Scalar_F16>;
+ defm V_S_LOG_F32 : VOP3PseudoScalarInst<"v_s_log_f32", VOP_Pseudo_Scalar_F32, AMDGPUlog>;
+ defm V_S_LOG_F16 : VOP3PseudoScalarInst<"v_s_log_f16", VOP_Pseudo_Scalar_F16>;
+ defm V_S_RCP_F32 : VOP3PseudoScalarInst<"v_s_rcp_f32", VOP_Pseudo_Scalar_F32, AMDGPUrcp>;
+ defm V_S_RCP_F16 : VOP3PseudoScalarInst<"v_s_rcp_f16", VOP_Pseudo_Scalar_F16>;
+ defm V_S_RSQ_F32 : VOP3PseudoScalarInst<"v_s_rsq_f32", VOP_Pseudo_Scalar_F32, AMDGPUrsq>;
+ defm V_S_RSQ_F16 : VOP3PseudoScalarInst<"v_s_rsq_f16", VOP_Pseudo_Scalar_F16>;
+ defm V_S_SQRT_F32 : VOP3PseudoScalarInst<"v_s_sqrt_f32", VOP_Pseudo_Scalar_F32, any_amdgcn_sqrt>;
+ defm V_S_SQRT_F16 : VOP3PseudoScalarInst<"v_s_sqrt_f16", VOP_Pseudo_Scalar_F16>;
+}
+
+class PseudoScalarPatF16<SDPatternOperator node, VOP3_Pseudo inst> : GCNPat <
+ (f16 (UniformUnaryFrag<node> (f16 (VOP3Mods0 f16:$src0, i32:$src0_modifiers,
+ i1:$clamp, i32:$omod)))),
+ (f16 (COPY_TO_REGCLASS (f32 (inst i32:$src0_modifiers, f16:$src0, i1:$clamp,
+ i32:$omod)),
+ SReg_32_XEXEC))
+>;
+
+let SubtargetPredicate = HasPseudoScalarTrans in {
+ def : PseudoScalarPatF16<AMDGPUexpf16, V_S_EXP_F16_e64>;
+ def : PseudoScalarPatF16<AMDGPUlogf16, V_S_LOG_F16_e64>;
+ def : PseudoScalarPatF16<AMDGPUrcp, V_S_RCP_F16_e64>;
+ def : PseudoScalarPatF16<AMDGPUrsq, V_S_RSQ_F16_e64>;
+ def : PseudoScalarPatF16<any_amdgcn_sqrt, V_S_SQRT_F16_e64>;
+}
+
//===----------------------------------------------------------------------===//
// Integer Clamp Patterns
//===----------------------------------------------------------------------===//
@@ -837,125 +955,195 @@ def : IntClampPat<V_MQSAD_U32_U8_e64, int_amdgcn_mqsad_u32_u8>;
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
-// GFX11.
+// GFX12.
+//===----------------------------------------------------------------------===//
+
+defm V_MIN3_NUM_F32 : VOP3_Realtriple_with_name_gfx12<0x229, "V_MIN3_F32", "v_min3_num_f32">;
+defm V_MAX3_NUM_F32 : VOP3_Realtriple_with_name_gfx12<0x22a, "V_MAX3_F32", "v_max3_num_f32">;
+defm V_MIN3_NUM_F16 : VOP3_Realtriple_with_name_gfx12<0x22b, "V_MIN3_F16", "v_min3_num_f16">;
+defm V_MAX3_NUM_F16 : VOP3_Realtriple_with_name_gfx12<0x22c, "V_MAX3_F16", "v_max3_num_f16">;
+defm V_MINIMUM3_F32 : VOP3Only_Realtriple_gfx12<0x22d>;
+defm V_MAXIMUM3_F32 : VOP3Only_Realtriple_gfx12<0x22e>;
+defm V_MINIMUM3_F16 : VOP3Only_Realtriple_t16_gfx12<0x22f>;
+defm V_MAXIMUM3_F16 : VOP3Only_Realtriple_t16_gfx12<0x230>;
+defm V_MED3_NUM_F32 : VOP3_Realtriple_with_name_gfx12<0x231, "V_MED3_F32", "v_med3_num_f32">;
+defm V_MED3_NUM_F16 : VOP3_Realtriple_with_name_gfx12<0x232, "V_MED3_F16", "v_med3_num_f16">;
+defm V_MINMAX_NUM_F32 : VOP3_Realtriple_with_name_gfx12<0x268, "V_MINMAX_F32", "v_minmax_num_f32">;
+defm V_MAXMIN_NUM_F32 : VOP3_Realtriple_with_name_gfx12<0x269, "V_MAXMIN_F32", "v_maxmin_num_f32">;
+defm V_MINMAX_NUM_F16 : VOP3_Realtriple_with_name_gfx12<0x26a, "V_MINMAX_F16", "v_minmax_num_f16">;
+defm V_MAXMIN_NUM_F16 : VOP3_Realtriple_with_name_gfx12<0x26b, "V_MAXMIN_F16", "v_maxmin_num_f16">;
+defm V_MINIMUMMAXIMUM_F32 : VOP3Only_Realtriple_gfx12<0x26c>;
+defm V_MAXIMUMMINIMUM_F32 : VOP3Only_Realtriple_gfx12<0x26d>;
+defm V_MINIMUMMAXIMUM_F16 : VOP3Only_Realtriple_t16_gfx12<0x26e>;
+defm V_MAXIMUMMINIMUM_F16 : VOP3Only_Realtriple_t16_gfx12<0x26f>;
+defm V_S_EXP_F32 : VOP3Only_Real_Base_gfx12<0x280>;
+defm V_S_EXP_F16 : VOP3Only_Real_Base_gfx12<0x281>;
+defm V_S_LOG_F32 : VOP3Only_Real_Base_gfx12<0x282>;
+defm V_S_LOG_F16 : VOP3Only_Real_Base_gfx12<0x283>;
+defm V_S_RCP_F32 : VOP3Only_Real_Base_gfx12<0x284>;
+defm V_S_RCP_F16 : VOP3Only_Real_Base_gfx12<0x285>;
+defm V_S_RSQ_F32 : VOP3Only_Real_Base_gfx12<0x286>;
+defm V_S_RSQ_F16 : VOP3Only_Real_Base_gfx12<0x287>;
+defm V_S_SQRT_F32 : VOP3Only_Real_Base_gfx12<0x288>;
+defm V_S_SQRT_F16 : VOP3Only_Real_Base_gfx12<0x289>;
+defm V_MAD_CO_U64_U32 : VOP3be_Real_with_name_gfx12<0x2fe, "V_MAD_U64_U32", "v_mad_co_u64_u32">;
+defm V_MAD_CO_I64_I32 : VOP3be_Real_with_name_gfx12<0x2ff, "V_MAD_I64_I32", "v_mad_co_i64_i32">;
+defm V_MINIMUM_F64 : VOP3Only_Real_Base_gfx12<0x341>;
+defm V_MAXIMUM_F64 : VOP3Only_Real_Base_gfx12<0x342>;
+defm V_MINIMUM_F32 : VOP3Only_Realtriple_gfx12<0x365>;
+defm V_MAXIMUM_F32 : VOP3Only_Realtriple_gfx12<0x366>;
+defm V_MINIMUM_F16 : VOP3Only_Realtriple_t16_gfx12<0x367>;
+defm V_MAXIMUM_F16 : VOP3Only_Realtriple_t16_gfx12<0x368>;
+
+defm V_PERMLANE16_VAR_B32 : VOP3Only_Real_Base_gfx12<0x30f>;
+defm V_PERMLANEX16_VAR_B32 : VOP3Only_Real_Base_gfx12<0x310>;
+
+//===----------------------------------------------------------------------===//
+// GFX11, GFX12
//===----------------------------------------------------------------------===//
-defm V_FMA_DX9_ZERO_F32 : VOP3_Real_with_name_gfx11<0x209, "V_FMA_LEGACY_F32", "v_fma_dx9_zero_f32">;
-defm V_MAD_I32_I24 : VOP3_Realtriple_gfx11<0x20a>;
-defm V_MAD_U32_U24 : VOP3_Realtriple_gfx11<0x20b>;
-defm V_CUBEID_F32 : VOP3_Realtriple_gfx11<0x20c>;
-defm V_CUBESC_F32 : VOP3_Realtriple_gfx11<0x20d>;
-defm V_CUBETC_F32 : VOP3_Realtriple_gfx11<0x20e>;
-defm V_CUBEMA_F32 : VOP3_Realtriple_gfx11<0x20f>;
-defm V_BFE_U32 : VOP3_Realtriple_gfx11<0x210>;
-defm V_BFE_I32 : VOP3_Realtriple_gfx11<0x211>;
-defm V_BFI_B32 : VOP3_Realtriple_gfx11<0x212>;
-defm V_FMA_F32 : VOP3_Realtriple_gfx11<0x213>;
-defm V_FMA_F64 : VOP3_Real_Base_gfx11<0x214>;
-defm V_LERP_U8 : VOP3_Realtriple_gfx11<0x215>;
-defm V_ALIGNBIT_B32 : VOP3_Realtriple_gfx11<0x216>;
-defm V_ALIGNBYTE_B32 : VOP3_Realtriple_gfx11<0x217>;
-defm V_MULLIT_F32 : VOP3_Realtriple_gfx11<0x218>;
+multiclass VOP3_Real_with_name_gfx11_gfx12<bits<10> op, string opName,
+ string asmName> :
+ VOP3_Real_with_name<GFX11Gen, op, opName, asmName>,
+ VOP3_Real_with_name<GFX12Gen, op, opName, asmName>;
+
+multiclass VOP3_Realtriple_gfx11_gfx12<bits<10> op> :
+ VOP3_Realtriple<GFX11Gen, op>, VOP3_Realtriple<GFX12Gen, op>;
+
+multiclass VOP3_Real_Base_gfx11_gfx12<bits<10> op> :
+ VOP3_Real_Base<GFX11Gen, op>, VOP3_Real_Base<GFX12Gen, op>;
+
+multiclass VOP3_Realtriple_with_name_gfx11_gfx12<bits<10> op, string opName,
+ string asmName> :
+ VOP3_Realtriple_with_name<GFX11Gen, op, opName, asmName>,
+ VOP3_Realtriple_with_name<GFX12Gen, op, opName, asmName>;
+
+multiclass VOP3Dot_Realtriple_gfx11_gfx12<bits<10> op> :
+ VOP3Dot_Realtriple<GFX11Gen, op>, VOP3Dot_Realtriple<GFX12Gen, op>;
+
+multiclass VOP3be_Real_gfx11_gfx12<bits<10> op, string opName, string asmName> :
+ VOP3be_Real<GFX11Gen, op, opName, asmName>,
+ VOP3be_Real<GFX12Gen, op, opName, asmName>;
+
+multiclass VOP3_Real_No_Suffix_gfx11_gfx12<bits<10> op> :
+ VOP3_Real_No_Suffix<GFX11Gen, op>, VOP3_Real_No_Suffix<GFX12Gen, op>;
+
+defm V_FMA_DX9_ZERO_F32 : VOP3_Real_with_name_gfx11_gfx12<0x209, "V_FMA_LEGACY_F32", "v_fma_dx9_zero_f32">;
+defm V_MAD_I32_I24 : VOP3_Realtriple_gfx11_gfx12<0x20a>;
+defm V_MAD_U32_U24 : VOP3_Realtriple_gfx11_gfx12<0x20b>;
+defm V_CUBEID_F32 : VOP3_Realtriple_gfx11_gfx12<0x20c>;
+defm V_CUBESC_F32 : VOP3_Realtriple_gfx11_gfx12<0x20d>;
+defm V_CUBETC_F32 : VOP3_Realtriple_gfx11_gfx12<0x20e>;
+defm V_CUBEMA_F32 : VOP3_Realtriple_gfx11_gfx12<0x20f>;
+defm V_BFE_U32 : VOP3_Realtriple_gfx11_gfx12<0x210>;
+defm V_BFE_I32 : VOP3_Realtriple_gfx11_gfx12<0x211>;
+defm V_BFI_B32 : VOP3_Realtriple_gfx11_gfx12<0x212>;
+defm V_FMA_F32 : VOP3_Realtriple_gfx11_gfx12<0x213>;
+defm V_FMA_F64 : VOP3_Real_Base_gfx11_gfx12<0x214>;
+defm V_LERP_U8 : VOP3_Realtriple_gfx11_gfx12<0x215>;
+defm V_ALIGNBIT_B32 : VOP3_Realtriple_gfx11_gfx12<0x216>;
+defm V_ALIGNBYTE_B32 : VOP3_Realtriple_gfx11_gfx12<0x217>;
+defm V_MULLIT_F32 : VOP3_Realtriple_gfx11_gfx12<0x218>;
defm V_MIN3_F32 : VOP3_Realtriple_gfx11<0x219>;
-defm V_MIN3_I32 : VOP3_Realtriple_gfx11<0x21a>;
-defm V_MIN3_U32 : VOP3_Realtriple_gfx11<0x21b>;
+defm V_MIN3_I32 : VOP3_Realtriple_gfx11_gfx12<0x21a>;
+defm V_MIN3_U32 : VOP3_Realtriple_gfx11_gfx12<0x21b>;
defm V_MAX3_F32 : VOP3_Realtriple_gfx11<0x21c>;
-defm V_MAX3_I32 : VOP3_Realtriple_gfx11<0x21d>;
-defm V_MAX3_U32 : VOP3_Realtriple_gfx11<0x21e>;
+defm V_MAX3_I32 : VOP3_Realtriple_gfx11_gfx12<0x21d>;
+defm V_MAX3_U32 : VOP3_Realtriple_gfx11_gfx12<0x21e>;
defm V_MED3_F32 : VOP3_Realtriple_gfx11<0x21f>;
-defm V_MED3_I32 : VOP3_Realtriple_gfx11<0x220>;
-defm V_MED3_U32 : VOP3_Realtriple_gfx11<0x221>;
-defm V_SAD_U8 : VOP3_Realtriple_gfx11<0x222>;
-defm V_SAD_HI_U8 : VOP3_Realtriple_gfx11<0x223>;
-defm V_SAD_U16 : VOP3_Realtriple_gfx11<0x224>;
-defm V_SAD_U32 : VOP3_Realtriple_gfx11<0x225>;
-defm V_CVT_PK_U8_F32 : VOP3_Realtriple_gfx11<0x226>;
-defm V_DIV_FIXUP_F32 : VOP3_Real_Base_gfx11<0x227>;
-defm V_DIV_FIXUP_F64 : VOP3_Real_Base_gfx11<0x228>;
-defm V_DIV_FMAS_F32 : VOP3_Real_Base_gfx11<0x237>;
-defm V_DIV_FMAS_F64 : VOP3_Real_Base_gfx11<0x238>;
-defm V_MSAD_U8 : VOP3_Realtriple_gfx11<0x239>;
-defm V_QSAD_PK_U16_U8 : VOP3_Real_Base_gfx11<0x23a>;
-defm V_MQSAD_PK_U16_U8 : VOP3_Real_Base_gfx11<0x23b>;
-defm V_MQSAD_U32_U8 : VOP3_Real_Base_gfx11<0x23d>;
-defm V_XOR3_B32 : VOP3_Realtriple_gfx11<0x240>;
-defm V_MAD_U16 : VOP3_Realtriple_with_name_gfx11<0x241, "V_MAD_U16_gfx9", "v_mad_u16">;
-defm V_PERM_B32 : VOP3_Realtriple_gfx11<0x244>;
-defm V_XAD_U32 : VOP3_Realtriple_gfx11<0x245>;
-defm V_LSHL_ADD_U32 : VOP3_Realtriple_gfx11<0x246>;
-defm V_ADD_LSHL_U32 : VOP3_Realtriple_gfx11<0x247>;
-defm V_FMA_F16 : VOP3_Realtriple_with_name_gfx11<0x248, "V_FMA_F16_gfx9", "v_fma_f16">;
+defm V_MED3_I32 : VOP3_Realtriple_gfx11_gfx12<0x220>;
+defm V_MED3_U32 : VOP3_Realtriple_gfx11_gfx12<0x221>;
+defm V_SAD_U8 : VOP3_Realtriple_gfx11_gfx12<0x222>;
+defm V_SAD_HI_U8 : VOP3_Realtriple_gfx11_gfx12<0x223>;
+defm V_SAD_U16 : VOP3_Realtriple_gfx11_gfx12<0x224>;
+defm V_SAD_U32 : VOP3_Realtriple_gfx11_gfx12<0x225>;
+defm V_CVT_PK_U8_F32 : VOP3_Realtriple_gfx11_gfx12<0x226>;
+defm V_DIV_FIXUP_F32 : VOP3_Real_Base_gfx11_gfx12<0x227>;
+defm V_DIV_FIXUP_F64 : VOP3_Real_Base_gfx11_gfx12<0x228>;
+defm V_DIV_FMAS_F32 : VOP3_Real_Base_gfx11_gfx12<0x237>;
+defm V_DIV_FMAS_F64 : VOP3_Real_Base_gfx11_gfx12<0x238>;
+defm V_MSAD_U8 : VOP3_Realtriple_gfx11_gfx12<0x239>;
+defm V_QSAD_PK_U16_U8 : VOP3_Real_Base_gfx11_gfx12<0x23a>;
+defm V_MQSAD_PK_U16_U8 : VOP3_Real_Base_gfx11_gfx12<0x23b>;
+defm V_MQSAD_U32_U8 : VOP3_Real_Base_gfx11_gfx12<0x23d>;
+defm V_XOR3_B32 : VOP3_Realtriple_gfx11_gfx12<0x240>;
+defm V_MAD_U16 : VOP3_Realtriple_with_name_gfx11_gfx12<0x241, "V_MAD_U16_gfx9", "v_mad_u16">;
+defm V_PERM_B32 : VOP3_Realtriple_gfx11_gfx12<0x244>;
+defm V_XAD_U32 : VOP3_Realtriple_gfx11_gfx12<0x245>;
+defm V_LSHL_ADD_U32 : VOP3_Realtriple_gfx11_gfx12<0x246>;
+defm V_ADD_LSHL_U32 : VOP3_Realtriple_gfx11_gfx12<0x247>;
+defm V_FMA_F16 : VOP3_Realtriple_with_name_gfx11_gfx12<0x248, "V_FMA_F16_gfx9", "v_fma_f16">;
defm V_MIN3_F16 : VOP3_Realtriple_gfx11<0x249>;
-defm V_MIN3_I16 : VOP3_Realtriple_gfx11<0x24a>;
-defm V_MIN3_U16 : VOP3_Realtriple_gfx11<0x24b>;
+defm V_MIN3_I16 : VOP3_Realtriple_gfx11_gfx12<0x24a>;
+defm V_MIN3_U16 : VOP3_Realtriple_gfx11_gfx12<0x24b>;
defm V_MAX3_F16 : VOP3_Realtriple_gfx11<0x24c>;
-defm V_MAX3_I16 : VOP3_Realtriple_gfx11<0x24d>;
-defm V_MAX3_U16 : VOP3_Realtriple_gfx11<0x24e>;
+defm V_MAX3_I16 : VOP3_Realtriple_gfx11_gfx12<0x24d>;
+defm V_MAX3_U16 : VOP3_Realtriple_gfx11_gfx12<0x24e>;
defm V_MED3_F16 : VOP3_Realtriple_gfx11<0x24f>;
-defm V_MED3_I16 : VOP3_Realtriple_gfx11<0x250>;
-defm V_MED3_U16 : VOP3_Realtriple_gfx11<0x251>;
-defm V_MAD_I16 : VOP3_Realtriple_with_name_gfx11<0x253, "V_MAD_I16_gfx9", "v_mad_i16">;
-defm V_DIV_FIXUP_F16 : VOP3_Realtriple_with_name_gfx11<0x254, "V_DIV_FIXUP_F16_gfx9", "v_div_fixup_f16">;
-defm V_ADD3_U32 : VOP3_Realtriple_gfx11<0x255>;
-defm V_LSHL_OR_B32 : VOP3_Realtriple_gfx11<0x256>;
-defm V_AND_OR_B32 : VOP3_Realtriple_gfx11<0x257>;
-defm V_OR3_B32 : VOP3_Realtriple_gfx11<0x258>;
-defm V_MAD_U32_U16 : VOP3_Realtriple_gfx11<0x259>;
-defm V_MAD_I32_I16 : VOP3_Realtriple_gfx11<0x25a>;
-defm V_PERMLANE16_B32 : VOP3_Real_Base_gfx11<0x25b>;
-defm V_PERMLANEX16_B32 : VOP3_Real_Base_gfx11<0x25c>;
+defm V_MED3_I16 : VOP3_Realtriple_gfx11_gfx12<0x250>;
+defm V_MED3_U16 : VOP3_Realtriple_gfx11_gfx12<0x251>;
+defm V_MAD_I16 : VOP3_Realtriple_with_name_gfx11_gfx12<0x253, "V_MAD_I16_gfx9", "v_mad_i16">;
+defm V_DIV_FIXUP_F16 : VOP3_Realtriple_with_name_gfx11_gfx12<0x254, "V_DIV_FIXUP_F16_gfx9", "v_div_fixup_f16">;
+defm V_ADD3_U32 : VOP3_Realtriple_gfx11_gfx12<0x255>;
+defm V_LSHL_OR_B32 : VOP3_Realtriple_gfx11_gfx12<0x256>;
+defm V_AND_OR_B32 : VOP3_Realtriple_gfx11_gfx12<0x257>;
+defm V_OR3_B32 : VOP3_Realtriple_gfx11_gfx12<0x258>;
+defm V_MAD_U32_U16 : VOP3_Realtriple_gfx11_gfx12<0x259>;
+defm V_MAD_I32_I16 : VOP3_Realtriple_gfx11_gfx12<0x25a>;
+defm V_PERMLANE16_B32 : VOP3_Real_Base_gfx11_gfx12<0x25b>;
+defm V_PERMLANEX16_B32 : VOP3_Real_Base_gfx11_gfx12<0x25c>;
defm V_MAXMIN_F32 : VOP3_Realtriple_gfx11<0x25e>;
defm V_MINMAX_F32 : VOP3_Realtriple_gfx11<0x25f>;
defm V_MAXMIN_F16 : VOP3_Realtriple_gfx11<0x260>;
defm V_MINMAX_F16 : VOP3_Realtriple_gfx11<0x261>;
-defm V_MAXMIN_U32 : VOP3_Realtriple_gfx11<0x262>;
-defm V_MINMAX_U32 : VOP3_Realtriple_gfx11<0x263>;
-defm V_MAXMIN_I32 : VOP3_Realtriple_gfx11<0x264>;
-defm V_MINMAX_I32 : VOP3_Realtriple_gfx11<0x265>;
-defm V_DOT2_F16_F16 : VOP3Dot_Realtriple_gfx11<0x266>;
-defm V_DOT2_BF16_BF16 : VOP3Dot_Realtriple_gfx11<0x267>;
-defm V_DIV_SCALE_F32 : VOP3be_Real_gfx11<0x2fc, "V_DIV_SCALE_F32", "v_div_scale_f32">;
-defm V_DIV_SCALE_F64 : VOP3be_Real_gfx11<0x2fd, "V_DIV_SCALE_F64", "v_div_scale_f64">;
+defm V_MAXMIN_U32 : VOP3_Realtriple_gfx11_gfx12<0x262>;
+defm V_MINMAX_U32 : VOP3_Realtriple_gfx11_gfx12<0x263>;
+defm V_MAXMIN_I32 : VOP3_Realtriple_gfx11_gfx12<0x264>;
+defm V_MINMAX_I32 : VOP3_Realtriple_gfx11_gfx12<0x265>;
+defm V_DOT2_F16_F16 : VOP3Dot_Realtriple_gfx11_gfx12<0x266>;
+defm V_DOT2_BF16_BF16 : VOP3Dot_Realtriple_gfx11_gfx12<0x267>;
+defm V_DIV_SCALE_F32 : VOP3be_Real_gfx11_gfx12<0x2fc, "V_DIV_SCALE_F32", "v_div_scale_f32">;
+defm V_DIV_SCALE_F64 : VOP3be_Real_gfx11_gfx12<0x2fd, "V_DIV_SCALE_F64", "v_div_scale_f64">;
defm V_MAD_U64_U32_gfx11 : VOP3be_Real_gfx11<0x2fe, "V_MAD_U64_U32_gfx11", "v_mad_u64_u32">;
defm V_MAD_I64_I32_gfx11 : VOP3be_Real_gfx11<0x2ff, "V_MAD_I64_I32_gfx11", "v_mad_i64_i32">;
-defm V_ADD_NC_U16 : VOP3Only_Realtriple_gfx11<0x303>;
-defm V_SUB_NC_U16 : VOP3Only_Realtriple_gfx11<0x304>;
-defm V_MUL_LO_U16_t16 : VOP3Only_Realtriple_t16_gfx11<0x305, "v_mul_lo_u16">;
-defm V_CVT_PK_I16_F32 : VOP3_Realtriple_gfx11<0x306>;
-defm V_CVT_PK_U16_F32 : VOP3_Realtriple_gfx11<0x307>;
-defm V_MAX_U16_t16 : VOP3Only_Realtriple_t16_gfx11<0x309, "v_max_u16">;
-defm V_MAX_I16_t16 : VOP3Only_Realtriple_t16_gfx11<0x30a, "v_max_i16">;
-defm V_MIN_U16_t16 : VOP3Only_Realtriple_t16_gfx11<0x30b, "v_min_u16">;
-defm V_MIN_I16_t16 : VOP3Only_Realtriple_t16_gfx11<0x30c, "v_min_i16">;
-defm V_ADD_NC_I16 : VOP3_Realtriple_with_name_gfx11<0x30d, "V_ADD_I16", "v_add_nc_i16">;
-defm V_SUB_NC_I16 : VOP3_Realtriple_with_name_gfx11<0x30e, "V_SUB_I16", "v_sub_nc_i16">;
-defm V_PACK_B32_F16 : VOP3_Realtriple_gfx11<0x311>;
-defm V_CVT_PK_NORM_I16_F16 : VOP3_Realtriple_with_name_gfx11<0x312, "V_CVT_PKNORM_I16_F16" , "v_cvt_pk_norm_i16_f16" >;
-defm V_CVT_PK_NORM_U16_F16 : VOP3_Realtriple_with_name_gfx11<0x313, "V_CVT_PKNORM_U16_F16" , "v_cvt_pk_norm_u16_f16" >;
-defm V_SUB_NC_I32 : VOP3_Realtriple_with_name_gfx11<0x325, "V_SUB_I32", "v_sub_nc_i32">;
-defm V_ADD_NC_I32 : VOP3_Realtriple_with_name_gfx11<0x326, "V_ADD_I32", "v_add_nc_i32">;
+defm V_ADD_NC_U16 : VOP3Only_Realtriple_gfx11_gfx12<0x303>;
+defm V_SUB_NC_U16 : VOP3Only_Realtriple_gfx11_gfx12<0x304>;
+defm V_MUL_LO_U16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x305, "v_mul_lo_u16">;
+defm V_CVT_PK_I16_F32 : VOP3_Realtriple_gfx11_gfx12<0x306>;
+defm V_CVT_PK_U16_F32 : VOP3_Realtriple_gfx11_gfx12<0x307>;
+defm V_MAX_U16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x309, "v_max_u16">;
+defm V_MAX_I16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x30a, "v_max_i16">;
+defm V_MIN_U16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x30b, "v_min_u16">;
+defm V_MIN_I16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x30c, "v_min_i16">;
+defm V_ADD_NC_I16 : VOP3_Realtriple_with_name_gfx11_gfx12<0x30d, "V_ADD_I16", "v_add_nc_i16">;
+defm V_SUB_NC_I16 : VOP3_Realtriple_with_name_gfx11_gfx12<0x30e, "V_SUB_I16", "v_sub_nc_i16">;
+defm V_PACK_B32_F16 : VOP3_Realtriple_gfx11_gfx12<0x311>;
+defm V_CVT_PK_NORM_I16_F16 : VOP3_Realtriple_with_name_gfx11_gfx12<0x312, "V_CVT_PKNORM_I16_F16" , "v_cvt_pk_norm_i16_f16" >;
+defm V_CVT_PK_NORM_U16_F16 : VOP3_Realtriple_with_name_gfx11_gfx12<0x313, "V_CVT_PKNORM_U16_F16" , "v_cvt_pk_norm_u16_f16" >;
+defm V_SUB_NC_I32 : VOP3_Realtriple_with_name_gfx11_gfx12<0x325, "V_SUB_I32", "v_sub_nc_i32">;
+defm V_ADD_NC_I32 : VOP3_Realtriple_with_name_gfx11_gfx12<0x326, "V_ADD_I32", "v_add_nc_i32">;
defm V_ADD_F64 : VOP3_Real_Base_gfx11<0x327>;
defm V_MUL_F64 : VOP3_Real_Base_gfx11<0x328>;
defm V_MIN_F64 : VOP3_Real_Base_gfx11<0x329>;
defm V_MAX_F64 : VOP3_Real_Base_gfx11<0x32a>;
-defm V_LDEXP_F64 : VOP3_Real_Base_gfx11<0x32b>;
-defm V_MUL_LO_U32 : VOP3_Real_Base_gfx11<0x32c>;
-defm V_MUL_HI_U32 : VOP3_Real_Base_gfx11<0x32d>;
-defm V_MUL_HI_I32 : VOP3_Real_Base_gfx11<0x32e>;
-defm V_TRIG_PREOP_F64 : VOP3_Real_Base_gfx11<0x32f>;
-defm V_LSHLREV_B16_t16 : VOP3Only_Realtriple_t16_gfx11<0x338, "v_lshlrev_b16">;
-defm V_LSHRREV_B16_t16 : VOP3Only_Realtriple_t16_gfx11<0x339, "v_lshrrev_b16">;
-defm V_ASHRREV_I16_t16 : VOP3Only_Realtriple_t16_gfx11<0x33a, "v_ashrrev_i16">;
+defm V_LDEXP_F64 : VOP3_Real_Base_gfx11_gfx12<0x32b>;
+defm V_MUL_LO_U32 : VOP3_Real_Base_gfx11_gfx12<0x32c>;
+defm V_MUL_HI_U32 : VOP3_Real_Base_gfx11_gfx12<0x32d>;
+defm V_MUL_HI_I32 : VOP3_Real_Base_gfx11_gfx12<0x32e>;
+defm V_TRIG_PREOP_F64 : VOP3_Real_Base_gfx11_gfx12<0x32f>;
+defm V_LSHLREV_B16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x338, "v_lshlrev_b16">;
+defm V_LSHRREV_B16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x339, "v_lshrrev_b16">;
+defm V_ASHRREV_I16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x33a, "v_ashrrev_i16">;
defm V_LSHLREV_B64 : VOP3_Real_Base_gfx11<0x33c>;
-defm V_LSHRREV_B64 : VOP3_Real_Base_gfx11<0x33d>;
-defm V_ASHRREV_I64 : VOP3_Real_Base_gfx11<0x33e>;
-defm V_READLANE_B32 : VOP3_Real_No_Suffix_gfx11<0x360>; // Pseudo in VOP2
+defm V_LSHRREV_B64 : VOP3_Real_Base_gfx11_gfx12<0x33d>;
+defm V_ASHRREV_I64 : VOP3_Real_Base_gfx11_gfx12<0x33e>;
+defm V_READLANE_B32 : VOP3_Real_No_Suffix_gfx11_gfx12<0x360>; // Pseudo in VOP2
let InOperandList = (ins SSrcOrLds_b32:$src0, SCSrc_b32:$src1, VGPR_32:$vdst_in) in {
- defm V_WRITELANE_B32 : VOP3_Real_No_Suffix_gfx11<0x361>; // Pseudo in VOP2
+ defm V_WRITELANE_B32 : VOP3_Real_No_Suffix_gfx11_gfx12<0x361>; // Pseudo in VOP2
} // End InOperandList = (ins SSrcOrLds_b32:$src0, SCSrc_b32:$src1, VGPR_32:$vdst_in)
-defm V_AND_B16_t16 : VOP3Only_Realtriple_t16_gfx11<0x362, "v_and_b16">;
-defm V_OR_B16_t16 : VOP3Only_Realtriple_t16_gfx11<0x363, "v_or_b16">;
-defm V_XOR_B16_t16 : VOP3Only_Realtriple_t16_gfx11<0x364, "v_xor_b16">;
+defm V_AND_B16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x362, "v_and_b16">;
+defm V_OR_B16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x363, "v_or_b16">;
+defm V_XOR_B16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x364, "v_xor_b16">;
//===----------------------------------------------------------------------===//
// GFX10.
diff --git a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td
index 07f69f68a1cf..d3cefb339d9e 100644
--- a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td
@@ -108,6 +108,11 @@ defm V_PK_MIN_I16 : VOP3PInst<"v_pk_min_i16", VOP3P_Profile<VOP_V2I16_V2I16_V2I1
defm V_PK_MIN_U16 : VOP3PInst<"v_pk_min_u16", VOP3P_Profile<VOP_V2I16_V2I16_V2I16>, umin>;
defm V_PK_MAX_I16 : VOP3PInst<"v_pk_max_i16", VOP3P_Profile<VOP_V2I16_V2I16_V2I16>, smax>;
defm V_PK_MAX_U16 : VOP3PInst<"v_pk_max_u16", VOP3P_Profile<VOP_V2I16_V2I16_V2I16>, umax>;
+
+let SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0 in {
+defm V_PK_MAXIMUM_F16 : VOP3PInst<"v_pk_maximum_f16", VOP3P_Profile<VOP_V2F16_V2F16_V2F16>, fmaximum>;
+defm V_PK_MINIMUM_F16 : VOP3PInst<"v_pk_minimum_f16", VOP3P_Profile<VOP_V2F16_V2F16_V2F16>, fminimum>;
+} // End SubtargetPredicate = isGFX12Plus, ReadsModeReg = 0
}
defm V_PK_SUB_U16 : VOP3PInst<"v_pk_sub_u16", VOP3P_Profile<VOP_V2I16_V2I16_V2I16>>;
@@ -940,56 +945,89 @@ class VOP3P_DPP8_Base<bits<7> op, VOP_Pseudo ps, string opName = ps.OpName>
}
//===----------------------------------------------------------------------===//
-// GFX11.
+// GFX11, GFX12
//===----------------------------------------------------------------------===//
-let AssemblerPredicate = isGFX11Plus,
- DecoderNamespace = "GFX11" in {
+multiclass VOP3P_Real_Base<GFXGen Gen, bits<7> op, string backing_ps_name = NAME,
+ string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic> {
+ def Gen.Suffix :
+ VOP3P_Real_Gen<!cast<VOP3P_Pseudo>(backing_ps_name), Gen, asmName>,
+ VOP3Pe_gfx11_gfx12<op, !cast<VOP3P_Pseudo>(backing_ps_name).Pfl>;
+}
- multiclass VOP3P_Real_gfx11<bits<7> op, string backing_ps_name = NAME,
- string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic> {
- def _gfx11 : VOP3P_Real<!cast<VOP3P_Pseudo>(backing_ps_name),
- SIEncodingFamily.GFX11, asmName>,
- VOP3Pe_gfx11<op, !cast<VOP3P_Pseudo>(backing_ps_name).Pfl>;
- }
+multiclass VOP3P_Real_with_name<GFXGen Gen, bits<7> op,
+ string backing_ps_name = NAME,
+ string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic> {
+ defvar ps = !cast<VOP3P_Pseudo>(backing_ps_name);
+ let AsmString = asmName # ps.AsmOperands in
+ def Gen.Suffix :
+ VOP3P_Real_Gen<!cast<VOP3P_Pseudo>(backing_ps_name), Gen, asmName>,
+ VOP3Pe_gfx11_gfx12<op, !cast<VOP3P_Pseudo>(backing_ps_name).Pfl>,
+ MnemonicAlias<ps.Mnemonic, asmName>, Requires<[Gen.AssemblerPredicate]>;
+}
- multiclass VOP3P_Real_dpp_gfx11<bits<7> op, string backing_ps_name = NAME,
- string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic> {
- defvar ps = !cast<VOP3P_Pseudo>(backing_ps_name);
- def _dpp_gfx11
- : VOP3P_DPP16<op, !cast<VOP_DPP_Pseudo>(backing_ps_name #"_dpp"),
- SIEncodingFamily.GFX11> {
- let AsmString = asmName #ps.Pfl.AsmVOP3DPP16;
- let DecoderNamespace = "DPPGFX11";
- }
+multiclass VOP3P_Real_dpp<GFXGen Gen, bits<7> op, string backing_ps_name = NAME,
+ string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic> {
+ defvar ps = !cast<VOP3P_Pseudo>(backing_ps_name);
+ def _dpp#Gen.Suffix
+ : VOP3P_DPP16<op, !cast<VOP_DPP_Pseudo>(backing_ps_name #"_dpp"),
+ Gen.Subtarget> {
+ let AsmString = asmName #ps.Pfl.AsmVOP3DPP16;
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
}
+}
- multiclass VOP3P_Real_dpp8_gfx11<bits<7> op, string backing_ps_name = NAME,
- string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic> {
- defvar ps = !cast<VOP3P_Pseudo>(backing_ps_name);
- def _dpp8_gfx11 : VOP3P_DPP8_Base<op, ps> {
- let AsmString = asmName #ps.Pfl.AsmVOP3DPP8;
- let DecoderNamespace = "DPP8GFX11";
- }
+multiclass VOP3P_Real_dpp8<GFXGen Gen, bits<7> op, string backing_ps_name = NAME,
+ string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic> {
+ defvar ps = !cast<VOP3P_Pseudo>(backing_ps_name);
+ def _dpp8#Gen.Suffix : VOP3P_DPP8_Base<op, ps> {
+ let AsmString = asmName #ps.Pfl.AsmVOP3DPP8;
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
}
+}
+
+multiclass VOP3P_Realtriple<GFXGen Gen, bits<7> op, string backing_ps_name = NAME,
+ string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic>
+ : VOP3P_Real_Base<Gen, op, backing_ps_name, asmName>,
+ VOP3P_Real_dpp<Gen, op, backing_ps_name, asmName>,
+ VOP3P_Real_dpp8<Gen, op, backing_ps_name, asmName>;
+
+//===----------------------------------------------------------------------===//
+// GFX12
+//===----------------------------------------------------------------------===//
+
+multiclass VOP3P_Real_gfx12<bits<7> op> : VOP3P_Real_Base<GFX12Gen, op>;
+
+multiclass VOP3P_Real_with_name_gfx12<bits<7> op,
+ string backing_ps_name = NAME,
+ string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic> :
+ VOP3P_Real_with_name<GFX12Gen, op, backing_ps_name, asmName>;
+
+defm V_PK_MIN_NUM_F16 : VOP3P_Real_with_name_gfx12<0x1b, "V_PK_MIN_F16", "v_pk_min_num_f16">;
+defm V_PK_MAX_NUM_F16 : VOP3P_Real_with_name_gfx12<0x1c, "V_PK_MAX_F16", "v_pk_max_num_f16">;
+
+defm V_PK_MINIMUM_F16 : VOP3P_Real_gfx12<0x1d>;
+defm V_PK_MAXIMUM_F16 : VOP3P_Real_gfx12<0x1e>;
+
+//===----------------------------------------------------------------------===//
+// GFX11
+//===----------------------------------------------------------------------===//
- multiclass VOP3P_Realtriple_gfx11<bits<7> op, string backing_ps_name = NAME,
- string asmName = !cast<VOP3P_Pseudo>(NAME).Mnemonic>
- : VOP3P_Real_gfx11<op, backing_ps_name, asmName>,
- VOP3P_Real_dpp_gfx11<op, backing_ps_name, asmName>,
- VOP3P_Real_dpp8_gfx11<op, backing_ps_name, asmName>;
-} // End AssemblerPredicate = isGFX11Plus, DecoderNamespace = "GFX11"
+multiclass VOP3P_Real_gfx11_gfx12<bits<7> op> :
+ VOP3P_Real_Base<GFX11Gen, op>, VOP3P_Real_Base<GFX12Gen, op>;
-defm V_DOT4_I32_IU8 : VOP3P_Real_gfx11 <0x16>;
-defm V_DOT8_I32_IU4 : VOP3P_Real_gfx11 <0x18>;
-defm V_DOT2_F32_BF16 : VOP3P_Real_gfx11 <0x1a>;
+defm V_DOT4_I32_IU8 : VOP3P_Real_gfx11_gfx12<0x16>;
+defm V_DOT8_I32_IU4 : VOP3P_Real_gfx11_gfx12<0x18>;
+defm V_DOT2_F32_BF16 : VOP3P_Real_gfx11_gfx12<0x1a>;
multiclass VOP3P_Real_WMMA <bits<7> op> {
let WaveSizePredicate = isWave32, DecoderNamespace = "GFX11" in {
- defm _twoaddr_w32 : VOP3P_Real_gfx11 <op>;
+ defm _twoaddr_w32 : VOP3P_Real_Base <GFX11Gen, op>;
}
let WaveSizePredicate = isWave64, DecoderNamespace = "WMMAGFX11" in {
- defm _twoaddr_w64 : VOP3P_Real_gfx11 <op>;
+ defm _twoaddr_w64 : VOP3P_Real_Base <GFX11Gen, op>;
}
}
@@ -1240,41 +1278,45 @@ let AssemblerPredicate = isGFX10Only, DecoderNamespace = "GFX10", VOP3P = 1 in {
}
} // End AssemblerPredicate = isGFX10Only, DecoderNamespace = "GFX10", VOP3P = 1
-multiclass VOP3P_Real_gfx10_gfx11<bits<7> op>
- : VOP3P_Real_gfx10<op>, VOP3P_Real_gfx11<op>;
-
-multiclass VOP3P_Real_gfx10_gfx11_Triple<bits<7> op>
- : VOP3P_Real_gfx10<op>, VOP3P_Realtriple_gfx11<op>;
-
-defm V_PK_MAD_I16 : VOP3P_Real_gfx10_gfx11<0x00>;
-defm V_PK_MUL_LO_U16 : VOP3P_Real_gfx10_gfx11<0x01>;
-defm V_PK_ADD_I16 : VOP3P_Real_gfx10_gfx11<0x02>;
-defm V_PK_SUB_I16 : VOP3P_Real_gfx10_gfx11<0x03>;
-defm V_PK_LSHLREV_B16 : VOP3P_Real_gfx10_gfx11<0x04>;
-defm V_PK_LSHRREV_B16 : VOP3P_Real_gfx10_gfx11<0x05>;
-defm V_PK_ASHRREV_I16 : VOP3P_Real_gfx10_gfx11<0x06>;
-defm V_PK_MAX_I16 : VOP3P_Real_gfx10_gfx11<0x07>;
-defm V_PK_MIN_I16 : VOP3P_Real_gfx10_gfx11<0x08>;
-defm V_PK_MAD_U16 : VOP3P_Real_gfx10_gfx11<0x09>;
-defm V_PK_ADD_U16 : VOP3P_Real_gfx10_gfx11<0x0a>;
-defm V_PK_SUB_U16 : VOP3P_Real_gfx10_gfx11<0x0b>;
-defm V_PK_MAX_U16 : VOP3P_Real_gfx10_gfx11<0x0c>;
-defm V_PK_MIN_U16 : VOP3P_Real_gfx10_gfx11<0x0d>;
-defm V_PK_FMA_F16 : VOP3P_Real_gfx10_gfx11<0x0e>;
-defm V_PK_ADD_F16 : VOP3P_Real_gfx10_gfx11<0x0f>;
-defm V_PK_MUL_F16 : VOP3P_Real_gfx10_gfx11<0x10>;
+multiclass VOP3P_Real_gfx10_gfx11<bits<7> op> :
+ VOP3P_Real_gfx10<op>, VOP3P_Real_Base<GFX11Gen, op>;
+
+multiclass VOP3P_Real_gfx10_gfx11_gfx12<bits<7> op> :
+ VOP3P_Real_gfx10_gfx11<op>, VOP3P_Real_Base<GFX12Gen, op>;
+
+multiclass VOP3P_Real_gfx10_gfx11_gfx12_Triple<bits<7> op> :
+ VOP3P_Real_gfx10<op>, VOP3P_Realtriple<GFX11Gen, op>,
+ VOP3P_Realtriple<GFX12Gen, op>;
+
+defm V_PK_MAD_I16 : VOP3P_Real_gfx10_gfx11_gfx12<0x00>;
+defm V_PK_MUL_LO_U16 : VOP3P_Real_gfx10_gfx11_gfx12<0x01>;
+defm V_PK_ADD_I16 : VOP3P_Real_gfx10_gfx11_gfx12<0x02>;
+defm V_PK_SUB_I16 : VOP3P_Real_gfx10_gfx11_gfx12<0x03>;
+defm V_PK_LSHLREV_B16 : VOP3P_Real_gfx10_gfx11_gfx12<0x04>;
+defm V_PK_LSHRREV_B16 : VOP3P_Real_gfx10_gfx11_gfx12<0x05>;
+defm V_PK_ASHRREV_I16 : VOP3P_Real_gfx10_gfx11_gfx12<0x06>;
+defm V_PK_MAX_I16 : VOP3P_Real_gfx10_gfx11_gfx12<0x07>;
+defm V_PK_MIN_I16 : VOP3P_Real_gfx10_gfx11_gfx12<0x08>;
+defm V_PK_MAD_U16 : VOP3P_Real_gfx10_gfx11_gfx12<0x09>;
+defm V_PK_ADD_U16 : VOP3P_Real_gfx10_gfx11_gfx12<0x0a>;
+defm V_PK_SUB_U16 : VOP3P_Real_gfx10_gfx11_gfx12<0x0b>;
+defm V_PK_MAX_U16 : VOP3P_Real_gfx10_gfx11_gfx12<0x0c>;
+defm V_PK_MIN_U16 : VOP3P_Real_gfx10_gfx11_gfx12<0x0d>;
+defm V_PK_FMA_F16 : VOP3P_Real_gfx10_gfx11_gfx12<0x0e>;
+defm V_PK_ADD_F16 : VOP3P_Real_gfx10_gfx11_gfx12<0x0f>;
+defm V_PK_MUL_F16 : VOP3P_Real_gfx10_gfx11_gfx12<0x10>;
defm V_PK_MIN_F16 : VOP3P_Real_gfx10_gfx11<0x11>;
defm V_PK_MAX_F16 : VOP3P_Real_gfx10_gfx11<0x12>;
-defm V_FMA_MIX_F32 : VOP3P_Real_gfx10_gfx11_Triple <0x20>;
-defm V_FMA_MIXLO_F16 : VOP3P_Real_gfx10_gfx11_Triple <0x21>;
-defm V_FMA_MIXHI_F16 : VOP3P_Real_gfx10_gfx11_Triple <0x22>;
+defm V_FMA_MIX_F32 : VOP3P_Real_gfx10_gfx11_gfx12_Triple<0x20>;
+defm V_FMA_MIXLO_F16 : VOP3P_Real_gfx10_gfx11_gfx12_Triple<0x21>;
+defm V_FMA_MIXHI_F16 : VOP3P_Real_gfx10_gfx11_gfx12_Triple<0x22>;
defm V_DOT2_I32_I16 : VOP3P_Real_gfx10 <0x14>;
defm V_DOT2_U32_U16 : VOP3P_Real_gfx10 <0x15>;
-defm V_DOT2_F32_F16 : VOP3P_Real_gfx10_gfx11_Triple <0x13>;
-defm V_DOT4_U32_U8 : VOP3P_Real_gfx10_gfx11 <0x17>;
-defm V_DOT8_U32_U4 : VOP3P_Real_gfx10_gfx11 <0x19>;
+defm V_DOT2_F32_F16 : VOP3P_Real_gfx10_gfx11_gfx12_Triple<0x13>;
+defm V_DOT4_U32_U8 : VOP3P_Real_gfx10_gfx11_gfx12<0x17>;
+defm V_DOT8_U32_U4 : VOP3P_Real_gfx10_gfx11_gfx12<0x19>;
defm V_DOT4_I32_I8 : VOP3P_Real_gfx10 <0x16>;
defm V_DOT8_I32_I4 : VOP3P_Real_gfx10 <0x18>;
diff --git a/llvm/lib/Target/AMDGPU/VOPCInstructions.td b/llvm/lib/Target/AMDGPU/VOPCInstructions.td
index cbea380ab28c..e5b801048e6d 100644
--- a/llvm/lib/Target/AMDGPU/VOPCInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPCInstructions.td
@@ -1323,53 +1323,52 @@ class VOPC64_DPP8_NoDst<bits<10> op, VOP_Pseudo ps, string opName = ps.OpName>
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
-// GFX11.
+// GFX11, GFX12
//===----------------------------------------------------------------------===//
-let AssemblerPredicate = isGFX11Only in {
- multiclass VOPC_Real_gfx11<bits<9> op> {
+multiclass VOPC_Real_Base<GFXGen Gen, bits<9> op> {
+ let AssemblerPredicate = Gen.AssemblerPredicate in {
defvar ps32 = !cast<VOPC_Pseudo>(NAME#"_e32");
defvar ps64 = !cast<VOP3_Pseudo>(NAME#"_e64");
- let DecoderNamespace = "GFX11" in {
- def _e32_gfx11 : VOPC_Real<ps32, SIEncodingFamily.GFX11>,
- VOPCe<op{7-0}>;
- def _e64_gfx11 : VOP3_Real<ps64, SIEncodingFamily.GFX11>,
- VOP3a_gfx11<{0, op}, ps64.Pfl> {
+ let DecoderNamespace = Gen.DecoderNamespace in {
+ def _e32#Gen.Suffix : VOPC_Real<ps32, Gen.Subtarget>,
+ VOPCe<op{7-0}>;
+ def _e64#Gen.Suffix : VOP3_Real<ps64, Gen.Subtarget>,
+ VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl> {
// Encoding used for VOPC instructions encoded as VOP3 differs from
// VOP3e by destination name (sdst) as VOPC doesn't have vector dst.
bits<8> sdst;
let Inst{7-0} = sdst;
}
- } // End DecoderNamespace = "GFX11"
+ } // End DecoderNamespace = Gen.DecoderNamespace
- defm : VOPCInstAliases<NAME, "gfx11">;
+ defm : VOPCInstAliases<NAME, !substr(Gen.Suffix,1)>;
if ps32.Pfl.HasExtDPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(NAME #"_e32" #"_dpp");
defvar AsmDPP = ps32.Pfl.AsmDPP16;
- let DecoderNamespace = "DPPGFX11" in {
- def _e32_dpp_gfx11 : VOPC_DPP16_SIMC<op{7-0}, psDPP,
- SIEncodingFamily.GFX11>;
- def _e32_dpp_w32_gfx11 : VOPC_DPP16<op{7-0}, psDPP> {
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace in {
+ def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP, Gen.Subtarget>;
+ def _e32_dpp_w32#Gen.Suffix : VOPC_DPP16<op{7-0}, psDPP> {
let AsmString = psDPP.OpName # " vcc_lo, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
- def _e32_dpp_w64_gfx11 : VOPC_DPP16<op{7-0}, psDPP> {
+ def _e32_dpp_w64#Gen.Suffix : VOPC_DPP16<op{7-0}, psDPP> {
let AsmString = psDPP.OpName # " vcc, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave64;
}
}
defvar AsmDPP8 = ps32.Pfl.AsmDPP8;
- let DecoderNamespace = "DPP8GFX11" in {
- def _e32_dpp8_gfx11 : VOPC_DPP8<op{7-0}, ps32>;
- def _e32_dpp8_w32_gfx11 : VOPC_DPP8<op{7-0}, ps32> {
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace in {
+ def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32>;
+ def _e32_dpp8_w32#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32> {
let AsmString = ps32.OpName # " vcc_lo, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
- def _e32_dpp8_w64_gfx11 : VOPC_DPP8<op{7-0}, ps32> {
+ def _e32_dpp8_w64#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32> {
let AsmString = ps32.OpName # " vcc, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave64;
@@ -1379,83 +1378,84 @@ let AssemblerPredicate = isGFX11Only in {
if ps64.Pfl.HasExtVOP3DPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(NAME #"_e64" #"_dpp");
defvar AsmDPP = ps64.Pfl.AsmVOP3DPP16;
- let DecoderNamespace = "DPPGFX11" in {
- def _e64_dpp_gfx11 : VOPC64_DPP16_Dst<{0, op}, psDPP>,
- SIMCInstr<psDPP.PseudoInstr, SIEncodingFamily.GFX11>;
- def _e64_dpp_w32_gfx11 : VOPC64_DPP16_Dst<{0, op}, psDPP> {
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace in {
+ def _e64_dpp#Gen.Suffix : VOPC64_DPP16_Dst<{0, op}, psDPP>,
+ SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget>;
+ def _e64_dpp_w32#Gen.Suffix : VOPC64_DPP16_Dst<{0, op}, psDPP> {
let AsmString = psDPP.OpName # " vcc_lo, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
- def _e64_dpp_w64_gfx11 : VOPC64_DPP16_Dst<{0, op}, psDPP> {
+ def _e64_dpp_w64#Gen.Suffix : VOPC64_DPP16_Dst<{0, op}, psDPP> {
let AsmString = psDPP.OpName # " vcc, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave64;
}
}
defvar AsmDPP8 = ps64.Pfl.AsmVOP3DPP8;
- let DecoderNamespace = "DPP8GFX11" in {
- def _e64_dpp8_gfx11 : VOPC64_DPP8_Dst<{0, op}, ps64>;
- def _e64_dpp8_w32_gfx11 : VOPC64_DPP8_Dst<{0, op}, ps64> {
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace in {
+ def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_Dst<{0, op}, ps64>;
+ def _e64_dpp8_w32#Gen.Suffix : VOPC64_DPP8_Dst<{0, op}, ps64> {
let AsmString = ps32.OpName # " vcc_lo, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
- def _e64_dpp8_w64_gfx11 : VOPC64_DPP8_Dst<{0, op}, ps64> {
+ def _e64_dpp8_w64#Gen.Suffix : VOPC64_DPP8_Dst<{0, op}, ps64> {
let AsmString = ps32.OpName # " vcc, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave64;
}
}
}
+ } // AssemblerPredicate = Gen.AssemblerPredicate
+}
- }
-
- multiclass VOPC_Real_with_name_gfx11<bits<9> op, string OpName,
- string asm_name, string pseudo_mnemonic = ""> {
+multiclass VOPC_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
+ string asm_name, string pseudo_mnemonic = ""> {
+ let AssemblerPredicate = Gen.AssemblerPredicate in {
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_e32");
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_e64");
- let DecoderNamespace = "GFX11" in {
- def _e32_gfx11 :
+ let DecoderNamespace = Gen.DecoderNamespace in {
+ def _e32#Gen.Suffix :
// 32 and 64 bit forms of the instruction have _e32 and _e64
// respectively appended to their assembly mnemonic.
// _e64 is printed as part of the VOPDstS64orS32 operand, whereas
// the destination-less 32bit forms add it to the asmString here.
- VOPC_Real<ps32, SIEncodingFamily.GFX11, asm_name#"_e32">,
+ VOPC_Real<ps32, Gen.Subtarget, asm_name#"_e32">,
VOPCe<op{7-0}>,
MnemonicAlias<!if(!empty(pseudo_mnemonic), ps32.Mnemonic,
pseudo_mnemonic),
asm_name, ps32.AsmVariantName>,
- Requires<[isGFX11Plus]>;
- def _e64_gfx11 :
- VOP3_Real<ps64, SIEncodingFamily.GFX11, asm_name>,
- VOP3a_gfx11<{0, op}, ps64.Pfl>,
+ Requires<[Gen.AssemblerPredicate]>;
+ def _e64#Gen.Suffix :
+ VOP3_Real<ps64, Gen.Subtarget, asm_name>,
+ VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl>,
MnemonicAlias<!if(!empty(pseudo_mnemonic), ps64.Mnemonic,
pseudo_mnemonic),
asm_name, ps64.AsmVariantName>,
- Requires<[isGFX11Plus]> {
+ Requires<[Gen.AssemblerPredicate]> {
// Encoding used for VOPC instructions encoded as VOP3 differs from
// VOP3e by destination name (sdst) as VOPC doesn't have vector dst.
bits<8> sdst;
let Inst{7-0} = sdst;
}
- } // End DecoderNamespace = "GFX11"
+ } // End DecoderNamespace = Gen.DecoderNamespace
- defm : VOPCInstAliases<OpName, "gfx11", NAME, asm_name>;
+ defm : VOPCInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;
if ps32.Pfl.HasExtDPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e32" #"_dpp");
defvar AsmDPP = ps32.Pfl.AsmDPP16;
- let DecoderNamespace = "DPPGFX11" in {
- def _e32_dpp_gfx11 : VOPC_DPP16_SIMC<op{7-0}, psDPP,
- SIEncodingFamily.GFX11, asm_name>;
- def _e32_dpp_w32_gfx11
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace in {
+ def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
+ Gen.Subtarget, asm_name>;
+ def _e32_dpp_w32#Gen.Suffix
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
let AsmString = asm_name # " vcc_lo, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
- def _e32_dpp_w64_gfx11
+ def _e32_dpp_w64#Gen.Suffix
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
let AsmString = asm_name # " vcc, " # AsmDPP;
let isAsmParserOnly = 1;
@@ -1463,15 +1463,15 @@ let AssemblerPredicate = isGFX11Only in {
}
}
defvar AsmDPP8 = ps32.Pfl.AsmDPP8;
- let DecoderNamespace = "DPP8GFX11" in {
- def _e32_dpp8_gfx11 : VOPC_DPP8<op{7-0}, ps32, asm_name>;
- def _e32_dpp8_w32_gfx11
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace in {
+ def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
+ def _e32_dpp8_w32#Gen.Suffix
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
let AsmString = asm_name # " vcc_lo, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
- def _e32_dpp8_w64_gfx11
+ def _e32_dpp8_w64#Gen.Suffix
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
let AsmString = asm_name # " vcc, " # AsmDPP8;
let isAsmParserOnly = 1;
@@ -1483,16 +1483,16 @@ let AssemblerPredicate = isGFX11Only in {
if ps64.Pfl.HasExtVOP3DPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e64" #"_dpp");
defvar AsmDPP = ps64.Pfl.AsmVOP3DPP16;
- let DecoderNamespace = "DPPGFX11" in {
- def _e64_dpp_gfx11 : VOPC64_DPP16_Dst<{0, op}, psDPP, asm_name>,
- SIMCInstr<psDPP.PseudoInstr, SIEncodingFamily.GFX11>;
- def _e64_dpp_w32_gfx11
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace in {
+ def _e64_dpp#Gen.Suffix : VOPC64_DPP16_Dst<{0, op}, psDPP, asm_name>,
+ SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget>;
+ def _e64_dpp_w32#Gen.Suffix
: VOPC64_DPP16_Dst<{0, op}, psDPP, asm_name> {
let AsmString = asm_name # " vcc_lo, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
- def _e64_dpp_w64_gfx11
+ def _e64_dpp_w64#Gen.Suffix
: VOPC64_DPP16_Dst<{0, op}, psDPP, asm_name> {
let AsmString = asm_name # " vcc, " # AsmDPP;
let isAsmParserOnly = 1;
@@ -1500,15 +1500,15 @@ let AssemblerPredicate = isGFX11Only in {
}
}
defvar AsmDPP8 = ps64.Pfl.AsmVOP3DPP8;
- let DecoderNamespace = "DPP8GFX11" in {
- def _e64_dpp8_gfx11 : VOPC64_DPP8_Dst<{0, op}, ps64, asm_name>;
- def _e64_dpp8_w32_gfx11
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace in {
+ def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_Dst<{0, op}, ps64, asm_name>;
+ def _e64_dpp8_w32#Gen.Suffix
: VOPC64_DPP8_Dst<{0, op}, ps64, asm_name> {
let AsmString = asm_name # " vcc_lo, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
- def _e64_dpp8_w64_gfx11
+ def _e64_dpp8_w64#Gen.Suffix
: VOPC64_DPP8_Dst<{0, op}, ps64, asm_name> {
let AsmString = asm_name # " vcc, " # AsmDPP8;
let isAsmParserOnly = 1;
@@ -1516,44 +1516,47 @@ let AssemblerPredicate = isGFX11Only in {
}
}
}
- }
+ } // AssemblerPredicate = Gen.AssemblerPredicate
+}
- multiclass VOPC_Real_t16_gfx11<bits<9> op, string asm_name,
- string OpName = NAME> : VOPC_Real_with_name_gfx11<op, OpName, asm_name>;
+multiclass VOPC_Real_t16<GFXGen Gen, bits<9> op, string asm_name,
+ string OpName = NAME, string pseudo_mnemonic = ""> :
+ VOPC_Real_with_name<Gen, op, OpName, asm_name, pseudo_mnemonic>;
- multiclass VOPCX_Real_gfx11<bits<9> op> {
+multiclass VOPCX_Real<GFXGen Gen, bits<9> op> {
+ let AssemblerPredicate = Gen.AssemblerPredicate in {
defvar ps32 = !cast<VOPC_Pseudo>(NAME#"_nosdst_e32");
defvar ps64 = !cast<VOP3_Pseudo>(NAME#"_nosdst_e64");
- let DecoderNamespace = "GFX11" in {
- def _e32_gfx11 :
- VOPC_Real<ps32, SIEncodingFamily.GFX11>,
+ let DecoderNamespace = Gen.DecoderNamespace in {
+ def _e32#Gen.Suffix :
+ VOPC_Real<ps32, Gen.Subtarget>,
VOPCe<op{7-0}> {
let AsmString = !subst("_nosdst", "", ps32.PseudoInstr)
# " " # ps32.AsmOperands;
}
- def _e64_gfx11 :
- VOP3_Real<ps64, SIEncodingFamily.GFX11>,
- VOP3a_gfx11<{0, op}, ps64.Pfl> {
+ def _e64#Gen.Suffix :
+ VOP3_Real<ps64, Gen.Subtarget>,
+ VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl> {
let Inst{7-0} = ?; // sdst
let AsmString = !subst("_nosdst", "", ps64.Mnemonic)
# "{_e64} " # ps64.AsmOperands;
}
- } // End DecoderNamespace = "GFX11"
+ } // End DecoderNamespace = Gen.DecoderNamespace
- defm : VOPCXInstAliases<NAME, "gfx11">;
+ defm : VOPCXInstAliases<NAME, !substr(Gen.Suffix, 1)>;
if ps32.Pfl.HasExtDPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(NAME #"_nosdst_e32" #"_dpp");
defvar AsmDPP = ps32.Pfl.AsmDPP16;
- let DecoderNamespace = "DPPGFX11" in {
- def _e32_dpp_gfx11
- : VOPC_DPP16_SIMC<op{7-0}, psDPP, SIEncodingFamily.GFX11> {
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace in {
+ def _e32_dpp#Gen.Suffix
+ : VOPC_DPP16_SIMC<op{7-0}, psDPP, Gen.Subtarget> {
let AsmString = !subst("_nosdst", "", psDPP.OpName) # " " # AsmDPP;
}
}
defvar AsmDPP8 = ps32.Pfl.AsmDPP8;
- let DecoderNamespace = "DPP8GFX11" in {
- def _e32_dpp8_gfx11 : VOPC_DPP8<op{7-0}, ps32> {
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace in {
+ def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32> {
let AsmString = !subst("_nosdst", "", ps32.OpName) # " " # AsmDPP8;
}
}
@@ -1562,268 +1565,305 @@ let AssemblerPredicate = isGFX11Only in {
if ps64.Pfl.HasExtVOP3DPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(NAME #"_nosdst_e64" #"_dpp");
defvar AsmDPP = ps64.Pfl.AsmVOP3DPP16;
- let DecoderNamespace = "DPPGFX11" in {
- def _e64_dpp_gfx11
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace in {
+ def _e64_dpp#Gen.Suffix
: VOPC64_DPP16_NoDst<{0, op}, psDPP>,
- SIMCInstr<psDPP.PseudoInstr, SIEncodingFamily.GFX11> {
+ SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget> {
let AsmString = !subst("_nosdst", "", psDPP.OpName)
# "{_e64_dpp} " # AsmDPP;
}
}
defvar AsmDPP8 = ps64.Pfl.AsmVOP3DPP8;
- let DecoderNamespace = "DPP8GFX11" in {
- def _e64_dpp8_gfx11 : VOPC64_DPP8_NoDst<{0, op}, ps64> {
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace in {
+ def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_NoDst<{0, op}, ps64> {
let AsmString = !subst("_nosdst", "", ps64.OpName)
# "{_e64_dpp} " # AsmDPP8;
}
}
}
- }
+ } // AssemblerPredicate = Gen.AssemblerPredicate
+}
- multiclass VOPCX_Real_with_name_gfx11<bits<9> op, string OpName,
- string asm_name, string pseudo_mnemonic = ""> {
+multiclass VOPCX_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
+ string asm_name, string pseudo_mnemonic = ""> {
+ let AssemblerPredicate = Gen.AssemblerPredicate in {
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_nosdst_e32");
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_nosdst_e64");
- let DecoderNamespace = "GFX11" in {
- def _e32_gfx11
- : VOPC_Real<ps32, SIEncodingFamily.GFX11, asm_name>,
+ let DecoderNamespace = Gen.DecoderNamespace in {
+ def _e32#Gen.Suffix
+ : VOPC_Real<ps32, Gen.Subtarget, asm_name>,
MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps32.Mnemonic),
pseudo_mnemonic),
asm_name, ps32.AsmVariantName>,
- Requires<[isGFX11Plus]>,
+ Requires<[Gen.AssemblerPredicate]>,
VOPCe<op{7-0}> {
let AsmString = asm_name # "{_e32} " # ps32.AsmOperands;
}
- def _e64_gfx11
- : VOP3_Real<ps64, SIEncodingFamily.GFX11, asm_name>,
+ def _e64#Gen.Suffix
+ : VOP3_Real<ps64, Gen.Subtarget, asm_name>,
MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps64.Mnemonic),
pseudo_mnemonic),
asm_name, ps64.AsmVariantName>,
- Requires<[isGFX11Plus]>,
- VOP3a_gfx11<{0, op}, ps64.Pfl> {
+ Requires<[Gen.AssemblerPredicate]>,
+ VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl> {
let Inst{7-0} = ? ; // sdst
let AsmString = asm_name # "{_e64} " # ps64.AsmOperands;
}
- } // End DecoderNamespace = "GFX11"
+ } // End DecoderNamespace = Gen.DecoderNamespace
- defm : VOPCXInstAliases<OpName, "gfx11", NAME, asm_name>;
+ defm : VOPCXInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;
if ps32.Pfl.HasExtDPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e32"#"_dpp");
- let DecoderNamespace = "DPPGFX11" in {
- def _e32_dpp_gfx11 : VOPC_DPP16_SIMC<op{7-0}, psDPP,
- SIEncodingFamily.GFX11, asm_name>;
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace in {
+ def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
+ Gen.Subtarget, asm_name>;
}
- let DecoderNamespace = "DPP8GFX11" in {
- def _e32_dpp8_gfx11 : VOPC_DPP8<op{7-0}, ps32, asm_name>;
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace in {
+ def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
}
}
if ps64.Pfl.HasExtVOP3DPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e64"#"_dpp");
defvar AsmDPP = ps64.Pfl.AsmVOP3DPP16;
- let DecoderNamespace = "DPPGFX11" in {
- def _e64_dpp_gfx11
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace in {
+ def _e64_dpp#Gen.Suffix
: VOPC64_DPP16_NoDst<{0, op}, psDPP, asm_name>,
- SIMCInstr<psDPP.PseudoInstr, SIEncodingFamily.GFX11> {
+ SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget> {
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP;
}
}
defvar AsmDPP8 = ps64.Pfl.AsmVOP3DPP8;
- let DecoderNamespace = "DPP8GFX11" in {
- def _e64_dpp8_gfx11 : VOPC64_DPP8_NoDst<{0, op}, ps64, asm_name> {
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace in {
+ def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_NoDst<{0, op}, ps64, asm_name> {
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP8;
}
}
}
- }
+ } // AssemblerPredicate = Gen.AssemblerPredicate
+}
- multiclass VOPCX_Real_t16_gfx11<bits<9> op, string asm_name,
- string OpName = NAME> : VOPCX_Real_with_name_gfx11<op, OpName, asm_name>;
+multiclass VOPCX_Real_t16<GFXGen Gen, bits<9> op, string asm_name,
+ string OpName = NAME, string pseudo_mnemonic = ""> :
+ VOPCX_Real_with_name<Gen, op, OpName, asm_name, pseudo_mnemonic>;
+multiclass VOPC_Real_gfx11<bits<9> op> : VOPC_Real_Base<GFX11Gen, op>;
-} // End AssemblerPredicate = isGFX11Only
+multiclass VOPC_Real_with_name_gfx11<bits<9> op, string OpName, string asm_name,
+ string pseudo_mnemonic = "">
+ : VOPC_Real_with_name<GFX11Gen, op, OpName, asm_name, pseudo_mnemonic>;
+
+multiclass VOPCX_Real_gfx11<bits<9> op> : VOPCX_Real<GFX11Gen, op>;
+
+multiclass VOPCX_Real_with_name_gfx11<bits<9> op, string OpName,
+ string asm_name, string pseudo_mnemonic = ""> :
+ VOPCX_Real_with_name<GFX11Gen, op, OpName, asm_name, pseudo_mnemonic>;
+
+multiclass VOPC_Real_gfx11_gfx12<bits<9> op> :
+ VOPC_Real_Base<GFX11Gen, op>, VOPC_Real_Base<GFX12Gen, op>;
+
+multiclass VOPCX_Real_gfx11_gfx12<bits<9> op> :
+ VOPCX_Real<GFX11Gen, op>, VOPCX_Real<GFX12Gen, op>;
+
+multiclass VOPC_Real_t16_gfx11<bits <9> op, string asm_name,
+ string OpName = NAME, string pseudo_mnemonic = ""> :
+ VOPC_Real_t16<GFX11Gen, op, asm_name, OpName, pseudo_mnemonic>;
+
+multiclass VOPC_Real_t16_gfx11_gfx12<bits <9> op, string asm_name,
+ string OpName = NAME, string pseudo_mnemonic = ""> :
+ VOPC_Real_t16<GFX11Gen, op, asm_name, OpName, pseudo_mnemonic>,
+ VOPC_Real_t16<GFX12Gen, op, asm_name, OpName, pseudo_mnemonic>;
+
+multiclass VOPCX_Real_t16_gfx11<bits<9> op, string asm_name,
+ string OpName = NAME, string pseudo_mnemonic = ""> :
+ VOPCX_Real_t16<GFX11Gen, op, asm_name, OpName, pseudo_mnemonic>;
+
+multiclass VOPCX_Real_t16_gfx11_gfx12<bits<9> op, string asm_name,
+ string OpName = NAME, string pseudo_mnemonic = ""> :
+ VOPCX_Real_t16<GFX11Gen, op, asm_name, OpName, pseudo_mnemonic>,
+ VOPCX_Real_t16<GFX12Gen, op, asm_name, OpName, pseudo_mnemonic>;
defm V_CMP_F_F16_t16 : VOPC_Real_t16_gfx11<0x000, "v_cmp_f_f16">;
-defm V_CMP_LT_F16_t16 : VOPC_Real_t16_gfx11<0x001, "v_cmp_lt_f16">;
-defm V_CMP_EQ_F16_t16 : VOPC_Real_t16_gfx11<0x002, "v_cmp_eq_f16">;
-defm V_CMP_LE_F16_t16 : VOPC_Real_t16_gfx11<0x003, "v_cmp_le_f16">;
-defm V_CMP_GT_F16_t16 : VOPC_Real_t16_gfx11<0x004, "v_cmp_gt_f16">;
-defm V_CMP_LG_F16_t16 : VOPC_Real_t16_gfx11<0x005, "v_cmp_lg_f16">;
-defm V_CMP_GE_F16_t16 : VOPC_Real_t16_gfx11<0x006, "v_cmp_ge_f16">;
-defm V_CMP_O_F16_t16 : VOPC_Real_t16_gfx11<0x007, "v_cmp_o_f16">;
-defm V_CMP_U_F16_t16 : VOPC_Real_t16_gfx11<0x008, "v_cmp_u_f16">;
-defm V_CMP_NGE_F16_t16 : VOPC_Real_t16_gfx11<0x009, "v_cmp_nge_f16">;
-defm V_CMP_NLG_F16_t16 : VOPC_Real_t16_gfx11<0x00a, "v_cmp_nlg_f16">;
-defm V_CMP_NGT_F16_t16 : VOPC_Real_t16_gfx11<0x00b, "v_cmp_ngt_f16">;
-defm V_CMP_NLE_F16_t16 : VOPC_Real_t16_gfx11<0x00c, "v_cmp_nle_f16">;
-defm V_CMP_NEQ_F16_t16 : VOPC_Real_t16_gfx11<0x00d, "v_cmp_neq_f16">;
-defm V_CMP_NLT_F16_t16 : VOPC_Real_t16_gfx11<0x00e, "v_cmp_nlt_f16">;
+defm V_CMP_LT_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x001, "v_cmp_lt_f16">;
+defm V_CMP_EQ_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x002, "v_cmp_eq_f16">;
+defm V_CMP_LE_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x003, "v_cmp_le_f16">;
+defm V_CMP_GT_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x004, "v_cmp_gt_f16">;
+defm V_CMP_LG_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x005, "v_cmp_lg_f16">;
+defm V_CMP_GE_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x006, "v_cmp_ge_f16">;
+defm V_CMP_O_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x007, "v_cmp_o_f16">;
+defm V_CMP_U_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x008, "v_cmp_u_f16">;
+defm V_CMP_NGE_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x009, "v_cmp_nge_f16">;
+defm V_CMP_NLG_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x00a, "v_cmp_nlg_f16">;
+defm V_CMP_NGT_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x00b, "v_cmp_ngt_f16">;
+defm V_CMP_NLE_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x00c, "v_cmp_nle_f16">;
+defm V_CMP_NEQ_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x00d, "v_cmp_neq_f16">;
+defm V_CMP_NLT_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x00e, "v_cmp_nlt_f16">;
defm V_CMP_T_F16_t16 : VOPC_Real_with_name_gfx11<0x00f, "V_CMP_TRU_F16_t16", "v_cmp_t_f16", "v_cmp_tru_f16">;
defm V_CMP_F_F32 : VOPC_Real_gfx11<0x010>;
-defm V_CMP_LT_F32 : VOPC_Real_gfx11<0x011>;
-defm V_CMP_EQ_F32 : VOPC_Real_gfx11<0x012>;
-defm V_CMP_LE_F32 : VOPC_Real_gfx11<0x013>;
-defm V_CMP_GT_F32 : VOPC_Real_gfx11<0x014>;
-defm V_CMP_LG_F32 : VOPC_Real_gfx11<0x015>;
-defm V_CMP_GE_F32 : VOPC_Real_gfx11<0x016>;
-defm V_CMP_O_F32 : VOPC_Real_gfx11<0x017>;
-defm V_CMP_U_F32 : VOPC_Real_gfx11<0x018>;
-defm V_CMP_NGE_F32 : VOPC_Real_gfx11<0x019>;
-defm V_CMP_NLG_F32 : VOPC_Real_gfx11<0x01a>;
-defm V_CMP_NGT_F32 : VOPC_Real_gfx11<0x01b>;
-defm V_CMP_NLE_F32 : VOPC_Real_gfx11<0x01c>;
-defm V_CMP_NEQ_F32 : VOPC_Real_gfx11<0x01d>;
-defm V_CMP_NLT_F32 : VOPC_Real_gfx11<0x01e>;
+defm V_CMP_LT_F32 : VOPC_Real_gfx11_gfx12<0x011>;
+defm V_CMP_EQ_F32 : VOPC_Real_gfx11_gfx12<0x012>;
+defm V_CMP_LE_F32 : VOPC_Real_gfx11_gfx12<0x013>;
+defm V_CMP_GT_F32 : VOPC_Real_gfx11_gfx12<0x014>;
+defm V_CMP_LG_F32 : VOPC_Real_gfx11_gfx12<0x015>;
+defm V_CMP_GE_F32 : VOPC_Real_gfx11_gfx12<0x016>;
+defm V_CMP_O_F32 : VOPC_Real_gfx11_gfx12<0x017>;
+defm V_CMP_U_F32 : VOPC_Real_gfx11_gfx12<0x018>;
+defm V_CMP_NGE_F32 : VOPC_Real_gfx11_gfx12<0x019>;
+defm V_CMP_NLG_F32 : VOPC_Real_gfx11_gfx12<0x01a>;
+defm V_CMP_NGT_F32 : VOPC_Real_gfx11_gfx12<0x01b>;
+defm V_CMP_NLE_F32 : VOPC_Real_gfx11_gfx12<0x01c>;
+defm V_CMP_NEQ_F32 : VOPC_Real_gfx11_gfx12<0x01d>;
+defm V_CMP_NLT_F32 : VOPC_Real_gfx11_gfx12<0x01e>;
defm V_CMP_T_F32 : VOPC_Real_with_name_gfx11<0x01f, "V_CMP_TRU_F32", "v_cmp_t_f32">;
defm V_CMP_T_F64 : VOPC_Real_with_name_gfx11<0x02f, "V_CMP_TRU_F64", "v_cmp_t_f64">;
-defm V_CMP_LT_I16_t16 : VOPC_Real_t16_gfx11<0x031, "v_cmp_lt_i16">;
-defm V_CMP_EQ_I16_t16 : VOPC_Real_t16_gfx11<0x032, "v_cmp_eq_i16">;
-defm V_CMP_LE_I16_t16 : VOPC_Real_t16_gfx11<0x033, "v_cmp_le_i16">;
-defm V_CMP_GT_I16_t16 : VOPC_Real_t16_gfx11<0x034, "v_cmp_gt_i16">;
-defm V_CMP_NE_I16_t16 : VOPC_Real_t16_gfx11<0x035, "v_cmp_ne_i16">;
-defm V_CMP_GE_I16_t16 : VOPC_Real_t16_gfx11<0x036, "v_cmp_ge_i16">;
-defm V_CMP_LT_U16_t16 : VOPC_Real_t16_gfx11<0x039, "v_cmp_lt_u16">;
-defm V_CMP_EQ_U16_t16 : VOPC_Real_t16_gfx11<0x03a, "v_cmp_eq_u16">;
-defm V_CMP_LE_U16_t16 : VOPC_Real_t16_gfx11<0x03b, "v_cmp_le_u16">;
-defm V_CMP_GT_U16_t16 : VOPC_Real_t16_gfx11<0x03c, "v_cmp_gt_u16">;
-defm V_CMP_NE_U16_t16 : VOPC_Real_t16_gfx11<0x03d, "v_cmp_ne_u16">;
-defm V_CMP_GE_U16_t16 : VOPC_Real_t16_gfx11<0x03e, "v_cmp_ge_u16">;
+defm V_CMP_LT_I16_t16 : VOPC_Real_t16_gfx11_gfx12<0x031, "v_cmp_lt_i16">;
+defm V_CMP_EQ_I16_t16 : VOPC_Real_t16_gfx11_gfx12<0x032, "v_cmp_eq_i16">;
+defm V_CMP_LE_I16_t16 : VOPC_Real_t16_gfx11_gfx12<0x033, "v_cmp_le_i16">;
+defm V_CMP_GT_I16_t16 : VOPC_Real_t16_gfx11_gfx12<0x034, "v_cmp_gt_i16">;
+defm V_CMP_NE_I16_t16 : VOPC_Real_t16_gfx11_gfx12<0x035, "v_cmp_ne_i16">;
+defm V_CMP_GE_I16_t16 : VOPC_Real_t16_gfx11_gfx12<0x036, "v_cmp_ge_i16">;
+defm V_CMP_LT_U16_t16 : VOPC_Real_t16_gfx11_gfx12<0x039, "v_cmp_lt_u16">;
+defm V_CMP_EQ_U16_t16 : VOPC_Real_t16_gfx11_gfx12<0x03a, "v_cmp_eq_u16">;
+defm V_CMP_LE_U16_t16 : VOPC_Real_t16_gfx11_gfx12<0x03b, "v_cmp_le_u16">;
+defm V_CMP_GT_U16_t16 : VOPC_Real_t16_gfx11_gfx12<0x03c, "v_cmp_gt_u16">;
+defm V_CMP_NE_U16_t16 : VOPC_Real_t16_gfx11_gfx12<0x03d, "v_cmp_ne_u16">;
+defm V_CMP_GE_U16_t16 : VOPC_Real_t16_gfx11_gfx12<0x03e, "v_cmp_ge_u16">;
defm V_CMP_F_I32 : VOPC_Real_gfx11<0x040>;
-defm V_CMP_LT_I32 : VOPC_Real_gfx11<0x041>;
-defm V_CMP_EQ_I32 : VOPC_Real_gfx11<0x042>;
-defm V_CMP_LE_I32 : VOPC_Real_gfx11<0x043>;
-defm V_CMP_GT_I32 : VOPC_Real_gfx11<0x044>;
-defm V_CMP_NE_I32 : VOPC_Real_gfx11<0x045>;
-defm V_CMP_GE_I32 : VOPC_Real_gfx11<0x046>;
+defm V_CMP_LT_I32 : VOPC_Real_gfx11_gfx12<0x041>;
+defm V_CMP_EQ_I32 : VOPC_Real_gfx11_gfx12<0x042>;
+defm V_CMP_LE_I32 : VOPC_Real_gfx11_gfx12<0x043>;
+defm V_CMP_GT_I32 : VOPC_Real_gfx11_gfx12<0x044>;
+defm V_CMP_NE_I32 : VOPC_Real_gfx11_gfx12<0x045>;
+defm V_CMP_GE_I32 : VOPC_Real_gfx11_gfx12<0x046>;
defm V_CMP_T_I32 : VOPC_Real_gfx11<0x047>;
defm V_CMP_F_U32 : VOPC_Real_gfx11<0x048>;
-defm V_CMP_LT_U32 : VOPC_Real_gfx11<0x049>;
-defm V_CMP_EQ_U32 : VOPC_Real_gfx11<0x04a>;
-defm V_CMP_LE_U32 : VOPC_Real_gfx11<0x04b>;
-defm V_CMP_GT_U32 : VOPC_Real_gfx11<0x04c>;
-defm V_CMP_NE_U32 : VOPC_Real_gfx11<0x04d>;
-defm V_CMP_GE_U32 : VOPC_Real_gfx11<0x04e>;
+defm V_CMP_LT_U32 : VOPC_Real_gfx11_gfx12<0x049>;
+defm V_CMP_EQ_U32 : VOPC_Real_gfx11_gfx12<0x04a>;
+defm V_CMP_LE_U32 : VOPC_Real_gfx11_gfx12<0x04b>;
+defm V_CMP_GT_U32 : VOPC_Real_gfx11_gfx12<0x04c>;
+defm V_CMP_NE_U32 : VOPC_Real_gfx11_gfx12<0x04d>;
+defm V_CMP_GE_U32 : VOPC_Real_gfx11_gfx12<0x04e>;
defm V_CMP_T_U32 : VOPC_Real_gfx11<0x04f>;
defm V_CMP_F_I64 : VOPC_Real_gfx11<0x050>;
-defm V_CMP_LT_I64 : VOPC_Real_gfx11<0x051>;
-defm V_CMP_EQ_I64 : VOPC_Real_gfx11<0x052>;
-defm V_CMP_LE_I64 : VOPC_Real_gfx11<0x053>;
-defm V_CMP_GT_I64 : VOPC_Real_gfx11<0x054>;
-defm V_CMP_NE_I64 : VOPC_Real_gfx11<0x055>;
-defm V_CMP_GE_I64 : VOPC_Real_gfx11<0x056>;
+defm V_CMP_LT_I64 : VOPC_Real_gfx11_gfx12<0x051>;
+defm V_CMP_EQ_I64 : VOPC_Real_gfx11_gfx12<0x052>;
+defm V_CMP_LE_I64 : VOPC_Real_gfx11_gfx12<0x053>;
+defm V_CMP_GT_I64 : VOPC_Real_gfx11_gfx12<0x054>;
+defm V_CMP_NE_I64 : VOPC_Real_gfx11_gfx12<0x055>;
+defm V_CMP_GE_I64 : VOPC_Real_gfx11_gfx12<0x056>;
defm V_CMP_T_I64 : VOPC_Real_gfx11<0x057>;
defm V_CMP_F_U64 : VOPC_Real_gfx11<0x058>;
-defm V_CMP_LT_U64 : VOPC_Real_gfx11<0x059>;
-defm V_CMP_EQ_U64 : VOPC_Real_gfx11<0x05a>;
-defm V_CMP_LE_U64 : VOPC_Real_gfx11<0x05b>;
-defm V_CMP_GT_U64 : VOPC_Real_gfx11<0x05c>;
-defm V_CMP_NE_U64 : VOPC_Real_gfx11<0x05d>;
-defm V_CMP_GE_U64 : VOPC_Real_gfx11<0x05e>;
+defm V_CMP_LT_U64 : VOPC_Real_gfx11_gfx12<0x059>;
+defm V_CMP_EQ_U64 : VOPC_Real_gfx11_gfx12<0x05a>;
+defm V_CMP_LE_U64 : VOPC_Real_gfx11_gfx12<0x05b>;
+defm V_CMP_GT_U64 : VOPC_Real_gfx11_gfx12<0x05c>;
+defm V_CMP_NE_U64 : VOPC_Real_gfx11_gfx12<0x05d>;
+defm V_CMP_GE_U64 : VOPC_Real_gfx11_gfx12<0x05e>;
defm V_CMP_T_U64 : VOPC_Real_gfx11<0x05f>;
-defm V_CMP_CLASS_F16_t16 : VOPC_Real_t16_gfx11<0x07d, "v_cmp_class_f16">;
-defm V_CMP_CLASS_F32 : VOPC_Real_gfx11<0x07e>;
-defm V_CMP_CLASS_F64 : VOPC_Real_gfx11<0x07f>;
+defm V_CMP_CLASS_F16_t16 : VOPC_Real_t16_gfx11_gfx12<0x07d, "v_cmp_class_f16">;
+defm V_CMP_CLASS_F32 : VOPC_Real_gfx11_gfx12<0x07e>;
+defm V_CMP_CLASS_F64 : VOPC_Real_gfx11_gfx12<0x07f>;
defm V_CMPX_F_F16_t16 : VOPCX_Real_t16_gfx11<0x080, "v_cmpx_f_f16">;
-defm V_CMPX_LT_F16_t16 : VOPCX_Real_t16_gfx11<0x081, "v_cmpx_lt_f16">;
-defm V_CMPX_EQ_F16_t16 : VOPCX_Real_t16_gfx11<0x082, "v_cmpx_eq_f16">;
-defm V_CMPX_LE_F16_t16 : VOPCX_Real_t16_gfx11<0x083, "v_cmpx_le_f16">;
-defm V_CMPX_GT_F16_t16 : VOPCX_Real_t16_gfx11<0x084, "v_cmpx_gt_f16">;
-defm V_CMPX_LG_F16_t16 : VOPCX_Real_t16_gfx11<0x085, "v_cmpx_lg_f16">;
-defm V_CMPX_GE_F16_t16 : VOPCX_Real_t16_gfx11<0x086, "v_cmpx_ge_f16">;
-defm V_CMPX_O_F16_t16 : VOPCX_Real_t16_gfx11<0x087, "v_cmpx_o_f16">;
-defm V_CMPX_U_F16_t16 : VOPCX_Real_t16_gfx11<0x088, "v_cmpx_u_f16">;
-defm V_CMPX_NGE_F16_t16 : VOPCX_Real_t16_gfx11<0x089, "v_cmpx_nge_f16">;
-defm V_CMPX_NLG_F16_t16 : VOPCX_Real_t16_gfx11<0x08a, "v_cmpx_nlg_f16">;
-defm V_CMPX_NGT_F16_t16 : VOPCX_Real_t16_gfx11<0x08b, "v_cmpx_ngt_f16">;
-defm V_CMPX_NLE_F16_t16 : VOPCX_Real_t16_gfx11<0x08c, "v_cmpx_nle_f16">;
-defm V_CMPX_NEQ_F16_t16 : VOPCX_Real_t16_gfx11<0x08d, "v_cmpx_neq_f16">;
-defm V_CMPX_NLT_F16_t16 : VOPCX_Real_t16_gfx11<0x08e, "v_cmpx_nlt_f16">;
+defm V_CMPX_LT_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x081, "v_cmpx_lt_f16">;
+defm V_CMPX_EQ_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x082, "v_cmpx_eq_f16">;
+defm V_CMPX_LE_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x083, "v_cmpx_le_f16">;
+defm V_CMPX_GT_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x084, "v_cmpx_gt_f16">;
+defm V_CMPX_LG_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x085, "v_cmpx_lg_f16">;
+defm V_CMPX_GE_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x086, "v_cmpx_ge_f16">;
+defm V_CMPX_O_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x087, "v_cmpx_o_f16">;
+defm V_CMPX_U_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x088, "v_cmpx_u_f16">;
+defm V_CMPX_NGE_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x089, "v_cmpx_nge_f16">;
+defm V_CMPX_NLG_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x08a, "v_cmpx_nlg_f16">;
+defm V_CMPX_NGT_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x08b, "v_cmpx_ngt_f16">;
+defm V_CMPX_NLE_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x08c, "v_cmpx_nle_f16">;
+defm V_CMPX_NEQ_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x08d, "v_cmpx_neq_f16">;
+defm V_CMPX_NLT_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x08e, "v_cmpx_nlt_f16">;
defm V_CMPX_T_F16_t16 : VOPCX_Real_with_name_gfx11<0x08f, "V_CMPX_TRU_F16_t16", "v_cmpx_t_f16", "v_cmpx_tru_f16">;
defm V_CMPX_F_F32 : VOPCX_Real_gfx11<0x090>;
-defm V_CMPX_LT_F32 : VOPCX_Real_gfx11<0x091>;
-defm V_CMPX_EQ_F32 : VOPCX_Real_gfx11<0x092>;
-defm V_CMPX_LE_F32 : VOPCX_Real_gfx11<0x093>;
-defm V_CMPX_GT_F32 : VOPCX_Real_gfx11<0x094>;
-defm V_CMPX_LG_F32 : VOPCX_Real_gfx11<0x095>;
-defm V_CMPX_GE_F32 : VOPCX_Real_gfx11<0x096>;
-defm V_CMPX_O_F32 : VOPCX_Real_gfx11<0x097>;
-defm V_CMPX_U_F32 : VOPCX_Real_gfx11<0x098>;
-defm V_CMPX_NGE_F32 : VOPCX_Real_gfx11<0x099>;
-defm V_CMPX_NLG_F32 : VOPCX_Real_gfx11<0x09a>;
-defm V_CMPX_NGT_F32 : VOPCX_Real_gfx11<0x09b>;
-defm V_CMPX_NLE_F32 : VOPCX_Real_gfx11<0x09c>;
-defm V_CMPX_NEQ_F32 : VOPCX_Real_gfx11<0x09d>;
-defm V_CMPX_NLT_F32 : VOPCX_Real_gfx11<0x09e>;
+defm V_CMPX_LT_F32 : VOPCX_Real_gfx11_gfx12<0x091>;
+defm V_CMPX_EQ_F32 : VOPCX_Real_gfx11_gfx12<0x092>;
+defm V_CMPX_LE_F32 : VOPCX_Real_gfx11_gfx12<0x093>;
+defm V_CMPX_GT_F32 : VOPCX_Real_gfx11_gfx12<0x094>;
+defm V_CMPX_LG_F32 : VOPCX_Real_gfx11_gfx12<0x095>;
+defm V_CMPX_GE_F32 : VOPCX_Real_gfx11_gfx12<0x096>;
+defm V_CMPX_O_F32 : VOPCX_Real_gfx11_gfx12<0x097>;
+defm V_CMPX_U_F32 : VOPCX_Real_gfx11_gfx12<0x098>;
+defm V_CMPX_NGE_F32 : VOPCX_Real_gfx11_gfx12<0x099>;
+defm V_CMPX_NLG_F32 : VOPCX_Real_gfx11_gfx12<0x09a>;
+defm V_CMPX_NGT_F32 : VOPCX_Real_gfx11_gfx12<0x09b>;
+defm V_CMPX_NLE_F32 : VOPCX_Real_gfx11_gfx12<0x09c>;
+defm V_CMPX_NEQ_F32 : VOPCX_Real_gfx11_gfx12<0x09d>;
+defm V_CMPX_NLT_F32 : VOPCX_Real_gfx11_gfx12<0x09e>;
defm V_CMPX_T_F32 : VOPCX_Real_with_name_gfx11<0x09f, "V_CMPX_TRU_F32", "v_cmpx_t_f32">;
defm V_CMPX_F_F64 : VOPCX_Real_gfx11<0x0a0>;
-defm V_CMPX_LT_F64 : VOPCX_Real_gfx11<0x0a1>;
-defm V_CMPX_EQ_F64 : VOPCX_Real_gfx11<0x0a2>;
-defm V_CMPX_LE_F64 : VOPCX_Real_gfx11<0x0a3>;
-defm V_CMPX_GT_F64 : VOPCX_Real_gfx11<0x0a4>;
-defm V_CMPX_LG_F64 : VOPCX_Real_gfx11<0x0a5>;
-defm V_CMPX_GE_F64 : VOPCX_Real_gfx11<0x0a6>;
-defm V_CMPX_O_F64 : VOPCX_Real_gfx11<0x0a7>;
-defm V_CMPX_U_F64 : VOPCX_Real_gfx11<0x0a8>;
-defm V_CMPX_NGE_F64 : VOPCX_Real_gfx11<0x0a9>;
-defm V_CMPX_NLG_F64 : VOPCX_Real_gfx11<0x0aa>;
-defm V_CMPX_NGT_F64 : VOPCX_Real_gfx11<0x0ab>;
-defm V_CMPX_NLE_F64 : VOPCX_Real_gfx11<0x0ac>;
-defm V_CMPX_NEQ_F64 : VOPCX_Real_gfx11<0x0ad>;
-defm V_CMPX_NLT_F64 : VOPCX_Real_gfx11<0x0ae>;
+defm V_CMPX_LT_F64 : VOPCX_Real_gfx11_gfx12<0x0a1>;
+defm V_CMPX_EQ_F64 : VOPCX_Real_gfx11_gfx12<0x0a2>;
+defm V_CMPX_LE_F64 : VOPCX_Real_gfx11_gfx12<0x0a3>;
+defm V_CMPX_GT_F64 : VOPCX_Real_gfx11_gfx12<0x0a4>;
+defm V_CMPX_LG_F64 : VOPCX_Real_gfx11_gfx12<0x0a5>;
+defm V_CMPX_GE_F64 : VOPCX_Real_gfx11_gfx12<0x0a6>;
+defm V_CMPX_O_F64 : VOPCX_Real_gfx11_gfx12<0x0a7>;
+defm V_CMPX_U_F64 : VOPCX_Real_gfx11_gfx12<0x0a8>;
+defm V_CMPX_NGE_F64 : VOPCX_Real_gfx11_gfx12<0x0a9>;
+defm V_CMPX_NLG_F64 : VOPCX_Real_gfx11_gfx12<0x0aa>;
+defm V_CMPX_NGT_F64 : VOPCX_Real_gfx11_gfx12<0x0ab>;
+defm V_CMPX_NLE_F64 : VOPCX_Real_gfx11_gfx12<0x0ac>;
+defm V_CMPX_NEQ_F64 : VOPCX_Real_gfx11_gfx12<0x0ad>;
+defm V_CMPX_NLT_F64 : VOPCX_Real_gfx11_gfx12<0x0ae>;
defm V_CMPX_T_F64 : VOPCX_Real_with_name_gfx11<0x0af, "V_CMPX_TRU_F64", "v_cmpx_t_f64">;
-defm V_CMPX_LT_I16_t16 : VOPCX_Real_t16_gfx11<0x0b1, "v_cmpx_lt_i16">;
-defm V_CMPX_EQ_I16_t16 : VOPCX_Real_t16_gfx11<0x0b2, "v_cmpx_eq_i16">;
-defm V_CMPX_LE_I16_t16 : VOPCX_Real_t16_gfx11<0x0b3, "v_cmpx_le_i16">;
-defm V_CMPX_GT_I16_t16 : VOPCX_Real_t16_gfx11<0x0b4, "v_cmpx_gt_i16">;
-defm V_CMPX_NE_I16_t16 : VOPCX_Real_t16_gfx11<0x0b5, "v_cmpx_ne_i16">;
-defm V_CMPX_GE_I16_t16 : VOPCX_Real_t16_gfx11<0x0b6, "v_cmpx_ge_i16">;
-defm V_CMPX_LT_U16_t16 : VOPCX_Real_t16_gfx11<0x0b9, "v_cmpx_lt_u16">;
-defm V_CMPX_EQ_U16_t16 : VOPCX_Real_t16_gfx11<0x0ba, "v_cmpx_eq_u16">;
-defm V_CMPX_LE_U16_t16 : VOPCX_Real_t16_gfx11<0x0bb, "v_cmpx_le_u16">;
-defm V_CMPX_GT_U16_t16 : VOPCX_Real_t16_gfx11<0x0bc, "v_cmpx_gt_u16">;
-defm V_CMPX_NE_U16_t16 : VOPCX_Real_t16_gfx11<0x0bd, "v_cmpx_ne_u16">;
-defm V_CMPX_GE_U16_t16 : VOPCX_Real_t16_gfx11<0x0be, "v_cmpx_ge_u16">;
+defm V_CMPX_LT_I16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0b1, "v_cmpx_lt_i16">;
+defm V_CMPX_EQ_I16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0b2, "v_cmpx_eq_i16">;
+defm V_CMPX_LE_I16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0b3, "v_cmpx_le_i16">;
+defm V_CMPX_GT_I16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0b4, "v_cmpx_gt_i16">;
+defm V_CMPX_NE_I16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0b5, "v_cmpx_ne_i16">;
+defm V_CMPX_GE_I16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0b6, "v_cmpx_ge_i16">;
+defm V_CMPX_LT_U16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0b9, "v_cmpx_lt_u16">;
+defm V_CMPX_EQ_U16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0ba, "v_cmpx_eq_u16">;
+defm V_CMPX_LE_U16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0bb, "v_cmpx_le_u16">;
+defm V_CMPX_GT_U16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0bc, "v_cmpx_gt_u16">;
+defm V_CMPX_NE_U16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0bd, "v_cmpx_ne_u16">;
+defm V_CMPX_GE_U16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0be, "v_cmpx_ge_u16">;
defm V_CMPX_F_I32 : VOPCX_Real_gfx11<0x0c0>;
-defm V_CMPX_LT_I32 : VOPCX_Real_gfx11<0x0c1>;
-defm V_CMPX_EQ_I32 : VOPCX_Real_gfx11<0x0c2>;
-defm V_CMPX_LE_I32 : VOPCX_Real_gfx11<0x0c3>;
-defm V_CMPX_GT_I32 : VOPCX_Real_gfx11<0x0c4>;
-defm V_CMPX_NE_I32 : VOPCX_Real_gfx11<0x0c5>;
-defm V_CMPX_GE_I32 : VOPCX_Real_gfx11<0x0c6>;
+defm V_CMPX_LT_I32 : VOPCX_Real_gfx11_gfx12<0x0c1>;
+defm V_CMPX_EQ_I32 : VOPCX_Real_gfx11_gfx12<0x0c2>;
+defm V_CMPX_LE_I32 : VOPCX_Real_gfx11_gfx12<0x0c3>;
+defm V_CMPX_GT_I32 : VOPCX_Real_gfx11_gfx12<0x0c4>;
+defm V_CMPX_NE_I32 : VOPCX_Real_gfx11_gfx12<0x0c5>;
+defm V_CMPX_GE_I32 : VOPCX_Real_gfx11_gfx12<0x0c6>;
defm V_CMPX_T_I32 : VOPCX_Real_gfx11<0x0c7>;
defm V_CMPX_F_U32 : VOPCX_Real_gfx11<0x0c8>;
-defm V_CMPX_LT_U32 : VOPCX_Real_gfx11<0x0c9>;
-defm V_CMPX_EQ_U32 : VOPCX_Real_gfx11<0x0ca>;
-defm V_CMPX_LE_U32 : VOPCX_Real_gfx11<0x0cb>;
-defm V_CMPX_GT_U32 : VOPCX_Real_gfx11<0x0cc>;
-defm V_CMPX_NE_U32 : VOPCX_Real_gfx11<0x0cd>;
-defm V_CMPX_GE_U32 : VOPCX_Real_gfx11<0x0ce>;
+defm V_CMPX_LT_U32 : VOPCX_Real_gfx11_gfx12<0x0c9>;
+defm V_CMPX_EQ_U32 : VOPCX_Real_gfx11_gfx12<0x0ca>;
+defm V_CMPX_LE_U32 : VOPCX_Real_gfx11_gfx12<0x0cb>;
+defm V_CMPX_GT_U32 : VOPCX_Real_gfx11_gfx12<0x0cc>;
+defm V_CMPX_NE_U32 : VOPCX_Real_gfx11_gfx12<0x0cd>;
+defm V_CMPX_GE_U32 : VOPCX_Real_gfx11_gfx12<0x0ce>;
defm V_CMPX_T_U32 : VOPCX_Real_gfx11<0x0cf>;
defm V_CMPX_F_I64 : VOPCX_Real_gfx11<0x0d0>;
-defm V_CMPX_LT_I64 : VOPCX_Real_gfx11<0x0d1>;
-defm V_CMPX_EQ_I64 : VOPCX_Real_gfx11<0x0d2>;
-defm V_CMPX_LE_I64 : VOPCX_Real_gfx11<0x0d3>;
-defm V_CMPX_GT_I64 : VOPCX_Real_gfx11<0x0d4>;
-defm V_CMPX_NE_I64 : VOPCX_Real_gfx11<0x0d5>;
-defm V_CMPX_GE_I64 : VOPCX_Real_gfx11<0x0d6>;
+defm V_CMPX_LT_I64 : VOPCX_Real_gfx11_gfx12<0x0d1>;
+defm V_CMPX_EQ_I64 : VOPCX_Real_gfx11_gfx12<0x0d2>;
+defm V_CMPX_LE_I64 : VOPCX_Real_gfx11_gfx12<0x0d3>;
+defm V_CMPX_GT_I64 : VOPCX_Real_gfx11_gfx12<0x0d4>;
+defm V_CMPX_NE_I64 : VOPCX_Real_gfx11_gfx12<0x0d5>;
+defm V_CMPX_GE_I64 : VOPCX_Real_gfx11_gfx12<0x0d6>;
defm V_CMPX_T_I64 : VOPCX_Real_gfx11<0x0d7>;
defm V_CMPX_F_U64 : VOPCX_Real_gfx11<0x0d8>;
-defm V_CMPX_LT_U64 : VOPCX_Real_gfx11<0x0d9>;
-defm V_CMPX_EQ_U64 : VOPCX_Real_gfx11<0x0da>;
-defm V_CMPX_LE_U64 : VOPCX_Real_gfx11<0x0db>;
-defm V_CMPX_GT_U64 : VOPCX_Real_gfx11<0x0dc>;
-defm V_CMPX_NE_U64 : VOPCX_Real_gfx11<0x0dd>;
-defm V_CMPX_GE_U64 : VOPCX_Real_gfx11<0x0de>;
+defm V_CMPX_LT_U64 : VOPCX_Real_gfx11_gfx12<0x0d9>;
+defm V_CMPX_EQ_U64 : VOPCX_Real_gfx11_gfx12<0x0da>;
+defm V_CMPX_LE_U64 : VOPCX_Real_gfx11_gfx12<0x0db>;
+defm V_CMPX_GT_U64 : VOPCX_Real_gfx11_gfx12<0x0dc>;
+defm V_CMPX_NE_U64 : VOPCX_Real_gfx11_gfx12<0x0dd>;
+defm V_CMPX_GE_U64 : VOPCX_Real_gfx11_gfx12<0x0de>;
defm V_CMPX_T_U64 : VOPCX_Real_gfx11<0x0df>;
-defm V_CMPX_CLASS_F16_t16 : VOPCX_Real_t16_gfx11<0x0fd, "v_cmpx_class_f16">;
-defm V_CMPX_CLASS_F32 : VOPCX_Real_gfx11<0x0fe>;
-defm V_CMPX_CLASS_F64 : VOPCX_Real_gfx11<0x0ff>;
+defm V_CMPX_CLASS_F16_t16 : VOPCX_Real_t16_gfx11_gfx12<0x0fd, "v_cmpx_class_f16">;
+defm V_CMPX_CLASS_F32 : VOPCX_Real_gfx11_gfx12<0x0fe>;
+defm V_CMPX_CLASS_F64 : VOPCX_Real_gfx11_gfx12<0x0ff>;
//===----------------------------------------------------------------------===//
// GFX10.
@@ -1976,10 +2016,13 @@ multiclass VOPCX_Real_gfx6_gfx7_gfx10 <bits<9> op> :
VOPC_Real_gfx6_gfx7<op>, VOPCX_Real_gfx10<op>;
multiclass VOPC_Real_gfx6_gfx7_gfx10_gfx11<bits<9> op> :
- VOPC_Real_gfx6_gfx7_gfx10<op>, VOPC_Real_gfx11<op>;
+ VOPC_Real_gfx6_gfx7_gfx10<op>, VOPC_Real_Base<GFX11Gen, op>;
multiclass VOPCX_Real_gfx6_gfx7_gfx10_gfx11<bits<9> op> :
- VOPCX_Real_gfx6_gfx7_gfx10<op>, VOPCX_Real_gfx11<op>;
+ VOPCX_Real_gfx6_gfx7_gfx10<op>, VOPCX_Real<GFX11Gen, op>;
+
+multiclass VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<bits<9> op> :
+ VOPC_Real_gfx6_gfx7_gfx10_gfx11<op>, VOPC_Real_Base<GFX12Gen, op>;
defm V_CMP_F_F32 : VOPC_Real_gfx6_gfx7_gfx10<0x000>;
defm V_CMP_LT_F32 : VOPC_Real_gfx6_gfx7_gfx10<0x001>;
@@ -2014,20 +2057,20 @@ defm V_CMPX_NEQ_F32 : VOPCX_Real_gfx6_gfx7_gfx10<0x01d>;
defm V_CMPX_NLT_F32 : VOPCX_Real_gfx6_gfx7_gfx10<0x01e>;
defm V_CMPX_TRU_F32 : VOPCX_Real_gfx6_gfx7_gfx10<0x01f>;
defm V_CMP_F_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x020>;
-defm V_CMP_LT_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x021>;
-defm V_CMP_EQ_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x022>;
-defm V_CMP_LE_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x023>;
-defm V_CMP_GT_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x024>;
-defm V_CMP_LG_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x025>;
-defm V_CMP_GE_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x026>;
-defm V_CMP_O_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x027>;
-defm V_CMP_U_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x028>;
-defm V_CMP_NGE_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x029>;
-defm V_CMP_NLG_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x02a>;
-defm V_CMP_NGT_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x02b>;
-defm V_CMP_NLE_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x02c>;
-defm V_CMP_NEQ_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x02d>;
-defm V_CMP_NLT_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11<0x02e>;
+defm V_CMP_LT_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x021>;
+defm V_CMP_EQ_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x022>;
+defm V_CMP_LE_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x023>;
+defm V_CMP_GT_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x024>;
+defm V_CMP_LG_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x025>;
+defm V_CMP_GE_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x026>;
+defm V_CMP_O_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x027>;
+defm V_CMP_U_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x028>;
+defm V_CMP_NGE_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x029>;
+defm V_CMP_NLG_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x02a>;
+defm V_CMP_NGT_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x02b>;
+defm V_CMP_NLE_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x02c>;
+defm V_CMP_NEQ_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x02d>;
+defm V_CMP_NLT_F64 : VOPC_Real_gfx6_gfx7_gfx10_gfx11_gfx12<0x02e>;
defm V_CMP_TRU_F64 : VOPC_Real_gfx6_gfx7_gfx10<0x02f>;
defm V_CMPX_F_F64 : VOPCX_Real_gfx6_gfx7_gfx10<0x030>;
defm V_CMPX_LT_F64 : VOPCX_Real_gfx6_gfx7_gfx10<0x031>;
diff --git a/llvm/lib/Target/AMDGPU/VOPDInstructions.td b/llvm/lib/Target/AMDGPU/VOPDInstructions.td
index c6dc4dd765e5..c6af3d67c560 100644
--- a/llvm/lib/Target/AMDGPU/VOPDInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPDInstructions.td
@@ -54,23 +54,34 @@ class VOPD_MADKe<bits<4> opX, bits<5> opY> : Enc96 {
// VOPD classes
//===----------------------------------------------------------------------===//
+
+class GFXGenD<GFXGen Gen, list<string> DXPseudos, list<string> DYPseudos,
+ Predicate subtargetPred = Gen.AssemblerPredicate> :
+ GFXGen<Gen.AssemblerPredicate, Gen.DecoderNamespace, Gen.Suffix,
+ Gen.Subtarget> {
+ list<string> VOPDXPseudos = DXPseudos;
+ list<string> VOPDYPseudos = DYPseudos;
+ Predicate SubtargetPredicate = subtargetPred;
+}
+
class VOPD_Base<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY,
- VOPD_Component XasVC, VOPD_Component YasVC>
+ VOPD_Component XasVC, VOPD_Component YasVC, GFXGenD Gen>
: VOPAnyCommon<outs, ins, asm, []>,
VOP<NAME>,
- SIMCInstr<NAME, SIEncodingFamily.GFX11> {
+ SIMCInstr<NAME, Gen.Subtarget> {
// Fields for table indexing
Instruction Opcode = !cast<Instruction>(NAME);
bits<5> OpX = XasVC.VOPDOp;
bits<5> OpY = YasVC.VOPDOp;
+ bits<4> SubTgt = Gen.Subtarget;
let VALU = 1;
- let DecoderNamespace = "GFX11";
- let AssemblerPredicate = isGFX11Plus;
+ let DecoderNamespace = Gen.DecoderNamespace;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
let WaveSizePredicate = isWave32;
let isCodeGenOnly = 0;
- let SubtargetPredicate = isGFX11Plus;
+ let SubtargetPredicate = Gen.SubtargetPredicate;
let AsmMatchConverter = "cvtVOPD";
let Size = 8;
let ReadsModeReg = !or(VDX.ReadsModeReg, VDY.ReadsModeReg);
@@ -97,16 +108,16 @@ class VOPD_Base<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY,
}
class VOPD<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY,
- VOPD_Component XasVC, VOPD_Component YasVC>
- : VOPD_Base<outs, ins, asm, VDX, VDY, XasVC, YasVC>,
+ VOPD_Component XasVC, VOPD_Component YasVC, GFXGenD Gen>
+ : VOPD_Base<outs, ins, asm, VDX, VDY, XasVC, YasVC, Gen>,
VOPDe<XasVC.VOPDOp{3-0}, YasVC.VOPDOp> {
let Inst{16-9} = !if (!eq(VDX.Mnemonic, "v_mov_b32"), 0x0, vsrc1X);
let Inst{48-41} = !if (!eq(VDY.Mnemonic, "v_mov_b32"), 0x0, vsrc1Y);
}
class VOPD_MADK<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY,
- VOPD_Component XasVC, VOPD_Component YasVC>
- : VOPD_Base<outs, ins, asm, VDX, VDY, XasVC, YasVC>,
+ VOPD_Component XasVC, VOPD_Component YasVC, GFXGenD Gen>
+ : VOPD_Base<outs, ins, asm, VDX, VDY, XasVC, YasVC, Gen>,
VOPD_MADKe<XasVC.VOPDOp{3-0}, YasVC.VOPDOp> {
let Inst{16-9} = !if (!eq(VDX.Mnemonic, "v_mov_b32"), 0x0, vsrc1X);
let Inst{48-41} = !if (!eq(VDY.Mnemonic, "v_mov_b32"), 0x0, vsrc1Y);
@@ -115,60 +126,85 @@ class VOPD_MADK<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY,
}
// V_DUAL_DOT2ACC_F32_BF16 is a legal instruction, but V_DOT2ACC_F32_BF16 is
-// not. Since we generate the DUAL form by converting from the normal form we
-// will never generate it.
-defvar VOPDYPseudos = [
+// not. V_DUAL_DOT2C_F32_BF16 is a legal instruction on GFX12, but
+// V_DOT2C_F32_F16_e32 is not. Since we generate the DUAL form by converting
+// from the normal form we will never generate them.
+defvar VOPDPseudosCommon = [
"V_FMAC_F32_e32", "V_FMAAK_F32", "V_FMAMK_F32", "V_MUL_F32_e32",
"V_ADD_F32_e32", "V_SUB_F32_e32", "V_SUBREV_F32_e32", "V_MUL_LEGACY_F32_e32",
- "V_MOV_B32_e32", "V_CNDMASK_B32_e32", "V_MAX_F32_e32", "V_MIN_F32_e32",
- "V_DOT2C_F32_F16_e32", "V_ADD_U32_e32", "V_LSHLREV_B32_e32", "V_AND_B32_e32"
+ "V_MOV_B32_e32", "V_CNDMASK_B32_e32", "V_MAX_F32_e32", "V_MIN_F32_e32"
];
-defvar VOPDXPseudos = VOPDYPseudos[0...VOPDX_Max_Index];
+defvar VOPDPseudosGFX11 = ["V_DOT2C_F32_F16_e32"];
+defvar VOPDYOnlyPseudosCommon = ["V_ADD_U32_e32", "V_LSHLREV_B32_e32",
+ "V_AND_B32_e32"];
+
+defvar VOPDXPseudosGFX11 = !listconcat(VOPDPseudosCommon, VOPDPseudosGFX11);
+defvar VOPDXPseudosGFX12 = VOPDPseudosCommon;
+defvar VOPDYPseudosGFX11 = !listconcat(VOPDXPseudosGFX11, VOPDYOnlyPseudosCommon);
+defvar VOPDYPseudosGFX12 = !listconcat(VOPDXPseudosGFX12, VOPDYOnlyPseudosCommon);
+
+def GFX11GenD : GFXGenD<GFX11Gen, VOPDXPseudosGFX11, VOPDYPseudosGFX11>;
+def GFX12GenD : GFXGenD<GFX12Gen, VOPDXPseudosGFX12, VOPDYPseudosGFX12>;
+
def VOPDDstYOperand : RegisterOperand<VGPR_32, "printRegularOperand"> {
let DecoderMethod = "decodeOperandVOPDDstY";
}
-foreach x = VOPDXPseudos in {
- foreach y = VOPDYPseudos in {
- defvar xInst = !cast<VOP_Pseudo>(x);
- defvar yInst = !cast<VOP_Pseudo>(y);
- defvar XasVC = !cast<VOPD_Component>(x);
- defvar YasVC = !cast<VOPD_Component>(y);
- defvar isMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32"),
- !eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32"));
- // If X or Y is MADK (have a mandatory immediate), all src operands which
- // may contain an optional literal must use the VSrc_*_Deferred operand
- // type. Optional literal operands in MADK VOPD components always use this
- // operand form. If Both X and Y are MADK, the mandatory literal of X
- // additionally must use an alternate operand format which defers to the
- // 'real' Y literal
- defvar isOpXMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32"));
- defvar isOpYMADK = !or(!eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32"));
- defvar OpName = "V_DUAL_" # !substr(x,2) # "_X_" # !substr(y,2);
- defvar outs = (outs VGPRSrc_32:$vdstX, VOPDDstYOperand:$vdstY);
- if !or(isOpXMADK, isOpYMADK) then {
- if !and(isOpXMADK, isOpYMADK) then {
- defvar X_MADK_Pfl = !cast<VOP_MADK_Base>(xInst.Pfl);
- defvar ins = !con(xInst.Pfl.InsVOPDXDeferred, yInst.Pfl.InsVOPDY);
- defvar asm = XasVC.VOPDName #" "# X_MADK_Pfl.AsmVOPDXDeferred #" :: "# YasVC.VOPDName #" "# yInst.Pfl.AsmVOPDY;
- def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC>;
- } else {
- defvar asm = XasVC.VOPDName #" "# xInst.Pfl.AsmVOPDX #" :: "# YasVC.VOPDName #" "# yInst.Pfl.AsmVOPDY;
- if isOpXMADK then {
- assert !not(isOpYMADK), "Expected only OpX as MADK";
- defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDYDeferred);
- def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC>;
- } else {
- assert !not(isOpXMADK), "Expected only OpY as MADK";
+class getRenamed<string VOPDName, GFXGen Gen> {
+ string ret = !if(!eq(Gen.Subtarget, GFX12Gen.Subtarget),
+ !if(!eq(VOPDName, "v_dual_max_f32"),
+ "v_dual_max_num_f32",
+ !if(!eq(VOPDName, "v_dual_min_f32"),
+ "v_dual_min_num_f32",
+ VOPDName)),
+ VOPDName);
+}
+
+foreach Gen = [GFX11GenD, GFX12GenD] in {
+ foreach x = Gen.VOPDXPseudos in {
+ foreach y = Gen.VOPDYPseudos in {
+ defvar xInst = !cast<VOP_Pseudo>(x);
+ defvar yInst = !cast<VOP_Pseudo>(y);
+ defvar XasVC = !cast<VOPD_Component>(x);
+ defvar YasVC = !cast<VOPD_Component>(y);
+ defvar xAsmName = getRenamed<XasVC.VOPDName, Gen>.ret;
+ defvar yAsmName = getRenamed<YasVC.VOPDName, Gen>.ret;
+ defvar isMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32"),
+ !eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32"));
+ // If X or Y is MADK (have a mandatory immediate), all src operands which
+ // may contain an optional literal must use the VSrc_*_Deferred operand
+ // type. Optional literal operands in MADK VOPD components always use this
+ // operand form. If Both X and Y are MADK, the mandatory literal of X
+ // additionally must use an alternate operand format which defers to the
+ // 'real' Y literal
+ defvar isOpXMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32"));
+ defvar isOpYMADK = !or(!eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32"));
+ defvar OpName = "V_DUAL_" # !substr(x,2) # "_X_" # !substr(y,2) # Gen.Suffix;
+ defvar outs = (outs VGPRSrc_32:$vdstX, VOPDDstYOperand:$vdstY);
+ if !or(isOpXMADK, isOpYMADK) then {
+ if !and(isOpXMADK, isOpYMADK) then {
+ defvar X_MADK_Pfl = !cast<VOP_MADK_Base>(xInst.Pfl);
defvar ins = !con(xInst.Pfl.InsVOPDXDeferred, yInst.Pfl.InsVOPDY);
- def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC>;
+ defvar asm = xAsmName #" "# X_MADK_Pfl.AsmVOPDXDeferred #" :: "# yAsmName #" "# yInst.Pfl.AsmVOPDY;
+ def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>;
+ } else {
+ defvar asm = xAsmName #" "# xInst.Pfl.AsmVOPDX #" :: "# yAsmName #" "# yInst.Pfl.AsmVOPDY;
+ if isOpXMADK then {
+ assert !not(isOpYMADK), "Expected only OpX as MADK";
+ defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDYDeferred);
+ def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>;
+ } else {
+ assert !not(isOpXMADK), "Expected only OpY as MADK";
+ defvar ins = !con(xInst.Pfl.InsVOPDXDeferred, yInst.Pfl.InsVOPDY);
+ def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>;
+ }
}
+ } else {
+ defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDY);
+ defvar asm = xAsmName #" "# xInst.Pfl.AsmVOPDX #" :: "# yAsmName #" "# yInst.Pfl.AsmVOPDY;
+ def OpName : VOPD<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>;
}
- } else {
- defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDY);
- defvar asm = XasVC.VOPDName #" "# xInst.Pfl.AsmVOPDX #" :: "# YasVC.VOPDName #" "# yInst.Pfl.AsmVOPDY;
- def OpName : VOPD<outs, ins, asm, xInst, yInst, XasVC, YasVC>;
}
}
}
diff --git a/llvm/lib/Target/AMDGPU/VOPInstructions.td b/llvm/lib/Target/AMDGPU/VOPInstructions.td
index 395bb01f867c..fd4626d902ac 100644
--- a/llvm/lib/Target/AMDGPU/VOPInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPInstructions.td
@@ -29,6 +29,22 @@ class LetDummies {
string DecoderNamespace;
}
+//===----------------------------------------------------------------------===//
+// VOP Subtarget info
+//===----------------------------------------------------------------------===//
+
+class GFXGen<Predicate pred, string dn, string suffix, int sub> {
+ Predicate AssemblerPredicate = pred;
+ string DecoderNamespace = dn;
+ string Suffix = suffix;
+ int Subtarget = sub;
+}
+
+def GFX12Gen : GFXGen<isGFX12Only, "GFX12", "_gfx12", SIEncodingFamily.GFX12>;
+def GFX11Gen : GFXGen<isGFX11Only, "GFX11", "_gfx11", SIEncodingFamily.GFX11>;
+
+//===----------------------------------------------------------------------===//
+
class VOP <string opName> {
string OpName = opName;
}
@@ -190,6 +206,14 @@ class VOP3_Real <VOP_Pseudo ps, int EncodingFamily, string asm_name = ps.Mnemoni
VOPProfile Pfl = ps.Pfl;
}
+class VOP3_Real_Gen <VOP_Pseudo ps, GFXGen Gen, string asm_name = ps.Mnemonic> :
+ VOP3_Real <ps, Gen.Subtarget, asm_name> {
+ let AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts,
+ Gen.AssemblerPredicate);
+ let DecoderNamespace = Gen.DecoderNamespace#
+ !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+}
+
// XXX - Is there any reason to distinguish this from regular VOP3
// here?
class VOP3P_Real<VOP_Pseudo ps, int EncodingFamily, string asm_name = ps.Mnemonic> :
@@ -199,6 +223,12 @@ class VOP3P_Real<VOP_Pseudo ps, int EncodingFamily, string asm_name = ps.Mnemoni
let Constraints = !if(!eq(!substr(ps.Mnemonic,0,6), "v_wmma"), "", ps.Constraints);
}
+class VOP3P_Real_Gen<VOP_Pseudo ps, GFXGen Gen, string asm_name = ps.Mnemonic> :
+ VOP3P_Real<ps, Gen.Subtarget, asm_name> {
+ let AssemblerPredicate = Gen.AssemblerPredicate;
+ let DecoderNamespace = Gen.DecoderNamespace;
+}
+
class VOP3a<VOPProfile P> : Enc64 {
bits<4> src0_modifiers;
bits<9> src0;
@@ -234,7 +264,7 @@ class VOP3a_gfx10<bits<10> op, VOPProfile p> : VOP3a<p> {
let Inst{31-26} = 0x35;
}
-class VOP3a_gfx11<bits<10> op, VOPProfile p> : VOP3a_gfx10<op, p>;
+class VOP3a_gfx11_gfx12<bits<10> op, VOPProfile p> : VOP3a_gfx10<op, p>;
class VOP3a_vi <bits<10> op, VOPProfile P> : VOP3a<P> {
let Inst{25-16} = op;
@@ -251,7 +281,7 @@ class VOP3e_gfx10<bits<10> op, VOPProfile p> : VOP3a_gfx10<op, p> {
let Inst{7-0} = !if(p.EmitDst, vdst{7-0}, 0);
}
-class VOP3e_gfx11<bits<10> op, VOPProfile p> : VOP3e_gfx10<op, p>;
+class VOP3e_gfx11_gfx12<bits<10> op, VOPProfile p> : VOP3e_gfx10<op, p>;
class VOP3e_vi <bits<10> op, VOPProfile P> : VOP3a_vi <op, P> {
bits<8> vdst;
@@ -272,9 +302,9 @@ class VOP3OpSel_gfx10<bits<10> op, VOPProfile p> : VOP3e_gfx10<op, p> {
let Inst{14} = !if(p.HasDst, src0_modifiers{3}, 0);
}
-class VOP3OpSel_gfx11<bits<10> op, VOPProfile p> : VOP3OpSel_gfx10<op, p>;
+class VOP3OpSel_gfx11_gfx12<bits<10> op, VOPProfile p> : VOP3OpSel_gfx10<op, p>;
-class VOP3DotOpSel_gfx11<bits<10> op, VOPProfile p> : VOP3OpSel_gfx11<op, p>{
+class VOP3DotOpSel_gfx11_gfx12<bits<10> op, VOPProfile p> : VOP3OpSel_gfx11_gfx12<op, p>{
let Inst{11} = ?;
let Inst{12} = ?;
}
@@ -435,7 +465,7 @@ class VOP3Pe_gfx10 <bits<7> op, VOPProfile P> : VOP3Pe<op, P> {
let Inst{31-23} = 0x198; //encoding
}
-class VOP3Pe_gfx11<bits<7> op, VOPProfile P> : VOP3Pe_gfx10<op, P>;
+class VOP3Pe_gfx11_gfx12<bits<7> op, VOPProfile P> : VOP3Pe_gfx10<op, P>;
class VOP3be_gfx6_gfx7<bits<9> op, VOPProfile p> : VOP3be<p> {
let Inst{25-17} = op;
@@ -448,7 +478,7 @@ class VOP3be_gfx10<bits<10> op, VOPProfile p> : VOP3be<p> {
let Inst{31-26} = 0x35;
}
-class VOP3be_gfx11<bits<10> op, VOPProfile p> : VOP3be_gfx10<op, p>;
+class VOP3be_gfx11_gfx12<bits<10> op, VOPProfile p> : VOP3be_gfx10<op, p>;
class VOP3be_vi <bits<10> op, VOPProfile P> : VOP3be<P> {
bits<1> clamp;
@@ -1273,6 +1303,19 @@ multiclass VOP3Inst<string OpName, VOPProfile P, SDPatternOperator node = null_f
} // end SubtargetPredicate = isGFX11Plus
}
+class UniformUnaryFragOrOp<SDPatternOperator Op> {
+ SDPatternOperator ret = !if(!or(!isa<SDNode>(Op), !isa<PatFrags>(Op)),
+ UniformUnaryFrag<Op>, Op);
+}
+
+multiclass VOP3PseudoScalarInst<string OpName, VOPProfile P,
+ SDPatternOperator node = null_frag> {
+ def _e64 : VOP3_Pseudo<OpName, P, [(set P.DstVT:$vdst,
+ (UniformUnaryFragOrOp<node>.ret
+ (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp,
+ i32:$omod))))]>;
+}
+
//===----------------------------------------------------------------------===//
// VOP3 DPP
//===----------------------------------------------------------------------===//
@@ -1294,6 +1337,15 @@ class VOP3_DPP16<bits<10> op, VOP_DPP_Pseudo ps, int subtarget,
string opName = ps.OpName>
: Base_VOP3_DPP16<op, ps, opName>, SIMCInstr<ps.PseudoInstr, subtarget>;
+class VOP3_DPP16_Gen<bits<10> op, VOP_DPP_Pseudo ps, GFXGen Gen,
+ string opName = ps.OpName> :
+ VOP3_DPP16 <op, ps, Gen.Subtarget, opName> {
+ let AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts,
+ Gen.AssemblerPredicate);
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace#
+ !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+}
+
class Base_VOP3_DPP8<bits<10> op, VOP_Pseudo ps, string opName = ps.OpName>
: VOP3_DPP8<op, opName, ps.Pfl> {
let VOP3_OPSEL = ps.Pfl.HasOpSel;
@@ -1320,170 +1372,240 @@ class VOP3b_DPP8_Base<bits<10> op, VOP_Pseudo ps, string opName = ps.OpName>
}
//===----------------------------------------------------------------------===//
-// VOP3 GFX11
+// VOP3 GFX11, GFX12
//===----------------------------------------------------------------------===//
-let AssemblerPredicate = isGFX11Only,
- DecoderNamespace = "GFX11" in {
- multiclass VOP3_Real_Base_gfx11<bits<10> op, string opName = NAME,
- bit isSingle = 0> {
- defvar ps = !cast<VOP_Pseudo>(opName#"_e64");
- let IsSingle = !or(isSingle, ps.Pfl.IsSingle) in {
- if ps.Pfl.HasOpSel then
- def _e64_gfx11 :
- VOP3_Real<ps, SIEncodingFamily.GFX11>,
- VOP3OpSel_gfx11<op, ps.Pfl>;
- if !not(ps.Pfl.HasOpSel) then
- def _e64_gfx11 :
- VOP3_Real<ps, SIEncodingFamily.GFX11>,
- VOP3e_gfx11<op, ps.Pfl>;
- }
- }
- multiclass VOP3Dot_Real_Base_gfx11<bits<10> op, string opName = NAME,
- bit isSingle = 0> {
- defvar ps = !cast<VOP_Pseudo>(opName#"_e64");
- let IsSingle = !or(isSingle, ps.Pfl.IsSingle) in {
- def _e64_gfx11 :
- VOP3_Real<ps, SIEncodingFamily.GFX11>,
- VOP3DotOpSel_gfx11<op, ps.Pfl>;
- }
- }
- multiclass VOP3_Real_with_name_gfx11<bits<10> op, string opName,
- string asmName, bit isSingle = 0> {
- defvar ps = !cast<VOP_Pseudo>(opName#"_e64");
- let AsmString = asmName # ps.AsmOperands,
- IsSingle = !or(isSingle, ps.Pfl.IsSingle) in {
- if ps.Pfl.HasOpSel then
- def _e64_gfx11 :
- VOP3_Real<ps, SIEncodingFamily.GFX11>,
- VOP3OpSel_gfx11<op, ps.Pfl>;
- if !not(ps.Pfl.HasOpSel) then
- let DecoderNamespace = !if(ps.Pfl.IsRealTrue16, "GFX11", "GFX11_FAKE16"),
- AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, isGFX11Only) in
- def _e64_gfx11 :
- VOP3_Real<ps, SIEncodingFamily.GFX11>,
- VOP3e_gfx11<op, ps.Pfl>;
- }
- def _gfx11_VOP3_alias : MnemonicAlias<ps.Mnemonic, asmName>, Requires<[isGFX11Plus]>, LetDummies;
- }
- // for READLANE/WRITELANE
- multiclass VOP3_Real_No_Suffix_gfx11<bits<10> op, string opName = NAME> {
- defvar ps = !cast<VOP_Pseudo>(opName);
- def _e64_gfx11 :
- VOP3_Real<ps, SIEncodingFamily.GFX11>,
- VOP3e_gfx11<op, ps.Pfl>;
- }
- multiclass VOP3_Real_dpp_Base_gfx11<bits<10> op, string opName = NAME> {
- def _e64_dpp_gfx11 : VOP3_DPP16<op, !cast<VOP_DPP_Pseudo>(opName#"_e64"#"_dpp"), SIEncodingFamily.GFX11> {
- let DecoderNamespace = "DPPGFX11";
- }
+multiclass VOP3_Real_Base<GFXGen Gen, bits<10> op, string opName = NAME,
+ bit isSingle = 0> {
+ defvar ps = !cast<VOP_Pseudo>(opName#"_e64");
+ let IsSingle = !or(isSingle, ps.Pfl.IsSingle) in {
+ if ps.Pfl.HasOpSel then
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<ps, Gen>,
+ VOP3OpSel_gfx11_gfx12<op, ps.Pfl>;
+ if !not(ps.Pfl.HasOpSel) then
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<ps, Gen>,
+ VOP3e_gfx11_gfx12<op, ps.Pfl>;
}
+}
- multiclass VOP3Dot_Real_dpp_Base_gfx11<bits<10> op, string opName = NAME> {
- def _e64_dpp_gfx11 : VOP3_DPP16<op, !cast<VOP_DPP_Pseudo>(opName#"_e64"#"_dpp"), SIEncodingFamily.GFX11> {
- let Inst{11} = ?;
- let Inst{12} = ?;
- let DecoderNamespace = "DPPGFX11";
- }
+multiclass VOP3Dot_Real_Base<GFXGen Gen, bits<10> op, string opName = NAME,
+ bit isSingle = 0> {
+ defvar ps = !cast<VOP_Pseudo>(opName#"_e64");
+ let IsSingle = !or(isSingle, ps.Pfl.IsSingle) in {
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<ps, Gen>,
+ VOP3DotOpSel_gfx11_gfx12<op, ps.Pfl>;
}
+}
- multiclass VOP3_Real_dpp_with_name_gfx11<bits<10> op, string opName,
- string asmName> {
- defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
- let AsmString = asmName # ps.Pfl.AsmVOP3DPP16,
- DecoderNamespace = !if(ps.Pfl.IsRealTrue16, "DPPGFX11", "DPPGFX11_FAKE16"),
- AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, isGFX11Only) in {
- defm NAME : VOP3_Real_dpp_Base_gfx11<op, opName>;
- }
- }
- multiclass VOP3_Real_dpp8_Base_gfx11<bits<10> op, string opName = NAME> {
- defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
- def _e64_dpp8_gfx11 : Base_VOP3_DPP8<op, ps> {
- let DecoderNamespace = "DPP8GFX11";
- }
+multiclass VOP3_Real_with_name<GFXGen Gen, bits<10> op, string opName,
+ string asmName, bit isSingle = 0> {
+ defvar ps = !cast<VOP_Pseudo>(opName#"_e64");
+ let AsmString = asmName # ps.AsmOperands,
+ IsSingle = !or(isSingle, ps.Pfl.IsSingle) in {
+ if ps.Pfl.HasOpSel then
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<ps, Gen>,
+ VOP3OpSel_gfx11_gfx12<op, ps.Pfl>;
+ if !not(ps.Pfl.HasOpSel) then
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<ps, Gen>,
+ VOP3e_gfx11_gfx12<op, ps.Pfl>;
}
+ def Gen.Suffix#"_VOP3_alias" : MnemonicAlias<ps.Mnemonic, asmName>, Requires<[Gen.AssemblerPredicate]>, LetDummies;
+}
+
+// for READLANE/WRITELANE
+multiclass VOP3_Real_No_Suffix<GFXGen Gen, bits<10> op, string opName = NAME> {
+ defvar ps = !cast<VOP_Pseudo>(opName);
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<ps, Gen>,
+ VOP3e_gfx11_gfx12<op, ps.Pfl>;
+}
+
+multiclass VOP3_Real_dpp_Base<GFXGen Gen, bits<10> op, string opName = NAME> {
+ def _e64_dpp#Gen.Suffix :
+ VOP3_DPP16_Gen<op, !cast<VOP_DPP_Pseudo>(opName#"_e64"#"_dpp"), Gen>;
+}
- multiclass VOP3Dot_Real_dpp8_Base_gfx11<bits<10> op, string opName = NAME> {
- defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
- def _e64_dpp8_gfx11 : Base_VOP3_DPP8<op, ps> {
+multiclass VOP3Dot_Real_dpp_Base<GFXGen Gen, bits<10> op, string opName = NAME> {
+ def _e64_dpp#Gen.Suffix :
+ VOP3_DPP16_Gen<op, !cast<VOP_DPP_Pseudo>(opName#"_e64"#"_dpp"), Gen> {
let Inst{11} = ?;
let Inst{12} = ?;
- let DecoderNamespace = "DPP8GFX11";
}
+}
+
+multiclass VOP3_Real_dpp_with_name<GFXGen Gen, bits<10> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
+ let AsmString = asmName # ps.Pfl.AsmVOP3DPP16 in {
+ defm NAME : VOP3_Real_dpp_Base<Gen, op, opName>;
}
+}
- multiclass VOP3_Real_dpp8_with_name_gfx11<bits<10> op, string opName,
- string asmName> {
- defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
- let AsmString = asmName # ps.Pfl.AsmVOP3DPP8,
- DecoderNamespace = !if(ps.Pfl.IsRealTrue16, "DPP8GFX11", "DPP8GFX11_FAKE16"),
- AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, isGFX11Only) in {
- defm NAME : VOP3_Real_dpp8_Base_gfx11<op, opName>;
- }
+multiclass VOP3_Real_dpp8_Base<GFXGen Gen, bits<10> op, string opName = NAME> {
+ defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
+ def _e64_dpp8#Gen.Suffix : Base_VOP3_DPP8<op, ps> {
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
}
- multiclass VOP3be_Real_gfx11<bits<10> op, string opName, string asmName,
- bit isSingle = 0> {
- defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
- let IsSingle = !or(isSingle, ps.Pfl.IsSingle) in
- def _e64_gfx11 :
- VOP3_Real<ps, SIEncodingFamily.GFX11, asmName>,
- VOP3be_gfx11<op, ps.Pfl> ;
+}
+
+multiclass VOP3Dot_Real_dpp8_Base<GFXGen Gen, bits<10> op, string opName = NAME> {
+ defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
+ def _e64_dpp8#Gen.Suffix : Base_VOP3_DPP8<op, ps> {
+ let Inst{11} = ?;
+ let Inst{12} = ?;
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
}
- multiclass VOP3be_Real_dpp_gfx11<bits<10> op, string opName, string asmName> {
- defvar ps = !cast<VOP3_Pseudo>(opName #"_e64");
- defvar dpp_ps = !cast<VOP_DPP_Pseudo>(opName #"_e64" #"_dpp");
- def _e64_dpp_gfx11 : Base_VOP3b_DPP16<op, dpp_ps, asmName>,
- SIMCInstr<dpp_ps.PseudoInstr, SIEncodingFamily.GFX11> {
- let DecoderNamespace = "DPPGFX11";
- }
+}
+
+multiclass VOP3_Real_dpp8_with_name<GFXGen Gen, bits<10> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
+ let AsmString = asmName # ps.Pfl.AsmVOP3DPP8,
+ DecoderNamespace = "DPP8"#Gen.DecoderNamespace#
+ !if(ps.Pfl.IsRealTrue16, "", "_FAKE16"),
+ AssemblerPredicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts,
+ Gen.AssemblerPredicate) in {
+
+ defm NAME : VOP3_Real_dpp8_Base<Gen, op, opName>;
}
- multiclass VOP3be_Real_dpp8_gfx11<bits<10> op, string opName, string asmName> {
- defvar ps = !cast<VOP3_Pseudo>(opName #"_e64");
- def _e64_dpp8_gfx11 : VOP3b_DPP8_Base<op, ps, asmName> {
- let DecoderNamespace = "DPP8GFX11";
- }
+}
+
+multiclass VOP3be_Real<GFXGen Gen, bits<10> op, string opName, string asmName,
+ bit isSingle = 0> {
+ defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
+ let IsSingle = !or(isSingle, ps.Pfl.IsSingle) in
+ def _e64#Gen.Suffix :
+ VOP3_Real_Gen<ps, Gen, asmName>,
+ VOP3be_gfx11_gfx12<op, ps.Pfl> ;
+}
+
+multiclass VOP3be_Real_dpp<GFXGen Gen, bits<10> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP3_Pseudo>(opName #"_e64");
+ defvar dpp_ps = !cast<VOP_DPP_Pseudo>(opName #"_e64" #"_dpp");
+ def _e64_dpp#Gen.Suffix : Base_VOP3b_DPP16<op, dpp_ps, asmName>,
+ SIMCInstr<dpp_ps.PseudoInstr, Gen.Subtarget> {
+ let DecoderNamespace = "DPP"#Gen.DecoderNamespace;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
+ }
+}
+
+multiclass VOP3be_Real_dpp8<GFXGen Gen, bits<10> op, string opName,
+ string asmName> {
+ defvar ps = !cast<VOP3_Pseudo>(opName #"_e64");
+ def _e64_dpp8#Gen.Suffix : VOP3b_DPP8_Base<op, ps, asmName> {
+ let DecoderNamespace = "DPP8"#Gen.DecoderNamespace;
+ let AssemblerPredicate = Gen.AssemblerPredicate;
}
-} // End AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11"
+}
// VOP1 and VOP2 depend on these triple defs
-multiclass VOP3_Realtriple_gfx11<bits<10> op,
- bit isSingle = 0, string opName = NAME> :
- VOP3_Real_Base_gfx11<op, opName, isSingle>,
- VOP3_Real_dpp_Base_gfx11<op, opName>,
- VOP3_Real_dpp8_Base_gfx11<op, opName>;
-
-multiclass VOP3Dot_Realtriple_gfx11<bits<10> op,
- bit isSingle = 0, string opName = NAME> :
- VOP3Dot_Real_Base_gfx11<op, opName, isSingle>,
- VOP3Dot_Real_dpp_Base_gfx11<op, opName>,
- VOP3Dot_Real_dpp8_Base_gfx11<op, opName>;
-
-multiclass VOP3Only_Realtriple_gfx11<bits<10> op> :
- VOP3_Realtriple_gfx11<op, 1>;
-
-multiclass VOP3_Realtriple_with_name_gfx11<bits<10> op, string opName,
- string asmName, bit isSingle = 0> :
- VOP3_Real_with_name_gfx11<op, opName, asmName, isSingle>,
- VOP3_Real_dpp_with_name_gfx11<op, opName, asmName>,
- VOP3_Real_dpp8_with_name_gfx11<op, opName, asmName>;
+multiclass VOP3_Realtriple<GFXGen Gen, bits<10> op, bit isSingle = 0,
+ string opName = NAME> :
+ VOP3_Real_Base<Gen, op, opName, isSingle>,
+ VOP3_Real_dpp_Base<Gen, op, opName>,
+ VOP3_Real_dpp8_Base<Gen, op, opName>;
+
+multiclass VOP3Dot_Realtriple<GFXGen Gen, bits<10> op, bit isSingle = 0,
+ string opName = NAME> :
+ VOP3Dot_Real_Base<Gen, op, opName, isSingle>,
+ VOP3Dot_Real_dpp_Base<Gen, op, opName>,
+ VOP3Dot_Real_dpp8_Base<Gen, op, opName>;
+
+multiclass VOP3Only_Realtriple<GFXGen Gen, bits<10> op> :
+ VOP3_Realtriple<Gen, op, 1>;
+
+multiclass VOP3_Realtriple_with_name<GFXGen Gen, bits<10> op, string opName,
+ string asmName, bit isSingle = 0> :
+ VOP3_Real_with_name<Gen, op, opName, asmName, isSingle>,
+ VOP3_Real_dpp_with_name<Gen, op, opName, asmName>,
+ VOP3_Real_dpp8_with_name<Gen, op, opName, asmName>;
+
+multiclass VOP3Only_Realtriple_with_name<GFXGen Gen, bits<10> op, string opName,
+ string asmName> :
+ VOP3_Realtriple_with_name<Gen, op, opName, asmName, 1>;
+
+multiclass VOP3Only_Realtriple_t16<GFXGen Gen, bits<10> op, string asmName,
+ string opName = NAME>
+ : VOP3Only_Realtriple_with_name<Gen, op, opName, asmName>;
+
+multiclass VOP3be_Realtriple<
+ GFXGen Gen, bits<10> op, bit isSingle = 0, string opName = NAME,
+ string asmName = !cast<VOP_Pseudo>(opName#"_e64").Mnemonic> :
+ VOP3be_Real<Gen, op, opName, asmName, isSingle>,
+ VOP3be_Real_dpp<Gen, op, opName, asmName>,
+ VOP3be_Real_dpp8<Gen, op, opName, asmName>;
-multiclass VOP3Only_Realtriple_with_name_gfx11<bits<10> op, string opName,
- string asmName> :
- VOP3_Realtriple_with_name_gfx11<op, opName, asmName, 1>;
+multiclass VOP3beOnly_Realtriple<GFXGen Gen, bits<10> op> :
+ VOP3be_Realtriple<Gen, op, 1>;
+
+//===----------------------------------------------------------------------===//
+// VOP3 GFX11
+//===----------------------------------------------------------------------===//
+
+multiclass VOP3be_Real_gfx11<bits<10> op, string opName, string asmName,
+ bit isSingle = 0> :
+ VOP3be_Real<GFX11Gen, op, opName, asmName, isSingle>;
+
+multiclass VOP3_Real_Base_gfx11<bits<10> op, string opName = NAME,
+ bit isSingle = 0> :
+ VOP3_Real_Base<GFX11Gen, op, opName, isSingle>;
+
+multiclass VOP3_Realtriple_gfx11<bits<10> op, bit isSingle = 0,
+ string opName = NAME> :
+ VOP3_Realtriple<GFX11Gen, op, isSingle, opName>;
multiclass VOP3Only_Realtriple_t16_gfx11<bits<10> op, string asmName,
string opName = NAME>
- : VOP3Only_Realtriple_with_name_gfx11<op, opName, asmName>;
+ : VOP3Only_Realtriple_with_name<GFX11Gen, op, opName, asmName>;
-multiclass VOP3be_Realtriple_gfx11<
- bits<10> op, bit isSingle = 0, string opName = NAME,
- string asmName = !cast<VOP_Pseudo>(opName#"_e64").Mnemonic> :
- VOP3be_Real_gfx11<op, opName, asmName, isSingle>,
- VOP3be_Real_dpp_gfx11<op, opName, asmName>,
- VOP3be_Real_dpp8_gfx11<op, opName, asmName>;
+//===----------------------------------------------------------------------===//
+// VOP3 GFX12
+//===----------------------------------------------------------------------===//
+
+multiclass VOP3Only_Realtriple_gfx12<bits<10> op, bit isSingle = 0> :
+ VOP3_Realtriple<GFX12Gen, op, isSingle>;
+
+// IsSingle is captured from the vopprofile for these instructions, but the
+// following alternative is more explicit
+multiclass VOP3Only_Real_Base_gfx12<bits<10> op> :
+ VOP3_Real_Base<GFX12Gen, op, NAME, 1/*IsSingle*/>;
-multiclass VOP3beOnly_Realtriple_gfx11<bits<10> op> :
- VOP3be_Realtriple_gfx11<op, 1>;
+multiclass VOP3Only_Realtriple_t16_gfx12<bits<10> op> :
+ VOP3Only_Realtriple<GFX12Gen, op>;
+
+multiclass VOP3be_Real_with_name_gfx12<bits<10> op, string opName,
+ string asmName, bit isSingle = 0> {
+ defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
+ let AsmString = asmName # ps.AsmOperands,
+ IsSingle = !or(isSingle, ps.Pfl.IsSingle) in
+ def _e64_gfx12 :
+ VOP3_Real_Gen<ps, GFX12Gen, asmName>,
+ VOP3be_gfx11_gfx12<op, ps.Pfl>,
+ MnemonicAlias<ps.Mnemonic, asmName>, Requires<[isGFX12Only]>;
+}
+
+multiclass VOP3_Realtriple_with_name_gfx12<bits<10> op, string opName,
+ string asmName, bit isSingle = 0> :
+ VOP3_Realtriple_with_name<GFX12Gen, op, opName, asmName, isSingle>;
+
+multiclass VOP3Only_Realtriple_with_name_gfx11_gfx12<bits<10> op, string opName,
+ string asmName> :
+ VOP3Only_Realtriple_with_name<GFX11Gen, op, opName, asmName>,
+ VOP3Only_Realtriple_with_name<GFX12Gen, op, opName, asmName>;
+
+multiclass VOP3Only_Realtriple_with_name_t16_gfx12<bits<10> op, string asmName,
+ string opName = NAME>
+ : VOP3Only_Realtriple_with_name<GFX12Gen, op, opName, asmName>;
+
+//===----------------------------------------------------------------------===//
include "VOPCInstructions.td"
include "VOP1Instructions.td"
diff --git a/llvm/lib/Target/ARM/ARM.td b/llvm/lib/Target/ARM/ARM.td
index 3df428b9ce96..97d1444a553e 100644
--- a/llvm/lib/Target/ARM/ARM.td
+++ b/llvm/lib/Target/ARM/ARM.td
@@ -1662,7 +1662,7 @@ def : ProcNoItin<"neoverse-n1", [ARMv82a,
FeatureCRC,
FeatureDotProd]>;
-def : ProcNoItin<"neoverse-n2", [ARMv85a,
+def : ProcNoItin<"neoverse-n2", [ARMv9a,
FeatureBF16,
FeatureMatMulInt8]>;
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index b85107ec4719..a0776296b8eb 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -6435,20 +6435,20 @@ void ARMBaseInstrInfo::saveLROnStack(MachineBasicBlock &MBB,
MachineBasicBlock::iterator It, bool CFI,
bool Auth) const {
int Align = std::max(Subtarget.getStackAlignment().value(), uint64_t(8));
+ unsigned MIFlags = CFI ? MachineInstr::FrameSetup : 0;
assert(Align >= 8 && Align <= 256);
if (Auth) {
assert(Subtarget.isThumb2());
// Compute PAC in R12. Outlining ensures R12 is dead across the outlined
// sequence.
- BuildMI(MBB, It, DebugLoc(), get(ARM::t2PAC))
- .setMIFlags(MachineInstr::FrameSetup);
+ BuildMI(MBB, It, DebugLoc(), get(ARM::t2PAC)).setMIFlags(MIFlags);
BuildMI(MBB, It, DebugLoc(), get(ARM::t2STRD_PRE), ARM::SP)
.addReg(ARM::R12, RegState::Kill)
.addReg(ARM::LR, RegState::Kill)
.addReg(ARM::SP)
.addImm(-Align)
.add(predOps(ARMCC::AL))
- .setMIFlags(MachineInstr::FrameSetup);
+ .setMIFlags(MIFlags);
} else {
unsigned Opc = Subtarget.isThumb() ? ARM::t2STR_PRE : ARM::STR_PRE_IMM;
BuildMI(MBB, It, DebugLoc(), get(Opc), ARM::SP)
@@ -6456,7 +6456,7 @@ void ARMBaseInstrInfo::saveLROnStack(MachineBasicBlock &MBB,
.addReg(ARM::SP)
.addImm(-Align)
.add(predOps(ARMCC::AL))
- .setMIFlags(MachineInstr::FrameSetup);
+ .setMIFlags(MIFlags);
}
if (!CFI)
@@ -6511,6 +6511,7 @@ void ARMBaseInstrInfo::restoreLRFromStack(MachineBasicBlock &MBB,
MachineBasicBlock::iterator It,
bool CFI, bool Auth) const {
int Align = Subtarget.getStackAlignment().value();
+ unsigned MIFlags = CFI ? MachineInstr::FrameDestroy : 0;
if (Auth) {
assert(Subtarget.isThumb2());
// Restore return address PAC and LR.
@@ -6521,7 +6522,7 @@ void ARMBaseInstrInfo::restoreLRFromStack(MachineBasicBlock &MBB,
.addReg(ARM::SP)
.addImm(Align)
.add(predOps(ARMCC::AL))
- .setMIFlags(MachineInstr::FrameDestroy);
+ .setMIFlags(MIFlags);
// LR authentication is after the CFI instructions, below.
} else {
unsigned Opc = Subtarget.isThumb() ? ARM::t2LDR_POST : ARM::LDR_POST_IMM;
@@ -6532,7 +6533,7 @@ void ARMBaseInstrInfo::restoreLRFromStack(MachineBasicBlock &MBB,
MIB.addReg(0);
MIB.addImm(Subtarget.getStackAlignment().value())
.add(predOps(ARMCC::AL))
- .setMIFlags(MachineInstr::FrameDestroy);
+ .setMIFlags(MIFlags);
}
if (CFI) {
diff --git a/llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp b/llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp
index ec2d8f59ee9b..a364992fab3e 100644
--- a/llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp
@@ -13,6 +13,18 @@ using namespace llvm;
void ARMFunctionInfo::anchor() {}
+yaml::ARMFunctionInfo::ARMFunctionInfo(const llvm::ARMFunctionInfo &MFI)
+ : LRSpilled(MFI.isLRSpilled()) {}
+
+void yaml::ARMFunctionInfo::mappingImpl(yaml::IO &YamlIO) {
+ MappingTraits<ARMFunctionInfo>::mapping(YamlIO, *this);
+}
+
+void ARMFunctionInfo::initializeBaseYamlFields(
+ const yaml::ARMFunctionInfo &YamlMFI) {
+ LRSpilled = YamlMFI.LRSpilled;
+}
+
static bool GetBranchTargetEnforcement(const Function &F,
const ARMSubtarget *Subtarget) {
if (!Subtarget->isMClass() || !Subtarget->hasV7Ops())
diff --git a/llvm/lib/Target/ARM/ARMMachineFunctionInfo.h b/llvm/lib/Target/ARM/ARMMachineFunctionInfo.h
index f7531ce78cca..b9ff3a08f998 100644
--- a/llvm/lib/Target/ARM/ARMMachineFunctionInfo.h
+++ b/llvm/lib/Target/ARM/ARMMachineFunctionInfo.h
@@ -15,6 +15,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/CodeGen/MIRYamlMapping.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/Support/ErrorHandling.h"
@@ -22,6 +23,10 @@
namespace llvm {
+namespace yaml {
+struct ARMFunctionInfo;
+} // end namespace yaml
+
class ARMSubtarget;
/// ARMFunctionInfo - This class is derived from MachineFunctionInfo and
@@ -293,8 +298,29 @@ public:
}
bool branchTargetEnforcement() const { return BranchTargetEnforcement; }
+
+ void initializeBaseYamlFields(const yaml::ARMFunctionInfo &YamlMFI);
};
+namespace yaml {
+struct ARMFunctionInfo final : public yaml::MachineFunctionInfo {
+ bool LRSpilled;
+
+ ARMFunctionInfo() = default;
+ ARMFunctionInfo(const llvm::ARMFunctionInfo &MFI);
+
+ void mappingImpl(yaml::IO &YamlIO) override;
+ ~ARMFunctionInfo() = default;
+};
+
+template <> struct MappingTraits<ARMFunctionInfo> {
+ static void mapping(IO &YamlIO, ARMFunctionInfo &MFI) {
+ YamlIO.mapOptional("isLRSpilled", MFI.LRSpilled);
+ }
+};
+
+} // end namespace yaml
+
} // end namespace llvm
#endif // LLVM_LIB_TARGET_ARM_ARMMACHINEFUNCTIONINFO_H
diff --git a/llvm/lib/Target/ARM/ARMSLSHardening.cpp b/llvm/lib/Target/ARM/ARMSLSHardening.cpp
index 09357ae2e3a3..23d72b34902d 100644
--- a/llvm/lib/Target/ARM/ARMSLSHardening.cpp
+++ b/llvm/lib/Target/ARM/ARMSLSHardening.cpp
@@ -210,7 +210,7 @@ ArmInsertedThunks SLSBLRThunkInserter::insertThunks(MachineModuleInfo &MMI,
void SLSBLRThunkInserter::populateThunk(MachineFunction &MF) {
// FIXME: How to better communicate Register number, rather than through
// name and lookup table?
- assert(MF.getName().startswith(getThunkPrefix()));
+ assert(MF.getName().starts_with(getThunkPrefix()));
auto ThunkIt = llvm::find_if(
SLSBLRThunks, [&MF](auto T) { return T.Name == MF.getName(); });
assert(ThunkIt != std::end(SLSBLRThunks));
diff --git a/llvm/lib/Target/ARM/ARMSubtarget.h b/llvm/lib/Target/ARM/ARMSubtarget.h
index aa8bea103dd6..43b4123a1b55 100644
--- a/llvm/lib/Target/ARM/ARMSubtarget.h
+++ b/llvm/lib/Target/ARM/ARMSubtarget.h
@@ -32,6 +32,7 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/TargetParser/Triple.h"
+#include <bitset>
#include <memory>
#include <string>
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
index a80d485e750b..a99773691df1 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
@@ -30,6 +30,7 @@
#include "llvm/CodeGen/GlobalISel/Legalizer.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
+#include "llvm/CodeGen/MIRParser/MIParser.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/Passes.h"
@@ -130,9 +131,9 @@ computeTargetABI(const Triple &TT, StringRef CPU,
if (ABIName == "aapcs16")
return ARMBaseTargetMachine::ARM_ABI_AAPCS16;
- else if (ABIName.startswith("aapcs"))
+ else if (ABIName.starts_with("aapcs"))
return ARMBaseTargetMachine::ARM_ABI_AAPCS;
- else if (ABIName.startswith("apcs"))
+ else if (ABIName.starts_with("apcs"))
return ARMBaseTargetMachine::ARM_ABI_APCS;
llvm_unreachable("Unhandled/unknown ABI Name!");
@@ -619,3 +620,23 @@ void ARMPassConfig::addPreEmitPass2() {
addPass(createEHContGuardCatchretPass());
}
}
+
+yaml::MachineFunctionInfo *
+ARMBaseTargetMachine::createDefaultFuncInfoYAML() const {
+ return new yaml::ARMFunctionInfo();
+}
+
+yaml::MachineFunctionInfo *
+ARMBaseTargetMachine::convertFuncInfoToYAML(const MachineFunction &MF) const {
+ const auto *MFI = MF.getInfo<ARMFunctionInfo>();
+ return new yaml::ARMFunctionInfo(*MFI);
+}
+
+bool ARMBaseTargetMachine::parseMachineFunctionInfo(
+ const yaml::MachineFunctionInfo &MFI, PerFunctionMIParsingState &PFS,
+ SMDiagnostic &Error, SMRange &SourceRange) const {
+ const auto &YamlMFI = static_cast<const yaml::ARMFunctionInfo &>(MFI);
+ MachineFunction &MF = PFS.MF;
+ MF.getInfo<ARMFunctionInfo>()->initializeBaseYamlFields(YamlMFI);
+ return false;
+}
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.h b/llvm/lib/Target/ARM/ARMTargetMachine.h
index 1754382692ba..69d8fa8ada64 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.h
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.h
@@ -83,6 +83,14 @@ public:
// Addrspacecasts are always noops.
return true;
}
+
+ yaml::MachineFunctionInfo *createDefaultFuncInfoYAML() const override;
+ yaml::MachineFunctionInfo *
+ convertFuncInfoToYAML(const MachineFunction &MF) const override;
+ bool parseMachineFunctionInfo(const yaml::MachineFunctionInfo &,
+ PerFunctionMIParsingState &PFS,
+ SMDiagnostic &Error,
+ SMRange &SourceRange) const override;
};
/// ARM/Thumb little endian target machine.
diff --git a/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp b/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp
index ab0a8f78b156..cbc5e5210865 100644
--- a/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp
@@ -1984,7 +1984,7 @@ bool ARMTTIImpl::isLoweredToCall(const Function *F) {
return BaseT::isLoweredToCall(F);
// Assume all Arm-specific intrinsics map to an instruction.
- if (F->getName().startswith("llvm.arm"))
+ if (F->getName().starts_with("llvm.arm"))
return false;
switch (F->getIntrinsicID()) {
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 20b52ebc544a..18dccb26b877 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -191,7 +191,7 @@ public:
/// Returns true iff a given mnemonic is a CDE instruction
bool isCDEInstr(StringRef Mnemonic) {
// Quick check before searching the set
- if (!Mnemonic.startswith("cx") && !Mnemonic.startswith("vcx"))
+ if (!Mnemonic.starts_with("cx") && !Mnemonic.starts_with("vcx"))
return false;
return CDE.count(Mnemonic);
}
@@ -199,7 +199,7 @@ public:
/// Returns true iff a given mnemonic is a VPT-predicable CDE instruction
/// (possibly with a predication suffix "e" or "t")
bool isVPTPredicableCDEInstr(StringRef Mnemonic) {
- if (!Mnemonic.startswith("vcx"))
+ if (!Mnemonic.starts_with("vcx"))
return false;
return CDEWithVPTSuffix.count(Mnemonic);
}
@@ -207,17 +207,17 @@ public:
/// Returns true iff a given mnemonic is an IT-predicable CDE instruction
/// (possibly with a condition suffix)
bool isITPredicableCDEInstr(StringRef Mnemonic) {
- if (!Mnemonic.startswith("cx"))
+ if (!Mnemonic.starts_with("cx"))
return false;
- return Mnemonic.startswith("cx1a") || Mnemonic.startswith("cx1da") ||
- Mnemonic.startswith("cx2a") || Mnemonic.startswith("cx2da") ||
- Mnemonic.startswith("cx3a") || Mnemonic.startswith("cx3da");
+ return Mnemonic.starts_with("cx1a") || Mnemonic.starts_with("cx1da") ||
+ Mnemonic.starts_with("cx2a") || Mnemonic.starts_with("cx2da") ||
+ Mnemonic.starts_with("cx3a") || Mnemonic.starts_with("cx3da");
}
/// Return true iff a given mnemonic is an integer CDE instruction with
/// dual-register destination
bool isCDEDualRegInstr(StringRef Mnemonic) {
- if (!Mnemonic.startswith("cx"))
+ if (!Mnemonic.starts_with("cx"))
return false;
return Mnemonic == "cx1d" || Mnemonic == "cx1da" ||
Mnemonic == "cx2d" || Mnemonic == "cx2da" ||
@@ -6083,7 +6083,7 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
case AsmToken::LBrac:
return parseMemory(Operands);
case AsmToken::LCurly:
- return parseRegisterList(Operands, !Mnemonic.startswith("clr"));
+ return parseRegisterList(Operands, !Mnemonic.starts_with("clr"));
case AsmToken::Dollar:
case AsmToken::Hash: {
// #42 -> immediate
@@ -6295,32 +6295,29 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic,
// Ignore some mnemonics we know aren't predicated forms.
//
// FIXME: Would be nice to autogen this.
- if ((Mnemonic == "movs" && isThumb()) ||
- Mnemonic == "teq" || Mnemonic == "vceq" || Mnemonic == "svc" ||
- Mnemonic == "mls" || Mnemonic == "smmls" || Mnemonic == "vcls" ||
- Mnemonic == "vmls" || Mnemonic == "vnmls" || Mnemonic == "vacge" ||
- Mnemonic == "vcge" || Mnemonic == "vclt" || Mnemonic == "vacgt" ||
- Mnemonic == "vaclt" || Mnemonic == "vacle" || Mnemonic == "hlt" ||
- Mnemonic == "vcgt" || Mnemonic == "vcle" || Mnemonic == "smlal" ||
- Mnemonic == "umaal" || Mnemonic == "umlal" || Mnemonic == "vabal" ||
- Mnemonic == "vmlal" || Mnemonic == "vpadal" || Mnemonic == "vqdmlal" ||
- Mnemonic == "fmuls" || Mnemonic == "vmaxnm" || Mnemonic == "vminnm" ||
- Mnemonic == "vcvta" || Mnemonic == "vcvtn" || Mnemonic == "vcvtp" ||
- Mnemonic == "vcvtm" || Mnemonic == "vrinta" || Mnemonic == "vrintn" ||
- Mnemonic == "vrintp" || Mnemonic == "vrintm" || Mnemonic == "hvc" ||
- Mnemonic.startswith("vsel") || Mnemonic == "vins" || Mnemonic == "vmovx" ||
- Mnemonic == "bxns" || Mnemonic == "blxns" ||
- Mnemonic == "vdot" || Mnemonic == "vmmla" ||
- Mnemonic == "vudot" || Mnemonic == "vsdot" ||
- Mnemonic == "vcmla" || Mnemonic == "vcadd" ||
- Mnemonic == "vfmal" || Mnemonic == "vfmsl" ||
- Mnemonic == "wls" || Mnemonic == "le" || Mnemonic == "dls" ||
- Mnemonic == "csel" || Mnemonic == "csinc" ||
- Mnemonic == "csinv" || Mnemonic == "csneg" || Mnemonic == "cinc" ||
- Mnemonic == "cinv" || Mnemonic == "cneg" || Mnemonic == "cset" ||
- Mnemonic == "csetm" ||
- Mnemonic == "aut" || Mnemonic == "pac" || Mnemonic == "pacbti" ||
- Mnemonic == "bti")
+ if ((Mnemonic == "movs" && isThumb()) || Mnemonic == "teq" ||
+ Mnemonic == "vceq" || Mnemonic == "svc" || Mnemonic == "mls" ||
+ Mnemonic == "smmls" || Mnemonic == "vcls" || Mnemonic == "vmls" ||
+ Mnemonic == "vnmls" || Mnemonic == "vacge" || Mnemonic == "vcge" ||
+ Mnemonic == "vclt" || Mnemonic == "vacgt" || Mnemonic == "vaclt" ||
+ Mnemonic == "vacle" || Mnemonic == "hlt" || Mnemonic == "vcgt" ||
+ Mnemonic == "vcle" || Mnemonic == "smlal" || Mnemonic == "umaal" ||
+ Mnemonic == "umlal" || Mnemonic == "vabal" || Mnemonic == "vmlal" ||
+ Mnemonic == "vpadal" || Mnemonic == "vqdmlal" || Mnemonic == "fmuls" ||
+ Mnemonic == "vmaxnm" || Mnemonic == "vminnm" || Mnemonic == "vcvta" ||
+ Mnemonic == "vcvtn" || Mnemonic == "vcvtp" || Mnemonic == "vcvtm" ||
+ Mnemonic == "vrinta" || Mnemonic == "vrintn" || Mnemonic == "vrintp" ||
+ Mnemonic == "vrintm" || Mnemonic == "hvc" ||
+ Mnemonic.starts_with("vsel") || Mnemonic == "vins" ||
+ Mnemonic == "vmovx" || Mnemonic == "bxns" || Mnemonic == "blxns" ||
+ Mnemonic == "vdot" || Mnemonic == "vmmla" || Mnemonic == "vudot" ||
+ Mnemonic == "vsdot" || Mnemonic == "vcmla" || Mnemonic == "vcadd" ||
+ Mnemonic == "vfmal" || Mnemonic == "vfmsl" || Mnemonic == "wls" ||
+ Mnemonic == "le" || Mnemonic == "dls" || Mnemonic == "csel" ||
+ Mnemonic == "csinc" || Mnemonic == "csinv" || Mnemonic == "csneg" ||
+ Mnemonic == "cinc" || Mnemonic == "cinv" || Mnemonic == "cneg" ||
+ Mnemonic == "cset" || Mnemonic == "csetm" || Mnemonic == "aut" ||
+ Mnemonic == "pac" || Mnemonic == "pacbti" || Mnemonic == "bti")
return Mnemonic;
// First, split out any predication code. Ignore mnemonics we know aren't
@@ -6330,16 +6327,13 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic,
Mnemonic != "umlals" && Mnemonic != "umulls" && Mnemonic != "lsls" &&
Mnemonic != "sbcs" && Mnemonic != "rscs" &&
!(hasMVE() &&
- (Mnemonic == "vmine" ||
- Mnemonic == "vshle" || Mnemonic == "vshlt" || Mnemonic == "vshllt" ||
- Mnemonic == "vrshle" || Mnemonic == "vrshlt" ||
- Mnemonic == "vmvne" || Mnemonic == "vorne" ||
- Mnemonic == "vnege" || Mnemonic == "vnegt" ||
- Mnemonic == "vmule" || Mnemonic == "vmult" ||
- Mnemonic == "vrintne" ||
- Mnemonic == "vcmult" || Mnemonic == "vcmule" ||
- Mnemonic == "vpsele" || Mnemonic == "vpselt" ||
- Mnemonic.startswith("vq")))) {
+ (Mnemonic == "vmine" || Mnemonic == "vshle" || Mnemonic == "vshlt" ||
+ Mnemonic == "vshllt" || Mnemonic == "vrshle" || Mnemonic == "vrshlt" ||
+ Mnemonic == "vmvne" || Mnemonic == "vorne" || Mnemonic == "vnege" ||
+ Mnemonic == "vnegt" || Mnemonic == "vmule" || Mnemonic == "vmult" ||
+ Mnemonic == "vrintne" || Mnemonic == "vcmult" ||
+ Mnemonic == "vcmule" || Mnemonic == "vpsele" || Mnemonic == "vpselt" ||
+ Mnemonic.starts_with("vq")))) {
unsigned CC = ARMCondCodeFromString(Mnemonic.substr(Mnemonic.size()-2));
if (CC != ~0U) {
Mnemonic = Mnemonic.slice(0, Mnemonic.size() - 2);
@@ -6349,18 +6343,17 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic,
// Next, determine if we have a carry setting bit. We explicitly ignore all
// the instructions we know end in 's'.
- if (Mnemonic.endswith("s") &&
- !(Mnemonic == "cps" || Mnemonic == "mls" ||
- Mnemonic == "mrs" || Mnemonic == "smmls" || Mnemonic == "vabs" ||
- Mnemonic == "vcls" || Mnemonic == "vmls" || Mnemonic == "vmrs" ||
- Mnemonic == "vnmls" || Mnemonic == "vqabs" || Mnemonic == "vrecps" ||
- Mnemonic == "vrsqrts" || Mnemonic == "srs" || Mnemonic == "flds" ||
- Mnemonic == "fmrs" || Mnemonic == "fsqrts" || Mnemonic == "fsubs" ||
- Mnemonic == "fsts" || Mnemonic == "fcpys" || Mnemonic == "fdivs" ||
- Mnemonic == "fmuls" || Mnemonic == "fcmps" || Mnemonic == "fcmpzs" ||
- Mnemonic == "vfms" || Mnemonic == "vfnms" || Mnemonic == "fconsts" ||
- Mnemonic == "bxns" || Mnemonic == "blxns" || Mnemonic == "vfmas" ||
- Mnemonic == "vmlas" ||
+ if (Mnemonic.ends_with("s") &&
+ !(Mnemonic == "cps" || Mnemonic == "mls" || Mnemonic == "mrs" ||
+ Mnemonic == "smmls" || Mnemonic == "vabs" || Mnemonic == "vcls" ||
+ Mnemonic == "vmls" || Mnemonic == "vmrs" || Mnemonic == "vnmls" ||
+ Mnemonic == "vqabs" || Mnemonic == "vrecps" || Mnemonic == "vrsqrts" ||
+ Mnemonic == "srs" || Mnemonic == "flds" || Mnemonic == "fmrs" ||
+ Mnemonic == "fsqrts" || Mnemonic == "fsubs" || Mnemonic == "fsts" ||
+ Mnemonic == "fcpys" || Mnemonic == "fdivs" || Mnemonic == "fmuls" ||
+ Mnemonic == "fcmps" || Mnemonic == "fcmpzs" || Mnemonic == "vfms" ||
+ Mnemonic == "vfnms" || Mnemonic == "fconsts" || Mnemonic == "bxns" ||
+ Mnemonic == "blxns" || Mnemonic == "vfmas" || Mnemonic == "vmlas" ||
(Mnemonic == "movs" && isThumb()))) {
Mnemonic = Mnemonic.slice(0, Mnemonic.size() - 1);
CarrySetting = true;
@@ -6368,7 +6361,7 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic,
// The "cps" instruction can have a interrupt mode operand which is glued into
// the mnemonic. Check if this is the case, split it and parse the imod op
- if (Mnemonic.startswith("cps")) {
+ if (Mnemonic.starts_with("cps")) {
// Split out any imod code.
unsigned IMod =
StringSwitch<unsigned>(Mnemonic.substr(Mnemonic.size()-2, 2))
@@ -6397,16 +6390,15 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic,
}
// The "it" instruction has the condition mask on the end of the mnemonic.
- if (Mnemonic.startswith("it")) {
+ if (Mnemonic.starts_with("it")) {
ITMask = Mnemonic.slice(2, Mnemonic.size());
Mnemonic = Mnemonic.slice(0, 2);
}
- if (Mnemonic.startswith("vpst")) {
+ if (Mnemonic.starts_with("vpst")) {
ITMask = Mnemonic.slice(4, Mnemonic.size());
Mnemonic = Mnemonic.slice(0, 4);
- }
- else if (Mnemonic.startswith("vpt")) {
+ } else if (Mnemonic.starts_with("vpt")) {
ITMask = Mnemonic.slice(3, Mnemonic.size());
Mnemonic = Mnemonic.slice(0, 3);
}
@@ -6441,39 +6433,36 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic,
if (Mnemonic == "bkpt" || Mnemonic == "cbnz" || Mnemonic == "setend" ||
Mnemonic == "cps" || Mnemonic == "it" || Mnemonic == "cbz" ||
Mnemonic == "trap" || Mnemonic == "hlt" || Mnemonic == "udf" ||
- Mnemonic.startswith("crc32") || Mnemonic.startswith("cps") ||
- Mnemonic.startswith("vsel") || Mnemonic == "vmaxnm" ||
+ Mnemonic.starts_with("crc32") || Mnemonic.starts_with("cps") ||
+ Mnemonic.starts_with("vsel") || Mnemonic == "vmaxnm" ||
Mnemonic == "vminnm" || Mnemonic == "vcvta" || Mnemonic == "vcvtn" ||
Mnemonic == "vcvtp" || Mnemonic == "vcvtm" || Mnemonic == "vrinta" ||
Mnemonic == "vrintn" || Mnemonic == "vrintp" || Mnemonic == "vrintm" ||
- Mnemonic.startswith("aes") || Mnemonic == "hvc" || Mnemonic == "setpan" ||
- Mnemonic.startswith("sha1") || Mnemonic.startswith("sha256") ||
- (FullInst.startswith("vmull") && FullInst.endswith(".p64")) ||
- Mnemonic == "vmovx" || Mnemonic == "vins" ||
- Mnemonic == "vudot" || Mnemonic == "vsdot" ||
- Mnemonic == "vcmla" || Mnemonic == "vcadd" ||
- Mnemonic == "vfmal" || Mnemonic == "vfmsl" ||
- Mnemonic == "vfmat" || Mnemonic == "vfmab" ||
- Mnemonic == "vdot" || Mnemonic == "vmmla" ||
- Mnemonic == "sb" || Mnemonic == "ssbb" ||
- Mnemonic == "pssbb" || Mnemonic == "vsmmla" ||
- Mnemonic == "vummla" || Mnemonic == "vusmmla" ||
- Mnemonic == "vusdot" || Mnemonic == "vsudot" ||
- Mnemonic == "bfcsel" || Mnemonic == "wls" ||
- Mnemonic == "dls" || Mnemonic == "le" || Mnemonic == "csel" ||
- Mnemonic == "csinc" || Mnemonic == "csinv" || Mnemonic == "csneg" ||
- Mnemonic == "cinc" || Mnemonic == "cinv" || Mnemonic == "cneg" ||
- Mnemonic == "cset" || Mnemonic == "csetm" ||
+ Mnemonic.starts_with("aes") || Mnemonic == "hvc" ||
+ Mnemonic == "setpan" || Mnemonic.starts_with("sha1") ||
+ Mnemonic.starts_with("sha256") ||
+ (FullInst.starts_with("vmull") && FullInst.ends_with(".p64")) ||
+ Mnemonic == "vmovx" || Mnemonic == "vins" || Mnemonic == "vudot" ||
+ Mnemonic == "vsdot" || Mnemonic == "vcmla" || Mnemonic == "vcadd" ||
+ Mnemonic == "vfmal" || Mnemonic == "vfmsl" || Mnemonic == "vfmat" ||
+ Mnemonic == "vfmab" || Mnemonic == "vdot" || Mnemonic == "vmmla" ||
+ Mnemonic == "sb" || Mnemonic == "ssbb" || Mnemonic == "pssbb" ||
+ Mnemonic == "vsmmla" || Mnemonic == "vummla" || Mnemonic == "vusmmla" ||
+ Mnemonic == "vusdot" || Mnemonic == "vsudot" || Mnemonic == "bfcsel" ||
+ Mnemonic == "wls" || Mnemonic == "dls" || Mnemonic == "le" ||
+ Mnemonic == "csel" || Mnemonic == "csinc" || Mnemonic == "csinv" ||
+ Mnemonic == "csneg" || Mnemonic == "cinc" || Mnemonic == "cinv" ||
+ Mnemonic == "cneg" || Mnemonic == "cset" || Mnemonic == "csetm" ||
(hasCDE() && MS.isCDEInstr(Mnemonic) &&
!MS.isITPredicableCDEInstr(Mnemonic)) ||
- Mnemonic.startswith("vpt") || Mnemonic.startswith("vpst") ||
+ Mnemonic.starts_with("vpt") || Mnemonic.starts_with("vpst") ||
Mnemonic == "pac" || Mnemonic == "pacbti" || Mnemonic == "aut" ||
Mnemonic == "bti" ||
(hasMVE() &&
- (Mnemonic.startswith("vst2") || Mnemonic.startswith("vld2") ||
- Mnemonic.startswith("vst4") || Mnemonic.startswith("vld4") ||
- Mnemonic.startswith("wlstp") || Mnemonic.startswith("dlstp") ||
- Mnemonic.startswith("letp")))) {
+ (Mnemonic.starts_with("vst2") || Mnemonic.starts_with("vld2") ||
+ Mnemonic.starts_with("vst4") || Mnemonic.starts_with("vld4") ||
+ Mnemonic.starts_with("wlstp") || Mnemonic.starts_with("dlstp") ||
+ Mnemonic.starts_with("letp")))) {
// These mnemonics are never predicable
CanAcceptPredicationCode = false;
} else if (!isThumb()) {
@@ -6484,9 +6473,8 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic,
Mnemonic != "dmb" && Mnemonic != "dfb" && Mnemonic != "dsb" &&
Mnemonic != "isb" && Mnemonic != "pld" && Mnemonic != "pli" &&
Mnemonic != "pldw" && Mnemonic != "ldc2" && Mnemonic != "ldc2l" &&
- Mnemonic != "stc2" && Mnemonic != "stc2l" &&
- Mnemonic != "tsb" &&
- !Mnemonic.startswith("rfe") && !Mnemonic.startswith("srs");
+ Mnemonic != "stc2" && Mnemonic != "stc2l" && Mnemonic != "tsb" &&
+ !Mnemonic.starts_with("rfe") && !Mnemonic.starts_with("srs");
} else if (isThumbOne()) {
if (hasV6MOps())
CanAcceptPredicationCode = Mnemonic != "movs";
@@ -6782,16 +6770,16 @@ bool ARMAsmParser::shouldOmitVectorPredicateOperand(StringRef Mnemonic,
if (!hasMVE() || Operands.size() < 3)
return true;
- if (Mnemonic.startswith("vld2") || Mnemonic.startswith("vld4") ||
- Mnemonic.startswith("vst2") || Mnemonic.startswith("vst4"))
+ if (Mnemonic.starts_with("vld2") || Mnemonic.starts_with("vld4") ||
+ Mnemonic.starts_with("vst2") || Mnemonic.starts_with("vst4"))
return true;
- if (Mnemonic.startswith("vctp") || Mnemonic.startswith("vpnot"))
+ if (Mnemonic.starts_with("vctp") || Mnemonic.starts_with("vpnot"))
return false;
- if (Mnemonic.startswith("vmov") &&
- !(Mnemonic.startswith("vmovl") || Mnemonic.startswith("vmovn") ||
- Mnemonic.startswith("vmovx"))) {
+ if (Mnemonic.starts_with("vmov") &&
+ !(Mnemonic.starts_with("vmovl") || Mnemonic.starts_with("vmovn") ||
+ Mnemonic.starts_with("vmovx"))) {
for (auto &Operand : Operands) {
if (static_cast<ARMOperand &>(*Operand).isVectorIndex() ||
((*Operand).isReg() &&
@@ -6831,7 +6819,7 @@ static bool isDataTypeToken(StringRef Tok) {
// in the .td files that matches the suffix instead of having it be
// a literal string token the way it is now.
static bool doesIgnoreDataTypeSuffix(StringRef Mnemonic, StringRef DT) {
- return Mnemonic.startswith("vldm") || Mnemonic.startswith("vstm");
+ return Mnemonic.starts_with("vldm") || Mnemonic.starts_with("vstm");
}
static void applyMnemonicAliases(StringRef &Mnemonic,
@@ -7001,8 +6989,8 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// ITxyz -> xyz1 (e.g. ITEET -> 1101)
// Note: See the ARM::PredBlockMask enum in
// /lib/Target/ARM/Utils/ARMBaseInfo.h
- if (Mnemonic == "it" || Mnemonic.startswith("vpt") ||
- Mnemonic.startswith("vpst")) {
+ if (Mnemonic == "it" || Mnemonic.starts_with("vpt") ||
+ Mnemonic.starts_with("vpst")) {
SMLoc Loc = Mnemonic == "it" ? SMLoc::getFromPointer(NameLoc.getPointer() + 2) :
Mnemonic == "vpt" ? SMLoc::getFromPointer(NameLoc.getPointer() + 3) :
SMLoc::getFromPointer(NameLoc.getPointer() + 4);
@@ -7080,8 +7068,8 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// scalar predication operand we do not add the vector one and leave until
// now to fix it up.
if (CanAcceptVPTPredicationCode && Mnemonic != "vmov" &&
- !Mnemonic.startswith("vcmp") &&
- !(Mnemonic.startswith("vcvt") && Mnemonic != "vcvta" &&
+ !Mnemonic.starts_with("vcmp") &&
+ !(Mnemonic.starts_with("vcvt") && Mnemonic != "vcvta" &&
Mnemonic != "vcvtn" && Mnemonic != "vcvtp" && Mnemonic != "vcvtm")) {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Mnemonic.size() +
CarrySetting);
@@ -7226,10 +7214,11 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// special parsing. So now we have to see if they require vector
// predication and replace the scalar one with the vector predication
// operand if that is the case.
- else if (Mnemonic == "vmov" || Mnemonic.startswith("vcmp") ||
- (Mnemonic.startswith("vcvt") && !Mnemonic.startswith("vcvta") &&
- !Mnemonic.startswith("vcvtn") && !Mnemonic.startswith("vcvtp") &&
- !Mnemonic.startswith("vcvtm"))) {
+ else if (Mnemonic == "vmov" || Mnemonic.starts_with("vcmp") ||
+ (Mnemonic.starts_with("vcvt") && !Mnemonic.starts_with("vcvta") &&
+ !Mnemonic.starts_with("vcvtn") &&
+ !Mnemonic.starts_with("vcvtp") &&
+ !Mnemonic.starts_with("vcvtm"))) {
if (!shouldOmitVectorPredicateOperand(Mnemonic, Operands)) {
// We could not split the vector predicate off vcvt because it might
// have been the scalar vcvtt instruction. Now we know its a vector
@@ -7237,11 +7226,11 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// predicated vcvt with 'Then' predication or the vector vcvtt. We can
// distinguish the two based on the suffixes, if it is any of
// ".f16.f32", ".f32.f16", ".f16.f64" or ".f64.f16" then it is the vcvtt.
- if (Mnemonic.startswith("vcvtt") && Operands.size() >= 4) {
+ if (Mnemonic.starts_with("vcvtt") && Operands.size() >= 4) {
auto Sz1 = static_cast<ARMOperand &>(*Operands[2]);
auto Sz2 = static_cast<ARMOperand &>(*Operands[3]);
- if (!(Sz1.isToken() && Sz1.getToken().startswith(".f") &&
- Sz2.isToken() && Sz2.getToken().startswith(".f"))) {
+ if (!(Sz1.isToken() && Sz1.getToken().starts_with(".f") &&
+ Sz2.isToken() && Sz2.getToken().starts_with(".f"))) {
Operands.erase(Operands.begin());
SMLoc MLoc = SMLoc::getFromPointer(NameLoc.getPointer());
VPTPredicationCode = ARMVCC::Then;
@@ -12798,12 +12787,12 @@ bool ARMAsmParser::isMnemonicVPTPredicable(StringRef Mnemonic,
return false;
if (MS.isVPTPredicableCDEInstr(Mnemonic) ||
- (Mnemonic.startswith("vldrh") && Mnemonic != "vldrhi") ||
- (Mnemonic.startswith("vmov") &&
+ (Mnemonic.starts_with("vldrh") && Mnemonic != "vldrhi") ||
+ (Mnemonic.starts_with("vmov") &&
!(ExtraToken == ".f16" || ExtraToken == ".32" || ExtraToken == ".16" ||
ExtraToken == ".8")) ||
- (Mnemonic.startswith("vrint") && Mnemonic != "vrintr") ||
- (Mnemonic.startswith("vstrh") && Mnemonic != "vstrhi"))
+ (Mnemonic.starts_with("vrint") && Mnemonic != "vrintr") ||
+ (Mnemonic.starts_with("vstrh") && Mnemonic != "vstrhi"))
return true;
const char *predicable_prefixes[] = {
@@ -12833,5 +12822,5 @@ bool ARMAsmParser::isMnemonicVPTPredicable(StringRef Mnemonic,
return std::any_of(
std::begin(predicable_prefixes), std::end(predicable_prefixes),
- [&Mnemonic](const char *prefix) { return Mnemonic.startswith(prefix); });
+ [&Mnemonic](const char *prefix) { return Mnemonic.starts_with(prefix); });
}
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp
index e84b597e4382..1237e50c22fd 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp
@@ -177,7 +177,7 @@ void ARMTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) {
switchVendor("aeabi");
const StringRef CPUString = STI.getCPU();
- if (!CPUString.empty() && !CPUString.startswith("generic")) {
+ if (!CPUString.empty() && !CPUString.starts_with("generic")) {
// FIXME: remove krait check when GNU tools support krait cpu
if (STI.hasFeature(ARM::ProcKrait)) {
emitTextAttribute(ARMBuildAttrs::CPU_name, "cortex-a9");
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp
index 62404f7add48..c62d17fd427a 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "ARMUnwindOpAsm.h"
+#include "llvm/ADT/bit.h"
#include "llvm/Support/ARMEHABI.h"
#include "llvm/Support/LEB128.h"
-#include "llvm/Support/MathExtras.h"
#include <cassert>
using namespace llvm;
diff --git a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
index abe5dcc48340..1c8213b668f7 100644
--- a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
+++ b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
@@ -251,13 +251,13 @@ bool AVRAsmPrinter::doFinalization(Module &M) {
}
auto *Section = cast<MCSectionELF>(TLOF.SectionForGlobal(&GO, TM));
- if (Section->getName().startswith(".data"))
+ if (Section->getName().starts_with(".data"))
NeedsCopyData = true;
- else if (Section->getName().startswith(".rodata") && SubTM->hasLPM())
+ else if (Section->getName().starts_with(".rodata") && SubTM->hasLPM())
// AVRs that have a separate program memory (that's most AVRs) store
// .rodata sections in RAM.
NeedsCopyData = true;
- else if (Section->getName().startswith(".bss"))
+ else if (Section->getName().starts_with(".bss"))
NeedsClearBSS = true;
}
diff --git a/llvm/lib/Target/BPF/BPF.h b/llvm/lib/Target/BPF/BPF.h
index 436cd62c2581..5c77d183e1ef 100644
--- a/llvm/lib/Target/BPF/BPF.h
+++ b/llvm/lib/Target/BPF/BPF.h
@@ -16,7 +16,10 @@
#include "llvm/Target/TargetMachine.h"
namespace llvm {
+class BPFRegisterBankInfo;
+class BPFSubtarget;
class BPFTargetMachine;
+class InstructionSelector;
class PassRegistry;
ModulePass *createBPFCheckAndAdjustIR();
@@ -27,6 +30,10 @@ FunctionPass *createBPFMIPeepholePass();
FunctionPass *createBPFMIPreEmitPeepholePass();
FunctionPass *createBPFMIPreEmitCheckingPass();
+InstructionSelector *createBPFInstructionSelector(const BPFTargetMachine &,
+ const BPFSubtarget &,
+ const BPFRegisterBankInfo &);
+
void initializeBPFCheckAndAdjustIRPass(PassRegistry&);
void initializeBPFDAGToDAGISelPass(PassRegistry &);
void initializeBPFMIPeepholePass(PassRegistry &);
diff --git a/llvm/lib/Target/BPF/BPF.td b/llvm/lib/Target/BPF/BPF.td
index 7f38fbdd8c5c..dff76ca07af5 100644
--- a/llvm/lib/Target/BPF/BPF.td
+++ b/llvm/lib/Target/BPF/BPF.td
@@ -11,6 +11,7 @@ include "llvm/Target/Target.td"
include "BPFRegisterInfo.td"
include "BPFCallingConv.td"
include "BPFInstrInfo.td"
+include "GISel/BPFRegisterBanks.td"
def BPFInstrInfo : InstrInfo;
diff --git a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
index 9634c16a30dc..f2d1206d0231 100644
--- a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
+++ b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
@@ -338,7 +338,7 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
const auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
if (!GV)
return false;
- if (GV->getName().startswith("llvm.preserve.array.access.index")) {
+ if (GV->getName().starts_with("llvm.preserve.array.access.index")) {
CInfo.Kind = BPFPreserveArrayAI;
CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
if (!CInfo.Metadata)
@@ -348,7 +348,7 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
CInfo.RecordAlignment = DL->getABITypeAlign(getBaseElementType(Call));
return true;
}
- if (GV->getName().startswith("llvm.preserve.union.access.index")) {
+ if (GV->getName().starts_with("llvm.preserve.union.access.index")) {
CInfo.Kind = BPFPreserveUnionAI;
CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
if (!CInfo.Metadata)
@@ -358,7 +358,7 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
CInfo.Base = Call->getArgOperand(0);
return true;
}
- if (GV->getName().startswith("llvm.preserve.struct.access.index")) {
+ if (GV->getName().starts_with("llvm.preserve.struct.access.index")) {
CInfo.Kind = BPFPreserveStructAI;
CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
if (!CInfo.Metadata)
@@ -369,7 +369,7 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
CInfo.RecordAlignment = DL->getABITypeAlign(getBaseElementType(Call));
return true;
}
- if (GV->getName().startswith("llvm.bpf.preserve.field.info")) {
+ if (GV->getName().starts_with("llvm.bpf.preserve.field.info")) {
CInfo.Kind = BPFPreserveFieldInfoAI;
CInfo.Metadata = nullptr;
// Check validity of info_kind as clang did not check this.
@@ -379,7 +379,7 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
CInfo.AccessIndex = InfoKind;
return true;
}
- if (GV->getName().startswith("llvm.bpf.preserve.type.info")) {
+ if (GV->getName().starts_with("llvm.bpf.preserve.type.info")) {
CInfo.Kind = BPFPreserveFieldInfoAI;
CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
if (!CInfo.Metadata)
@@ -395,7 +395,7 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
CInfo.AccessIndex = BTF::TYPE_SIZE;
return true;
}
- if (GV->getName().startswith("llvm.bpf.preserve.enum.value")) {
+ if (GV->getName().starts_with("llvm.bpf.preserve.enum.value")) {
CInfo.Kind = BPFPreserveFieldInfoAI;
CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
if (!CInfo.Metadata)
diff --git a/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp b/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp
index 56c89f61b319..81effc9b1db4 100644
--- a/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp
+++ b/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp
@@ -119,7 +119,7 @@ bool BPFCheckAndAdjustIR::removePassThroughBuiltin(Module &M) {
auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
if (!GV)
continue;
- if (!GV->getName().startswith("llvm.bpf.passthrough"))
+ if (!GV->getName().starts_with("llvm.bpf.passthrough"))
continue;
Changed = true;
Value *Arg = Call->getArgOperand(1);
@@ -149,7 +149,7 @@ bool BPFCheckAndAdjustIR::removeCompareBuiltin(Module &M) {
auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
if (!GV)
continue;
- if (!GV->getName().startswith("llvm.bpf.compare"))
+ if (!GV->getName().starts_with("llvm.bpf.compare"))
continue;
Changed = true;
diff --git a/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp b/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
index b0cfca3b7ab6..909c7c005735 100644
--- a/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
+++ b/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
@@ -192,20 +192,6 @@ void BPFDAGToDAGISel::Select(SDNode *Node) {
switch (Opcode) {
default:
break;
- case ISD::SDIV: {
- if (!Subtarget->hasSdivSmod()) {
- DebugLoc Empty;
- const DebugLoc &DL = Node->getDebugLoc();
- if (DL != Empty)
- errs() << "Error at line " << DL.getLine() << ": ";
- else
- errs() << "Error: ";
- errs() << "Unsupport signed division for DAG: ";
- Node->print(errs(), CurDAG);
- errs() << "Please convert to unsigned div/mod.\n";
- }
- break;
- }
case ISD::INTRINSIC_W_CHAIN: {
unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
switch (IntNo) {
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp
index f3368b8979d6..2fe86e75ddae 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.cpp
+++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp
@@ -99,8 +99,10 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SDIVREM, VT, Expand);
setOperationAction(ISD::UDIVREM, VT, Expand);
- if (!STI.hasSdivSmod())
- setOperationAction(ISD::SREM, VT, Expand);
+ if (!STI.hasSdivSmod()) {
+ setOperationAction(ISD::SDIV, VT, Custom);
+ setOperationAction(ISD::SREM, VT, Custom);
+ }
setOperationAction(ISD::MULHU, VT, Expand);
setOperationAction(ISD::MULHS, VT, Expand);
setOperationAction(ISD::UMUL_LOHI, VT, Expand);
@@ -307,8 +309,11 @@ SDValue BPFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
return LowerGlobalAddress(Op, DAG);
case ISD::SELECT_CC:
return LowerSELECT_CC(Op, DAG);
+ case ISD::SDIV:
+ case ISD::SREM:
+ return LowerSDIVSREM(Op, DAG);
case ISD::DYNAMIC_STACKALLOC:
- report_fatal_error("unsupported dynamic stack allocation");
+ return LowerDYNAMIC_STACKALLOC(Op, DAG);
}
}
@@ -617,6 +622,21 @@ static void NegateCC(SDValue &LHS, SDValue &RHS, ISD::CondCode &CC) {
}
}
+SDValue BPFTargetLowering::LowerSDIVSREM(SDValue Op, SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ fail(DL, DAG,
+ "unsupported signed division, please convert to unsigned div/mod.");
+ return DAG.getUNDEF(Op->getValueType(0));
+}
+
+SDValue BPFTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
+ SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ fail(DL, DAG, "unsupported dynamic stack allocation");
+ auto Ops = {DAG.getConstant(0, SDLoc(), Op.getValueType()), Op.getOperand(0)};
+ return DAG.getMergeValues(Ops, SDLoc());
+}
+
SDValue BPFTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h
index 3be1c04bca3d..819711b650c1 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.h
+++ b/llvm/lib/Target/BPF/BPFISelLowering.h
@@ -73,6 +73,8 @@ private:
bool HasJmpExt;
bool HasMovsx;
+ SDValue LowerSDIVSREM(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.td b/llvm/lib/Target/BPF/BPFInstrInfo.td
index 5972c9d49c51..7d443a344901 100644
--- a/llvm/lib/Target/BPF/BPFInstrInfo.td
+++ b/llvm/lib/Target/BPF/BPFInstrInfo.td
@@ -49,8 +49,8 @@ def BPFWrapper : SDNode<"BPFISD::Wrapper", SDT_BPFWrapper>;
def BPFmemcpy : SDNode<"BPFISD::MEMCPY", SDT_BPFMEMCPY,
[SDNPHasChain, SDNPInGlue, SDNPOutGlue,
SDNPMayStore, SDNPMayLoad]>;
-def BPFIsLittleEndian : Predicate<"CurDAG->getDataLayout().isLittleEndian()">;
-def BPFIsBigEndian : Predicate<"!CurDAG->getDataLayout().isLittleEndian()">;
+def BPFIsLittleEndian : Predicate<"Subtarget->isLittleEndian()">;
+def BPFIsBigEndian : Predicate<"!Subtarget->isLittleEndian()">;
def BPFHasALU32 : Predicate<"Subtarget->getHasAlu32()">;
def BPFNoALU32 : Predicate<"!Subtarget->getHasAlu32()">;
def BPFHasLdsx : Predicate<"Subtarget->hasLdsx()">;
diff --git a/llvm/lib/Target/BPF/BPFPreserveDIType.cpp b/llvm/lib/Target/BPF/BPFPreserveDIType.cpp
index fc4fb4d8f800..dae1aeea3521 100644
--- a/llvm/lib/Target/BPF/BPFPreserveDIType.cpp
+++ b/llvm/lib/Target/BPF/BPFPreserveDIType.cpp
@@ -57,7 +57,7 @@ static bool BPFPreserveDITypeImpl(Function &F) {
if (!GV)
continue;
- if (GV->getName().startswith("llvm.bpf.btf.type.id")) {
+ if (GV->getName().starts_with("llvm.bpf.btf.type.id")) {
if (!Call->getMetadata(LLVMContext::MD_preserve_access_index))
report_fatal_error(
"Missing metadata for llvm.bpf.btf.type.id intrinsic");
diff --git a/llvm/lib/Target/BPF/BPFSubtarget.cpp b/llvm/lib/Target/BPF/BPFSubtarget.cpp
index ce02c831828e..9a8e42f32371 100644
--- a/llvm/lib/Target/BPF/BPFSubtarget.cpp
+++ b/llvm/lib/Target/BPF/BPFSubtarget.cpp
@@ -12,6 +12,10 @@
#include "BPFSubtarget.h"
#include "BPF.h"
+#include "BPFTargetMachine.h"
+#include "GISel/BPFCallLowering.h"
+#include "GISel/BPFLegalizerInfo.h"
+#include "GISel/BPFRegisterBankInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/TargetParser/Host.h"
@@ -93,4 +97,30 @@ BPFSubtarget::BPFSubtarget(const Triple &TT, const std::string &CPU,
const std::string &FS, const TargetMachine &TM)
: BPFGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS),
FrameLowering(initializeSubtargetDependencies(CPU, FS)),
- TLInfo(TM, *this) {}
+ TLInfo(TM, *this) {
+ IsLittleEndian = TT.isLittleEndian();
+
+ CallLoweringInfo.reset(new BPFCallLowering(*getTargetLowering()));
+ Legalizer.reset(new BPFLegalizerInfo(*this));
+ auto *RBI = new BPFRegisterBankInfo(*getRegisterInfo());
+ RegBankInfo.reset(RBI);
+
+ InstSelector.reset(createBPFInstructionSelector(
+ *static_cast<const BPFTargetMachine *>(&TM), *this, *RBI));
+}
+
+const CallLowering *BPFSubtarget::getCallLowering() const {
+ return CallLoweringInfo.get();
+}
+
+InstructionSelector *BPFSubtarget::getInstructionSelector() const {
+ return InstSelector.get();
+}
+
+const LegalizerInfo *BPFSubtarget::getLegalizerInfo() const {
+ return Legalizer.get();
+}
+
+const RegisterBankInfo *BPFSubtarget::getRegBankInfo() const {
+ return RegBankInfo.get();
+}
diff --git a/llvm/lib/Target/BPF/BPFSubtarget.h b/llvm/lib/Target/BPF/BPFSubtarget.h
index 6e81daa4d955..33747546eadc 100644
--- a/llvm/lib/Target/BPF/BPFSubtarget.h
+++ b/llvm/lib/Target/BPF/BPFSubtarget.h
@@ -16,7 +16,12 @@
#include "BPFFrameLowering.h"
#include "BPFISelLowering.h"
#include "BPFInstrInfo.h"
+#include "BPFRegisterInfo.h"
#include "BPFSelectionDAGInfo.h"
+#include "llvm/CodeGen/GlobalISel/CallLowering.h"
+#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
+#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
+#include "llvm/CodeGen/RegisterBankInfo.h"
#include "llvm/CodeGen/SelectionDAGTargetInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DataLayout.h"
@@ -43,6 +48,8 @@ protected:
// unused
bool isDummyMode;
+ bool IsLittleEndian;
+
// whether the cpu supports jmp ext
bool HasJmpExt;
@@ -59,6 +66,11 @@ protected:
// whether cpu v4 insns are enabled.
bool HasLdsx, HasMovsx, HasBswap, HasSdivSmod, HasGotol, HasStoreImm;
+ std::unique_ptr<CallLowering> CallLoweringInfo;
+ std::unique_ptr<InstructionSelector> InstSelector;
+ std::unique_ptr<LegalizerInfo> Legalizer;
+ std::unique_ptr<RegisterBankInfo> RegBankInfo;
+
public:
// This constructor initializes the data members to match that
// of the specified triple.
@@ -81,6 +93,8 @@ public:
bool hasGotol() const { return HasGotol; }
bool hasStoreImm() const { return HasStoreImm; }
+ bool isLittleEndian() const { return IsLittleEndian; }
+
const BPFInstrInfo *getInstrInfo() const override { return &InstrInfo; }
const BPFFrameLowering *getFrameLowering() const override {
return &FrameLowering;
@@ -91,9 +105,14 @@ public:
const BPFSelectionDAGInfo *getSelectionDAGInfo() const override {
return &TSInfo;
}
- const TargetRegisterInfo *getRegisterInfo() const override {
+ const BPFRegisterInfo *getRegisterInfo() const override {
return &InstrInfo.getRegisterInfo();
}
+
+ const CallLowering *getCallLowering() const override;
+ InstructionSelector *getInstructionSelector() const override;
+ const LegalizerInfo *getLegalizerInfo() const override;
+ const RegisterBankInfo *getRegBankInfo() const override;
};
} // End llvm namespace
diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
index 65286c822c4b..ab0db576f7f7 100644
--- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp
+++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
@@ -15,10 +15,15 @@
#include "BPFTargetTransformInfo.h"
#include "MCTargetDesc/BPFMCAsmInfo.h"
#include "TargetInfo/BPFTargetInfo.h"
+#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
+#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
+#include "llvm/CodeGen/GlobalISel/Legalizer.h"
+#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/PassManager.h"
+#include "llvm/InitializePasses.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/FormattedStream.h"
@@ -40,6 +45,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() {
RegisterTargetMachine<BPFTargetMachine> Z(getTheBPFTarget());
PassRegistry &PR = *PassRegistry::getPassRegistry();
+ initializeGlobalISel(PR);
initializeBPFCheckAndAdjustIRPass(PR);
initializeBPFMIPeepholePass(PR);
initializeBPFDAGToDAGISelPass(PR);
@@ -90,6 +96,11 @@ public:
bool addInstSelector() override;
void addMachineSSAOptimization() override;
void addPreEmitPass() override;
+
+ bool addIRTranslator() override;
+ bool addLegalizeMachineIR() override;
+ bool addRegBankSelect() override;
+ bool addGlobalInstructionSelect() override;
};
}
@@ -174,3 +185,23 @@ void BPFPassConfig::addPreEmitPass() {
if (!DisableMIPeephole)
addPass(createBPFMIPreEmitPeepholePass());
}
+
+bool BPFPassConfig::addIRTranslator() {
+ addPass(new IRTranslator());
+ return false;
+}
+
+bool BPFPassConfig::addLegalizeMachineIR() {
+ addPass(new Legalizer());
+ return false;
+}
+
+bool BPFPassConfig::addRegBankSelect() {
+ addPass(new RegBankSelect());
+ return false;
+}
+
+bool BPFPassConfig::addGlobalInstructionSelect() {
+ addPass(new InstructionSelect(getOptLevel()));
+ return false;
+}
diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
index f91ce7f25035..ebd8447eba85 100644
--- a/llvm/lib/Target/BPF/BTFDebug.cpp
+++ b/llvm/lib/Target/BPF/BTFDebug.cpp
@@ -977,7 +977,7 @@ std::string BTFDebug::populateFileContent(const DISubprogram *SP) {
auto File = SP->getFile();
std::string FileName;
- if (!File->getFilename().startswith("/") && File->getDirectory().size())
+ if (!File->getFilename().starts_with("/") && File->getDirectory().size())
FileName = File->getDirectory().str() + "/" + File->getFilename().str();
else
FileName = std::string(File->getFilename());
@@ -1417,7 +1417,7 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
SecName = Sec->getName();
}
- if (ProcessingMapDef != SecName.startswith(".maps"))
+ if (ProcessingMapDef != SecName.starts_with(".maps"))
continue;
// Create a .rodata datasec if the global variable is an initialized
@@ -1443,7 +1443,7 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
DIGlobalVariable *DIGlobal = nullptr;
for (auto *GVE : GVs) {
DIGlobal = GVE->getVariable();
- if (SecName.startswith(".maps"))
+ if (SecName.starts_with(".maps"))
visitMapDefType(DIGlobal->getType(), GVTypeId);
else
visitTypeEntry(DIGlobal->getType(), GVTypeId, false, false);
diff --git a/llvm/lib/Target/BPF/GISel/BPFCallLowering.cpp b/llvm/lib/Target/BPF/GISel/BPFCallLowering.cpp
new file mode 100644
index 000000000000..3829a1a3151f
--- /dev/null
+++ b/llvm/lib/Target/BPF/GISel/BPFCallLowering.cpp
@@ -0,0 +1,46 @@
+//===-- BPFCallLowering.cpp - Call lowering for GlobalISel ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the lowering of LLVM calls to machine code calls for
+/// GlobalISel.
+///
+//===----------------------------------------------------------------------===//
+
+#include "BPFCallLowering.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "bpf-call-lowering"
+
+using namespace llvm;
+
+BPFCallLowering::BPFCallLowering(const BPFTargetLowering &TLI)
+ : CallLowering(&TLI) {}
+
+bool BPFCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
+ const Value *Val, ArrayRef<Register> VRegs,
+ FunctionLoweringInfo &FLI,
+ Register SwiftErrorVReg) const {
+ if (!VRegs.empty())
+ return false;
+ MIRBuilder.buildInstr(BPF::RET);
+ return true;
+}
+
+bool BPFCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
+ const Function &F,
+ ArrayRef<ArrayRef<Register>> VRegs,
+ FunctionLoweringInfo &FLI) const {
+ return VRegs.empty();
+}
+
+bool BPFCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
+ CallLoweringInfo &Info) const {
+ return false;
+}
diff --git a/llvm/lib/Target/BPF/GISel/BPFCallLowering.h b/llvm/lib/Target/BPF/GISel/BPFCallLowering.h
new file mode 100644
index 000000000000..0099d2048fe5
--- /dev/null
+++ b/llvm/lib/Target/BPF/GISel/BPFCallLowering.h
@@ -0,0 +1,39 @@
+//===-- BPFCallLowering.h - Call lowering for GlobalISel --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file describes how to lower LLVM calls to machine code calls.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_BPF_GISEL_BPFCALLLOWERING_H
+#define LLVM_LIB_TARGET_BPF_GISEL_BPFCALLLOWERING_H
+
+#include "BPFISelLowering.h"
+#include "llvm/CodeGen/GlobalISel/CallLowering.h"
+#include "llvm/IR/CallingConv.h"
+
+namespace llvm {
+
+class BPFTargetLowering;
+
+class BPFCallLowering : public CallLowering {
+public:
+ BPFCallLowering(const BPFTargetLowering &TLI);
+ bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val,
+ ArrayRef<Register> VRegs, FunctionLoweringInfo &FLI,
+ Register SwiftErrorVReg) const override;
+ bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
+ ArrayRef<ArrayRef<Register>> VRegs,
+ FunctionLoweringInfo &FLI) const override;
+ bool lowerCall(MachineIRBuilder &MIRBuilder,
+ CallLoweringInfo &Info) const override;
+};
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/BPF/GISel/BPFInstructionSelector.cpp b/llvm/lib/Target/BPF/GISel/BPFInstructionSelector.cpp
new file mode 100644
index 000000000000..c7db93a260c4
--- /dev/null
+++ b/llvm/lib/Target/BPF/GISel/BPFInstructionSelector.cpp
@@ -0,0 +1,93 @@
+//===- BPFInstructionSelector.cpp --------------------------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements the targeting of the InstructionSelector class for BPF.
+//===----------------------------------------------------------------------===//
+
+#include "BPFInstrInfo.h"
+#include "BPFRegisterBankInfo.h"
+#include "BPFSubtarget.h"
+#include "BPFTargetMachine.h"
+#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
+#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/IR/IntrinsicsBPF.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "bpf-gisel"
+
+using namespace llvm;
+
+namespace {
+
+#define GET_GLOBALISEL_PREDICATE_BITSET
+#include "BPFGenGlobalISel.inc"
+#undef GET_GLOBALISEL_PREDICATE_BITSET
+
+class BPFInstructionSelector : public InstructionSelector {
+public:
+ BPFInstructionSelector(const BPFTargetMachine &TM, const BPFSubtarget &STI,
+ const BPFRegisterBankInfo &RBI);
+
+ bool select(MachineInstr &I) override;
+ static const char *getName() { return DEBUG_TYPE; }
+
+private:
+ /// tblgen generated 'select' implementation that is used as the initial
+ /// selector for the patterns that do not require complex C++.
+ bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
+
+ const BPFInstrInfo &TII;
+ const BPFRegisterInfo &TRI;
+ const BPFRegisterBankInfo &RBI;
+
+#define GET_GLOBALISEL_PREDICATES_DECL
+#include "BPFGenGlobalISel.inc"
+#undef GET_GLOBALISEL_PREDICATES_DECL
+
+#define GET_GLOBALISEL_TEMPORARIES_DECL
+#include "BPFGenGlobalISel.inc"
+#undef GET_GLOBALISEL_TEMPORARIES_DECL
+};
+
+} // namespace
+
+#define GET_GLOBALISEL_IMPL
+#include "BPFGenGlobalISel.inc"
+#undef GET_GLOBALISEL_IMPL
+
+BPFInstructionSelector::BPFInstructionSelector(const BPFTargetMachine &TM,
+ const BPFSubtarget &STI,
+ const BPFRegisterBankInfo &RBI)
+ : TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI),
+#define GET_GLOBALISEL_PREDICATES_INIT
+#include "BPFGenGlobalISel.inc"
+#undef GET_GLOBALISEL_PREDICATES_INIT
+#define GET_GLOBALISEL_TEMPORARIES_INIT
+#include "BPFGenGlobalISel.inc"
+#undef GET_GLOBALISEL_TEMPORARIES_INIT
+{
+}
+
+bool BPFInstructionSelector::select(MachineInstr &I) {
+ if (!isPreISelGenericOpcode(I.getOpcode()))
+ return true;
+ if (selectImpl(I, *CoverageInfo))
+ return true;
+ return false;
+}
+
+namespace llvm {
+InstructionSelector *
+createBPFInstructionSelector(const BPFTargetMachine &TM,
+ const BPFSubtarget &Subtarget,
+ const BPFRegisterBankInfo &RBI) {
+ return new BPFInstructionSelector(TM, Subtarget, RBI);
+}
+} // namespace llvm
diff --git a/llvm/lib/Target/BPF/GISel/BPFLegalizerInfo.cpp b/llvm/lib/Target/BPF/GISel/BPFLegalizerInfo.cpp
new file mode 100644
index 000000000000..04220c176376
--- /dev/null
+++ b/llvm/lib/Target/BPF/GISel/BPFLegalizerInfo.cpp
@@ -0,0 +1,22 @@
+//===- BPFLegalizerInfo.h ----------------------------------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements the targeting of the Machinelegalizer class for BPF
+//===----------------------------------------------------------------------===//
+
+#include "BPFLegalizerInfo.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "bpf-legalinfo"
+
+using namespace llvm;
+using namespace LegalizeActions;
+
+BPFLegalizerInfo::BPFLegalizerInfo(const BPFSubtarget &ST) {
+ getLegacyLegalizerInfo().computeTables();
+}
diff --git a/llvm/lib/Target/BPF/GISel/BPFLegalizerInfo.h b/llvm/lib/Target/BPF/GISel/BPFLegalizerInfo.h
new file mode 100644
index 000000000000..1704bc03144c
--- /dev/null
+++ b/llvm/lib/Target/BPF/GISel/BPFLegalizerInfo.h
@@ -0,0 +1,28 @@
+//===- BPFLegalizerInfo.h ----------------------------------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares the targeting of the Machinelegalizer class for BPF
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_BPF_GISEL_BPFMACHINELEGALIZER_H
+#define LLVM_LIB_TARGET_BPF_GISEL_BPFMACHINELEGALIZER_H
+
+#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
+
+namespace llvm {
+
+class BPFSubtarget;
+
+/// This class provides the information for the BPF target legalizer for
+/// GlobalISel.
+class BPFLegalizerInfo : public LegalizerInfo {
+public:
+ BPFLegalizerInfo(const BPFSubtarget &ST);
+};
+} // namespace llvm
+#endif
diff --git a/llvm/lib/Target/BPF/GISel/BPFRegisterBankInfo.cpp b/llvm/lib/Target/BPF/GISel/BPFRegisterBankInfo.cpp
new file mode 100644
index 000000000000..f50e8f524a87
--- /dev/null
+++ b/llvm/lib/Target/BPF/GISel/BPFRegisterBankInfo.cpp
@@ -0,0 +1,25 @@
+//===- BPFRegisterBankInfo.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements the targeting of the RegisterBankInfo class for BPF
+//===----------------------------------------------------------------------===//
+
+#include "BPFRegisterBankInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "bpf-reg-bank-info"
+
+#define GET_TARGET_REGBANK_IMPL
+#include "BPFGenRegisterBank.inc"
+
+using namespace llvm;
+
+BPFRegisterBankInfo::BPFRegisterBankInfo(const TargetRegisterInfo &TRI)
+ : BPFGenRegisterBankInfo() {}
diff --git a/llvm/lib/Target/BPF/GISel/BPFRegisterBankInfo.h b/llvm/lib/Target/BPF/GISel/BPFRegisterBankInfo.h
new file mode 100644
index 000000000000..82421916ca5e
--- /dev/null
+++ b/llvm/lib/Target/BPF/GISel/BPFRegisterBankInfo.h
@@ -0,0 +1,39 @@
+//===-- BPFRegisterBankInfo.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file declares the targeting of the RegisterBankInfo class for BPF.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_BPF_GISEL_BPFREGISTERBANKINFO_H
+#define LLVM_LIB_TARGET_BPF_GISEL_BPFREGISTERBANKINFO_H
+
+#include "MCTargetDesc/BPFMCTargetDesc.h"
+#include "llvm/CodeGen/RegisterBankInfo.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+
+#define GET_REGBANK_DECLARATIONS
+#include "BPFGenRegisterBank.inc"
+
+namespace llvm {
+class TargetRegisterInfo;
+
+class BPFGenRegisterBankInfo : public RegisterBankInfo {
+protected:
+#define GET_TARGET_REGBANK_CLASS
+#include "BPFGenRegisterBank.inc"
+};
+
+class BPFRegisterBankInfo final : public BPFGenRegisterBankInfo {
+public:
+ BPFRegisterBankInfo(const TargetRegisterInfo &TRI);
+};
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/BPF/GISel/BPFRegisterBanks.td b/llvm/lib/Target/BPF/GISel/BPFRegisterBanks.td
new file mode 100644
index 000000000000..af4af40a2537
--- /dev/null
+++ b/llvm/lib/Target/BPF/GISel/BPFRegisterBanks.td
@@ -0,0 +1,15 @@
+//===-- BPFRegisterBanks.td - Describe the BPF Banks -------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Define the BPF register banks used for GlobalISel.
+///
+//===----------------------------------------------------------------------===//
+
+/// General Purpose Registers
+def GPRRegBank : RegisterBank<"GPRB", [GPR]>;
diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
index ea30e714a5b7..f12b79586baf 100644
--- a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
+++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
@@ -30,8 +30,7 @@ class MCSubtargetInfo;
class MCTargetOptions;
class Target;
-MCCodeEmitter *createBPFMCCodeEmitter(const MCInstrInfo &MCII,
- MCContext &Ctx);
+MCCodeEmitter *createBPFMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx);
MCCodeEmitter *createBPFbeMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx);
@@ -43,7 +42,7 @@ MCAsmBackend *createBPFbeAsmBackend(const Target &T, const MCSubtargetInfo &STI,
const MCTargetOptions &Options);
std::unique_ptr<MCObjectTargetWriter> createBPFELFObjectWriter(uint8_t OSABI);
-}
+} // namespace llvm
// Defines symbolic names for BPF registers. This defines a mapping from
// register name to register number.
diff --git a/llvm/lib/Target/DirectX/DXILResource.cpp b/llvm/lib/Target/DirectX/DXILResource.cpp
index 041b8fafcd6a..d3ff12a1f7b3 100644
--- a/llvm/lib/Target/DirectX/DXILResource.cpp
+++ b/llvm/lib/Target/DirectX/DXILResource.cpp
@@ -234,7 +234,7 @@ void ResourceBase::print(raw_ostream &OS, StringRef IDPrefix,
UAVResource::UAVResource(uint32_t I, FrontendResource R)
: ResourceBase(I, R), Shape(R.getResourceKind()), GloballyCoherent(false),
- HasCounter(false), IsROV(false), ExtProps() {
+ HasCounter(false), IsROV(R.getIsROV()), ExtProps() {
parseSourceType(R.getSourceType());
}
@@ -258,12 +258,10 @@ void UAVResource::print(raw_ostream &OS) const {
// information we need to remove the source type string from here (See issue:
// https://github.com/llvm/llvm-project/issues/57991).
void UAVResource::parseSourceType(StringRef S) {
- IsROV = S.startswith("RasterizerOrdered");
-
S = S.substr(S.find("<") + 1);
constexpr size_t PrefixLen = StringRef("vector<").size();
- if (S.startswith("vector<"))
+ if (S.starts_with("vector<"))
S = S.substr(PrefixLen, S.find(",") - PrefixLen);
else
S = S.substr(0, S.find(">"));
diff --git a/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp b/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
index e1ad15bbc7c1..4df811f188df 100644
--- a/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
@@ -116,13 +116,13 @@ HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
if (!llvm::count_if(Features.getFeatures(), IsQFloatFS)) {
auto getHvxVersion = [&Features](StringRef FS) -> StringRef {
for (StringRef F : llvm::reverse(Features.getFeatures())) {
- if (F.startswith("+hvxv"))
+ if (F.starts_with("+hvxv"))
return F;
}
for (StringRef F : llvm::reverse(Features.getFeatures())) {
if (F == "-hvx")
return StringRef();
- if (F.startswith("+hvx") || F == "-hvx")
+ if (F.starts_with("+hvx") || F == "-hvx")
return F.take_front(4); // Return "+hvx" or "-hvx".
}
return StringRef();
@@ -130,7 +130,7 @@ HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
bool AddQFloat = false;
StringRef HvxVer = getHvxVersion(FS);
- if (HvxVer.startswith("+hvxv")) {
+ if (HvxVer.starts_with("+hvxv")) {
int Ver = 0;
if (!HvxVer.drop_front(5).consumeInteger(10, Ver) && Ver >= 68)
AddQFloat = true;
diff --git a/llvm/lib/Target/Hexagon/HexagonTargetMachine.h b/llvm/lib/Target/Hexagon/HexagonTargetMachine.h
index 4ffd0fd89de6..dddd79ad1fcf 100644
--- a/llvm/lib/Target/Hexagon/HexagonTargetMachine.h
+++ b/llvm/lib/Target/Hexagon/HexagonTargetMachine.h
@@ -21,8 +21,6 @@
namespace llvm {
-class Module;
-
class HexagonTargetMachine : public LLVMTargetMachine {
std::unique_ptr<TargetLoweringObjectFile> TLOF;
mutable StringMap<std::unique_ptr<HexagonSubtarget>> SubtargetMap;
diff --git a/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp b/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp
index 8355de4cfe96..a7ac24e25a5f 100644
--- a/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp
@@ -140,7 +140,7 @@ MCSection *HexagonTargetObjectFile::SelectSectionForGlobal(
// If the lookup table is used by more than one function, do not place
// it in text section.
- if (EmitLutInText && GO->getName().startswith("switch.table")) {
+ if (EmitLutInText && GO->getName().starts_with("switch.table")) {
if (const Function *Fn = getLutUsedFunction(GO))
return selectSectionForLookupTable(GO, TM, Fn);
}
diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
index cf6fa78a2005..fffd5abd9f8b 100644
--- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
+++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
@@ -253,7 +253,7 @@ public:
if (!Duplex.second.empty()) {
OS << Indent << Duplex.first << Separator;
InstTxt = Duplex.second;
- } else if (!HeadTail.first.trim().startswith("immext")) {
+ } else if (!HeadTail.first.trim().starts_with("immext")) {
InstTxt = Duplex.first;
}
if (!InstTxt.empty())
diff --git a/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp b/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
index cf6f7800a441..d0a89ad72b4c 100644
--- a/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
+++ b/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
@@ -1048,15 +1048,15 @@ StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc,
StringRef Mnemonic = Name;
bool IsBRR = false;
- if (Name.endswith(".r")) {
+ if (Name.ends_with(".r")) {
Mnemonic = Name.substr(0, Name.size() - 2);
IsBRR = true;
}
// Match b?? and s?? (BR, BRR, and SCC instruction classes).
if (Mnemonic[0] == 'b' ||
- (Mnemonic[0] == 's' && !Mnemonic.startswith("sel") &&
- !Mnemonic.startswith("st"))) {
+ (Mnemonic[0] == 's' && !Mnemonic.starts_with("sel") &&
+ !Mnemonic.starts_with("st"))) {
// Parse instructions with a conditional code. For example, 'bne' is
// converted into two operands 'b' and 'ne'.
LPCC::CondCode CondCode =
@@ -1077,8 +1077,8 @@ StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc,
// We ignore .f here and assume they are flag-setting operations, not
// conditional codes (except for select instructions where flag-setting
// variants are not yet implemented).
- if (Mnemonic.startswith("sel") ||
- (!Mnemonic.endswith(".f") && !Mnemonic.startswith("st"))) {
+ if (Mnemonic.starts_with("sel") ||
+ (!Mnemonic.ends_with(".f") && !Mnemonic.starts_with("st"))) {
LPCC::CondCode CondCode = LPCC::suffixToLanaiCondCode(Mnemonic);
if (CondCode != LPCC::UNKNOWN) {
size_t Next = Mnemonic.rfind('.', Name.size());
@@ -1087,7 +1087,7 @@ StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc,
// expected by the generated matcher). If the mnemonic starts with 'sel'
// then include the period as part of the mnemonic, else don't include it
// as part of the mnemonic.
- if (Mnemonic.startswith("sel")) {
+ if (Mnemonic.starts_with("sel")) {
Mnemonic = Mnemonic.substr(0, Next + 1);
} else {
Mnemonic = Mnemonic.substr(0, Next);
@@ -1194,7 +1194,7 @@ bool LanaiAsmParser::ParseInstruction(ParseInstructionInfo & /*Info*/,
// If the instruction is a bt instruction with 1 operand (in assembly) then it
// is an unconditional branch instruction and the first two elements of
// operands need to be merged.
- if (Lexer.is(AsmToken::EndOfStatement) && Name.startswith("bt") &&
+ if (Lexer.is(AsmToken::EndOfStatement) && Name.starts_with("bt") &&
Operands.size() == 3) {
Operands.erase(Operands.begin(), Operands.begin() + 2);
Operands.insert(Operands.begin(), LanaiOperand::CreateToken("bt", NameLoc));
diff --git a/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp b/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp
index a421f3156153..a366a89af863 100644
--- a/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp
+++ b/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp
@@ -80,7 +80,7 @@ bool LanaiTargetObjectFile::isGlobalInSmallSectionImpl(
// Global values placed in sections starting with .ldata do not fit in
// 21-bits, so always use large memory access for them. FIXME: This is a
// workaround for a tool limitation.
- if (GVA->getSection().startswith(".ldata"))
+ if (GVA->getSection().starts_with(".ldata"))
return false;
if (TM.getCodeModel() == CodeModel::Small)
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 61ec63ff6c1c..4794a131edae 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -4665,8 +4665,8 @@ LoongArchTargetLowering::getRegForInlineAsmConstraint(
// decode the usage of register name aliases into their official names. And
// AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
// official register names.
- if (Constraint.startswith("{$r") || Constraint.startswith("{$f") ||
- Constraint.startswith("{$vr") || Constraint.startswith("{$xr")) {
+ if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
+ Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
bool IsFP = Constraint[2] == 'f';
std::pair<StringRef, StringRef> Temp = Constraint.split('$');
std::pair<unsigned, const TargetRegisterClass *> R;
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index ec1e3351ac87..2d73a7394946 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -21,7 +21,6 @@
namespace llvm {
class LoongArchSubtarget;
-struct LoongArchRegisterInfo;
namespace LoongArchISD {
enum NodeType : unsigned {
FIRST_NUMBER = ISD::BUILTIN_OP_END,
diff --git a/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td
index 8559baa0e525..ec6983d0f487 100644
--- a/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td
@@ -1455,6 +1455,32 @@ def : Pat<(fma v8f32:$xj, v8f32:$xk, v8f32:$xa),
def : Pat<(fma v4f64:$xj, v4f64:$xk, v4f64:$xa),
(XVFMADD_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+// XVFMSUB_{S/D}
+def : Pat<(fma v8f32:$xj, v8f32:$xk, (fneg v8f32:$xa)),
+ (XVFMSUB_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fma v4f64:$xj, v4f64:$xk, (fneg v4f64:$xa)),
+ (XVFMSUB_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+
+// XVFNMADD_{S/D}
+def : Pat<(fneg (fma v8f32:$xj, v8f32:$xk, v8f32:$xa)),
+ (XVFNMADD_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fneg (fma v4f64:$xj, v4f64:$xk, v4f64:$xa)),
+ (XVFNMADD_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+def : Pat<(fma_nsz (fneg v8f32:$xj), v8f32:$xk, (fneg v8f32:$xa)),
+ (XVFNMADD_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fma_nsz (fneg v4f64:$xj), v4f64:$xk, (fneg v4f64:$xa)),
+ (XVFNMADD_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+
+// XVFNMSUB_{S/D}
+def : Pat<(fneg (fma v8f32:$xj, v8f32:$xk, (fneg v8f32:$xa))),
+ (XVFNMSUB_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fneg (fma v4f64:$xj, v4f64:$xk, (fneg v4f64:$xa))),
+ (XVFNMSUB_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+def : Pat<(fma_nsz (fneg v8f32:$xj), v8f32:$xk, v8f32:$xa),
+ (XVFNMSUB_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fma_nsz (fneg v4f64:$xj), v4f64:$xk, v4f64:$xa),
+ (XVFNMSUB_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+
// XVFSQRT_{S/D}
defm : PatXrF<fsqrt, "XVFSQRT">;
diff --git a/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
index 5947f241bb59..e468176885d7 100644
--- a/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
@@ -1555,6 +1555,32 @@ def : Pat<(fma v4f32:$vj, v4f32:$vk, v4f32:$va),
def : Pat<(fma v2f64:$vj, v2f64:$vk, v2f64:$va),
(VFMADD_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+// VFMSUB_{S/D}
+def : Pat<(fma v4f32:$vj, v4f32:$vk, (fneg v4f32:$va)),
+ (VFMSUB_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fma v2f64:$vj, v2f64:$vk, (fneg v2f64:$va)),
+ (VFMSUB_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+
+// VFNMADD_{S/D}
+def : Pat<(fneg (fma v4f32:$vj, v4f32:$vk, v4f32:$va)),
+ (VFNMADD_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fneg (fma v2f64:$vj, v2f64:$vk, v2f64:$va)),
+ (VFNMADD_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+def : Pat<(fma_nsz (fneg v4f32:$vj), v4f32:$vk, (fneg v4f32:$va)),
+ (VFNMADD_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fma_nsz (fneg v2f64:$vj), v2f64:$vk, (fneg v2f64:$va)),
+ (VFNMADD_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+
+// VFNMSUB_{S/D}
+def : Pat<(fneg (fma v4f32:$vj, v4f32:$vk, (fneg v4f32:$va))),
+ (VFNMSUB_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fneg (fma v2f64:$vj, v2f64:$vk, (fneg v2f64:$va))),
+ (VFNMSUB_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+def : Pat<(fma_nsz (fneg v4f32:$vj), v4f32:$vk, v4f32:$va),
+ (VFNMSUB_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fma_nsz (fneg v2f64:$vj), v2f64:$vk, v2f64:$va),
+ (VFNMSUB_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+
// VFSQRT_{S/D}
defm : PatVrF<fsqrt, "VFSQRT">;
diff --git a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
index 31e525ad4d79..b2c0fda1ccc2 100644
--- a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
+++ b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
@@ -156,6 +156,7 @@ public:
bool isAReg() const;
bool isDReg() const;
bool isFPDReg() const;
+ bool isFPCReg() const;
unsigned getReg() const override;
void addRegOperands(MCInst &Inst, unsigned N) const;
@@ -254,9 +255,13 @@ static inline unsigned getRegisterIndex(unsigned Register) {
// SP is sadly not contiguous with the rest of the An registers
return 15;
+ // We don't care about the indices of these registers.
case M68k::PC:
case M68k::CCR:
- return 16;
+ case M68k::FPC:
+ case M68k::FPS:
+ case M68k::FPIAR:
+ return UINT_MAX;
default:
llvm_unreachable("unexpected register number");
@@ -488,7 +493,8 @@ void M68kOperand::addPCIOperands(MCInst &Inst, unsigned N) const {
}
static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address,
- bool SP, bool FPDR = false) {
+ bool SP, bool FPDR = false,
+ bool FPCR = false) {
switch (RegNo) {
case M68k::A0:
case M68k::A1:
@@ -526,6 +532,11 @@ static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address,
case M68k::FP7:
return FPDR;
+ case M68k::FPC:
+ case M68k::FPS:
+ case M68k::FPIAR:
+ return FPCR;
+
default:
llvm_unreachable("unexpected register type");
return false;
@@ -551,6 +562,13 @@ bool M68kOperand::isFPDReg() const {
/*FPDR=*/true);
}
+bool M68kOperand::isFPCReg() const {
+ return isReg() && checkRegisterClass(getReg(),
+ /*Data=*/false,
+ /*Address=*/false, /*SP=*/false,
+ /*FPDR=*/false, /*FPCR=*/true);
+}
+
unsigned M68kAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op,
unsigned Kind) {
M68kOperand &Operand = (M68kOperand &)Op;
@@ -660,12 +678,22 @@ bool M68kAsmParser::parseRegisterName(MCRegister &RegNo, SMLoc Loc,
}
} else if (StringRef(RegisterNameLower).starts_with("fp") &&
RegisterNameLower.size() > 2) {
- // Floating point data register.
auto RegIndex = unsigned(RegisterNameLower[2] - '0');
- if (RegIndex >= 8 || RegisterNameLower.size() > 3)
- return false;
- RegNo = getRegisterByIndex(16 + RegIndex);
- return true;
+ if (RegIndex < 8 && RegisterNameLower.size() == 3) {
+ // Floating point data register.
+ RegNo = getRegisterByIndex(16 + RegIndex);
+ return true;
+ } else {
+ // Floating point control register.
+ RegNo = StringSwitch<unsigned>(RegisterNameLower)
+ .Cases("fpc", "fpcr", M68k::FPC)
+ .Cases("fps", "fpsr", M68k::FPS)
+ .Cases("fpi", "fpiar", M68k::FPIAR)
+ .Default(M68k::NoRegister);
+ assert(RegNo != M68k::NoRegister &&
+ "Unrecognized FP control register name");
+ return true;
+ }
}
return false;
diff --git a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
index 2124a35cc65a..7f0f737faccd 100644
--- a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
+++ b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
@@ -33,10 +33,11 @@ using namespace llvm;
typedef MCDisassembler::DecodeStatus DecodeStatus;
static const unsigned RegisterDecode[] = {
- M68k::D0, M68k::D1, M68k::D2, M68k::D3, M68k::D4, M68k::D5,
- M68k::D6, M68k::D7, M68k::A0, M68k::A1, M68k::A2, M68k::A3,
- M68k::A4, M68k::A5, M68k::A6, M68k::SP, M68k::FP0, M68k::FP1,
- M68k::FP2, M68k::FP3, M68k::FP4, M68k::FP5, M68k::FP6, M68k::FP7};
+ M68k::D0, M68k::D1, M68k::D2, M68k::D3, M68k::D4, M68k::D5,
+ M68k::D6, M68k::D7, M68k::A0, M68k::A1, M68k::A2, M68k::A3,
+ M68k::A4, M68k::A5, M68k::A6, M68k::SP, M68k::FP0, M68k::FP1,
+ M68k::FP2, M68k::FP3, M68k::FP4, M68k::FP5, M68k::FP6, M68k::FP7,
+ M68k::FPIAR, M68k::FPS, M68k::FPC};
static DecodeStatus DecodeRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address, const void *Decoder) {
@@ -97,6 +98,13 @@ static DecodeStatus DecodeFPDRRegisterClass(MCInst &Inst, uint64_t RegNo,
#define DecodeFPDR64RegisterClass DecodeFPDRRegisterClass
#define DecodeFPDR80RegisterClass DecodeFPDRRegisterClass
+static DecodeStatus DecodeFPCSCRegisterClass(MCInst &Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ return DecodeRegisterClass(Inst, (RegNo >> 1) + 24, Address, Decoder);
+}
+#define DecodeFPICRegisterClass DecodeFPCSCRegisterClass
+
static DecodeStatus DecodeCCRCRegisterClass(MCInst &Inst, APInt &Insn,
uint64_t Address,
const void *Decoder) {
@@ -114,6 +122,7 @@ static DecodeStatus DecodeImm32(MCInst &Inst, uint64_t Imm, uint64_t Address,
#undef DecodeFPDR32RegisterClass
#undef DecodeFPDR64RegisterClass
#undef DecodeFPDR80RegisterClass
+#undef DecodeFPICRegisterClass
/// A disassembler class for M68k.
struct M68kDisassembler : public MCDisassembler {
diff --git a/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp b/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp
index bb63516e957f..e7e629516494 100644
--- a/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp
+++ b/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp
@@ -25,6 +25,27 @@
using namespace llvm;
+namespace {
+
+struct M68kFormalArgHandler : public M68kIncomingValueHandler {
+ M68kFormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
+ : M68kIncomingValueHandler(MIRBuilder, MRI) {}
+};
+
+struct CallReturnHandler : public M68kIncomingValueHandler {
+ CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
+ MachineInstrBuilder &MIB)
+ : M68kIncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
+
+private:
+ void assignValueToReg(Register ValVReg, Register PhysReg,
+ const CCValAssign &VA) override;
+
+ MachineInstrBuilder &MIB;
+};
+
+} // end anonymous namespace
+
M68kCallLowering::M68kCallLowering(const M68kTargetLowering &TLI)
: CallLowering(&TLI) {}
@@ -119,7 +140,7 @@ bool M68kCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
CCAssignFn *AssignFn =
TLI.getCCAssignFn(F.getCallingConv(), false, F.isVarArg());
IncomingValueAssigner ArgAssigner(AssignFn);
- FormalArgHandler ArgHandler(MIRBuilder, MRI);
+ M68kFormalArgHandler ArgHandler(MIRBuilder, MRI);
return determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgs,
MIRBuilder, F.getCallingConv(),
F.isVarArg());
diff --git a/llvm/lib/Target/M68k/GISel/M68kCallLowering.h b/llvm/lib/Target/M68k/GISel/M68kCallLowering.h
index 7644e6cffbb1..53696df21794 100644
--- a/llvm/lib/Target/M68k/GISel/M68kCallLowering.h
+++ b/llvm/lib/Target/M68k/GISel/M68kCallLowering.h
@@ -63,23 +63,6 @@ private:
MachinePointerInfo &MPO,
ISD::ArgFlagsTy Flags) override;
};
-
-struct FormalArgHandler : public M68kIncomingValueHandler {
- FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
- : M68kIncomingValueHandler(MIRBuilder, MRI) {}
-};
-
-struct CallReturnHandler : public M68kIncomingValueHandler {
- CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
- MachineInstrBuilder &MIB)
- : M68kIncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
-
-private:
- void assignValueToReg(Register ValVReg, Register PhysReg,
- const CCValAssign &VA) override;
-
- MachineInstrBuilder &MIB;
-};
} // end namespace llvm
#endif // LLVM_LIB_TARGET_M68K_GLSEL_M68KCALLLOWERING_H
diff --git a/llvm/lib/Target/M68k/M68kInstrData.td b/llvm/lib/Target/M68k/M68kInstrData.td
index e6d4471f7aab..624093661d19 100644
--- a/llvm/lib/Target/M68k/M68kInstrData.td
+++ b/llvm/lib/Target/M68k/M68kInstrData.td
@@ -672,3 +672,49 @@ foreach rounding = ["", "s", "d"] in {
foreach size = [32, 64] in
def F # !toupper(rounding) # MOV # size # fp_fp : MxFMove_FF<rounding, size>;
}
+// Direction
+defvar MxFMove_FP_EA = false;
+defvar MxFMove_EA_FP = true;
+
+// Encoding scheme for FPSYS <-> R/M
+class MxEncFSysMove<bit dir, MxEncMemOp EAEnc, string fsys_reg> {
+ dag Value = (ascend
+ (descend 0b1111,
+ /*COPROCESSOR ID*/0b001,
+ 0b000,
+ /*MODE + REGISTER*/
+ EAEnc.EA
+ ),
+ (descend 0b10, /*dir*/ dir,
+ /*REGISTER SELECT*/
+ (operand "$"#fsys_reg, 3, (encoder "encodeFPSYSSelect")),
+ 0b0000000000
+ )
+ );
+}
+
+// FPSYS <-> R
+class MxFMove_FSYS_R<string src_reg,
+ MxOpBundle SrcOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#src_reg),
+ MxOpBundle DstOpnd = !cond(!eq(src_reg, "d"): MxOp32AddrMode_fpcs,
+ !eq(src_reg, "a"): MxOp32AddrMode_fpi),
+ MxEncMemOp SrcEnc = !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#src_reg)>
+ : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
+ [(null_frag)]> {
+ let Inst = MxEncFSysMove<MxFMove_FP_EA, SrcEnc, "dst">.Value;
+}
+
+class MxFMove_R_FSYS<string dst_reg,
+ MxOpBundle SrcOpnd = !cond(!eq(dst_reg, "d"): MxOp32AddrMode_fpcs,
+ !eq(dst_reg, "a"): MxOp32AddrMode_fpi),
+ MxOpBundle DstOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#dst_reg),
+ MxEncMemOp DstEnc = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#dst_reg)>
+ : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
+ [(null_frag)]> {
+ let Inst = MxEncFSysMove<MxFMove_EA_FP, DstEnc, "src">.Value;
+}
+
+def FMOVE32fpcs_d : MxFMove_FSYS_R<"d">;
+def FMOVE32d_fpcs : MxFMove_R_FSYS<"d">;
+def FMOVE32fpi_a : MxFMove_FSYS_R<"a">;
+def FMOVE32a_fpi : MxFMove_R_FSYS<"a">;
diff --git a/llvm/lib/Target/M68k/M68kInstrInfo.td b/llvm/lib/Target/M68k/M68kInstrInfo.td
index 6d3370d5ee90..dc66e103361a 100644
--- a/llvm/lib/Target/M68k/M68kInstrInfo.td
+++ b/llvm/lib/Target/M68k/M68kInstrInfo.td
@@ -186,6 +186,7 @@ let RenderMethod = "addRegOperands", SuperClasses = [MxRegClass]in {
def MxDRegClass : MxOpClass<"DReg">;
def MxFPDRegClass : MxOpClass<"FPDReg">;
+ def MxFPCRegClass : MxOpClass<"FPCReg">;
}
class MxOperand<ValueType vt, MxSize size, string letter, RegisterClass rc, dag pat = (null_frag)> {
@@ -242,6 +243,12 @@ let ParserMatchClass = MxFPDRegClass in {
def MxFPR80 : MxRegOp<f80, FPDR80, MxSizeF80, "fp">;
}
+// FLOATING POINT SYSTEM CONTROL REGISTER
+let ParserMatchClass = MxFPCRegClass in {
+ def MxFPCSR : MxRegOp<i32, FPCSC, MxSize32, "fpcs">;
+ def MxFPIR : MxRegOp<i32, FPIC, MxSize32, "fpi">;
+}
+
class MxMemOp<dag ops, MxSize size, string letter,
string printMethod = "printOperand",
AsmOperandClass parserMatchClass = ImmAsmOperand>
@@ -727,6 +734,9 @@ foreach size = [32, 64, 80] in
def MxOp#size#AddrMode_fpr
: MxOpBundle<size, !cast<MxOperand>("MxFPR"#size), ?>;
+def MxOp32AddrMode_fpcs : MxOpBundle<32, MxFPCSR, ?>;
+def MxOp32AddrMode_fpi : MxOpBundle<32, MxFPIR, ?>;
+
class MxType8Class<string rLet, MxOperand reg>
: MxType<i8, "b", "", rLet, reg,
MxARI8, MxCP_ARI,
diff --git a/llvm/lib/Target/M68k/M68kRegisterInfo.td b/llvm/lib/Target/M68k/M68kRegisterInfo.td
index 1567bcbb7319..45b492eba4ec 100644
--- a/llvm/lib/Target/M68k/M68kRegisterInfo.td
+++ b/llvm/lib/Target/M68k/M68kRegisterInfo.td
@@ -125,7 +125,10 @@ let CopyCost = -1 in {
def CCRC : MxRegClass<[i8], 16, (add CCR)>;
def SRC : MxRegClass<[i16], 16, (add SR)>;
- def FPCR : MxRegClass<[i32], 32, (add FPC, FPS, FPIAR)>;
+ // Float Point System Control Registers
+ def FPIC : MxRegClass<[i32], 32, (add FPIAR)>;
+ def FPCSC : MxRegClass<[i32], 32, (add FPC, FPS)>;
+ def FPSYSC : MxRegClass<[i32], 32, (add FPCSC, FPIC)>;
}
let isAllocatable = 0 in {
diff --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
index a9ff059bc990..e6bc3af6e191 100644
--- a/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
+++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
@@ -59,6 +59,10 @@ class M68kMCCodeEmitter : public MCCodeEmitter {
APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ void encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
+ APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
public:
M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
: MCII(mcii), Ctx(ctx) {}
@@ -172,6 +176,26 @@ void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,
}
}
+void M68kMCCodeEmitter::encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx,
+ unsigned InsertPos, APInt &Value,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ MCRegister FPSysReg = MI.getOperand(OpIdx).getReg();
+ switch (FPSysReg) {
+ case M68k::FPC:
+ Value = 0b100;
+ break;
+ case M68k::FPS:
+ Value = 0b010;
+ break;
+ case M68k::FPIAR:
+ Value = 0b001;
+ break;
+ default:
+ llvm_unreachable("Unrecognized FPSYS register");
+ }
+}
+
void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
unsigned InsertPos, APInt &Value,
SmallVectorImpl<MCFixup> &Fixups,
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 60075c819b29..3c673ae938fd 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -6249,7 +6249,7 @@ int MipsAsmParser::matchFPURegisterName(StringRef Name) {
}
int MipsAsmParser::matchFCCRegisterName(StringRef Name) {
- if (Name.startswith("fcc")) {
+ if (Name.starts_with("fcc")) {
StringRef NumString = Name.substr(3);
unsigned IntVal;
if (NumString.getAsInteger(10, IntVal))
@@ -6262,7 +6262,7 @@ int MipsAsmParser::matchFCCRegisterName(StringRef Name) {
}
int MipsAsmParser::matchACRegisterName(StringRef Name) {
- if (Name.startswith("ac")) {
+ if (Name.starts_with("ac")) {
StringRef NumString = Name.substr(2);
unsigned IntVal;
if (NumString.getAsInteger(10, IntVal))
@@ -6567,7 +6567,7 @@ bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) {
if (Expr->getKind() == MCExpr::SymbolRef) {
const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr *>(Expr);
StringRef DefSymbol = Ref->getSymbol().getName();
- if (DefSymbol.startswith("$")) {
+ if (DefSymbol.starts_with("$")) {
ParseStatus Res =
matchAnyRegisterNameWithoutDollar(Operands, DefSymbol.substr(1), S);
if (Res.isSuccess()) {
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
index 81c1ccec7bed..94e3d28a4186 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
@@ -56,11 +56,11 @@ unsigned MipsABIInfo::GetCalleeAllocdArgSizeInBytes(CallingConv::ID CC) const {
MipsABIInfo MipsABIInfo::computeTargetABI(const Triple &TT, StringRef CPU,
const MCTargetOptions &Options) {
- if (Options.getABIName().startswith("o32"))
+ if (Options.getABIName().starts_with("o32"))
return MipsABIInfo::O32();
- if (Options.getABIName().startswith("n32"))
+ if (Options.getABIName().starts_with("n32"))
return MipsABIInfo::N32();
- if (Options.getABIName().startswith("n64"))
+ if (Options.getABIName().starts_with("n64"))
return MipsABIInfo::N64();
if (TT.getEnvironment() == llvm::Triple::GNUABIN32)
return MipsABIInfo::N32();
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index f09d52aa5fd6..a0cab8024386 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -4064,7 +4064,7 @@ parseRegForInlineAsmConstraint(StringRef C, MVT VT) const {
RC = TRI->getRegClass(Prefix == "hi" ?
Mips::HI32RegClassID : Mips::LO32RegClassID);
return std::make_pair(*(RC->begin()), RC);
- } else if (Prefix.startswith("$msa")) {
+ } else if (Prefix.starts_with("$msa")) {
// Parse $msa(ir|csr|access|save|modify|request|map|unmap)
// No numeric characters follow the name.
diff --git a/llvm/lib/Target/NVPTX/NVPTX.td b/llvm/lib/Target/NVPTX/NVPTX.td
index 02fa2a4ee81e..f2a4ce381b40 100644
--- a/llvm/lib/Target/NVPTX/NVPTX.td
+++ b/llvm/lib/Target/NVPTX/NVPTX.td
@@ -24,23 +24,24 @@ include "NVPTXInstrInfo.td"
// TableGen in NVPTXGenSubtarget.inc.
//===----------------------------------------------------------------------===//
-class FeatureSM<int version>:
- SubtargetFeature<"sm_"# version, "SmVersion",
- "" # version,
- "Target SM " # version>;
-def SM90a: FeatureSM<90>;
+class FeatureSM<string sm, int value>:
+ SubtargetFeature<"sm_"# sm, "FullSmVersion",
+ "" # value,
+ "Target SM " # sm>;
class FeaturePTX<int version>:
SubtargetFeature<"ptx"# version, "PTXVersion",
"" # version,
"Use PTX version " # version>;
-foreach version = [20, 21, 30, 32, 35, 37, 50, 52, 53,
- 60, 61, 62, 70, 72, 75, 80, 86, 87, 89, 90] in
- def SM#version: FeatureSM<version>;
+foreach sm = [20, 21, 30, 32, 35, 37, 50, 52, 53,
+ 60, 61, 62, 70, 72, 75, 80, 86, 87, 89, 90] in
+ def SM#sm: FeatureSM<""#sm, !mul(sm, 10)>;
+
+def SM90a: FeatureSM<"90a", 901>;
foreach version = [32, 40, 41, 42, 43, 50, 60, 61, 63, 64, 65,
- 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81] in
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83] in
def PTX#version: FeaturePTX<version>;
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
index 5ced4129ee80..6a03c7b0abc3 100644
--- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
@@ -1016,8 +1016,8 @@ void NVPTXAsmPrinter::printModuleLevelGV(const GlobalVariable *GVar,
}
// Skip LLVM intrinsic global variables
- if (GVar->getName().startswith("llvm.") ||
- GVar->getName().startswith("nvvm."))
+ if (GVar->getName().starts_with("llvm.") ||
+ GVar->getName().starts_with("nvvm."))
return;
const DataLayout &DL = getDataLayout();
diff --git a/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp b/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp
index 4f03e474edb4..3d6bd1d8ad06 100644
--- a/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp
@@ -62,7 +62,7 @@ bool GenericToNVVM::runOnModule(Module &M) {
for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) {
if (GV.getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC &&
!llvm::isTexture(GV) && !llvm::isSurface(GV) && !llvm::isSampler(GV) &&
- !GV.getName().startswith("llvm.")) {
+ !GV.getName().starts_with("llvm.")) {
GlobalVariable *NewGV = new GlobalVariable(
M, GV.getValueType(), GV.isConstant(), GV.getLinkage(),
GV.hasInitializer() ? GV.getInitializer() : nullptr, "", &GV,
diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
index 61285c6ba98d..e8f36bf50a1b 100644
--- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
@@ -37,6 +37,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/FPEnv.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
@@ -639,6 +640,11 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
setOperationAction(ISD::ConstantFP, MVT::f16, Legal);
setOperationAction(ISD::ConstantFP, MVT::bf16, Legal);
+ // Lowering of DYNAMIC_STACKALLOC is unsupported.
+ // Custom lower to produce an error.
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom);
+
// TRAP can be lowered to PTX trap
setOperationAction(ISD::TRAP, MVT::Other, Legal);
@@ -766,6 +772,17 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
AddPromotedToType(Op, MVT::bf16, MVT::f32);
}
+ // sm_80 only has conversions between f32 and bf16. Custom lower all other
+ // bf16 conversions.
+ if (STI.hasBF16Math() &&
+ (STI.getSmVersion() < 90 || STI.getPTXVersion() < 78)) {
+ for (MVT VT : {MVT::i1, MVT::i16, MVT::i32, MVT::i64}) {
+ setOperationAction(
+ {ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_TO_SINT, ISD::FP_TO_UINT},
+ VT, Custom);
+ }
+ }
+
setOperationAction(ISD::FROUND, MVT::f16, Promote);
setOperationAction(ISD::FROUND, MVT::v2f16, Expand);
setOperationAction(ISD::FROUND, MVT::v2bf16, Expand);
@@ -2198,6 +2215,18 @@ SDValue NVPTXTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
return Chain;
}
+SDValue NVPTXTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
+ SelectionDAG &DAG) const {
+ const Function &Fn = DAG.getMachineFunction().getFunction();
+
+ DiagnosticInfoUnsupported NoDynamicAlloca(
+ Fn, "dynamic alloca unsupported by NVPTX backend",
+ SDLoc(Op).getDebugLoc());
+ DAG.getContext()->diagnose(NoDynamicAlloca);
+ auto Ops = {DAG.getConstant(0, SDLoc(), Op.getValueType()), Op.getOperand(0)};
+ return DAG.getMergeValues(Ops, SDLoc());
+}
+
// By default CONCAT_VECTORS is lowered by ExpandVectorBuildThroughStack()
// (see LegalizeDAG.cpp). This is slow and uses local memory.
// We use extract/insert/build vector just as what LegalizeOp() does in llvm 2.5
@@ -2580,6 +2609,37 @@ SDValue NVPTXTargetLowering::LowerFROUND64(SDValue Op,
return DAG.getNode(ISD::SELECT, SL, VT, IsLarge, A, RoundedA);
}
+SDValue NVPTXTargetLowering::LowerINT_TO_FP(SDValue Op,
+ SelectionDAG &DAG) const {
+ assert(STI.getSmVersion() < 90 || STI.getPTXVersion() < 78);
+
+ if (Op.getValueType() == MVT::bf16) {
+ SDLoc Loc(Op);
+ return DAG.getNode(
+ ISD::FP_ROUND, Loc, MVT::bf16,
+ DAG.getNode(Op.getOpcode(), Loc, MVT::f32, Op.getOperand(0)),
+ DAG.getIntPtrConstant(0, Loc));
+ }
+
+ // Everything else is considered legal.
+ return Op;
+}
+
+SDValue NVPTXTargetLowering::LowerFP_TO_INT(SDValue Op,
+ SelectionDAG &DAG) const {
+ assert(STI.getSmVersion() < 90 || STI.getPTXVersion() < 78);
+
+ if (Op.getOperand(0).getValueType() == MVT::bf16) {
+ SDLoc Loc(Op);
+ return DAG.getNode(
+ Op.getOpcode(), Loc, Op.getValueType(),
+ DAG.getNode(ISD::FP_EXTEND, Loc, MVT::f32, Op.getOperand(0)));
+ }
+
+ // Everything else is considered legal.
+ return Op;
+}
+
static SDValue LowerVectorArith(SDValue Op, SelectionDAG &DAG) {
SDLoc DL(Op);
if (Op.getValueType() != MVT::v2i16)
@@ -2636,6 +2696,12 @@ NVPTXTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
return LowerSelect(Op, DAG);
case ISD::FROUND:
return LowerFROUND(Op, DAG);
+ case ISD::SINT_TO_FP:
+ case ISD::UINT_TO_FP:
+ return LowerINT_TO_FP(Op, DAG);
+ case ISD::FP_TO_SINT:
+ case ISD::FP_TO_UINT:
+ return LowerFP_TO_INT(Op, DAG);
case ISD::VAARG:
return LowerVAARG(Op, DAG);
case ISD::VASTART:
@@ -2652,6 +2718,8 @@ NVPTXTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::SREM:
case ISD::UREM:
return LowerVectorArith(Op, DAG);
+ case ISD::DYNAMIC_STACKALLOC:
+ return LowerDYNAMIC_STACKALLOC(Op, DAG);
default:
llvm_unreachable("Custom lowering not defined for operation");
}
diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.h b/llvm/lib/Target/NVPTX/NVPTXISelLowering.h
index 54e34dedc667..06adc0c47f05 100644
--- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.h
+++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.h
@@ -513,6 +513,8 @@ public:
SDValue LowerCall(CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const override;
+ SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
+
std::string
getPrototype(const DataLayout &DL, Type *, const ArgListTy &,
const SmallVectorImpl<ISD::OutputArg> &, MaybeAlign retAlignment,
@@ -607,6 +609,9 @@ private:
SDValue LowerFROUND32(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFROUND64(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) const;
+
SDValue LowerLOAD(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerLOADi1(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp b/llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp
index 4bd820e98f05..85f75df39c0d 100644
--- a/llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp
@@ -1812,7 +1812,7 @@ findIndexForHandle(MachineOperand &Op, MachineFunction &MF, unsigned &Idx) {
StringRef Sym = TexHandleDef.getOperand(6).getSymbolName();
std::string ParamBaseName = std::string(MF.getName());
ParamBaseName += "_param_";
- assert(Sym.startswith(ParamBaseName) && "Invalid symbol reference");
+ assert(Sym.starts_with(ParamBaseName) && "Invalid symbol reference");
unsigned Param = atoi(Sym.data()+ParamBaseName.size());
std::string NewSym;
raw_string_ostream NewSymStr(NewSym);
diff --git a/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp b/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp
index 7fa64af196b9..420065585b38 100644
--- a/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp
@@ -36,6 +36,11 @@ NVPTXSubtarget &NVPTXSubtarget::initializeSubtargetDependencies(StringRef CPU,
ParseSubtargetFeatures(TargetName, /*TuneCPU*/ TargetName, FS);
+ // Re-map SM version numbers, SmVersion carries the regular SMs which do
+ // have relative order, while FullSmVersion allows distinguishing sm_90 from
+ // sm_90a, which would *not* be a subset of sm_91.
+ SmVersion = getSmVersion();
+
// Set default to PTX 6.0 (CUDA 9.0)
if (PTXVersion == 0) {
PTXVersion = 60;
@@ -48,7 +53,7 @@ NVPTXSubtarget::NVPTXSubtarget(const Triple &TT, const std::string &CPU,
const std::string &FS,
const NVPTXTargetMachine &TM)
: NVPTXGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), PTXVersion(0),
- SmVersion(20), TM(TM),
+ FullSmVersion(200), SmVersion(getSmVersion()), TM(TM),
TLInfo(TM, initializeSubtargetDependencies(CPU, FS)) {}
bool NVPTXSubtarget::hasImageHandles() const {
diff --git a/llvm/lib/Target/NVPTX/NVPTXSubtarget.h b/llvm/lib/Target/NVPTX/NVPTXSubtarget.h
index 93af11c258b4..3ca4c1a24c79 100644
--- a/llvm/lib/Target/NVPTX/NVPTXSubtarget.h
+++ b/llvm/lib/Target/NVPTX/NVPTXSubtarget.h
@@ -35,7 +35,12 @@ class NVPTXSubtarget : public NVPTXGenSubtargetInfo {
// PTX version x.y is represented as 10*x+y, e.g. 3.1 == 31
unsigned PTXVersion;
- // SM version x.y is represented as 10*x+y, e.g. 3.1 == 31
+ // Full SM version x.y is represented as 100*x+10*y+feature, e.g. 3.1 == 310
+ // sm_90a == 901
+ unsigned int FullSmVersion;
+
+ // SM version x.y is represented as 10*x+y, e.g. 3.1 == 31. Derived from
+ // FullSmVersion.
unsigned int SmVersion;
const NVPTXTargetMachine &TM;
@@ -80,7 +85,15 @@ public:
bool allowFP16Math() const;
bool hasMaskOperator() const { return PTXVersion >= 71; }
bool hasNoReturn() const { return SmVersion >= 30 && PTXVersion >= 64; }
- unsigned int getSmVersion() const { return SmVersion; }
+ unsigned int getFullSmVersion() const { return FullSmVersion; }
+ unsigned int getSmVersion() const { return getFullSmVersion() / 10; }
+ // GPUs with "a" suffix have include architecture-accelerated features that
+ // are supported on the specified architecture only, hence such targets do not
+ // follow the onion layer model. hasAAFeatures() allows distinguishing such
+ // GPU variants from the base GPU architecture.
+ // - 0 represents base GPU model,
+ // - non-zero value identifies particular architecture-accelerated variant.
+ bool hasAAFeatures() const { return getFullSmVersion() % 10; }
std::string getTargetName() const { return TargetName; }
// Get maximum value of required alignments among the supported data types.
diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index a33f44542eb5..8108cfa521c8 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -1744,7 +1744,7 @@ bool PPCAsmParser::ParseDirective(AsmToken DirectiveID) {
ParseDirectiveAbiVersion(DirectiveID.getLoc());
else if (IDVal == ".localentry")
ParseDirectiveLocalEntry(DirectiveID.getLoc());
- else if (IDVal.startswith(".gnu_attribute"))
+ else if (IDVal.starts_with(".gnu_attribute"))
ParseGNUAttribute(DirectiveID.getLoc());
else
return true;
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
index ccbb650c6536..9a4291c90408 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
@@ -484,7 +484,10 @@ void PPCInstPrinter::printAbsBranchOperand(const MCInst *MI, unsigned OpNo,
if (!MI->getOperand(OpNo).isImm())
return printOperand(MI, OpNo, STI, O);
- O << SignExtend32<32>((unsigned)MI->getOperand(OpNo).getImm() << 2);
+ uint64_t Imm = static_cast<uint64_t>(MI->getOperand(OpNo).getImm()) << 2;
+ if (!TT.isPPC64())
+ Imm = static_cast<uint32_t>(Imm);
+ O << formatHex(Imm);
}
void PPCInstPrinter::printcrbitm(const MCInst *MI, unsigned OpNo,
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 4b551bc51c4f..780b22b4fbe6 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2519,7 +2519,7 @@ void PPCAIXAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
}
void PPCAIXAsmPrinter::emitGlobalVariableHelper(const GlobalVariable *GV) {
- assert(!GV->getName().startswith("llvm.") &&
+ assert(!GV->getName().starts_with("llvm.") &&
"Unhandled intrinsic global variable.");
if (GV->hasComdat())
diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.td b/llvm/lib/Target/PowerPC/PPCRegisterInfo.td
index 6151faf403aa..375e63654db1 100644
--- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.td
+++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.td
@@ -798,6 +798,7 @@ def directbrtarget : Operand<OtherVT> {
def absdirectbrtarget : Operand<OtherVT> {
let PrintMethod = "printAbsBranchOperand";
let EncoderMethod = "getAbsDirectBrEncoding";
+ let DecoderMethod = "decodeDirectBrTarget";
let ParserMatchClass = PPCDirectBrAsmOperand;
}
def PPCCondBrAsmOperand : AsmOperandClass {
@@ -814,6 +815,7 @@ def condbrtarget : Operand<OtherVT> {
def abscondbrtarget : Operand<OtherVT> {
let PrintMethod = "printAbsBranchOperand";
let EncoderMethod = "getAbsCondBrEncoding";
+ let DecoderMethod = "decodeCondBrTarget";
let ParserMatchClass = PPCCondBrAsmOperand;
}
def calltarget : Operand<iPTR> {
@@ -826,6 +828,7 @@ def calltarget : Operand<iPTR> {
def abscalltarget : Operand<iPTR> {
let PrintMethod = "printAbsBranchOperand";
let EncoderMethod = "getAbsDirectBrEncoding";
+ let DecoderMethod = "decodeDirectBrTarget";
let ParserMatchClass = PPCDirectBrAsmOperand;
}
def PPCCRBitMaskOperand : AsmOperandClass {
diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
index b09975172bf5..d676fa86a10e 100644
--- a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
+++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
@@ -242,9 +242,9 @@ static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
static PPCTargetMachine::PPCABI computeTargetABI(const Triple &TT,
const TargetOptions &Options) {
- if (Options.MCOptions.getABIName().startswith("elfv1"))
+ if (Options.MCOptions.getABIName().starts_with("elfv1"))
return PPCTargetMachine::PPC_ABI_ELFv1;
- else if (Options.MCOptions.getABIName().startswith("elfv2"))
+ else if (Options.MCOptions.getABIName().starts_with("elfv2"))
return PPCTargetMachine::PPC_ABI_ELFv2;
assert(Options.MCOptions.getABIName().empty() &&
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 138134d00f64..f3ea0f597eec 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -286,11 +286,11 @@ public:
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
auto ABIName = StringRef(Options.ABIName);
- if (ABIName.endswith("f") && !getSTI().hasFeature(RISCV::FeatureStdExtF)) {
+ if (ABIName.ends_with("f") && !getSTI().hasFeature(RISCV::FeatureStdExtF)) {
errs() << "Hard-float 'f' ABI can't be used for a target that "
"doesn't support the F instruction set extension (ignoring "
"target-abi)\n";
- } else if (ABIName.endswith("d") &&
+ } else if (ABIName.ends_with("d") &&
!getSTI().hasFeature(RISCV::FeatureStdExtD)) {
errs() << "Hard-float 'd' ABI can't be used for a target that "
"doesn't support the D instruction set extension (ignoring "
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
index edcca8805dfc..66a46a485f53 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
@@ -47,11 +47,11 @@ ABI computeTargetABI(const Triple &TT, const FeatureBitset &FeatureBits,
errs()
<< "'" << ABIName
<< "' is not a recognized ABI for this target (ignoring target-abi)\n";
- } else if (ABIName.startswith("ilp32") && IsRV64) {
+ } else if (ABIName.starts_with("ilp32") && IsRV64) {
errs() << "32-bit ABIs are not supported for 64-bit targets (ignoring "
"target-abi)\n";
TargetABI = ABI_Unknown;
- } else if (ABIName.startswith("lp64") && !IsRV64) {
+ } else if (ABIName.starts_with("lp64") && !IsRV64) {
errs() << "64-bit ABIs are not supported for 32-bit targets (ignoring "
"target-abi)\n";
TargetABI = ABI_Unknown;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
index a6f3f7f8d18e..195dda0b8b14 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
@@ -91,7 +91,7 @@ void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
}
if (MO.isImm()) {
- markup(O, Markup::Immediate) << MO.getImm();
+ markup(O, Markup::Immediate) << formatImm(MO.getImm());
return;
}
@@ -113,7 +113,7 @@ void RISCVInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address,
Target &= 0xffffffff;
markup(O, Markup::Target) << formatHex(Target);
} else {
- markup(O, Markup::Target) << MO.getImm();
+ markup(O, Markup::Target) << formatImm(MO.getImm());
}
}
@@ -128,7 +128,7 @@ void RISCVInstPrinter::printCSRSystemRegister(const MCInst *MI, unsigned OpNo,
else if (SysReg && SysReg->haveRequiredFeatures(STI.getFeatureBits()))
markup(O, Markup::Register) << SysReg->Name;
else
- markup(O, Markup::Register) << Imm;
+ markup(O, Markup::Register) << formatImm(Imm);
}
void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo,
@@ -212,7 +212,7 @@ void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo,
// or non-zero in bits 8 and above.
if (RISCVVType::getVLMUL(Imm) == RISCVII::VLMUL::LMUL_RESERVED ||
RISCVVType::getSEW(Imm) > 64 || (Imm >> 8) != 0) {
- O << Imm;
+ O << formatImm(Imm);
return;
}
// Print the text form.
diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index ad1713cad64c..9eb18099894b 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -18,13 +18,8 @@
#include "llvm/Target/TargetMachine.h"
namespace llvm {
-class AsmPrinter;
class FunctionPass;
class InstructionSelector;
-class MCInst;
-class MCOperand;
-class MachineInstr;
-class MachineOperand;
class PassRegistry;
class RISCVRegisterBankInfo;
class RISCVSubtarget;
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 7d142d38d0f9..294927aecb94 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -970,6 +970,16 @@ def TuneLUIADDIFusion
: SubtargetFeature<"lui-addi-fusion", "HasLUIADDIFusion",
"true", "Enable LUI+ADDI macrofusion">;
+def TuneAUIPCADDIFusion
+ : SubtargetFeature<"auipc-addi-fusion", "HasAUIPCADDIFusion",
+ "true", "Enable AUIPC+ADDI macrofusion">;
+def TuneShiftedZExtFusion
+ : SubtargetFeature<"shifted-zext-fusion", "HasShiftedZExtFusion",
+ "true", "Enable SLLI+SRLI to be fused when computing (shifted) zero extension">;
+def TuneLDADDFusion
+ : SubtargetFeature<"ld-add-fusion", "HasLDADDFusion",
+ "true", "Enable LD+ADD macrofusion.">;
+
def TuneNoDefaultUnroll
: SubtargetFeature<"no-default-unroll", "EnableDefaultUnroll", "false",
"Disable default unroll preference.">;
@@ -987,9 +997,12 @@ def TuneSiFive7 : SubtargetFeature<"sifive7", "RISCVProcFamily", "SiFive7",
[TuneNoDefaultUnroll,
TuneShortForwardBranchOpt]>;
-def TuneVentanaVeyron : SubtargetFeature<"ventana-veyron", "RISCVProcFamily", "VentanaVeyron",
- "Ventana-Veyron Series processors",
- [TuneLUIADDIFusion]>;
+def TuneVeyronFusions : SubtargetFeature<"ventana-veyron", "RISCVProcFamily", "VentanaVeyron",
+ "Ventana Veyron-Series processors",
+ [TuneLUIADDIFusion,
+ TuneAUIPCADDIFusion,
+ TuneShiftedZExtFusion,
+ TuneLDADDFusion]>;
// Assume that lock-free native-width atomics are available, even if the target
// and operating system combination would not usually provide them. The user
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index f2ec422b54a9..03e994586d0c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -335,6 +335,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
if (Subtarget.is64Bit())
setOperationAction({ISD::ROTL, ISD::ROTR}, MVT::i32, Custom);
setOperationAction({ISD::ROTL, ISD::ROTR}, XLenVT, Custom);
+ } else if (Subtarget.hasVendorXCVbitmanip()) {
+ setOperationAction(ISD::ROTL, XLenVT, Expand);
} else {
setOperationAction({ISD::ROTL, ISD::ROTR}, XLenVT, Expand);
if (RV64LegalI32 && Subtarget.is64Bit())
@@ -355,9 +357,14 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
? Promote
: Expand);
- // Zbkb can use rev8+brev8 to implement bitreverse.
- setOperationAction(ISD::BITREVERSE, XLenVT,
- Subtarget.hasStdExtZbkb() ? Custom : Expand);
+
+ if (Subtarget.hasVendorXCVbitmanip()) {
+ setOperationAction(ISD::BITREVERSE, XLenVT, Legal);
+ } else {
+ // Zbkb can use rev8+brev8 to implement bitreverse.
+ setOperationAction(ISD::BITREVERSE, XLenVT,
+ Subtarget.hasStdExtZbkb() ? Custom : Expand);
+ }
if (Subtarget.hasStdExtZbb()) {
setOperationAction({ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}, XLenVT,
@@ -372,13 +379,14 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
else
setOperationAction({ISD::CTTZ, ISD::CTTZ_ZERO_UNDEF}, MVT::i32, Custom);
}
- } else {
+ } else if (!Subtarget.hasVendorXCVbitmanip()) {
setOperationAction({ISD::CTTZ, ISD::CTPOP}, XLenVT, Expand);
if (RV64LegalI32 && Subtarget.is64Bit())
setOperationAction({ISD::CTTZ, ISD::CTPOP}, MVT::i32, Expand);
}
- if (Subtarget.hasStdExtZbb() || Subtarget.hasVendorXTHeadBb()) {
+ if (Subtarget.hasStdExtZbb() || Subtarget.hasVendorXTHeadBb() ||
+ Subtarget.hasVendorXCVbitmanip()) {
// We need the custom lowering to make sure that the resulting sequence
// for the 32bit case is efficient on 64bit targets.
if (Subtarget.is64Bit()) {
@@ -1363,9 +1371,6 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment());
setPrefLoopAlignment(Subtarget.getPrefLoopAlignment());
- // Jumps are expensive, compared to logic
- setJumpIsExpensive();
-
setTargetDAGCombine({ISD::INTRINSIC_VOID, ISD::INTRINSIC_W_CHAIN,
ISD::INTRINSIC_WO_CHAIN, ISD::ADD, ISD::SUB, ISD::AND,
ISD::OR, ISD::XOR, ISD::SETCC, ISD::SELECT});
@@ -1799,11 +1804,12 @@ bool RISCVTargetLowering::signExtendConstant(const ConstantInt *CI) const {
}
bool RISCVTargetLowering::isCheapToSpeculateCttz(Type *Ty) const {
- return Subtarget.hasStdExtZbb();
+ return Subtarget.hasStdExtZbb() || Subtarget.hasVendorXCVbitmanip();
}
bool RISCVTargetLowering::isCheapToSpeculateCtlz(Type *Ty) const {
- return Subtarget.hasStdExtZbb() || Subtarget.hasVendorXTHeadBb();
+ return Subtarget.hasStdExtZbb() || Subtarget.hasVendorXTHeadBb() ||
+ Subtarget.hasVendorXCVbitmanip();
}
bool RISCVTargetLowering::isMaskAndCmp0FoldingBeneficial(
@@ -2583,8 +2589,15 @@ static SDValue getAllOnesMask(MVT VecVT, SDValue VL, const SDLoc &DL,
return DAG.getNode(RISCVISD::VMSET_VL, DL, MaskVT, VL);
}
-static SDValue getVLOp(uint64_t NumElts, const SDLoc &DL, SelectionDAG &DAG,
- const RISCVSubtarget &Subtarget) {
+static SDValue getVLOp(uint64_t NumElts, MVT ContainerVT, const SDLoc &DL,
+ SelectionDAG &DAG, const RISCVSubtarget &Subtarget) {
+ // If we know the exact VLEN, our VL is exactly equal to VLMAX, and
+ // we can't encode the AVL as an immediate, use the VLMAX encoding.
+ const auto [MinVLMAX, MaxVLMAX] =
+ RISCVTargetLowering::computeVLMAXBounds(ContainerVT, Subtarget);
+ if (MinVLMAX == MaxVLMAX && NumElts == MinVLMAX && NumElts > 31)
+ return DAG.getRegister(RISCV::X0, Subtarget.getXLenVT());
+
return DAG.getConstant(NumElts, DL, Subtarget.getXLenVT());
}
@@ -2601,7 +2614,7 @@ static std::pair<SDValue, SDValue>
getDefaultVLOps(uint64_t NumElts, MVT ContainerVT, const SDLoc &DL,
SelectionDAG &DAG, const RISCVSubtarget &Subtarget) {
assert(ContainerVT.isScalableVector() && "Expecting scalable container type");
- SDValue VL = getVLOp(NumElts, DL, DAG, Subtarget);
+ SDValue VL = getVLOp(NumElts, ContainerVT, DL, DAG, Subtarget);
SDValue Mask = getAllOnesMask(ContainerVT, VL, DL, DAG);
return {Mask, VL};
}
@@ -2627,6 +2640,25 @@ SDValue RISCVTargetLowering::computeVLMax(MVT VecVT, const SDLoc &DL,
VecVT.getVectorElementCount());
}
+std::pair<unsigned, unsigned>
+RISCVTargetLowering::computeVLMAXBounds(MVT VecVT,
+ const RISCVSubtarget &Subtarget) {
+ assert(VecVT.isScalableVector() && "Expected scalable vector");
+
+ unsigned EltSize = VecVT.getScalarSizeInBits();
+ unsigned MinSize = VecVT.getSizeInBits().getKnownMinValue();
+
+ unsigned VectorBitsMax = Subtarget.getRealMaxVLen();
+ unsigned MaxVLMAX =
+ RISCVTargetLowering::computeVLMAX(VectorBitsMax, EltSize, MinSize);
+
+ unsigned VectorBitsMin = Subtarget.getRealMinVLen();
+ unsigned MinVLMAX =
+ RISCVTargetLowering::computeVLMAX(VectorBitsMin, EltSize, MinSize);
+
+ return std::make_pair(MinVLMAX, MaxVLMAX);
+}
+
// The state of RVV BUILD_VECTOR and VECTOR_SHUFFLE lowering is that very few
// of either is (currently) supported. This can get us into an infinite loop
// where we try to lower a BUILD_VECTOR as a VECTOR_SHUFFLE as a BUILD_VECTOR
@@ -8126,16 +8158,8 @@ static SDValue lowerVectorIntrinsicScalars(SDValue Op, SelectionDAG &DAG,
// Optimize for constant AVL
if (isa<ConstantSDNode>(AVL)) {
- unsigned EltSize = VT.getScalarSizeInBits();
- unsigned MinSize = VT.getSizeInBits().getKnownMinValue();
-
- unsigned VectorBitsMax = Subtarget.getRealMaxVLen();
- unsigned MaxVLMAX =
- RISCVTargetLowering::computeVLMAX(VectorBitsMax, EltSize, MinSize);
-
- unsigned VectorBitsMin = Subtarget.getRealMinVLen();
- unsigned MinVLMAX =
- RISCVTargetLowering::computeVLMAX(VectorBitsMin, EltSize, MinSize);
+ const auto [MinVLMAX, MaxVLMAX] =
+ RISCVTargetLowering::computeVLMAXBounds(VT, Subtarget);
uint64_t AVLInt = cast<ConstantSDNode>(AVL)->getZExtValue();
if (AVLInt <= MinVLMAX) {
@@ -8642,7 +8666,8 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
MVT VT = Op->getSimpleValueType(0);
MVT ContainerVT = getContainerForFixedLengthVector(VT);
- SDValue VL = getVLOp(VT.getVectorNumElements(), DL, DAG, Subtarget);
+ SDValue VL = getVLOp(VT.getVectorNumElements(), ContainerVT, DL, DAG,
+ Subtarget);
SDValue IntID = DAG.getTargetConstant(VlsegInts[NF - 2], DL, XLenVT);
auto *Load = cast<MemIntrinsicSDNode>(Op);
SmallVector<EVT, 9> ContainerVTs(NF, ContainerVT);
@@ -8777,7 +8802,8 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
MVT VT = Op->getOperand(2).getSimpleValueType();
MVT ContainerVT = getContainerForFixedLengthVector(VT);
- SDValue VL = getVLOp(VT.getVectorNumElements(), DL, DAG, Subtarget);
+ SDValue VL = getVLOp(VT.getVectorNumElements(), ContainerVT, DL, DAG,
+ Subtarget);
SDValue IntID = DAG.getTargetConstant(VssegInts[NF - 2], DL, XLenVT);
SDValue Ptr = Op->getOperand(NF + 2);
@@ -9236,7 +9262,7 @@ SDValue RISCVTargetLowering::lowerINSERT_SUBVECTOR(SDValue Op,
// Set the vector length to only the number of elements we care about. Note
// that for slideup this includes the offset.
unsigned EndIndex = OrigIdx + SubVecVT.getVectorNumElements();
- SDValue VL = getVLOp(EndIndex, DL, DAG, Subtarget);
+ SDValue VL = getVLOp(EndIndex, ContainerVT, DL, DAG, Subtarget);
// Use tail agnostic policy if we're inserting over Vec's tail.
unsigned Policy = RISCVII::TAIL_UNDISTURBED_MASK_UNDISTURBED;
@@ -9413,7 +9439,8 @@ SDValue RISCVTargetLowering::lowerEXTRACT_SUBVECTOR(SDValue Op,
getDefaultVLOps(VecVT, ContainerVT, DL, DAG, Subtarget).first;
// Set the vector length to only the number of elements we care about. This
// avoids sliding down elements we're going to discard straight away.
- SDValue VL = getVLOp(SubVecVT.getVectorNumElements(), DL, DAG, Subtarget);
+ SDValue VL = getVLOp(SubVecVT.getVectorNumElements(), ContainerVT, DL, DAG,
+ Subtarget);
SDValue SlidedownAmt = DAG.getConstant(OrigIdx, DL, XLenVT);
SDValue Slidedown =
getVSlidedown(DAG, Subtarget, DL, ContainerVT,
@@ -9820,7 +9847,20 @@ RISCVTargetLowering::lowerFixedLengthVectorLoadToRVV(SDValue Op,
MVT XLenVT = Subtarget.getXLenVT();
MVT ContainerVT = getContainerForFixedLengthVector(VT);
- SDValue VL = getVLOp(VT.getVectorNumElements(), DL, DAG, Subtarget);
+ // If we know the exact VLEN and our fixed length vector completely fills
+ // the container, use a whole register load instead.
+ const auto [MinVLMAX, MaxVLMAX] =
+ RISCVTargetLowering::computeVLMAXBounds(ContainerVT, Subtarget);
+ if (MinVLMAX == MaxVLMAX && MinVLMAX == VT.getVectorNumElements() &&
+ getLMUL1VT(ContainerVT).bitsLE(ContainerVT)) {
+ SDValue NewLoad =
+ DAG.getLoad(ContainerVT, DL, Load->getChain(), Load->getBasePtr(),
+ Load->getMemOperand());
+ SDValue Result = convertFromScalableVector(VT, NewLoad, DAG, Subtarget);
+ return DAG.getMergeValues({Result, NewLoad.getValue(1)}, DL);
+ }
+
+ SDValue VL = getVLOp(VT.getVectorNumElements(), ContainerVT, DL, DAG, Subtarget);
bool IsMaskOp = VT.getVectorElementType() == MVT::i1;
SDValue IntID = DAG.getTargetConstant(
@@ -9864,11 +9904,22 @@ RISCVTargetLowering::lowerFixedLengthVectorStoreToRVV(SDValue Op,
MVT ContainerVT = getContainerForFixedLengthVector(VT);
- SDValue VL = getVLOp(VT.getVectorNumElements(), DL, DAG, Subtarget);
-
SDValue NewValue =
convertToScalableVector(ContainerVT, StoreVal, DAG, Subtarget);
+
+ // If we know the exact VLEN and our fixed length vector completely fills
+ // the container, use a whole register store instead.
+ const auto [MinVLMAX, MaxVLMAX] =
+ RISCVTargetLowering::computeVLMAXBounds(ContainerVT, Subtarget);
+ if (MinVLMAX == MaxVLMAX && MinVLMAX == VT.getVectorNumElements() &&
+ getLMUL1VT(ContainerVT).bitsLE(ContainerVT))
+ return DAG.getStore(Store->getChain(), DL, NewValue, Store->getBasePtr(),
+ Store->getMemOperand());
+
+ SDValue VL = getVLOp(VT.getVectorNumElements(), ContainerVT, DL, DAG,
+ Subtarget);
+
bool IsMaskOp = VT.getVectorElementType() == MVT::i1;
SDValue IntID = DAG.getTargetConstant(
IsMaskOp ? Intrinsic::riscv_vsm : Intrinsic::riscv_vse, DL, XLenVT);
@@ -16038,6 +16089,7 @@ unsigned RISCVTargetLowering::ComputeNumSignBitsForTargetNode(
assert(Subtarget.hasStdExtA());
return 33;
}
+ break;
}
}
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index ae798cc47bf8..41a2dc5771c8 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -744,7 +744,13 @@ public:
// The following equations have been reordered to prevent loss of precision
// when calculating fractional LMUL.
return ((VectorBits / EltSize) * MinSize) / RISCV::RVVBitsPerBlock;
- };
+ }
+
+ // Return inclusive (low, high) bounds on the value of VLMAX for the
+ // given scalable container type given known bounds on VLEN.
+ static std::pair<unsigned, unsigned>
+ computeVLMAXBounds(MVT ContainerVT, const RISCVSubtarget &Subtarget);
+
static unsigned getRegClassIDForLMUL(RISCVII::VLMUL LMul);
static unsigned getSubregIndexByMVT(MVT VT, unsigned Index);
static unsigned getRegClassIDForVecVT(MVT VT);
diff --git a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
index ed3489f6db1c..3400b24e0abb 100644
--- a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
@@ -149,6 +149,13 @@ static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) {
}
}
+static bool isNonZeroLoadImmediate(MachineInstr &MI) {
+ return MI.getOpcode() == RISCV::ADDI &&
+ MI.getOperand(1).isReg() && MI.getOperand(2).isImm() &&
+ MI.getOperand(1).getReg() == RISCV::X0 &&
+ MI.getOperand(2).getImm() != 0;
+}
+
/// Return true if this is an operation on mask registers. Note that
/// this includes both arithmetic/logical ops and load/store (vlm/vsm).
static bool isMaskRegOp(const MachineInstr &MI) {
@@ -501,10 +508,7 @@ public:
if (getAVLReg() == RISCV::X0)
return true;
if (MachineInstr *MI = MRI.getVRegDef(getAVLReg());
- MI && MI->getOpcode() == RISCV::ADDI &&
- MI->getOperand(1).isReg() && MI->getOperand(2).isImm() &&
- MI->getOperand(1).getReg() == RISCV::X0 &&
- MI->getOperand(2).getImm() != 0)
+ MI && isNonZeroLoadImmediate(*MI))
return true;
return false;
}
@@ -1040,9 +1044,23 @@ bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI,
return true;
}
+// If we don't use LMUL or the SEW/LMUL ratio, then adjust LMUL so that we
+// maintain the SEW/LMUL ratio. This allows us to eliminate VL toggles in more
+// places.
static VSETVLIInfo adjustIncoming(VSETVLIInfo PrevInfo, VSETVLIInfo NewInfo,
- DemandedFields &Demanded,
- const MachineRegisterInfo *MRI);
+ DemandedFields &Demanded) {
+ VSETVLIInfo Info = NewInfo;
+
+ if (!Demanded.LMUL && !Demanded.SEWLMULRatio && PrevInfo.isValid() &&
+ !PrevInfo.isUnknown()) {
+ if (auto NewVLMul = RISCVVType::getSameRatioLMUL(
+ PrevInfo.getSEW(), PrevInfo.getVLMUL(), Info.getSEW()))
+ Info.setVLMul(*NewVLMul);
+ Demanded.LMUL = true;
+ }
+
+ return Info;
+}
// Given an incoming state reaching MI, minimally modifies that state so that it
// is compatible with MI. The resulting state is guaranteed to be semantically
@@ -1059,19 +1077,22 @@ void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info,
return;
const VSETVLIInfo PrevInfo = Info;
- if (Info.hasSEWLMULRatioOnly() || !Info.isValid() || Info.isUnknown())
- Info = NewInfo;
-
- if (!RISCVII::hasVLOp(TSFlags)) {
+ if (!Info.isValid() || Info.isUnknown())
Info = NewInfo;
- return;
- }
DemandedFields Demanded = getDemanded(MI, MRI, ST);
- const VSETVLIInfo IncomingInfo =
- adjustIncoming(PrevInfo, NewInfo, Demanded, MRI);
-
- if (Demanded.usedVL())
+ const VSETVLIInfo IncomingInfo = adjustIncoming(PrevInfo, NewInfo, Demanded);
+
+ // If MI only demands that VL has the same zeroness, we only need to set the
+ // AVL if the zeroness differs. This removes a vsetvli entirely if the types
+ // match or allows use of cheaper avl preserving variant if VLMAX doesn't
+ // change. If VLMAX might change, we couldn't use the 'vsetvli x0, x0, vtype"
+ // variant, so we avoid the transform to prevent extending live range of an
+ // avl register operand.
+ // TODO: We can probably relax this for immediates.
+ bool EquallyZero = IncomingInfo.hasEquallyZeroAVL(PrevInfo, *MRI) &&
+ IncomingInfo.hasSameVLMAX(PrevInfo);
+ if (Demanded.VLAny || (Demanded.VLZeroness && !EquallyZero))
Info.setAVL(IncomingInfo);
Info.setVTYPE(
@@ -1084,39 +1105,14 @@ void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info,
IncomingInfo.getTailAgnostic(),
(Demanded.MaskPolicy ? IncomingInfo : Info).getMaskAgnostic() ||
IncomingInfo.getMaskAgnostic());
-}
-static VSETVLIInfo adjustIncoming(VSETVLIInfo PrevInfo, VSETVLIInfo NewInfo,
- DemandedFields &Demanded,
- const MachineRegisterInfo *MRI) {
- VSETVLIInfo Info = NewInfo;
-
- // If we don't use LMUL or the SEW/LMUL ratio, then adjust LMUL so that we
- // maintain the SEW/LMUL ratio. This allows us to eliminate VL toggles in more
- // places.
- if (!Demanded.LMUL && !Demanded.SEWLMULRatio && PrevInfo.isValid() &&
- !PrevInfo.isUnknown()) {
- if (auto NewVLMul = RISCVVType::getSameRatioLMUL(
- PrevInfo.getSEW(), PrevInfo.getVLMUL(), Info.getSEW()))
- Info.setVLMul(*NewVLMul);
- Demanded.LMUL = true;
+ // If we only knew the sew/lmul ratio previously, replace the VTYPE but keep
+ // the AVL.
+ if (Info.hasSEWLMULRatioOnly()) {
+ VSETVLIInfo RatiolessInfo = IncomingInfo;
+ RatiolessInfo.setAVL(Info);
+ Info = RatiolessInfo;
}
-
- // If we only demand VL zeroness (i.e. vmv.s.x and vmv.x.s), then there are
- // only two behaviors, VL = 0 and VL > 0. We can discard the user requested
- // AVL and just use the last one if we can prove it equally zero. This
- // removes a vsetvli entirely if the types match or allows use of cheaper avl
- // preserving variant if VLMAX doesn't change. If VLMAX might change, we
- // couldn't use the 'vsetvli x0, x0, vtype" variant, so we avoid the transform
- // to prevent extending live range of an avl register operand.
- // TODO: We can probably relax this for immediates.
- if (Demanded.VLZeroness && !Demanded.VLAny && PrevInfo.isValid() &&
- PrevInfo.hasEquallyZeroAVL(Info, *MRI) && Info.hasSameVLMAX(PrevInfo)) {
- Info.setAVL(PrevInfo);
- Demanded.demandVL();
- }
-
- return Info;
}
// Given a state with which we evaluated MI (see transferBefore above for why
@@ -1299,9 +1295,20 @@ void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) {
if (RISCVII::hasVLOp(TSFlags)) {
MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
if (VLOp.isReg()) {
+ Register Reg = VLOp.getReg();
+ MachineInstr *VLOpDef = MRI->getVRegDef(Reg);
+
// Erase the AVL operand from the instruction.
VLOp.setReg(RISCV::NoRegister);
VLOp.setIsKill(false);
+
+ // If the AVL was an immediate > 31, then it would have been emitted
+ // as an ADDI. However, the ADDI might not have been used in the
+ // vsetvli, or a vsetvli might not have been emitted, so it may be
+ // dead now.
+ if (VLOpDef && TII->isAddImmediate(*VLOpDef, Reg) &&
+ MRI->use_nodbg_empty(Reg))
+ VLOpDef->eraseFromParent();
}
MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false,
/*isImp*/ true));
@@ -1452,9 +1459,16 @@ static void doUnion(DemandedFields &A, DemandedFields B) {
A.MaskPolicy |= B.MaskPolicy;
}
-static bool isNonZeroAVL(const MachineOperand &MO) {
- if (MO.isReg())
- return RISCV::X0 == MO.getReg();
+static bool isNonZeroAVL(const MachineOperand &MO,
+ const MachineRegisterInfo &MRI) {
+ if (MO.isReg()) {
+ if (MO.getReg() == RISCV::X0)
+ return true;
+ if (MachineInstr *MI = MRI.getVRegDef(MO.getReg());
+ MI && isNonZeroLoadImmediate(*MI))
+ return true;
+ return false;
+ }
assert(MO.isImm());
return 0 != MO.getImm();
}
@@ -1463,7 +1477,8 @@ static bool isNonZeroAVL(const MachineOperand &MO) {
// fields which would be observed.
static bool canMutatePriorConfig(const MachineInstr &PrevMI,
const MachineInstr &MI,
- const DemandedFields &Used) {
+ const DemandedFields &Used,
+ const MachineRegisterInfo &MRI) {
// If the VL values aren't equal, return false if either a) the former is
// demanded, or b) we can't rewrite the former to be the later for
// implementation reasons.
@@ -1476,8 +1491,8 @@ static bool canMutatePriorConfig(const MachineInstr &PrevMI,
if (Used.VLZeroness) {
if (isVLPreservingConfig(PrevMI))
return false;
- if (!isNonZeroAVL(MI.getOperand(1)) ||
- !isNonZeroAVL(PrevMI.getOperand(1)))
+ if (!isNonZeroAVL(MI.getOperand(1), MRI) ||
+ !isNonZeroAVL(PrevMI.getOperand(1), MRI))
return false;
}
@@ -1521,14 +1536,23 @@ void RISCVInsertVSETVLI::doLocalPostpass(MachineBasicBlock &MBB) {
ToDelete.push_back(&MI);
// Leave NextMI unchanged
continue;
- } else if (canMutatePriorConfig(MI, *NextMI, Used)) {
+ } else if (canMutatePriorConfig(MI, *NextMI, Used, *MRI)) {
if (!isVLPreservingConfig(*NextMI)) {
MI.getOperand(0).setReg(NextMI->getOperand(0).getReg());
MI.getOperand(0).setIsDead(false);
+ Register OldVLReg;
+ if (MI.getOperand(1).isReg())
+ OldVLReg = MI.getOperand(1).getReg();
if (NextMI->getOperand(1).isImm())
MI.getOperand(1).ChangeToImmediate(NextMI->getOperand(1).getImm());
else
MI.getOperand(1).ChangeToRegister(NextMI->getOperand(1).getReg(), false);
+ if (OldVLReg) {
+ MachineInstr *VLOpDef = MRI->getUniqueVRegDef(OldVLReg);
+ if (VLOpDef && TII->isAddImmediate(*VLOpDef, OldVLReg) &&
+ MRI->use_nodbg_empty(OldVLReg))
+ VLOpDef->eraseFromParent();
+ }
MI.setDesc(NextMI->getDesc());
}
MI.getOperand(2).setImm(NextMI->getOperand(2).getImm());
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
index 6622e811bbb8..924e91e15c34 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
@@ -33,7 +33,7 @@ let DecoderNamespace = "XCVbitmanip" in {
class CVBitManipR<bits<7> funct7, string opcodestr>
: RVInstR<funct7, 0b011, OPC_CUSTOM_1, (outs GPR:$rd),
- (ins GPR:$rs1, GPR:$rs2), opcodestr, "$rd, $rs1"> {
+ (ins GPR:$rs1), opcodestr, "$rd, $rs1"> {
let rs2 = 0b00000;
}
}
@@ -658,3 +658,49 @@ let Predicates = [HasVendorXCVelw, IsRV32], hasSideEffects = 0,
// Event load
def CV_ELW : CVLoad_ri<0b011, "cv.elw">;
}
+
+def cv_tuimm2 : TImmLeaf<XLenVT, [{return isUInt<2>(Imm);}]>;
+def cv_tuimm5 : TImmLeaf<XLenVT, [{return isUInt<5>(Imm);}]>;
+def cv_uimm10 : ImmLeaf<XLenVT, [{return isUInt<10>(Imm);}]>;
+
+def CV_LO5: SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(N->getZExtValue() & 0x1f, SDLoc(N),
+ N->getValueType(0));
+}]>;
+
+def CV_HI5: SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(N->getZExtValue() >> 5, SDLoc(N),
+ N->getValueType(0));
+}]>;
+
+multiclass PatCoreVBitManip<Intrinsic intr> {
+ def : PatGprGpr<intr, !cast<RVInst>("CV_" # NAME # "R")>;
+ def : Pat<(intr GPR:$rs1, cv_uimm10:$imm),
+ (!cast<RVInst>("CV_" # NAME)
+ GPR:$rs1, (CV_HI5 cv_uimm10:$imm), (CV_LO5 cv_uimm10:$imm))>;
+}
+
+let Predicates = [HasVendorXCVbitmanip, IsRV32] in {
+ defm EXTRACT : PatCoreVBitManip<int_riscv_cv_bitmanip_extract>;
+ defm EXTRACTU : PatCoreVBitManip<int_riscv_cv_bitmanip_extractu>;
+ defm BCLR : PatCoreVBitManip<int_riscv_cv_bitmanip_bclr>;
+ defm BSET : PatCoreVBitManip<int_riscv_cv_bitmanip_bset>;
+
+ def : Pat<(int_riscv_cv_bitmanip_insert GPR:$rs1, GPR:$rs2, GPR:$rd),
+ (CV_INSERTR GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+ def : Pat<(int_riscv_cv_bitmanip_insert GPR:$rs1, cv_uimm10:$imm, GPR:$rd),
+ (CV_INSERT GPR:$rd, GPR:$rs1, (CV_HI5 cv_uimm10:$imm),
+ (CV_LO5 cv_uimm10:$imm))>;
+
+ def : PatGpr<cttz, CV_FF1>;
+ def : PatGpr<ctlz, CV_FL1>;
+ def : PatGpr<int_riscv_cv_bitmanip_clb, CV_CLB>;
+ def : PatGpr<ctpop, CV_CNT>;
+
+ def : PatGprGpr<rotr, CV_ROR>;
+
+ def : Pat<(int_riscv_cv_bitmanip_bitrev GPR:$rs1, cv_tuimm5:$pts,
+ cv_tuimm2:$radix),
+ (CV_BITREV GPR:$rs1, cv_tuimm2:$radix, cv_tuimm5:$pts)>;
+ def : Pat<(bitreverse (XLenVT GPR:$rs)), (CV_BITREV GPR:$rs, 0, 0)>;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVMacroFusion.cpp b/llvm/lib/Target/RISCV/RISCVMacroFusion.cpp
index 02a8d5c18fe1..02ea5270823d 100644
--- a/llvm/lib/Target/RISCV/RISCVMacroFusion.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMacroFusion.cpp
@@ -18,6 +18,101 @@
using namespace llvm;
+static bool checkRegisters(Register FirstDest, const MachineInstr &SecondMI) {
+ if (!SecondMI.getOperand(1).isReg())
+ return false;
+
+ if (SecondMI.getOperand(1).getReg() != FirstDest)
+ return false;
+
+ // If the input is virtual make sure this is the only user.
+ if (FirstDest.isVirtual()) {
+ auto &MRI = SecondMI.getMF()->getRegInfo();
+ return MRI.hasOneNonDBGUse(FirstDest);
+ }
+
+ return SecondMI.getOperand(0).getReg() == FirstDest;
+}
+
+// Fuse load with add:
+// add rd, rs1, rs2
+// ld rd, 0(rd)
+static bool isLDADD(const MachineInstr *FirstMI, const MachineInstr &SecondMI) {
+ if (SecondMI.getOpcode() != RISCV::LD)
+ return false;
+
+ if (!SecondMI.getOperand(2).isImm())
+ return false;
+
+ if (SecondMI.getOperand(2).getImm() != 0)
+ return false;
+
+ // Given SecondMI, when FirstMI is unspecified, we must return
+ // if SecondMI may be part of a fused pair at all.
+ if (!FirstMI)
+ return true;
+
+ if (FirstMI->getOpcode() != RISCV::ADD)
+ return true;
+
+ return checkRegisters(FirstMI->getOperand(0).getReg(), SecondMI);
+}
+
+// Fuse these patterns:
+//
+// slli rd, rs1, 32
+// srli rd, rd, x
+// where 0 <= x <= 32
+//
+// and
+//
+// slli rd, rs1, 48
+// srli rd, rd, x
+static bool isShiftedZExt(const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI) {
+ if (SecondMI.getOpcode() != RISCV::SRLI)
+ return false;
+
+ if (!SecondMI.getOperand(2).isImm())
+ return false;
+
+ unsigned SRLIImm = SecondMI.getOperand(2).getImm();
+ bool IsShiftBy48 = SRLIImm == 48;
+ if (SRLIImm > 32 && !IsShiftBy48)
+ return false;
+
+ // Given SecondMI, when FirstMI is unspecified, we must return
+ // if SecondMI may be part of a fused pair at all.
+ if (!FirstMI)
+ return true;
+
+ if (FirstMI->getOpcode() != RISCV::SLLI)
+ return false;
+
+ unsigned SLLIImm = FirstMI->getOperand(2).getImm();
+ if (IsShiftBy48 ? (SLLIImm != 48) : (SLLIImm != 32))
+ return false;
+
+ return checkRegisters(FirstMI->getOperand(0).getReg(), SecondMI);
+}
+
+// Fuse AUIPC followed by ADDI
+// auipc rd, imm20
+// addi rd, rd, imm12
+static bool isAUIPCADDI(const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI) {
+ if (SecondMI.getOpcode() != RISCV::ADDI)
+ return false;
+ // Assume the 1st instr to be a wildcard if it is unspecified.
+ if (!FirstMI)
+ return true;
+
+ if (FirstMI->getOpcode() != RISCV::AUIPC)
+ return false;
+
+ return checkRegisters(FirstMI->getOperand(0).getReg(), SecondMI);
+}
+
// Fuse LUI followed by ADDI or ADDIW.
// rd = imm[31:0] which decomposes to
// lui rd, imm[31:12]
@@ -27,7 +122,6 @@ static bool isLUIADDI(const MachineInstr *FirstMI,
if (SecondMI.getOpcode() != RISCV::ADDI &&
SecondMI.getOpcode() != RISCV::ADDIW)
return false;
-
// Assume the 1st instr to be a wildcard if it is unspecified.
if (!FirstMI)
return true;
@@ -35,21 +129,7 @@ static bool isLUIADDI(const MachineInstr *FirstMI,
if (FirstMI->getOpcode() != RISCV::LUI)
return false;
- Register FirstDest = FirstMI->getOperand(0).getReg();
-
- // Destination of LUI should be the ADDI(W) source register.
- if (SecondMI.getOperand(1).getReg() != FirstDest)
- return false;
-
- // If the input is virtual make sure this is the only user.
- if (FirstDest.isVirtual()) {
- auto &MRI = SecondMI.getMF()->getRegInfo();
- return MRI.hasOneNonDBGUse(FirstDest);
- }
-
- // If the FirstMI destination is non-virtual, it should match the SecondMI
- // destination.
- return SecondMI.getOperand(0).getReg() == FirstDest;
+ return checkRegisters(FirstMI->getOperand(0).getReg(), SecondMI);
}
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
@@ -61,6 +141,15 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
if (ST.hasLUIADDIFusion() && isLUIADDI(FirstMI, SecondMI))
return true;
+ if (ST.hasAUIPCADDIFusion() && isAUIPCADDI(FirstMI, SecondMI))
+ return true;
+
+ if (ST.hasShiftedZExtFusion() && isShiftedZExt(FirstMI, SecondMI))
+ return true;
+
+ if (ST.hasLDADDFusion() && isLDADD(FirstMI, SecondMI))
+ return true;
+
return false;
}
diff --git a/llvm/lib/Target/RISCV/RISCVProcessors.td b/llvm/lib/Target/RISCV/RISCVProcessors.td
index 90ba99d3f845..58989fd716fa 100644
--- a/llvm/lib/Target/RISCV/RISCVProcessors.td
+++ b/llvm/lib/Target/RISCV/RISCVProcessors.td
@@ -254,7 +254,7 @@ def VENTANA_VEYRON_V1 : RISCVProcessorModel<"veyron-v1",
FeatureStdExtZicbop,
FeatureStdExtZicboz,
FeatureVendorXVentanaCondOps],
- [TuneVentanaVeyron]>;
+ [TuneVeyronFusions]>;
def XIANGSHAN_NANHU : RISCVProcessorModel<"xiangshan-nanhu",
NoSchedModel,
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index 52f00f1f0990..23d56cfa6e4e 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -25,6 +25,7 @@
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Target/TargetMachine.h"
+#include <bitset>
#define GET_SUBTARGETINFO_HEADER
#include "RISCVGenSubtargetInfo.inc"
@@ -192,7 +193,10 @@ public:
return UserReservedRegister[i];
}
- bool hasMacroFusion() const { return hasLUIADDIFusion(); }
+ bool hasMacroFusion() const {
+ return hasLUIADDIFusion() || hasAUIPCADDIFusion() ||
+ hasShiftedZExtFusion() || hasLDADDFusion();
+ }
// Vector codegen related methods.
bool hasVInstructions() const { return HasStdExtZve32x; }
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index 3a2f2f39cd1c..4614446b2150 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -172,7 +172,9 @@ RISCVTTIImpl::getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
TargetTransformInfo::PopcntSupportKind
RISCVTTIImpl::getPopcntSupport(unsigned TyWidth) {
assert(isPowerOf2_32(TyWidth) && "Ty width must be power of 2");
- return ST->hasStdExtZbb() ? TTI::PSK_FastHardware : TTI::PSK_Software;
+ return ST->hasStdExtZbb() || ST->hasVendorXCVbitmanip()
+ ? TTI::PSK_FastHardware
+ : TTI::PSK_Software;
}
bool RISCVTTIImpl::shouldExpandReduction(const IntrinsicInst *II) const {
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
index 1af7b7a5d784..b69031adb167 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
@@ -177,7 +177,7 @@ std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue) {
bool getSpirvBuiltInIdByName(llvm::StringRef Name,
SPIRV::BuiltIn::BuiltIn &BI) {
const std::string Prefix = "__spirv_BuiltIn";
- if (!Name.startswith(Prefix))
+ if (!Name.starts_with(Prefix))
return false;
const SPIRV::SymbolicOperand *Lookup =
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index ae9e801f8f50..5ac45079bd00 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -872,8 +872,8 @@ static bool generateGroupInst(const SPIRV::IncomingCall *Call,
std::tie(GroupResultRegister, GroupResultType) =
buildBoolRegister(MIRBuilder, Call->ReturnType, GR);
- auto Scope = Builtin->Name.startswith("sub_group") ? SPIRV::Scope::Subgroup
- : SPIRV::Scope::Workgroup;
+ auto Scope = Builtin->Name.starts_with("sub_group") ? SPIRV::Scope::Subgroup
+ : SPIRV::Scope::Workgroup;
Register ScopeRegister = buildConstantIntReg(Scope, MIRBuilder, GR);
// Build work/sub group instruction.
@@ -1999,13 +1999,13 @@ struct OpenCLType {
//===----------------------------------------------------------------------===//
static Type *parseTypeString(const StringRef Name, LLVMContext &Context) {
- if (Name.startswith("void"))
+ if (Name.starts_with("void"))
return Type::getVoidTy(Context);
- else if (Name.startswith("int") || Name.startswith("uint"))
+ else if (Name.starts_with("int") || Name.starts_with("uint"))
return Type::getInt32Ty(Context);
- else if (Name.startswith("float"))
+ else if (Name.starts_with("float"))
return Type::getFloatTy(Context);
- else if (Name.startswith("half"))
+ else if (Name.starts_with("half"))
return Type::getHalfTy(Context);
llvm_unreachable("Unable to recognize type!");
}
@@ -2081,7 +2081,7 @@ parseBuiltinTypeNameToTargetExtType(std::string TypeName,
// Pointers-to-opaque-structs representing OpenCL types are first translated
// to equivalent SPIR-V types. OpenCL builtin type names should have the
// following format: e.g. %opencl.event_t
- if (NameWithParameters.startswith("opencl.")) {
+ if (NameWithParameters.starts_with("opencl.")) {
const SPIRV::OpenCLType *OCLTypeRecord =
SPIRV::lookupOpenCLType(NameWithParameters);
if (!OCLTypeRecord)
@@ -2093,7 +2093,7 @@ parseBuiltinTypeNameToTargetExtType(std::string TypeName,
// Names of the opaque structs representing a SPIR-V builtins without
// parameters should have the following format: e.g. %spirv.Event
- assert(NameWithParameters.startswith("spirv.") &&
+ assert(NameWithParameters.starts_with("spirv.") &&
"Unknown builtin opaque type!");
// Parameterized SPIR-V builtins names follow this format:
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index d450613196f3..b8a6784ff3c6 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -962,35 +962,35 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVTypeByName(
if (TypeStr.starts_with("atomic_"))
TypeStr = TypeStr.substr(strlen("atomic_"));
- if (TypeStr.startswith("void")) {
+ if (TypeStr.starts_with("void")) {
Ty = Type::getVoidTy(Ctx);
TypeStr = TypeStr.substr(strlen("void"));
- } else if (TypeStr.startswith("bool")) {
+ } else if (TypeStr.starts_with("bool")) {
Ty = Type::getIntNTy(Ctx, 1);
TypeStr = TypeStr.substr(strlen("bool"));
- } else if (TypeStr.startswith("char") || TypeStr.startswith("uchar")) {
+ } else if (TypeStr.starts_with("char") || TypeStr.starts_with("uchar")) {
Ty = Type::getInt8Ty(Ctx);
- TypeStr = TypeStr.startswith("char") ? TypeStr.substr(strlen("char"))
- : TypeStr.substr(strlen("uchar"));
- } else if (TypeStr.startswith("short") || TypeStr.startswith("ushort")) {
+ TypeStr = TypeStr.starts_with("char") ? TypeStr.substr(strlen("char"))
+ : TypeStr.substr(strlen("uchar"));
+ } else if (TypeStr.starts_with("short") || TypeStr.starts_with("ushort")) {
Ty = Type::getInt16Ty(Ctx);
- TypeStr = TypeStr.startswith("short") ? TypeStr.substr(strlen("short"))
- : TypeStr.substr(strlen("ushort"));
- } else if (TypeStr.startswith("int") || TypeStr.startswith("uint")) {
+ TypeStr = TypeStr.starts_with("short") ? TypeStr.substr(strlen("short"))
+ : TypeStr.substr(strlen("ushort"));
+ } else if (TypeStr.starts_with("int") || TypeStr.starts_with("uint")) {
Ty = Type::getInt32Ty(Ctx);
- TypeStr = TypeStr.startswith("int") ? TypeStr.substr(strlen("int"))
- : TypeStr.substr(strlen("uint"));
+ TypeStr = TypeStr.starts_with("int") ? TypeStr.substr(strlen("int"))
+ : TypeStr.substr(strlen("uint"));
} else if (TypeStr.starts_with("long") || TypeStr.starts_with("ulong")) {
Ty = Type::getInt64Ty(Ctx);
- TypeStr = TypeStr.startswith("long") ? TypeStr.substr(strlen("long"))
- : TypeStr.substr(strlen("ulong"));
- } else if (TypeStr.startswith("half")) {
+ TypeStr = TypeStr.starts_with("long") ? TypeStr.substr(strlen("long"))
+ : TypeStr.substr(strlen("ulong"));
+ } else if (TypeStr.starts_with("half")) {
Ty = Type::getHalfTy(Ctx);
TypeStr = TypeStr.substr(strlen("half"));
- } else if (TypeStr.startswith("float")) {
+ } else if (TypeStr.starts_with("float")) {
Ty = Type::getFloatTy(Ctx);
TypeStr = TypeStr.substr(strlen("float"));
- } else if (TypeStr.startswith("double")) {
+ } else if (TypeStr.starts_with("double")) {
Ty = Type::getDoubleTy(Ctx);
TypeStr = TypeStr.substr(strlen("double"));
} else
@@ -1007,7 +1007,7 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVTypeByName(
// Handle "typeN*" or "type vector[N]*".
bool IsPtrToVec = TypeStr.consume_back("*");
- if (TypeStr.startswith(" vector[")) {
+ if (TypeStr.starts_with(" vector[")) {
TypeStr = TypeStr.substr(strlen(" vector["));
TypeStr = TypeStr.substr(0, TypeStr.find(']'));
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp b/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
index 3a51e29dcf16..322e051a87db 100644
--- a/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
@@ -177,8 +177,8 @@ void SPIRVRegularizer::visitCallInst(CallInst &CI) {
StringRef DemangledName(NameStr);
// TODO: add support for other builtins.
- if (DemangledName.startswith("fmin") || DemangledName.startswith("fmax") ||
- DemangledName.startswith("min") || DemangledName.startswith("max"))
+ if (DemangledName.starts_with("fmin") || DemangledName.starts_with("fmax") ||
+ DemangledName.starts_with("min") || DemangledName.starts_with("max"))
visitCallScalToVec(&CI, MangledName, DemangledName);
free(NameStr);
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 0bd51436082d..1c0e8d84e2fd 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -279,7 +279,7 @@ static bool isKernelQueryBI(const StringRef MangledName) {
}
static bool isNonMangledOCLBuiltin(StringRef Name) {
- if (!Name.startswith("__"))
+ if (!Name.starts_with("__"))
return false;
return isEnqueueKernelBI(Name) || isKernelQueryBI(Name) ||
@@ -289,8 +289,8 @@ static bool isNonMangledOCLBuiltin(StringRef Name) {
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) {
bool IsNonMangledOCL = isNonMangledOCLBuiltin(Name);
- bool IsNonMangledSPIRV = Name.startswith("__spirv_");
- bool IsMangled = Name.startswith("_Z");
+ bool IsNonMangledSPIRV = Name.starts_with("__spirv_");
+ bool IsMangled = Name.starts_with("_Z");
if (!IsNonMangledOCL && !IsNonMangledSPIRV && !IsMangled)
return std::string();
@@ -311,7 +311,7 @@ std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) {
// Similar to ::std:: in C++.
size_t Start, Len = 0;
size_t DemangledNameLenStart = 2;
- if (Name.startswith("_ZN")) {
+ if (Name.starts_with("_ZN")) {
// Skip CV and ref qualifiers.
size_t NameSpaceStart = Name.find_first_not_of("rVKRO", 3);
// All built-ins are in the ::cl:: namespace.
diff --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
index c16004e2fea2..a58e8e0dfedf 100644
--- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
+++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
@@ -1203,7 +1203,7 @@ ParseStatus SystemZAsmParser::parseDirective(AsmToken DirectiveID) {
return ParseDirectiveInsn(DirectiveID.getLoc());
if (IDVal == ".machine")
return ParseDirectiveMachine(DirectiveID.getLoc());
- if (IDVal.startswith(".gnu_attribute"))
+ if (IDVal.starts_with(".gnu_attribute"))
return ParseGNUAttribute(DirectiveID.getLoc());
return ParseStatus::NoMatch;
diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.td b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
index 29b4a26736b2..136d3d254721 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.td
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
@@ -102,9 +102,10 @@ def CC_SystemZ_ELF : CallingConv<[
// A SwiftError is passed in callee-saved R9.
CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R9D]>>>,
- // Force long double values to the stack and pass i64 pointers to them.
- CCIfType<[f128], CCPassIndirect<i64>>,
- // Same for i128 values. These are already split into two i64 here,
+ // Force i128 (if the type is legal) and long double values to the stack
+ // and pass i64 pointers to them.
+ CCIfType<[i128, f128], CCPassIndirect<i64>>,
+ // If i128 is not legal, such values are already split into two i64 here,
// so we have to use a custom handler.
CCIfType<[i64], CCCustom<"CC_SystemZ_I128Indirect">>,
@@ -240,9 +241,10 @@ def CC_SystemZ_XPLINK64 : CallingConv<[
// A SwiftError is passed in R0.
CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R0D]>>>,
- // First i128 values. These are already split into two i64 here,
- // so we have to use a custom handler and assign into registers, if possible
- // We need to deal with this first
+ // Force i128 values to the stack and pass i64 pointers to them.
+ CCIfType<[i128], CCPassIndirect<i64>>,
+ // If i128 is not legal, such values are already split into two i64 here,
+ // so we have to use a custom handler.
CCIfType<[i64], CCCustom<"CC_SystemZ_I128Indirect">>,
// The first 3 integer arguments are passed in registers R1D-R3D.
// The rest will be passed in the user area. The address offset of the user
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 4cc69530db01..e5e1e91916f3 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -307,6 +307,8 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
void loadVectorConstant(const SystemZVectorConstantInfo &VCI,
SDNode *Node);
+ SDNode *loadPoolVectorConstant(APInt Val, EVT VT, SDLoc DL);
+
// Try to use gather instruction Opcode to implement vector insertion N.
bool tryGather(SDNode *N, unsigned Opcode);
@@ -784,6 +786,8 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) const {
case ISD::TRUNCATE: {
if (RxSBG.Opcode == SystemZ::RNSBG)
return false;
+ if (N.getOperand(0).getValueSizeInBits() > 64)
+ return false;
uint64_t BitSize = N.getValueSizeInBits();
uint64_t Mask = allOnes(BitSize);
if (!refineRxSBGMask(RxSBG, Mask))
@@ -1183,6 +1187,35 @@ void SystemZDAGToDAGISel::loadVectorConstant(
SelectCode(Op.getNode());
}
+SDNode *SystemZDAGToDAGISel::loadPoolVectorConstant(APInt Val, EVT VT, SDLoc DL) {
+ SDNode *ResNode;
+ assert (VT.getSizeInBits() == 128);
+
+ SDValue CP = CurDAG->getTargetConstantPool(
+ ConstantInt::get(Type::getInt128Ty(*CurDAG->getContext()), Val),
+ TLI->getPointerTy(CurDAG->getDataLayout()));
+
+ EVT PtrVT = CP.getValueType();
+ SDValue Ops[] = {
+ SDValue(CurDAG->getMachineNode(SystemZ::LARL, DL, PtrVT, CP), 0),
+ CurDAG->getTargetConstant(0, DL, PtrVT),
+ CurDAG->getRegister(0, PtrVT),
+ CurDAG->getEntryNode()
+ };
+ ResNode = CurDAG->getMachineNode(SystemZ::VL, DL, VT, MVT::Other, Ops);
+
+ // Annotate ResNode with memory operand information so that MachineInstr
+ // queries work properly. This e.g. gives the register allocation the
+ // required information for rematerialization.
+ MachineFunction& MF = CurDAG->getMachineFunction();
+ MachineMemOperand *MemOp =
+ MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
+ MachineMemOperand::MOLoad, 16, Align(8));
+
+ CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {MemOp});
+ return ResNode;
+}
+
bool SystemZDAGToDAGISel::tryGather(SDNode *N, unsigned Opcode) {
SDValue ElemV = N->getOperand(2);
auto *ElemN = dyn_cast<ConstantSDNode>(ElemV);
@@ -1558,6 +1591,9 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
break;
}
}
+ // Don't split an XOR with -1 as LCGR/AGHI is more compact.
+ if (Opcode == ISD::XOR && Op1->isAllOnes())
+ break;
if (!SystemZ::isImmLF(Val) && !SystemZ::isImmHF(Val)) {
splitLargeImmediate(Opcode, Node, Node->getOperand(0),
Val - uint32_t(Val), uint32_t(Val));
@@ -1579,6 +1615,27 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
return;
break;
+ case ISD::BSWAP:
+ if (Node->getValueType(0) == MVT::i128) {
+ SDLoc DL(Node);
+ SDValue Src = Node->getOperand(0);
+ Src = CurDAG->getNode(ISD::BITCAST, DL, MVT::v16i8, Src);
+
+ uint64_t Bytes[2] = { 0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL };
+ SDNode *Mask = loadPoolVectorConstant(APInt(128, Bytes), MVT::v16i8, DL);
+ SDValue Ops[] = { Src, Src, SDValue(Mask, 0) };
+ SDValue Res = SDValue(CurDAG->getMachineNode(SystemZ::VPERM, DL,
+ MVT::v16i8, Ops), 0);
+
+ Res = CurDAG->getNode(ISD::BITCAST, DL, MVT::i128, Res);
+ SDNode *ResNode = Res.getNode();
+ ReplaceNode(Node, ResNode);
+ SelectCode(Src.getNode());
+ SelectCode(ResNode);
+ return;
+ }
+ break;
+
case ISD::Constant:
// If this is a 64-bit constant that is out of the range of LLILF,
// LLIHF and LGFI, split it into two 32-bit pieces.
@@ -1590,6 +1647,18 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
return;
}
}
+ if (Node->getValueType(0) == MVT::i128) {
+ const APInt &Val = cast<ConstantSDNode>(Node)->getAPIntValue();
+ SystemZVectorConstantInfo VCI(Val);
+ if (VCI.isVectorConstantLegal(*Subtarget)) {
+ loadVectorConstant(VCI, Node);
+ return;
+ }
+ // If we can't materialize the constant we need to use a literal pool.
+ SDNode *ResNode = loadPoolVectorConstant(Val, MVT::i128, SDLoc(Node));
+ ReplaceNode(Node, ResNode);
+ return;
+ }
break;
case SystemZISD::SELECT_CCMASK: {
@@ -1600,6 +1669,7 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
if ((Op1.getOpcode() == ISD::LOAD && Op0.getOpcode() != ISD::LOAD) ||
(Subtarget->hasLoadStoreOnCond2() &&
Node->getValueType(0).isInteger() &&
+ Node->getValueType(0).getSizeInBits() <= 64 &&
Op1.getOpcode() == ISD::Constant &&
isInt<16>(cast<ConstantSDNode>(Op1)->getSExtValue()) &&
!(Op0.getOpcode() == ISD::Constant &&
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index f79787d4baa4..a1803cf9a042 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -112,6 +112,9 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
addRegisterClass(MVT::v4f32, &SystemZ::VR128BitRegClass);
addRegisterClass(MVT::v2f64, &SystemZ::VR128BitRegClass);
}
+
+ if (Subtarget.hasVector())
+ addRegisterClass(MVT::i128, &SystemZ::VR128BitRegClass);
}
// Compute derived properties from the register classes
@@ -163,12 +166,12 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
// Expand BRCOND into a BR_CC (see above).
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
- // Handle integer types.
+ // Handle integer types except i128.
for (unsigned I = MVT::FIRST_INTEGER_VALUETYPE;
I <= MVT::LAST_INTEGER_VALUETYPE;
++I) {
MVT VT = MVT::SimpleValueType(I);
- if (isTypeLegal(VT)) {
+ if (isTypeLegal(VT) && VT != MVT::i128) {
setOperationAction(ISD::ABS, VT, Legal);
// Expand individual DIV and REMs into DIVREMs.
@@ -236,6 +239,45 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
}
}
+ // Handle i128 if legal.
+ if (isTypeLegal(MVT::i128)) {
+ // No special instructions for these.
+ setOperationAction(ISD::SDIVREM, MVT::i128, Expand);
+ setOperationAction(ISD::UDIVREM, MVT::i128, Expand);
+ setOperationAction(ISD::SMUL_LOHI, MVT::i128, Expand);
+ setOperationAction(ISD::UMUL_LOHI, MVT::i128, Expand);
+ setOperationAction(ISD::ROTR, MVT::i128, Expand);
+ setOperationAction(ISD::ROTL, MVT::i128, Expand);
+ setOperationAction(ISD::MUL, MVT::i128, Expand);
+ setOperationAction(ISD::MULHS, MVT::i128, Expand);
+ setOperationAction(ISD::MULHU, MVT::i128, Expand);
+ setOperationAction(ISD::SDIV, MVT::i128, Expand);
+ setOperationAction(ISD::UDIV, MVT::i128, Expand);
+ setOperationAction(ISD::SREM, MVT::i128, Expand);
+ setOperationAction(ISD::UREM, MVT::i128, Expand);
+ setOperationAction(ISD::CTLZ, MVT::i128, Expand);
+ setOperationAction(ISD::CTTZ, MVT::i128, Expand);
+
+ // Support addition/subtraction with carry.
+ setOperationAction(ISD::UADDO, MVT::i128, Custom);
+ setOperationAction(ISD::USUBO, MVT::i128, Custom);
+ setOperationAction(ISD::UADDO_CARRY, MVT::i128, Custom);
+ setOperationAction(ISD::USUBO_CARRY, MVT::i128, Custom);
+
+ // Use VPOPCT and add up partial results.
+ setOperationAction(ISD::CTPOP, MVT::i128, Custom);
+
+ // We have to use libcalls for these.
+ setOperationAction(ISD::FP_TO_UINT, MVT::i128, LibCall);
+ setOperationAction(ISD::FP_TO_SINT, MVT::i128, LibCall);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i128, LibCall);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i128, LibCall);
+ setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i128, LibCall);
+ setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i128, LibCall);
+ setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i128, LibCall);
+ setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i128, LibCall);
+ }
+
// Type legalization will convert 8- and 16-bit atomic operations into
// forms that operate on i32s (but still keeping the original memory VT).
// Lower them into full i32 operations.
@@ -251,7 +293,7 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Custom);
setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Custom);
- // Even though i128 is not a legal type, we still need to custom lower
+ // Whether or not i128 is not a legal type, we need to custom lower
// the atomic operations in order to exploit SystemZ instructions.
setOperationAction(ISD::ATOMIC_LOAD, MVT::i128, Custom);
setOperationAction(ISD::ATOMIC_STORE, MVT::i128, Custom);
@@ -299,7 +341,8 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setLibcallName(RTLIB::SRA_I128, nullptr);
// Handle bitcast from fp128 to i128.
- setOperationAction(ISD::BITCAST, MVT::i128, Custom);
+ if (!isTypeLegal(MVT::i128))
+ setOperationAction(ISD::BITCAST, MVT::i128, Custom);
// We have native instructions for i8, i16 and i32 extensions, but not i1.
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
@@ -1386,24 +1429,6 @@ bool SystemZTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
return CI->isTailCall();
}
-// We do not yet support 128-bit single-element vector types. If the user
-// attempts to use such types as function argument or return type, prefer
-// to error out instead of emitting code violating the ABI.
-static void VerifyVectorType(MVT VT, EVT ArgVT) {
- if (ArgVT.isVector() && !VT.isVector())
- report_fatal_error("Unsupported vector argument or return type");
-}
-
-static void VerifyVectorTypes(const SmallVectorImpl<ISD::InputArg> &Ins) {
- for (unsigned i = 0; i < Ins.size(); ++i)
- VerifyVectorType(Ins[i].VT, Ins[i].ArgVT);
-}
-
-static void VerifyVectorTypes(const SmallVectorImpl<ISD::OutputArg> &Outs) {
- for (unsigned i = 0; i < Outs.size(); ++i)
- VerifyVectorType(Outs[i].VT, Outs[i].ArgVT);
-}
-
// Value is a value that has been passed to us in the location described by VA
// (and so has type VA.getLocVT()). Convert Value to VA.getValVT(), chaining
// any loads onto Chain.
@@ -1474,7 +1499,15 @@ static SDValue convertValVTToLocVT(SelectionDAG &DAG, const SDLoc &DL,
static SDValue lowerI128ToGR128(SelectionDAG &DAG, SDValue In) {
SDLoc DL(In);
SDValue Lo, Hi;
- std::tie(Lo, Hi) = DAG.SplitScalar(In, DL, MVT::i64, MVT::i64);
+ if (DAG.getTargetLoweringInfo().isTypeLegal(MVT::i128)) {
+ Lo = DAG.getNode(ISD::TRUNCATE, DL, MVT::i64, In);
+ Hi = DAG.getNode(ISD::TRUNCATE, DL, MVT::i64,
+ DAG.getNode(ISD::SRL, DL, MVT::i128, In,
+ DAG.getConstant(64, DL, MVT::i32)));
+ } else {
+ std::tie(Lo, Hi) = DAG.SplitScalar(In, DL, MVT::i64, MVT::i64);
+ }
+
SDNode *Pair = DAG.getMachineNode(SystemZ::PAIR128, DL,
MVT::Untyped, Hi, Lo);
return SDValue(Pair, 0);
@@ -1486,7 +1519,16 @@ static SDValue lowerGR128ToI128(SelectionDAG &DAG, SDValue In) {
DL, MVT::i64, In);
SDValue Lo = DAG.getTargetExtractSubreg(SystemZ::subreg_l64,
DL, MVT::i64, In);
- return DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i128, Lo, Hi);
+
+ if (DAG.getTargetLoweringInfo().isTypeLegal(MVT::i128)) {
+ Lo = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i128, Lo);
+ Hi = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i128, Hi);
+ Hi = DAG.getNode(ISD::SHL, DL, MVT::i128, Hi,
+ DAG.getConstant(64, DL, MVT::i32));
+ return DAG.getNode(ISD::OR, DL, MVT::i128, Lo, Hi);
+ } else {
+ return DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i128, Lo, Hi);
+ }
}
bool SystemZTargetLowering::splitValueIntoRegisterParts(
@@ -1526,10 +1568,6 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
auto *TFL = Subtarget.getFrameLowering<SystemZELFFrameLowering>();
EVT PtrVT = getPointerTy(DAG.getDataLayout());
- // Detect unsupported vector argument types.
- if (Subtarget.hasVector())
- VerifyVectorTypes(Ins);
-
// Assign locations to all of the incoming arguments.
SmallVector<CCValAssign, 16> ArgLocs;
SystemZCCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
@@ -1830,12 +1868,6 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
if (Subtarget.isTargetXPLINK64())
IsTailCall = false;
- // Detect unsupported vector argument and return types.
- if (Subtarget.hasVector()) {
- VerifyVectorTypes(Outs);
- VerifyVectorTypes(Ins);
- }
-
// Analyze the operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
SystemZCCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, Ctx);
@@ -2079,12 +2111,8 @@ CanLowerReturn(CallingConv::ID CallConv,
MachineFunction &MF, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
LLVMContext &Context) const {
- // Detect unsupported vector return types.
- if (Subtarget.hasVector())
- VerifyVectorTypes(Outs);
-
// Special case that we cannot easily detect in RetCC_SystemZ since
- // i128 is not a legal type.
+ // i128 may not be a legal type.
for (auto &Out : Outs)
if (Out.ArgVT == MVT::i128)
return false;
@@ -2102,10 +2130,6 @@ SystemZTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
const SDLoc &DL, SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
- // Detect unsupported vector return types.
- if (Subtarget.hasVector())
- VerifyVectorTypes(Outs);
-
// Assign locations to each returned value.
SmallVector<CCValAssign, 16> RetLocs;
CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());
@@ -2403,7 +2427,7 @@ static void adjustZeroCmp(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) {
return;
auto *ConstOp1 = dyn_cast<ConstantSDNode>(C.Op1.getNode());
- if (!ConstOp1)
+ if (!ConstOp1 || ConstOp1->getValueSizeInBits(0) > 64)
return;
int64_t Value = ConstOp1->getSExtValue();
@@ -2437,6 +2461,8 @@ static void adjustSubwordCmp(SelectionDAG &DAG, const SDLoc &DL,
// The load must be an extending one and the constant must be within the
// range of the unextended value.
auto *ConstOp1 = cast<ConstantSDNode>(C.Op1);
+ if (!ConstOp1 || ConstOp1->getValueSizeInBits(0) > 64)
+ return;
uint64_t Value = ConstOp1->getZExtValue();
uint64_t Mask = (1 << NumBits) - 1;
if (Load->getExtensionType() == ISD::SEXTLOAD) {
@@ -2515,7 +2541,9 @@ static bool isNaturalMemoryOperand(SDValue Op, unsigned ICmpType) {
// Return true if it is better to swap the operands of C.
static bool shouldSwapCmpOperands(const Comparison &C) {
- // Leave f128 comparisons alone, since they have no memory forms.
+ // Leave i128 and f128 comparisons alone, since they have no memory forms.
+ if (C.Op0.getValueType() == MVT::i128)
+ return false;
if (C.Op0.getValueType() == MVT::f128)
return false;
@@ -2652,6 +2680,7 @@ static void adjustICmpTruncate(SelectionDAG &DAG, const SDLoc &DL,
if (C.Op0.getOpcode() == ISD::TRUNCATE &&
C.Op0.getOperand(0).getOpcode() == ISD::LOAD &&
C.Op1.getOpcode() == ISD::Constant &&
+ cast<ConstantSDNode>(C.Op1)->getValueSizeInBits(0) <= 64 &&
cast<ConstantSDNode>(C.Op1)->getZExtValue() == 0) {
auto *L = cast<LoadSDNode>(C.Op0.getOperand(0));
if (L->getMemoryVT().getStoreSizeInBits().getFixedValue() <=
@@ -2780,6 +2809,27 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask,
// Update the arguments with the TM version if so.
static void adjustForTestUnderMask(SelectionDAG &DAG, const SDLoc &DL,
Comparison &C) {
+ // Use VECTOR TEST UNDER MASK for i128 operations.
+ if (C.Op0.getValueType() == MVT::i128) {
+ // We can use VTM for EQ/NE comparisons of x & y against 0.
+ if (C.Op0.getOpcode() == ISD::AND &&
+ (C.CCMask == SystemZ::CCMASK_CMP_EQ ||
+ C.CCMask == SystemZ::CCMASK_CMP_NE)) {
+ auto *Mask = dyn_cast<ConstantSDNode>(C.Op1);
+ if (Mask && Mask->getAPIntValue() == 0) {
+ C.Opcode = SystemZISD::VTM;
+ C.Op1 = DAG.getNode(ISD::BITCAST, DL, MVT::v16i8, C.Op0.getOperand(1));
+ C.Op0 = DAG.getNode(ISD::BITCAST, DL, MVT::v16i8, C.Op0.getOperand(0));
+ C.CCValid = SystemZ::CCMASK_VCMP;
+ if (C.CCMask == SystemZ::CCMASK_CMP_EQ)
+ C.CCMask = SystemZ::CCMASK_VCMP_ALL;
+ else
+ C.CCMask = SystemZ::CCMASK_VCMP_ALL ^ C.CCValid;
+ }
+ }
+ return;
+ }
+
// Check that we have a comparison with a constant.
auto *ConstOp1 = dyn_cast<ConstantSDNode>(C.Op1);
if (!ConstOp1)
@@ -2866,6 +2916,51 @@ static void adjustForTestUnderMask(SelectionDAG &DAG, const SDLoc &DL,
C.CCMask = NewCCMask;
}
+// Implement i128 comparison in vector registers.
+static void adjustICmp128(SelectionDAG &DAG, const SDLoc &DL,
+ Comparison &C) {
+ if (C.Opcode != SystemZISD::ICMP)
+ return;
+ if (C.Op0.getValueType() != MVT::i128)
+ return;
+
+ // (In-)Equality comparisons can be implemented via VCEQGS.
+ if (C.CCMask == SystemZ::CCMASK_CMP_EQ ||
+ C.CCMask == SystemZ::CCMASK_CMP_NE) {
+ C.Opcode = SystemZISD::VICMPES;
+ C.Op0 = DAG.getNode(ISD::BITCAST, DL, MVT::v2i64, C.Op0);
+ C.Op1 = DAG.getNode(ISD::BITCAST, DL, MVT::v2i64, C.Op1);
+ C.CCValid = SystemZ::CCMASK_VCMP;
+ if (C.CCMask == SystemZ::CCMASK_CMP_EQ)
+ C.CCMask = SystemZ::CCMASK_VCMP_ALL;
+ else
+ C.CCMask = SystemZ::CCMASK_VCMP_ALL ^ C.CCValid;
+ return;
+ }
+
+ // Normalize other comparisons to GT.
+ bool Swap = false, Invert = false;
+ switch (C.CCMask) {
+ case SystemZ::CCMASK_CMP_GT: break;
+ case SystemZ::CCMASK_CMP_LT: Swap = true; break;
+ case SystemZ::CCMASK_CMP_LE: Invert = true; break;
+ case SystemZ::CCMASK_CMP_GE: Swap = Invert = true; break;
+ default: llvm_unreachable("Invalid integer condition!");
+ }
+ if (Swap)
+ std::swap(C.Op0, C.Op1);
+
+ if (C.ICmpType == SystemZICMP::UnsignedOnly)
+ C.Opcode = SystemZISD::UCMP128HI;
+ else
+ C.Opcode = SystemZISD::SCMP128HI;
+ C.CCValid = SystemZ::CCMASK_ANY;
+ C.CCMask = SystemZ::CCMASK_1;
+
+ if (Invert)
+ C.CCMask ^= C.CCValid;
+}
+
// See whether the comparison argument contains a redundant AND
// and remove it if so. This sometimes happens due to the generic
// BRCOND expansion.
@@ -2874,7 +2969,7 @@ static void adjustForRedundantAnd(SelectionDAG &DAG, const SDLoc &DL,
if (C.Op0.getOpcode() != ISD::AND)
return;
auto *Mask = dyn_cast<ConstantSDNode>(C.Op0.getOperand(1));
- if (!Mask)
+ if (!Mask || Mask->getValueSizeInBits(0) > 64)
return;
KnownBits Known = DAG.computeKnownBits(C.Op0.getOperand(0));
if ((~Known.Zero).getZExtValue() & ~Mask->getZExtValue())
@@ -2926,16 +3021,17 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
bool IsSignaling = false) {
if (CmpOp1.getOpcode() == ISD::Constant) {
assert(!Chain);
- uint64_t Constant = cast<ConstantSDNode>(CmpOp1)->getZExtValue();
unsigned Opcode, CCValid;
if (CmpOp0.getOpcode() == ISD::INTRINSIC_W_CHAIN &&
CmpOp0.getResNo() == 0 && CmpOp0->hasNUsesOfValue(1, 0) &&
isIntrinsicWithCCAndChain(CmpOp0, Opcode, CCValid))
- return getIntrinsicCmp(DAG, Opcode, CmpOp0, CCValid, Constant, Cond);
+ return getIntrinsicCmp(DAG, Opcode, CmpOp0, CCValid,
+ cast<ConstantSDNode>(CmpOp1)->getZExtValue(), Cond);
if (CmpOp0.getOpcode() == ISD::INTRINSIC_WO_CHAIN &&
CmpOp0.getResNo() == CmpOp0->getNumValues() - 1 &&
isIntrinsicWithCC(CmpOp0, Opcode, CCValid))
- return getIntrinsicCmp(DAG, Opcode, CmpOp0, CCValid, Constant, Cond);
+ return getIntrinsicCmp(DAG, Opcode, CmpOp0, CCValid,
+ cast<ConstantSDNode>(CmpOp1)->getZExtValue(), Cond);
}
Comparison C(CmpOp0, CmpOp1, Chain);
C.CCMask = CCMaskForCondCode(Cond);
@@ -2980,6 +3076,7 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
}
adjustForTestUnderMask(DAG, DL, C);
+ adjustICmp128(DAG, DL, C);
return C;
}
@@ -3007,6 +3104,11 @@ static SDValue emitCmp(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) {
return DAG.getNode(SystemZISD::TM, DL, MVT::i32, C.Op0, C.Op1,
DAG.getTargetConstant(RegisterOnly, DL, MVT::i32));
}
+ if (C.Opcode == SystemZISD::VICMPES) {
+ SDVTList VTs = DAG.getVTList(C.Op0.getValueType(), MVT::i32);
+ SDValue Val = DAG.getNode(C.Opcode, DL, VTs, C.Op0, C.Op1);
+ return SDValue(Val.getNode(), 1);
+ }
if (C.Chain) {
SDVTList VTs = DAG.getVTList(MVT::i32, MVT::Other);
return DAG.getNode(C.Opcode, DL, VTs, C.Chain, C.Op0, C.Op1);
@@ -3352,6 +3454,7 @@ SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op,
C.CCMask != SystemZ::CCMASK_CMP_EQ &&
C.CCMask != SystemZ::CCMASK_CMP_NE &&
C.Op1.getOpcode() == ISD::Constant &&
+ cast<ConstantSDNode>(C.Op1)->getValueSizeInBits(0) <= 64 &&
cast<ConstantSDNode>(C.Op1)->getZExtValue() == 0) {
if (isAbsolute(C.Op0, TrueOp, FalseOp))
return getAbsolute(DAG, DL, TrueOp, C.CCMask & SystemZ::CCMASK_CMP_LT);
@@ -4135,6 +4238,29 @@ SDValue SystemZTargetLowering::lowerXALUO(SDValue Op,
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
SDLoc DL(N);
+
+ if (N->getValueType(0) == MVT::i128) {
+ unsigned BaseOp = 0;
+ unsigned FlagOp = 0;
+ switch (Op.getOpcode()) {
+ default: llvm_unreachable("Unknown instruction!");
+ case ISD::UADDO:
+ BaseOp = ISD::ADD;
+ FlagOp = SystemZISD::VACC;
+ break;
+ case ISD::USUBO:
+ BaseOp = ISD::SUB;
+ FlagOp = SystemZISD::VSCBI;
+ break;
+ }
+ SDValue Result = DAG.getNode(BaseOp, DL, MVT::i128, LHS, RHS);
+ SDValue Flag = DAG.getNode(FlagOp, DL, MVT::i128, LHS, RHS);
+ Flag = DAG.getNode(ISD::AssertZext, DL, MVT::i128, Flag,
+ DAG.getValueType(MVT::i1));
+ Flag = DAG.getZExtOrTrunc(Flag, DL, N->getValueType(1));
+ return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Result, Flag);
+ }
+
unsigned BaseOp = 0;
unsigned CCValid = 0;
unsigned CCMask = 0;
@@ -4200,6 +4326,30 @@ SDValue SystemZTargetLowering::lowerUADDSUBO_CARRY(SDValue Op,
SDValue RHS = N->getOperand(1);
SDValue Carry = Op.getOperand(2);
SDLoc DL(N);
+
+ if (VT == MVT::i128) {
+ unsigned BaseOp = 0;
+ unsigned FlagOp = 0;
+ switch (Op.getOpcode()) {
+ default: llvm_unreachable("Unknown instruction!");
+ case ISD::UADDO_CARRY:
+ BaseOp = SystemZISD::VAC;
+ FlagOp = SystemZISD::VACCC;
+ break;
+ case ISD::USUBO_CARRY:
+ BaseOp = SystemZISD::VSBI;
+ FlagOp = SystemZISD::VSBCBI;
+ break;
+ }
+ Carry = DAG.getZExtOrTrunc(Carry, DL, MVT::i128);
+ SDValue Result = DAG.getNode(BaseOp, DL, MVT::i128, LHS, RHS, Carry);
+ SDValue Flag = DAG.getNode(FlagOp, DL, MVT::i128, LHS, RHS, Carry);
+ Flag = DAG.getNode(ISD::AssertZext, DL, MVT::i128, Flag,
+ DAG.getValueType(MVT::i1));
+ Flag = DAG.getZExtOrTrunc(Flag, DL, N->getValueType(1));
+ return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Result, Flag);
+ }
+
unsigned BaseOp = 0;
unsigned CCValid = 0;
unsigned CCMask = 0;
@@ -4245,6 +4395,15 @@ SDValue SystemZTargetLowering::lowerCTPOP(SDValue Op,
SDLoc DL(Op);
Op = Op.getOperand(0);
+ if (VT.getScalarSizeInBits() == 128) {
+ Op = DAG.getNode(ISD::BITCAST, DL, MVT::v2i64, Op);
+ Op = DAG.getNode(ISD::CTPOP, DL, MVT::v2i64, Op);
+ SDValue Tmp = DAG.getSplatBuildVector(MVT::v2i64, DL,
+ DAG.getConstant(0, DL, MVT::i64));
+ Op = DAG.getNode(SystemZISD::VSUM, DL, VT, Op, Tmp);
+ return Op;
+ }
+
// Handle vector types via VPOPCT.
if (VT.isVector()) {
Op = DAG.getNode(ISD::BITCAST, DL, MVT::v16i8, Op);
@@ -4338,6 +4497,12 @@ SDValue SystemZTargetLowering::lowerATOMIC_FENCE(SDValue Op,
SDValue SystemZTargetLowering::lowerATOMIC_LOAD(SDValue Op,
SelectionDAG &DAG) const {
auto *Node = cast<AtomicSDNode>(Op.getNode());
+ if (Node->getMemoryVT() == MVT::i128) {
+ // Use same code to handle both legal and non-legal i128 types.
+ SmallVector<SDValue, 2> Results;
+ LowerOperationWrapper(Node, Results, DAG);
+ return DAG.getMergeValues(Results, SDLoc(Op));
+ }
return DAG.getExtLoad(ISD::EXTLOAD, SDLoc(Op), Op.getValueType(),
Node->getChain(), Node->getBasePtr(),
Node->getMemoryVT(), Node->getMemOperand());
@@ -4347,6 +4512,12 @@ SDValue SystemZTargetLowering::lowerATOMIC_LOAD(SDValue Op,
SDValue SystemZTargetLowering::lowerATOMIC_STORE(SDValue Op,
SelectionDAG &DAG) const {
auto *Node = cast<AtomicSDNode>(Op.getNode());
+ if (Node->getMemoryVT() == MVT::i128) {
+ // Use same code to handle both legal and non-legal i128 types.
+ SmallVector<SDValue, 1> Results;
+ LowerOperationWrapper(Node, Results, DAG);
+ return DAG.getMergeValues(Results, SDLoc(Op));
+ }
SDValue Chain = DAG.getTruncStore(Node->getChain(), SDLoc(Op), Node->getVal(),
Node->getBasePtr(), Node->getMemoryVT(),
Node->getMemOperand());
@@ -4477,6 +4648,13 @@ SDValue SystemZTargetLowering::lowerATOMIC_CMP_SWAP(SDValue Op,
MachineMemOperand *MMO = Node->getMemOperand();
SDLoc DL(Node);
+ if (Node->getMemoryVT() == MVT::i128) {
+ // Use same code to handle both legal and non-legal i128 types.
+ SmallVector<SDValue, 3> Results;
+ LowerOperationWrapper(Node, Results, DAG);
+ return DAG.getMergeValues(Results, DL);
+ }
+
// We have native support for 32-bit and 64-bit compare and swap, but we
// still need to expand extracting the "success" result from the CC.
EVT NarrowVT = Node->getMemoryVT();
@@ -4682,6 +4860,40 @@ SystemZTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::s390_vsumqg:
return DAG.getNode(SystemZISD::VSUM, SDLoc(Op), Op.getValueType(),
Op.getOperand(1), Op.getOperand(2));
+
+ case Intrinsic::s390_vaq:
+ return DAG.getNode(ISD::ADD, SDLoc(Op), Op.getValueType(),
+ Op.getOperand(1), Op.getOperand(2));
+ case Intrinsic::s390_vaccb:
+ case Intrinsic::s390_vacch:
+ case Intrinsic::s390_vaccf:
+ case Intrinsic::s390_vaccg:
+ case Intrinsic::s390_vaccq:
+ return DAG.getNode(SystemZISD::VACC, SDLoc(Op), Op.getValueType(),
+ Op.getOperand(1), Op.getOperand(2));
+ case Intrinsic::s390_vacq:
+ return DAG.getNode(SystemZISD::VAC, SDLoc(Op), Op.getValueType(),
+ Op.getOperand(1), Op.getOperand(2), Op.getOperand(3));
+ case Intrinsic::s390_vacccq:
+ return DAG.getNode(SystemZISD::VACCC, SDLoc(Op), Op.getValueType(),
+ Op.getOperand(1), Op.getOperand(2), Op.getOperand(3));
+
+ case Intrinsic::s390_vsq:
+ return DAG.getNode(ISD::SUB, SDLoc(Op), Op.getValueType(),
+ Op.getOperand(1), Op.getOperand(2));
+ case Intrinsic::s390_vscbib:
+ case Intrinsic::s390_vscbih:
+ case Intrinsic::s390_vscbif:
+ case Intrinsic::s390_vscbig:
+ case Intrinsic::s390_vscbiq:
+ return DAG.getNode(SystemZISD::VSCBI, SDLoc(Op), Op.getValueType(),
+ Op.getOperand(1), Op.getOperand(2));
+ case Intrinsic::s390_vsbiq:
+ return DAG.getNode(SystemZISD::VSBI, SDLoc(Op), Op.getValueType(),
+ Op.getOperand(1), Op.getOperand(2), Op.getOperand(3));
+ case Intrinsic::s390_vsbcbiq:
+ return DAG.getNode(SystemZISD::VSBCBI, SDLoc(Op), Op.getValueType(),
+ Op.getOperand(1), Op.getOperand(2), Op.getOperand(3));
}
return SDValue();
@@ -6140,6 +6352,12 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
OPCODE(VSRA_BY_SCALAR);
OPCODE(VROTL_BY_SCALAR);
OPCODE(VSUM);
+ OPCODE(VACC);
+ OPCODE(VSCBI);
+ OPCODE(VAC);
+ OPCODE(VSBI);
+ OPCODE(VACCC);
+ OPCODE(VSBCBI);
OPCODE(VICMPE);
OPCODE(VICMPH);
OPCODE(VICMPHL);
@@ -6164,6 +6382,8 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
OPCODE(VROUND);
OPCODE(STRICT_VROUND);
OPCODE(VTM);
+ OPCODE(SCMP128HI);
+ OPCODE(UCMP128HI);
OPCODE(VFAE_CC);
OPCODE(VFAEZ_CC);
OPCODE(VFEE_CC);
@@ -6474,6 +6694,71 @@ SDValue SystemZTargetLowering::combineLOAD(
SDNode *N, DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
EVT LdVT = N->getValueType(0);
+ SDLoc DL(N);
+
+ // Replace an i128 load that is used solely to move its value into GPRs
+ // by separate loads of both halves.
+ if (LdVT == MVT::i128) {
+ LoadSDNode *LD = cast<LoadSDNode>(N);
+ if (!LD->isSimple() || !ISD::isNormalLoad(LD))
+ return SDValue();
+
+ // Scan through all users.
+ SmallVector<std::pair<SDNode *, int>, 2> Users;
+ int UsedElements = 0;
+ for (SDNode::use_iterator UI = LD->use_begin(), UIEnd = LD->use_end();
+ UI != UIEnd; ++UI) {
+ // Skip the uses of the chain.
+ if (UI.getUse().getResNo() != 0)
+ continue;
+
+ // Verify every user is a TRUNCATE to i64 of the low or high half ...
+ SDNode *User = *UI;
+ int Index = 1;
+ if (User->getOpcode() == ISD::SRL &&
+ User->getOperand(1).getOpcode() == ISD::Constant &&
+ cast<ConstantSDNode>(User->getOperand(1))->getZExtValue() == 64 &&
+ User->hasOneUse()) {
+ User = *User->use_begin();
+ Index = 0;
+ }
+ if (User->getOpcode() != ISD::TRUNCATE ||
+ User->getValueType(0) != MVT::i64)
+ return SDValue();
+
+ // ... and no half is extracted twice.
+ if (UsedElements & (1 << Index))
+ return SDValue();
+
+ UsedElements |= 1 << Index;
+ Users.push_back(std::make_pair(User, Index));
+ }
+
+ // Rewrite each extraction as an independent load.
+ SmallVector<SDValue, 2> ArgChains;
+ for (auto UserAndIndex : Users) {
+ SDNode *User = UserAndIndex.first;
+ unsigned Offset = User->getValueType(0).getStoreSize() * UserAndIndex.second;
+ SDValue Ptr =
+ DAG.getMemBasePlusOffset(LD->getBasePtr(), TypeSize::getFixed(Offset), DL);
+ SDValue EltLoad =
+ DAG.getLoad(User->getValueType(0), DL, LD->getChain(), Ptr,
+ LD->getPointerInfo().getWithOffset(Offset),
+ LD->getOriginalAlign(), LD->getMemOperand()->getFlags(),
+ LD->getAAInfo());
+
+ DCI.CombineTo(User, EltLoad, true);
+ ArgChains.push_back(EltLoad.getValue(1));
+ }
+
+ // Collect all chains via TokenFactor.
+ SDValue Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other,
+ ArgChains);
+ DAG.ReplaceAllUsesOfValueWith(SDValue(N, 1), Chain);
+ DCI.AddToWorklist(Chain.getNode());
+ return SDValue(N, 0);
+ }
+
if (LdVT.isVector() || LdVT.isInteger())
return SDValue();
// Transform a scalar load that is REPLICATEd as well as having other
@@ -6497,7 +6782,6 @@ SDValue SystemZTargetLowering::combineLOAD(
if (!Replicate || OtherUses.empty())
return SDValue();
- SDLoc DL(N);
SDValue Extract0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, LdVT,
Replicate, DAG.getConstant(0, DL, MVT::i32));
// Update uses of the loaded Value while preserving old chains.
@@ -6514,7 +6798,7 @@ bool SystemZTargetLowering::canLoadStoreByteSwapped(EVT VT) const {
if (VT == MVT::i16 || VT == MVT::i32 || VT == MVT::i64)
return true;
if (Subtarget.hasVectorEnhancements2())
- if (VT == MVT::v8i16 || VT == MVT::v4i32 || VT == MVT::v2i64)
+ if (VT == MVT::v8i16 || VT == MVT::v4i32 || VT == MVT::v2i64 || VT == MVT::i128)
return true;
return false;
}
@@ -6552,6 +6836,33 @@ static bool isOnlyUsedByStores(SDValue StoredVal, SelectionDAG &DAG) {
return true;
}
+static bool isMovedFromParts(SDValue Val, SDValue &LoPart, SDValue &HiPart) {
+ if (Val.getOpcode() != ISD::OR || !Val.getNode()->hasOneUse())
+ return false;
+
+ SDValue Op0 = Val.getOperand(0);
+ SDValue Op1 = Val.getOperand(1);
+
+ if (Op0.getOpcode() == ISD::SHL)
+ std::swap(Op0, Op1);
+ if (Op1.getOpcode() != ISD::SHL || !Op1.getNode()->hasOneUse() ||
+ Op1.getOperand(1).getOpcode() != ISD::Constant ||
+ cast<ConstantSDNode>(Op1.getOperand(1))->getZExtValue() != 64)
+ return false;
+ Op1 = Op1.getOperand(0);
+
+ if (Op0.getOpcode() != ISD::ZERO_EXTEND || !Op0.getNode()->hasOneUse() ||
+ Op0.getOperand(0).getValueType() != MVT::i64)
+ return false;
+ if (Op1.getOpcode() != ISD::ANY_EXTEND || !Op1.getNode()->hasOneUse() ||
+ Op1.getOperand(0).getValueType() != MVT::i64)
+ return false;
+
+ LoPart = Op0.getOperand(0);
+ HiPart = Op1.getOperand(0);
+ return true;
+}
+
SDValue SystemZTargetLowering::combineSTORE(
SDNode *N, DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
@@ -6610,6 +6921,27 @@ SDValue SystemZTargetLowering::combineSTORE(
}
}
+ // Transform a store of an i128 moved from GPRs into two separate stores.
+ if (MemVT == MVT::i128 && SN->isSimple() && ISD::isNormalStore(SN)) {
+ SDValue LoPart, HiPart;
+ if (isMovedFromParts(Op1, LoPart, HiPart)) {
+ SDLoc DL(SN);
+ SDValue Chain0 =
+ DAG.getStore(SN->getChain(), DL, HiPart, SN->getBasePtr(),
+ SN->getPointerInfo(), SN->getOriginalAlign(),
+ SN->getMemOperand()->getFlags(), SN->getAAInfo());
+ SDValue Chain1 =
+ DAG.getStore(SN->getChain(), DL, LoPart,
+ DAG.getObjectPtrOffset(DL, SN->getBasePtr(),
+ TypeSize::getFixed(8)),
+ SN->getPointerInfo().getWithOffset(8),
+ SN->getOriginalAlign(),
+ SN->getMemOperand()->getFlags(), SN->getAAInfo());
+
+ return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chain0, Chain1);
+ }
+ }
+
// Replicate a reg or immediate with VREP instead of scalar multiply or
// immediate load. It seems best to do this during the first DAGCombine as
// it is straight-forward to handle the zero-extend node in the initial
@@ -7700,6 +8032,7 @@ static bool isSelectPseudo(MachineInstr &MI) {
switch (MI.getOpcode()) {
case SystemZ::Select32:
case SystemZ::Select64:
+ case SystemZ::Select128:
case SystemZ::SelectF32:
case SystemZ::SelectF64:
case SystemZ::SelectF128:
@@ -7944,6 +8277,69 @@ MachineBasicBlock *SystemZTargetLowering::emitCondStore(MachineInstr &MI,
return JoinMBB;
}
+// Implement EmitInstrWithCustomInserter for pseudo [SU]Cmp128Hi instruction MI.
+MachineBasicBlock *
+SystemZTargetLowering::emitICmp128Hi(MachineInstr &MI,
+ MachineBasicBlock *MBB,
+ bool Unsigned) const {
+ MachineFunction &MF = *MBB->getParent();
+ const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+
+ // Synthetic instruction to compare 128-bit values.
+ // Sets CC 1 if Op0 > Op1, sets a different CC otherwise.
+ Register Op0 = MI.getOperand(0).getReg();
+ Register Op1 = MI.getOperand(1).getReg();
+
+ MachineBasicBlock *StartMBB = MBB;
+ MachineBasicBlock *JoinMBB = SystemZ::splitBlockAfter(MI, MBB);
+ MachineBasicBlock *HiEqMBB = SystemZ::emitBlockAfter(StartMBB);
+
+ // StartMBB:
+ //
+ // Use VECTOR ELEMENT COMPARE [LOGICAL] to compare the high parts.
+ // Swap the inputs to get:
+ // CC 1 if high(Op0) > high(Op1)
+ // CC 2 if high(Op0) < high(Op1)
+ // CC 0 if high(Op0) == high(Op1)
+ //
+ // If CC != 0, we'd done, so jump over the next instruction.
+ //
+ // VEC[L]G Op1, Op0
+ // JNE JoinMBB
+ // # fallthrough to HiEqMBB
+ MBB = StartMBB;
+ int HiOpcode = Unsigned? SystemZ::VECLG : SystemZ::VECG;
+ BuildMI(MBB, MI.getDebugLoc(), TII->get(HiOpcode))
+ .addReg(Op1).addReg(Op0);
+ BuildMI(MBB, MI.getDebugLoc(), TII->get(SystemZ::BRC))
+ .addImm(SystemZ::CCMASK_ICMP).addImm(SystemZ::CCMASK_CMP_NE).addMBB(JoinMBB);
+ MBB->addSuccessor(JoinMBB);
+ MBB->addSuccessor(HiEqMBB);
+
+ // HiEqMBB:
+ //
+ // Otherwise, use VECTOR COMPARE HIGH LOGICAL.
+ // Since we already know the high parts are equal, the CC
+ // result will only depend on the low parts:
+ // CC 1 if low(Op0) > low(Op1)
+ // CC 3 if low(Op0) <= low(Op1)
+ //
+ // VCHLGS Tmp, Op0, Op1
+ // # fallthrough to JoinMBB
+ MBB = HiEqMBB;
+ Register Temp = MRI.createVirtualRegister(&SystemZ::VR128BitRegClass);
+ BuildMI(MBB, MI.getDebugLoc(), TII->get(SystemZ::VCHLGS), Temp)
+ .addReg(Op0).addReg(Op1);
+ MBB->addSuccessor(JoinMBB);
+
+ // Mark CC as live-in to JoinMBB.
+ JoinMBB->addLiveIn(SystemZ::CC);
+
+ MI.eraseFromParent();
+ return JoinMBB;
+}
+
// Implement EmitInstrWithCustomInserter for subword pseudo ATOMIC_LOADW_* or
// ATOMIC_SWAPW instruction MI. BinOpcode is the instruction that performs
// the binary operation elided by "*", or 0 for ATOMIC_SWAPW. Invert says
@@ -8908,6 +9304,7 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
switch (MI.getOpcode()) {
case SystemZ::Select32:
case SystemZ::Select64:
+ case SystemZ::Select128:
case SystemZ::SelectF32:
case SystemZ::SelectF64:
case SystemZ::SelectF128:
@@ -8953,6 +9350,11 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
case SystemZ::CondStoreF64Inv:
return emitCondStore(MI, MBB, SystemZ::STD, 0, true);
+ case SystemZ::SCmp128Hi:
+ return emitICmp128Hi(MI, MBB, false);
+ case SystemZ::UCmp128Hi:
+ return emitICmp128Hi(MI, MBB, true);
+
case SystemZ::PAIR128:
return emitPair128(MI, MBB);
case SystemZ::AEXT128:
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index 1e2887cff816..6b3ce3f8c1d2 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -227,6 +227,13 @@ enum NodeType : unsigned {
// rightmost sub-element of the corresponding element of operand 1.
VSUM,
+ // Compute carry/borrow indication for add/subtract.
+ VACC, VSCBI,
+ // Add/subtract with carry/borrow.
+ VAC, VSBI,
+ // Compute carry/borrow indication for add/subtract with carry/borrow.
+ VACCC, VSBCBI,
+
// Compare integer vector operands 0 and 1 to produce the usual 0/-1
// vector result. VICMPE is for equality, VICMPH for "signed greater than"
// and VICMPHL for "unsigned greater than".
@@ -265,6 +272,10 @@ enum NodeType : unsigned {
// AND the two vector operands together and set CC based on the result.
VTM,
+ // i128 high integer comparisons.
+ SCMP128HI,
+ UCMP128HI,
+
// String operations that set CC as a side-effect.
VFAE_CC,
VFAEZ_CC,
@@ -432,7 +443,17 @@ public:
return 1;
return TargetLowering::getNumRegisters(Context, VT);
}
+ MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC,
+ EVT VT) const override {
+ // 128-bit single-element vector types are passed like other vectors,
+ // not like their element type.
+ if (VT.isVector() && VT.getSizeInBits() == 128 &&
+ VT.getVectorNumElements() == 1)
+ return MVT::v16i8;
+ return TargetLowering::getRegisterTypeForCallingConv(Context, CC, VT);
+ }
bool isCheapToSpeculateCtlz(Type *) const override { return true; }
+ bool isCheapToSpeculateCttz(Type *) const override { return true; }
bool preferZeroCompareBranch() const override { return true; }
bool isMaskAndCmp0FoldingBeneficial(const Instruction &AndI) const override {
ConstantInt* Mask = dyn_cast<ConstantInt>(AndI.getOperand(1));
@@ -742,6 +763,8 @@ private:
MachineBasicBlock *emitCondStore(MachineInstr &MI, MachineBasicBlock *BB,
unsigned StoreOpcode, unsigned STOCOpcode,
bool Invert) const;
+ MachineBasicBlock *emitICmp128Hi(MachineInstr &MI, MachineBasicBlock *BB,
+ bool Unsigned) const;
MachineBasicBlock *emitPair128(MachineInstr &MI,
MachineBasicBlock *MBB) const;
MachineBasicBlock *emitExt128(MachineInstr &MI, MachineBasicBlock *MBB,
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 210e6a51b6dc..937e36057a6e 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -2263,6 +2263,10 @@ let isCodeGenOnly = 1, hasSideEffects = 1 in {
def : Pat<(and (xor GR64:$x, (i64 -1)), GR64:$y),
(XGR GR64:$y, (NGR GR64:$y, GR64:$x))>;
+// Use LCGR/AGHI for i64 xor with -1.
+def : Pat<(xor GR64:$x, (i64 -1)),
+ (AGHI (LCGR GR64:$x), (i64 -1))>;
+
// Shift/rotate instructions only use the last 6 bits of the second operand
// register, so we can safely use NILL (16 fewer bits than NILF) to only AND the
// last 16 bits.
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrVector.td b/llvm/lib/Target/SystemZ/SystemZInstrVector.td
index 37d6945dc7a0..799b27d74414 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrVector.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrVector.td
@@ -266,7 +266,7 @@ let Predicates = [FeatureVectorEnhancements2] in {
def VLBRH : UnaryVRX<"vlbrh", 0xE606, z_loadbswap, v128h, 16, 1>;
def VLBRF : UnaryVRX<"vlbrf", 0xE606, z_loadbswap, v128f, 16, 2>;
def VLBRG : UnaryVRX<"vlbrg", 0xE606, z_loadbswap, v128g, 16, 3>;
- def VLBRQ : UnaryVRX<"vlbrq", 0xE606, null_frag, v128q, 16, 4>;
+ def VLBRQ : UnaryVRX<"vlbrq", 0xE606, z_loadbswap, v128q, 16, 4>;
// Load elements reversed.
def VLER : UnaryVRXGeneric<"vler", 0xE607>;
@@ -307,7 +307,7 @@ let Predicates = [FeatureVectorEnhancements2] in {
def VSTBRH : StoreVRX<"vstbrh", 0xE60E, z_storebswap, v128h, 16, 1>;
def VSTBRF : StoreVRX<"vstbrf", 0xE60E, z_storebswap, v128f, 16, 2>;
def VSTBRG : StoreVRX<"vstbrg", 0xE60E, z_storebswap, v128g, 16, 3>;
- def VSTBRQ : StoreVRX<"vstbrq", 0xE60E, null_frag, v128q, 16, 4>;
+ def VSTBRQ : StoreVRX<"vstbrq", 0xE60E, z_storebswap, v128q, 16, 4>;
// Store elements reversed.
def VSTER : StoreVRXGeneric<"vster", 0xE60F>;
@@ -478,26 +478,26 @@ let Predicates = [FeatureVector] in {
def VAH : BinaryVRRc<"vah", 0xE7F3, add, v128h, v128h, 1>;
def VAF : BinaryVRRc<"vaf", 0xE7F3, add, v128f, v128f, 2>;
def VAG : BinaryVRRc<"vag", 0xE7F3, add, v128g, v128g, 3>;
- def VAQ : BinaryVRRc<"vaq", 0xE7F3, int_s390_vaq, v128q, v128q, 4>;
+ def VAQ : BinaryVRRc<"vaq", 0xE7F3, add, v128q, v128q, 4>;
}
let isCommutable = 1 in {
// Add compute carry.
def VACC : BinaryVRRcGeneric<"vacc", 0xE7F1>;
- def VACCB : BinaryVRRc<"vaccb", 0xE7F1, int_s390_vaccb, v128b, v128b, 0>;
- def VACCH : BinaryVRRc<"vacch", 0xE7F1, int_s390_vacch, v128h, v128h, 1>;
- def VACCF : BinaryVRRc<"vaccf", 0xE7F1, int_s390_vaccf, v128f, v128f, 2>;
- def VACCG : BinaryVRRc<"vaccg", 0xE7F1, int_s390_vaccg, v128g, v128g, 3>;
- def VACCQ : BinaryVRRc<"vaccq", 0xE7F1, int_s390_vaccq, v128q, v128q, 4>;
+ def VACCB : BinaryVRRc<"vaccb", 0xE7F1, z_vacc, v128b, v128b, 0>;
+ def VACCH : BinaryVRRc<"vacch", 0xE7F1, z_vacc, v128h, v128h, 1>;
+ def VACCF : BinaryVRRc<"vaccf", 0xE7F1, z_vacc, v128f, v128f, 2>;
+ def VACCG : BinaryVRRc<"vaccg", 0xE7F1, z_vacc, v128g, v128g, 3>;
+ def VACCQ : BinaryVRRc<"vaccq", 0xE7F1, z_vacc, v128q, v128q, 4>;
// Add with carry.
def VAC : TernaryVRRdGeneric<"vac", 0xE7BB>;
- def VACQ : TernaryVRRd<"vacq", 0xE7BB, int_s390_vacq, v128q, v128q, 4>;
+ def VACQ : TernaryVRRd<"vacq", 0xE7BB, z_vac, v128q, v128q, 4>;
// Add with carry compute carry.
def VACCC : TernaryVRRdGeneric<"vaccc", 0xE7B9>;
- def VACCCQ : TernaryVRRd<"vacccq", 0xE7B9, int_s390_vacccq, v128q, v128q, 4>;
- }
+ def VACCCQ : TernaryVRRd<"vacccq", 0xE7B9, z_vaccc, v128q, v128q, 4>;
+ }
// And.
let isCommutable = 1 in
@@ -830,24 +830,23 @@ let Predicates = [FeatureVector] in {
def VSH : BinaryVRRc<"vsh", 0xE7F7, sub, v128h, v128h, 1>;
def VSF : BinaryVRRc<"vsf", 0xE7F7, sub, v128f, v128f, 2>;
def VSG : BinaryVRRc<"vsg", 0xE7F7, sub, v128g, v128g, 3>;
- def VSQ : BinaryVRRc<"vsq", 0xE7F7, int_s390_vsq, v128q, v128q, 4>;
+ def VSQ : BinaryVRRc<"vsq", 0xE7F7, sub, v128q, v128q, 4>;
// Subtract compute borrow indication.
def VSCBI : BinaryVRRcGeneric<"vscbi", 0xE7F5>;
- def VSCBIB : BinaryVRRc<"vscbib", 0xE7F5, int_s390_vscbib, v128b, v128b, 0>;
- def VSCBIH : BinaryVRRc<"vscbih", 0xE7F5, int_s390_vscbih, v128h, v128h, 1>;
- def VSCBIF : BinaryVRRc<"vscbif", 0xE7F5, int_s390_vscbif, v128f, v128f, 2>;
- def VSCBIG : BinaryVRRc<"vscbig", 0xE7F5, int_s390_vscbig, v128g, v128g, 3>;
- def VSCBIQ : BinaryVRRc<"vscbiq", 0xE7F5, int_s390_vscbiq, v128q, v128q, 4>;
+ def VSCBIB : BinaryVRRc<"vscbib", 0xE7F5, z_vscbi, v128b, v128b, 0>;
+ def VSCBIH : BinaryVRRc<"vscbih", 0xE7F5, z_vscbi, v128h, v128h, 1>;
+ def VSCBIF : BinaryVRRc<"vscbif", 0xE7F5, z_vscbi, v128f, v128f, 2>;
+ def VSCBIG : BinaryVRRc<"vscbig", 0xE7F5, z_vscbi, v128g, v128g, 3>;
+ def VSCBIQ : BinaryVRRc<"vscbiq", 0xE7F5, z_vscbi, v128q, v128q, 4>;
// Subtract with borrow indication.
def VSBI : TernaryVRRdGeneric<"vsbi", 0xE7BF>;
- def VSBIQ : TernaryVRRd<"vsbiq", 0xE7BF, int_s390_vsbiq, v128q, v128q, 4>;
+ def VSBIQ : TernaryVRRd<"vsbiq", 0xE7BF, z_vsbi, v128q, v128q, 4>;
// Subtract with borrow compute borrow indication.
def VSBCBI : TernaryVRRdGeneric<"vsbcbi", 0xE7BD>;
- def VSBCBIQ : TernaryVRRd<"vsbcbiq", 0xE7BD, int_s390_vsbcbiq,
- v128q, v128q, 4>;
+ def VSBCBIQ : TernaryVRRd<"vsbcbiq", 0xE7BD, z_vsbcbi, v128q, v128q, 4>;
// Sum across doubleword.
def VSUMG : BinaryVRRcGeneric<"vsumg", 0xE765>;
@@ -866,34 +865,35 @@ let Predicates = [FeatureVector] in {
}
// Instantiate the bitwise ops for type TYPE.
-multiclass BitwiseVectorOps<ValueType type> {
+multiclass BitwiseVectorOps<ValueType type, SDPatternOperator not_op> {
let Predicates = [FeatureVector] in {
def : Pat<(type (and VR128:$x, VR128:$y)), (VN VR128:$x, VR128:$y)>;
- def : Pat<(type (and VR128:$x, (z_vnot VR128:$y))),
+ def : Pat<(type (and VR128:$x, (not_op VR128:$y))),
(VNC VR128:$x, VR128:$y)>;
def : Pat<(type (or VR128:$x, VR128:$y)), (VO VR128:$x, VR128:$y)>;
def : Pat<(type (xor VR128:$x, VR128:$y)), (VX VR128:$x, VR128:$y)>;
def : Pat<(type (or (and VR128:$x, VR128:$z),
- (and VR128:$y, (z_vnot VR128:$z)))),
+ (and VR128:$y, (not_op VR128:$z)))),
(VSEL VR128:$x, VR128:$y, VR128:$z)>;
- def : Pat<(type (z_vnot (or VR128:$x, VR128:$y))),
+ def : Pat<(type (not_op (or VR128:$x, VR128:$y))),
(VNO VR128:$x, VR128:$y)>;
- def : Pat<(type (z_vnot VR128:$x)), (VNO VR128:$x, VR128:$x)>;
+ def : Pat<(type (not_op VR128:$x)), (VNO VR128:$x, VR128:$x)>;
}
let Predicates = [FeatureVectorEnhancements1] in {
- def : Pat<(type (z_vnot (xor VR128:$x, VR128:$y))),
+ def : Pat<(type (not_op (xor VR128:$x, VR128:$y))),
(VNX VR128:$x, VR128:$y)>;
- def : Pat<(type (z_vnot (and VR128:$x, VR128:$y))),
+ def : Pat<(type (not_op (and VR128:$x, VR128:$y))),
(VNN VR128:$x, VR128:$y)>;
- def : Pat<(type (or VR128:$x, (z_vnot VR128:$y))),
+ def : Pat<(type (or VR128:$x, (not_op VR128:$y))),
(VOC VR128:$x, VR128:$y)>;
}
}
-defm : BitwiseVectorOps<v16i8>;
-defm : BitwiseVectorOps<v8i16>;
-defm : BitwiseVectorOps<v4i32>;
-defm : BitwiseVectorOps<v2i64>;
+defm : BitwiseVectorOps<v16i8, z_vnot>;
+defm : BitwiseVectorOps<v8i16, z_vnot>;
+defm : BitwiseVectorOps<v4i32, z_vnot>;
+defm : BitwiseVectorOps<v2i64, z_vnot>;
+defm : BitwiseVectorOps<i128, not>;
// Instantiate additional patterns for absolute-related expressions on
// type TYPE. LC is the negate instruction for TYPE and LP is the absolute
@@ -962,6 +962,26 @@ defm : IntegerMinMaxVectorOps<v8i16, z_vicmphl, VMNLH, VMXLH>;
defm : IntegerMinMaxVectorOps<v4i32, z_vicmphl, VMNLF, VMXLF>;
defm : IntegerMinMaxVectorOps<v2i64, z_vicmphl, VMNLG, VMXLG>;
+// Instantiate full-vector shifts.
+multiclass FullVectorShiftOps<SDPatternOperator shift,
+ Instruction sbit, Instruction sbyte> {
+ let Predicates = [FeatureVector] in {
+ def : Pat<(shift (i128 VR128:$x), imm32nobytes:$amt),
+ (sbit VR128:$x, (VREPIB (UIMM8 imm:$amt)))>;
+ def : Pat<(shift (i128 VR128:$x), imm32nobits:$amt),
+ (sbyte VR128:$x, (VREPIB (UIMM8 imm:$amt)))>;
+ def : Pat<(shift (i128 VR128:$x), imm32:$amt),
+ (sbit (sbyte VR128:$x, (VREPIB (UIMM8 imm:$amt))),
+ (VREPIB (UIMM8 imm:$amt)))>;
+ def : Pat<(shift (i128 VR128:$x), GR32:$amt),
+ (sbit (sbyte VR128:$x, (VREPB (VLVGP32 GR32:$amt, GR32:$amt), 15)),
+ (VREPB (VLVGP32 GR32:$amt, GR32:$amt), 15))>;
+ }
+}
+defm : FullVectorShiftOps<vshiftop<shl>, VSL, VSLB>;
+defm : FullVectorShiftOps<vshiftop<srl>, VSRL, VSRLB>;
+defm : FullVectorShiftOps<vshiftop<sra>, VSRA, VSRAB>;
+
//===----------------------------------------------------------------------===//
// Integer comparison
//===----------------------------------------------------------------------===//
@@ -1517,12 +1537,165 @@ let Predicates = [FeatureVector] in {
}
//===----------------------------------------------------------------------===//
+// Support for 128-bit integer values in vector registers
+//===----------------------------------------------------------------------===//
+
+// Loads and stores.
+let Predicates = [FeatureVector] in {
+ def : Pat<(i128 (load bdxaddr12only:$addr)),
+ (VL bdxaddr12only:$addr)>;
+ def : Pat<(store (i128 VR128:$src), bdxaddr12only:$addr),
+ (VST VR128:$src, bdxaddr12only:$addr)>;
+}
+
+// Full i128 move from GPR pair.
+let Predicates = [FeatureVector] in
+ def : Pat<(i128 (or (zext GR64:$x), (shl (anyext GR64:$y), (i32 64)))),
+ (VLVGP GR64:$y, GR64:$x)>;
+
+// Any-extensions from GPR to i128.
+let Predicates = [FeatureVector] in {
+ def : Pat<(i128 (anyext GR32:$x)), (VLVGP32 GR32:$x, GR32:$x)>;
+ def : Pat<(i128 (anyext GR64:$x)), (VLVGP GR64:$x, GR64:$x)>;
+}
+
+// Any-extending loads into i128.
+let Predicates = [FeatureVector] in {
+ def : Pat<(i128 (extloadi8 bdxaddr12only:$addr)),
+ (VLREPB bdxaddr12only:$addr)>;
+ def : Pat<(i128 (extloadi16 bdxaddr12only:$addr)),
+ (VLREPH bdxaddr12only:$addr)>;
+ def : Pat<(i128 (extloadi32 bdxaddr12only:$addr)),
+ (VLREPF bdxaddr12only:$addr)>;
+ def : Pat<(i128 (extloadi64 bdxaddr12only:$addr)),
+ (VLREPG bdxaddr12only:$addr)>;
+}
+
+// Truncations from i128 to GPR.
+let Predicates = [FeatureVector] in {
+ def : Pat<(i32 (trunc (i128 VR128:$vec))),
+ (EXTRACT_SUBREG (VLGVF VR128:$vec, zero_reg, 3), subreg_l32)>;
+ def : Pat<(i32 (trunc (srl (i128 VR128:$vec), (i32 32)))),
+ (EXTRACT_SUBREG (VLGVF VR128:$vec, zero_reg, 2), subreg_l32)>;
+ def : Pat<(i32 (trunc (srl (i128 VR128:$vec), (i32 64)))),
+ (EXTRACT_SUBREG (VLGVF VR128:$vec, zero_reg, 1), subreg_l32)>;
+ def : Pat<(i32 (trunc (srl (i128 VR128:$vec), (i32 96)))),
+ (EXTRACT_SUBREG (VLGVF VR128:$vec, zero_reg, 0), subreg_l32)>;
+ def : Pat<(i64 (trunc (i128 VR128:$vec))),
+ (VLGVG VR128:$vec, zero_reg, 1)>;
+ def : Pat<(i64 (trunc (srl (i128 VR128:$vec), (i32 64)))),
+ (VLGVG VR128:$vec, zero_reg, 0)>;
+}
+
+// Truncating stores from i128.
+let Predicates = [FeatureVector] in {
+ def : Pat<(truncstorei8 (i128 VR128:$x), bdxaddr12only:$addr),
+ (VSTEB VR128:$x, bdxaddr12only:$addr, 15)>;
+ def : Pat<(truncstorei16 (i128 VR128:$x), bdxaddr12only:$addr),
+ (VSTEH VR128:$x, bdxaddr12only:$addr, 7)>;
+ def : Pat<(truncstorei32 (i128 VR128:$x), bdxaddr12only:$addr),
+ (VSTEF VR128:$x, bdxaddr12only:$addr, 3)>;
+ def : Pat<(truncstorei32 (srl (i128 VR128:$x), (i32 32)), bdxaddr12only:$addr),
+ (VSTEF VR128:$x, bdxaddr12only:$addr, 2)>;
+ def : Pat<(truncstorei32 (srl (i128 VR128:$x), (i32 64)), bdxaddr12only:$addr),
+ (VSTEF VR128:$x, bdxaddr12only:$addr, 1)>;
+ def : Pat<(truncstorei32 (srl (i128 VR128:$x), (i32 96)), bdxaddr12only:$addr),
+ (VSTEF VR128:$x, bdxaddr12only:$addr, 0)>;
+ def : Pat<(truncstorei64 (i128 VR128:$x), bdxaddr12only:$addr),
+ (VSTEG VR128:$x, bdxaddr12only:$addr, 1)>;
+ def : Pat<(truncstorei64 (srl (i128 VR128:$x), (i32 64)), bdxaddr12only:$addr),
+ (VSTEG VR128:$x, bdxaddr12only:$addr, 0)>;
+}
+
+// Zero-extensions from GPR to i128.
+let Predicates = [FeatureVector] in {
+ def : Pat<(i128 (zext8 (anyext GR32:$x))),
+ (VLVGB (VGBM 0), GR32:$x, zero_reg, 15)>;
+ def : Pat<(i128 (zext16 (anyext GR32:$x))),
+ (VLVGH (VGBM 0), GR32:$x, zero_reg, 7)>;
+ def : Pat<(i128 (zext GR32:$x)),
+ (VLVGF (VGBM 0), GR32:$x, zero_reg, 3)>;
+ def : Pat<(i128 (zext GR64:$x)),
+ (VLVGG (VGBM 0), GR64:$x, zero_reg, 1)>;
+}
+
+// Zero-extending loads into i128.
+let Predicates = [FeatureVector] in {
+ def : Pat<(i128 (zextloadi8 bdxaddr12only:$addr)),
+ (VLEB (VGBM 0), bdxaddr12only:$addr, 15)>;
+ def : Pat<(i128 (zextloadi16 bdxaddr12only:$addr)),
+ (VLEH (VGBM 0), bdxaddr12only:$addr, 7)>;
+ def : Pat<(i128 (zextloadi32 bdxaddr12only:$addr)),
+ (VLEF (VGBM 0), bdxaddr12only:$addr, 3)>;
+ def : Pat<(i128 (zextloadi64 bdxaddr12only:$addr)),
+ (VLEG (VGBM 0), bdxaddr12only:$addr, 1)>;
+}
+
+// In-register i128 sign-extensions.
+let Predicates = [FeatureVector] in {
+ def : Pat<(i128 (sext_inreg VR128:$x, i8)),
+ (VSRAB (VREPB VR128:$x, 15), (VREPIB 120))>;
+ def : Pat<(i128 (sext_inreg VR128:$x, i16)),
+ (VSRAB (VREPH VR128:$x, 7), (VREPIB 112))>;
+ def : Pat<(i128 (sext_inreg VR128:$x, i32)),
+ (VSRAB (VREPF VR128:$x, 3), (VREPIB 96))>;
+ def : Pat<(i128 (sext_inreg VR128:$x, i64)),
+ (VSRAB (VREPG VR128:$x, 1), (VREPIB 64))>;
+}
+
+// Sign-extensions from GPR to i128.
+let Predicates = [FeatureVector] in {
+ def : Pat<(i128 (sext_inreg (anyext GR32:$x), i8)),
+ (VLVGP (SRAG (LGBR (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
+ GR32:$x, subreg_l32)), zero_reg, 63),
+ (LGBR (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
+ GR32:$x, subreg_l32)))>;
+ def : Pat<(i128 (sext_inreg (anyext GR32:$x), i16)),
+ (VLVGP (SRAG (LGHR (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
+ GR32:$x, subreg_l32)), zero_reg, 63),
+ (LGHR (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
+ GR32:$x, subreg_l32)))>;
+ def : Pat<(i128 (sext GR32:$x)),
+ (VLVGP (SRAG (LGFR GR32:$x), zero_reg, 63), (LGFR GR32:$x))>;
+ def : Pat<(i128 (sext GR64:$x)),
+ (VLVGP (SRAG GR64:$x, zero_reg, 63), GR64:$x)>;
+}
+
+// Sign-extending loads into i128.
+let Predicates = [FeatureVector] in {
+ def : Pat<(i128 (sextloadi8 bdxaddr12only:$addr)),
+ (VSRAB (VLREPB bdxaddr12only:$addr), (VREPIB 120))>;
+ def : Pat<(i128 (sextloadi16 bdxaddr12only:$addr)),
+ (VSRAB (VLREPH bdxaddr12only:$addr), (VREPIB 112))>;
+ def : Pat<(i128 (sextloadi32 bdxaddr12only:$addr)),
+ (VSRAB (VLREPF bdxaddr12only:$addr), (VREPIB 96))>;
+ def : Pat<(i128 (sextloadi64 bdxaddr12only:$addr)),
+ (VSRAB (VLREPG bdxaddr12only:$addr), (VREPIB 64))>;
+}
+
+// i128 comparison pseudo-instructions.
+let Predicates = [FeatureVector], Defs = [CC],
+ usesCustomInserter = 1, hasNoSchedulingInfo = 1 in {
+ def SCmp128Hi : Pseudo<(outs), (ins VR128:$src1, VR128:$src2),
+ [(set CC, (z_scmp128hi (i128 VR128:$src1),
+ (i128 VR128:$src2)))]>;
+ def UCmp128Hi : Pseudo<(outs), (ins VR128:$src1, VR128:$src2),
+ [(set CC, (z_ucmp128hi (i128 VR128:$src1),
+ (i128 VR128:$src2)))]>;
+}
+
+// i128 select pseudo-instructions.
+let Predicates = [FeatureVector] in
+ def Select128 : SelectWrapper<i128, VR128>;
+
+//===----------------------------------------------------------------------===//
// Conversions
//===----------------------------------------------------------------------===//
def : Pat<(v16i8 (bitconvert (v8i16 VR128:$src))), (v16i8 VR128:$src)>;
def : Pat<(v16i8 (bitconvert (v4i32 VR128:$src))), (v16i8 VR128:$src)>;
def : Pat<(v16i8 (bitconvert (v2i64 VR128:$src))), (v16i8 VR128:$src)>;
+def : Pat<(v16i8 (bitconvert (i128 VR128:$src))), (v16i8 VR128:$src)>;
def : Pat<(v16i8 (bitconvert (v4f32 VR128:$src))), (v16i8 VR128:$src)>;
def : Pat<(v16i8 (bitconvert (v2f64 VR128:$src))), (v16i8 VR128:$src)>;
def : Pat<(v16i8 (bitconvert (f128 VR128:$src))), (v16i8 VR128:$src)>;
@@ -1530,6 +1703,7 @@ def : Pat<(v16i8 (bitconvert (f128 VR128:$src))), (v16i8 VR128:$src)>;
def : Pat<(v8i16 (bitconvert (v16i8 VR128:$src))), (v8i16 VR128:$src)>;
def : Pat<(v8i16 (bitconvert (v4i32 VR128:$src))), (v8i16 VR128:$src)>;
def : Pat<(v8i16 (bitconvert (v2i64 VR128:$src))), (v8i16 VR128:$src)>;
+def : Pat<(v8i16 (bitconvert (i128 VR128:$src))), (v8i16 VR128:$src)>;
def : Pat<(v8i16 (bitconvert (v4f32 VR128:$src))), (v8i16 VR128:$src)>;
def : Pat<(v8i16 (bitconvert (v2f64 VR128:$src))), (v8i16 VR128:$src)>;
def : Pat<(v8i16 (bitconvert (f128 VR128:$src))), (v8i16 VR128:$src)>;
@@ -1537,6 +1711,7 @@ def : Pat<(v8i16 (bitconvert (f128 VR128:$src))), (v8i16 VR128:$src)>;
def : Pat<(v4i32 (bitconvert (v16i8 VR128:$src))), (v4i32 VR128:$src)>;
def : Pat<(v4i32 (bitconvert (v8i16 VR128:$src))), (v4i32 VR128:$src)>;
def : Pat<(v4i32 (bitconvert (v2i64 VR128:$src))), (v4i32 VR128:$src)>;
+def : Pat<(v4i32 (bitconvert (i128 VR128:$src))), (v4i32 VR128:$src)>;
def : Pat<(v4i32 (bitconvert (v4f32 VR128:$src))), (v4i32 VR128:$src)>;
def : Pat<(v4i32 (bitconvert (v2f64 VR128:$src))), (v4i32 VR128:$src)>;
def : Pat<(v4i32 (bitconvert (f128 VR128:$src))), (v4i32 VR128:$src)>;
@@ -1544,6 +1719,7 @@ def : Pat<(v4i32 (bitconvert (f128 VR128:$src))), (v4i32 VR128:$src)>;
def : Pat<(v2i64 (bitconvert (v16i8 VR128:$src))), (v2i64 VR128:$src)>;
def : Pat<(v2i64 (bitconvert (v8i16 VR128:$src))), (v2i64 VR128:$src)>;
def : Pat<(v2i64 (bitconvert (v4i32 VR128:$src))), (v2i64 VR128:$src)>;
+def : Pat<(v2i64 (bitconvert (i128 VR128:$src))), (v2i64 VR128:$src)>;
def : Pat<(v2i64 (bitconvert (v4f32 VR128:$src))), (v2i64 VR128:$src)>;
def : Pat<(v2i64 (bitconvert (v2f64 VR128:$src))), (v2i64 VR128:$src)>;
def : Pat<(v2i64 (bitconvert (f128 VR128:$src))), (v2i64 VR128:$src)>;
@@ -1551,6 +1727,7 @@ def : Pat<(v2i64 (bitconvert (f128 VR128:$src))), (v2i64 VR128:$src)>;
def : Pat<(v4f32 (bitconvert (v16i8 VR128:$src))), (v4f32 VR128:$src)>;
def : Pat<(v4f32 (bitconvert (v8i16 VR128:$src))), (v4f32 VR128:$src)>;
def : Pat<(v4f32 (bitconvert (v4i32 VR128:$src))), (v4f32 VR128:$src)>;
+def : Pat<(v4f32 (bitconvert (i128 VR128:$src))), (v4f32 VR128:$src)>;
def : Pat<(v4f32 (bitconvert (v2i64 VR128:$src))), (v4f32 VR128:$src)>;
def : Pat<(v4f32 (bitconvert (v2f64 VR128:$src))), (v4f32 VR128:$src)>;
def : Pat<(v4f32 (bitconvert (f128 VR128:$src))), (v4f32 VR128:$src)>;
@@ -1558,6 +1735,7 @@ def : Pat<(v4f32 (bitconvert (f128 VR128:$src))), (v4f32 VR128:$src)>;
def : Pat<(v2f64 (bitconvert (v16i8 VR128:$src))), (v2f64 VR128:$src)>;
def : Pat<(v2f64 (bitconvert (v8i16 VR128:$src))), (v2f64 VR128:$src)>;
def : Pat<(v2f64 (bitconvert (v4i32 VR128:$src))), (v2f64 VR128:$src)>;
+def : Pat<(v2f64 (bitconvert (i128 VR128:$src))), (v2f64 VR128:$src)>;
def : Pat<(v2f64 (bitconvert (v2i64 VR128:$src))), (v2f64 VR128:$src)>;
def : Pat<(v2f64 (bitconvert (v4f32 VR128:$src))), (v2f64 VR128:$src)>;
def : Pat<(v2f64 (bitconvert (f128 VR128:$src))), (v2f64 VR128:$src)>;
@@ -1566,9 +1744,18 @@ def : Pat<(f128 (bitconvert (v16i8 VR128:$src))), (f128 VR128:$src)>;
def : Pat<(f128 (bitconvert (v8i16 VR128:$src))), (f128 VR128:$src)>;
def : Pat<(f128 (bitconvert (v4i32 VR128:$src))), (f128 VR128:$src)>;
def : Pat<(f128 (bitconvert (v2i64 VR128:$src))), (f128 VR128:$src)>;
+def : Pat<(f128 (bitconvert (i128 VR128:$src))), (f128 VR128:$src)>;
def : Pat<(f128 (bitconvert (v4f32 VR128:$src))), (f128 VR128:$src)>;
def : Pat<(f128 (bitconvert (v2f64 VR128:$src))), (f128 VR128:$src)>;
+def : Pat<(i128 (bitconvert (v16i8 VR128:$src))), (i128 VR128:$src)>;
+def : Pat<(i128 (bitconvert (v8i16 VR128:$src))), (i128 VR128:$src)>;
+def : Pat<(i128 (bitconvert (v4i32 VR128:$src))), (i128 VR128:$src)>;
+def : Pat<(i128 (bitconvert (v2i64 VR128:$src))), (i128 VR128:$src)>;
+def : Pat<(i128 (bitconvert (v4f32 VR128:$src))), (i128 VR128:$src)>;
+def : Pat<(i128 (bitconvert (v2f64 VR128:$src))), (i128 VR128:$src)>;
+def : Pat<(i128 (bitconvert (f128 VR128:$src))), (i128 VR128:$src)>;
+
//===----------------------------------------------------------------------===//
// Replicating scalars
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/SystemZ/SystemZOperands.td b/llvm/lib/Target/SystemZ/SystemZOperands.td
index c92e0abe38ac..0221e2c53f2f 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperands.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperands.td
@@ -314,70 +314,72 @@ def U48Imm : ImmediateAsmOperand<"U48Imm">;
// Immediates for the lower and upper 16 bits of an i32, with the other
// bits of the i32 being zero.
defm imm32ll16 : Immediate<i32, [{
- return SystemZ::isImmLL(N->getZExtValue());
+ return N->getAPIntValue().isIntN(32) && SystemZ::isImmLL(N->getZExtValue());
}], LL16, "U16Imm">;
defm imm32lh16 : Immediate<i32, [{
- return SystemZ::isImmLH(N->getZExtValue());
+ return N->getAPIntValue().isIntN(32) && SystemZ::isImmLH(N->getZExtValue());
}], LH16, "U16Imm">;
// Immediates for the lower and upper 16 bits of an i32, with the other
// bits of the i32 being one.
defm imm32ll16c : Immediate<i32, [{
- return SystemZ::isImmLL(uint32_t(~N->getZExtValue()));
+ return N->getAPIntValue().isIntN(32) &&
+ SystemZ::isImmLL(uint32_t(~N->getZExtValue()));
}], LL16, "U16Imm">;
defm imm32lh16c : Immediate<i32, [{
- return SystemZ::isImmLH(uint32_t(~N->getZExtValue()));
+ return N->getAPIntValue().isIntN(32) &&
+ SystemZ::isImmLH(uint32_t(~N->getZExtValue()));
}], LH16, "U16Imm">;
// Short immediates
defm imm32zx1 : Immediate<i32, [{
- return isUInt<1>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(1);
}], NOOP_SDNodeXForm, "U1Imm">;
defm imm32zx2 : Immediate<i32, [{
- return isUInt<2>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(2);
}], NOOP_SDNodeXForm, "U2Imm">;
defm imm32zx3 : Immediate<i32, [{
- return isUInt<3>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(3);
}], NOOP_SDNodeXForm, "U3Imm">;
defm imm32zx4 : Immediate<i32, [{
- return isUInt<4>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(4);
}], NOOP_SDNodeXForm, "U4Imm">;
// Note: this enforces an even value during code generation only.
// When used from the assembler, any 4-bit value is allowed.
defm imm32zx4even : Immediate<i32, [{
- return isUInt<4>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(4);
}], UIMM8EVEN, "U4Imm">;
defm imm32sx8 : Immediate<i32, [{
- return isInt<8>(N->getSExtValue());
+ return N->getAPIntValue().isSignedIntN(8);
}], SIMM8, "S8Imm">;
defm imm32zx8 : Immediate<i32, [{
- return isUInt<8>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(8);
}], UIMM8, "U8Imm">;
defm imm32zx8trunc : Immediate<i32, [{}], UIMM8, "U8Imm">;
defm imm32zx12 : Immediate<i32, [{
- return isUInt<12>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(12);
}], UIMM12, "U12Imm">;
defm imm32sx16 : Immediate<i32, [{
- return isInt<16>(N->getSExtValue());
+ return N->getAPIntValue().isSignedIntN(16);
}], SIMM16, "S16Imm">;
defm imm32sx16n : Immediate<i32, [{
- return isInt<16>(-N->getSExtValue());
+ return (-N->getAPIntValue()).isSignedIntN(16);
}], NEGSIMM16, "S16Imm">;
defm imm32zx16 : Immediate<i32, [{
- return isUInt<16>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(16);
}], UIMM16, "U16Imm">;
defm imm32sx16trunc : Immediate<i32, [{}], SIMM16, "S16Imm">;
@@ -390,7 +392,8 @@ defm simm32 : Immediate<i32, [{}], SIMM32, "S32Imm">;
defm uimm32 : Immediate<i32, [{}], UIMM32, "U32Imm">;
defm simm32n : Immediate<i32, [{
- return isInt<32>(-N->getSExtValue());
+ auto SImm = N->getAPIntValue().trySExtValue();
+ return SImm.has_value() && isInt<32>(-*SImm);
}], NEGSIMM32, "S32Imm">;
def imm32 : ImmLeaf<i32, [{}]>;
@@ -402,107 +405,115 @@ def imm32 : ImmLeaf<i32, [{}]>;
// Immediates for 16-bit chunks of an i64, with the other bits of the
// i32 being zero.
defm imm64ll16 : Immediate<i64, [{
- return SystemZ::isImmLL(N->getZExtValue());
+ return N->getAPIntValue().isIntN(64) && SystemZ::isImmLL(N->getZExtValue());
}], LL16, "U16Imm">;
defm imm64lh16 : Immediate<i64, [{
- return SystemZ::isImmLH(N->getZExtValue());
+ return N->getAPIntValue().isIntN(64) && SystemZ::isImmLH(N->getZExtValue());
}], LH16, "U16Imm">;
defm imm64hl16 : Immediate<i64, [{
- return SystemZ::isImmHL(N->getZExtValue());
+ return N->getAPIntValue().isIntN(64) && SystemZ::isImmHL(N->getZExtValue());
}], HL16, "U16Imm">;
defm imm64hh16 : Immediate<i64, [{
- return SystemZ::isImmHH(N->getZExtValue());
+ return N->getAPIntValue().isIntN(64) && SystemZ::isImmHH(N->getZExtValue());
}], HH16, "U16Imm">;
// Immediates for 16-bit chunks of an i64, with the other bits of the
// i32 being one.
defm imm64ll16c : Immediate<i64, [{
- return SystemZ::isImmLL(uint64_t(~N->getZExtValue()));
+ return N->getAPIntValue().isIntN(64) &&
+ SystemZ::isImmLL(uint64_t(~N->getZExtValue()));
}], LL16, "U16Imm">;
defm imm64lh16c : Immediate<i64, [{
- return SystemZ::isImmLH(uint64_t(~N->getZExtValue()));
+ return N->getAPIntValue().isIntN(64) &&
+ SystemZ::isImmLH(uint64_t(~N->getZExtValue()));
}], LH16, "U16Imm">;
defm imm64hl16c : Immediate<i64, [{
- return SystemZ::isImmHL(uint64_t(~N->getZExtValue()));
+ return N->getAPIntValue().isIntN(64) &&
+ SystemZ::isImmHL(uint64_t(~N->getZExtValue()));
}], HL16, "U16Imm">;
defm imm64hh16c : Immediate<i64, [{
- return SystemZ::isImmHH(uint64_t(~N->getZExtValue()));
+ return N->getAPIntValue().isIntN(64) &&
+ SystemZ::isImmHH(uint64_t(~N->getZExtValue()));
}], HH16, "U16Imm">;
// Immediates for the lower and upper 32 bits of an i64, with the other
// bits of the i32 being zero.
defm imm64lf32 : Immediate<i64, [{
- return SystemZ::isImmLF(N->getZExtValue());
+ return N->getAPIntValue().isIntN(64) && SystemZ::isImmLF(N->getZExtValue());
}], LF32, "U32Imm">;
defm imm64hf32 : Immediate<i64, [{
- return SystemZ::isImmHF(N->getZExtValue());
+ return N->getAPIntValue().isIntN(64) && SystemZ::isImmHF(N->getZExtValue());
}], HF32, "U32Imm">;
// Immediates for the lower and upper 32 bits of an i64, with the other
// bits of the i32 being one.
defm imm64lf32c : Immediate<i64, [{
- return SystemZ::isImmLF(uint64_t(~N->getZExtValue()));
+ return N->getAPIntValue().isIntN(64) &&
+ SystemZ::isImmLF(uint64_t(~N->getZExtValue()));
}], LF32, "U32Imm">;
defm imm64hf32c : Immediate<i64, [{
- return SystemZ::isImmHF(uint64_t(~N->getZExtValue()));
+ return N->getAPIntValue().isIntN(64) &&
+ SystemZ::isImmHF(uint64_t(~N->getZExtValue()));
}], HF32, "U32Imm">;
// Negated immediates that fit LF32 or LH16.
defm imm64lh16n : Immediate<i64, [{
- return SystemZ::isImmLH(uint64_t(-N->getZExtValue()));
+ return N->getAPIntValue().isIntN(64) &&
+ SystemZ::isImmLH(uint64_t(-N->getZExtValue()));
}], NEGLH16, "U16Imm">;
defm imm64lf32n : Immediate<i64, [{
- return SystemZ::isImmLF(uint64_t(-N->getZExtValue()));
+ return N->getAPIntValue().isIntN(64) &&
+ SystemZ::isImmLF(uint64_t(-N->getZExtValue()));
}], NEGLF32, "U32Imm">;
// Short immediates.
defm imm64sx8 : Immediate<i64, [{
- return isInt<8>(N->getSExtValue());
+ return N->getAPIntValue().isSignedIntN(8);
}], SIMM8, "S8Imm">;
defm imm64zx8 : Immediate<i64, [{
- return isUInt<8>(N->getSExtValue());
+ return N->getAPIntValue().isIntN(8);;
}], UIMM8, "U8Imm">;
defm imm64sx16 : Immediate<i64, [{
- return isInt<16>(N->getSExtValue());
+ return N->getAPIntValue().isSignedIntN(16);
}], SIMM16, "S16Imm">;
defm imm64sx16n : Immediate<i64, [{
- return isInt<16>(-N->getSExtValue());
+ return (-N->getAPIntValue()).isSignedIntN(16);
}], NEGSIMM16, "S16Imm">;
defm imm64zx16 : Immediate<i64, [{
- return isUInt<16>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(16);
}], UIMM16, "U16Imm">;
defm imm64sx32 : Immediate<i64, [{
- return isInt<32>(N->getSExtValue());
+ return N->getAPIntValue().isSignedIntN(32);
}], SIMM32, "S32Imm">;
defm imm64sx32n : Immediate<i64, [{
- return isInt<32>(-N->getSExtValue());
+ return (-N->getAPIntValue()).isSignedIntN(32);
}], NEGSIMM32, "S32Imm">;
defm imm64zx32 : Immediate<i64, [{
- return isUInt<32>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(32);
}], UIMM32, "U32Imm">;
defm imm64zx32n : Immediate<i64, [{
- return isUInt<32>(-N->getSExtValue());
+ return (-N->getAPIntValue()).isIntN(32);
}], NEGUIMM32, "U32Imm">;
defm imm64zx48 : Immediate<i64, [{
- return isUInt<64>(N->getZExtValue());
+ return N->getAPIntValue().isIntN(64);
}], UIMM48, "U48Imm">;
class Imm64 : ImmLeaf<i64, [{}]>, Operand<i64> {
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index 4f0f23fe3ef8..af6cf340f8a3 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -59,6 +59,15 @@ def SDT_ZBinaryWithCarry : SDTypeProfile<2, 3,
SDTCisSameAs<0, 2>,
SDTCisSameAs<0, 3>,
SDTCisVT<1, i32>]>;
+def SDT_ZBinaryConv : SDTypeProfile<1, 2,
+ [SDTCisInt<0>,
+ SDTCisInt<1>,
+ SDTCisSameAs<1, 2>]>;
+def SDT_ZTernary : SDTypeProfile<1, 3,
+ [SDTCisInt<0>,
+ SDTCisSameAs<0, 1>,
+ SDTCisSameAs<0, 2>,
+ SDTCisSameAs<0, 3>]>;
def SDT_ZAtomicLoadBinaryW : SDTypeProfile<1, 5,
[SDTCisVT<0, i32>,
SDTCisPtrTy<1>,
@@ -283,6 +292,12 @@ def z_uaddo : SDNode<"SystemZISD::UADDO", SDT_ZBinaryWithFlags>;
def z_usubo : SDNode<"SystemZISD::USUBO", SDT_ZBinaryWithFlags>;
def z_addcarry_1 : SDNode<"SystemZISD::ADDCARRY", SDT_ZBinaryWithCarry>;
def z_subcarry_1 : SDNode<"SystemZISD::SUBCARRY", SDT_ZBinaryWithCarry>;
+def z_vacc : SDNode<"SystemZISD::VACC", SDTIntBinOp>;
+def z_vac : SDNode<"SystemZISD::VAC", SDT_ZTernary>;
+def z_vaccc : SDNode<"SystemZISD::VACCC", SDT_ZTernary>;
+def z_vscbi : SDNode<"SystemZISD::VSCBI", SDTIntBinOp>;
+def z_vsbi : SDNode<"SystemZISD::VSBI", SDT_ZTernary>;
+def z_vsbcbi : SDNode<"SystemZISD::VSBCBI", SDT_ZTernary>;
def z_loadbswap : SDNode<"SystemZISD::LRV", SDTLoad,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
@@ -326,7 +341,7 @@ def z_vsra_by_scalar : SDNode<"SystemZISD::VSRA_BY_SCALAR",
SDT_ZVecBinaryInt>;
def z_vrotl_by_scalar : SDNode<"SystemZISD::VROTL_BY_SCALAR",
SDT_ZVecBinaryInt>;
-def z_vsum : SDNode<"SystemZISD::VSUM", SDT_ZVecBinaryConv>;
+def z_vsum : SDNode<"SystemZISD::VSUM", SDT_ZBinaryConv>;
def z_vicmpe : SDNode<"SystemZISD::VICMPE", SDT_ZVecBinary>;
def z_vicmph : SDNode<"SystemZISD::VICMPH", SDT_ZVecBinary>;
def z_vicmphl : SDNode<"SystemZISD::VICMPHL", SDT_ZVecBinary>;
@@ -358,6 +373,8 @@ def z_vround : SDNode<"SystemZISD::VROUND", SDT_ZVecUnaryConv>;
def z_strict_vround : SDNode<"SystemZISD::STRICT_VROUND",
SDT_ZVecUnaryConv, [SDNPHasChain]>;
def z_vtm : SDNode<"SystemZISD::VTM", SDT_ZCmp>;
+def z_scmp128hi : SDNode<"SystemZISD::SCMP128HI", SDT_ZCmp>;
+def z_ucmp128hi : SDNode<"SystemZISD::UCMP128HI", SDT_ZCmp>;
def z_vfae_cc : SDNode<"SystemZISD::VFAE_CC", SDT_ZVecTernaryIntCC>;
def z_vfaez_cc : SDNode<"SystemZISD::VFAEZ_CC", SDT_ZVecTernaryIntCC>;
def z_vfee_cc : SDNode<"SystemZISD::VFEE_CC", SDT_ZVecBinaryCC>;
@@ -757,10 +774,27 @@ class shiftop<SDPatternOperator operator>
[(operator node:$val, node:$count),
(operator node:$val, (and node:$count, imm32bottom6set))]>;
+// Create a shift operator that optionally ignores an AND of the
+// shift count with an immediate if the bottom 7 bits are all set.
+def imm32bottom7set : PatLeaf<(i32 imm), [{
+ return (N->getZExtValue() & 0x7f) == 0x7f;
+}]>;
+class vshiftop<SDPatternOperator operator>
+ : PatFrags<(ops node:$val, node:$count),
+ [(operator node:$val, node:$count),
+ (operator node:$val, (and node:$count, imm32bottom7set))]>;
+
def imm32mod64 : PatLeaf<(i32 imm), [{
return (N->getZExtValue() % 64 == 0);
}]>;
+def imm32nobits : PatLeaf<(i32 imm), [{
+ return (N->getZExtValue() & 0x07) == 0;
+}]>;
+def imm32nobytes : PatLeaf<(i32 imm), [{
+ return (N->getZExtValue() & 0x78) == 0;
+}]>;
+
// Load a scalar and replicate it in all elements of a vector.
class z_replicate_load<ValueType scalartype, SDPatternOperator load>
: PatFrag<(ops node:$addr),
diff --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
index 4d6b94da3a27..d5313acd8785 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
@@ -377,12 +377,12 @@ SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
}
bool SystemZRegisterInfo::shouldCoalesce(MachineInstr *MI,
- const TargetRegisterClass *SrcRC,
- unsigned SubReg,
- const TargetRegisterClass *DstRC,
- unsigned DstSubReg,
- const TargetRegisterClass *NewRC,
- LiveIntervals &LIS) const {
+ const TargetRegisterClass *SrcRC,
+ unsigned SubReg,
+ const TargetRegisterClass *DstRC,
+ unsigned DstSubReg,
+ const TargetRegisterClass *NewRC,
+ LiveIntervals &LIS) const {
assert (MI->isCopy() && "Only expecting COPY instructions");
// Coalesce anything which is not a COPY involving a subreg to/from GR128.
@@ -390,44 +390,26 @@ bool SystemZRegisterInfo::shouldCoalesce(MachineInstr *MI,
(getRegSizeInBits(*SrcRC) <= 64 || getRegSizeInBits(*DstRC) <= 64)))
return true;
- // Allow coalescing of a GR128 subreg COPY only if the live ranges are small
- // and local to one MBB with not too much interferring registers. Otherwise
+ // Allow coalescing of a GR128 subreg COPY only if the subreg liverange is
+ // local to one MBB with not too many interferring physreg clobbers. Otherwise
// regalloc may run out of registers.
+ unsigned SubregOpIdx = getRegSizeInBits(*SrcRC) == 128 ? 0 : 1;
+ LiveInterval &LI = LIS.getInterval(MI->getOperand(SubregOpIdx).getReg());
- unsigned WideOpNo = (getRegSizeInBits(*SrcRC) == 128 ? 1 : 0);
- Register GR128Reg = MI->getOperand(WideOpNo).getReg();
- Register GRNarReg = MI->getOperand((WideOpNo == 1) ? 0 : 1).getReg();
- LiveInterval &IntGR128 = LIS.getInterval(GR128Reg);
- LiveInterval &IntGRNar = LIS.getInterval(GRNarReg);
-
- // Check that the two virtual registers are local to MBB.
+ // Check that the subreg is local to MBB.
MachineBasicBlock *MBB = MI->getParent();
- MachineInstr *FirstMI_GR128 =
- LIS.getInstructionFromIndex(IntGR128.beginIndex());
- MachineInstr *FirstMI_GRNar =
- LIS.getInstructionFromIndex(IntGRNar.beginIndex());
- MachineInstr *LastMI_GR128 = LIS.getInstructionFromIndex(IntGR128.endIndex());
- MachineInstr *LastMI_GRNar = LIS.getInstructionFromIndex(IntGRNar.endIndex());
- if ((!FirstMI_GR128 || FirstMI_GR128->getParent() != MBB) ||
- (!FirstMI_GRNar || FirstMI_GRNar->getParent() != MBB) ||
- (!LastMI_GR128 || LastMI_GR128->getParent() != MBB) ||
- (!LastMI_GRNar || LastMI_GRNar->getParent() != MBB))
+ MachineInstr *FirstMI = LIS.getInstructionFromIndex(LI.beginIndex());
+ MachineInstr *LastMI = LIS.getInstructionFromIndex(LI.endIndex());
+ if (!FirstMI || FirstMI->getParent() != MBB ||
+ !LastMI || LastMI->getParent() != MBB)
return false;
- MachineBasicBlock::iterator MII = nullptr, MEE = nullptr;
- if (WideOpNo == 1) {
- MII = FirstMI_GR128;
- MEE = LastMI_GRNar;
- } else {
- MII = FirstMI_GRNar;
- MEE = LastMI_GR128;
- }
-
// Check if coalescing seems safe by finding the set of clobbered physreg
// pairs in the region.
BitVector PhysClobbered(getNumRegs());
- MEE++;
- for (; MII != MEE; ++MII) {
+ for (MachineBasicBlock::iterator MII = FirstMI,
+ MEE = std::next(LastMI->getIterator());
+ MII != MEE; ++MII)
for (const MachineOperand &MO : MII->operands())
if (MO.isReg() && MO.getReg().isPhysical()) {
for (MCPhysReg SI : superregs_inclusive(MO.getReg()))
@@ -436,7 +418,6 @@ bool SystemZRegisterInfo::shouldCoalesce(MachineInstr *MI,
break;
}
}
- }
// Demand an arbitrary margin of free regs.
unsigned const DemandedFreeGR128 = 3;
diff --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td
index 5d66501172b2..8f9bb56f2eb3 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td
@@ -124,7 +124,7 @@ defm GRX32 : SystemZRegClass<"GRX32", [i32], 32,
R12L,R12H,R13L,R13H,R14L,R14H,R15L,R15H)
]>;
-// The architecture doesn't really have any i128 support, so model the
+// On machines without SIMD support, i128 is not a legal type, so model the
// register pairs as untyped instead.
// XPLINK64: Allocate all registers in natural order
defm GR128 : SystemZRegClass<"GR128", [untyped], 128,
@@ -285,7 +285,8 @@ defm VF128 : SystemZRegClass<"VF128",
// All vector registers.
defm VR128 : SystemZRegClass<"VR128",
- [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64, f128],
+ [v16i8, v8i16, v4i32, v2i64, i128,
+ v4f32, v2f64, f128],
128, (add (sequence "V%u", 0, 7),
(sequence "V%u", 16, 31),
(sequence "V%u", 8, 15))>;
@@ -305,7 +306,7 @@ def v128b : TypedReg<v16i8, VR128>;
def v128h : TypedReg<v8i16, VR128>;
def v128f : TypedReg<v4i32, VR128>;
def v128g : TypedReg<v2i64, VR128>;
-def v128q : TypedReg<v16i8, VR128>;
+def v128q : TypedReg<i128, VR128>;
def v128sb : TypedReg<v4f32, VR128>;
def v128db : TypedReg<v2f64, VR128>;
def v128xb : TypedReg<f128, VR128>;
diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp
index ff496d29b391..3f96bd37755e 100644
--- a/llvm/lib/Target/TargetMachine.cpp
+++ b/llvm/lib/Target/TargetMachine.cpp
@@ -39,14 +39,21 @@ TargetMachine::TargetMachine(const Target &T, StringRef DataLayoutString,
TargetMachine::~TargetMachine() = default;
-bool TargetMachine::isLargeGlobalObject(const GlobalObject *GO) const {
+bool TargetMachine::isLargeGlobalValue(const GlobalValue *GVal) const {
if (getTargetTriple().getArch() != Triple::x86_64)
return false;
- if (isa<Function>(GO))
- return getCodeModel() == CodeModel::Large;
+ auto *GO = GVal->getAliaseeObject();
+
+ // Be conservative if we can't find an underlying GlobalObject.
+ if (!GO)
+ return true;
+
+ auto *GV = dyn_cast<GlobalVariable>(GO);
- auto *GV = cast<GlobalVariable>(GO);
+ // Functions/GlobalIFuncs are only large under the large code model.
+ if (!GV)
+ return getCodeModel() == CodeModel::Large;
if (GV->isThreadLocal())
return false;
@@ -54,6 +61,8 @@ bool TargetMachine::isLargeGlobalObject(const GlobalObject *GO) const {
// We should properly mark well-known section name prefixes as small/large,
// because otherwise the output section may have the wrong section flags and
// the linker will lay it out in an unexpected way.
+ // TODO: bring back lbss/ldata/lrodata checks after fixing accesses to large
+ // globals in the small code model.
StringRef Name = GV->getSection();
if (!Name.empty()) {
auto IsPrefix = [&](StringRef Prefix) {
@@ -62,8 +71,6 @@ bool TargetMachine::isLargeGlobalObject(const GlobalObject *GO) const {
};
if (IsPrefix(".bss") || IsPrefix(".data") || IsPrefix(".rodata"))
return false;
- if (IsPrefix(".lbss") || IsPrefix(".ldata") || IsPrefix(".lrodata"))
- return true;
}
// For x86-64, we treat an explicit GlobalVariable small code model to mean
@@ -78,6 +85,8 @@ bool TargetMachine::isLargeGlobalObject(const GlobalObject *GO) const {
if (getCodeModel() == CodeModel::Medium ||
getCodeModel() == CodeModel::Large) {
+ if (!GV->getValueType()->isSized())
+ return true;
const DataLayout &DL = GV->getParent()->getDataLayout();
uint64_t Size = DL.getTypeSizeInBits(GV->getValueType()) / 8;
return Size == 0 || Size > LargeDataThreshold;
diff --git a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp
index 19dd6c83b750..21d5f7653a68 100644
--- a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp
+++ b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp
@@ -923,31 +923,35 @@ StringRef VEAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc,
(Name[Next + 1] == 'd' || Name[Next + 1] == 's'))
ICC = false;
Mnemonic = parseCC(Name, Start, Next, ICC, true, NameLoc, Operands);
- } else if (Name.startswith("cmov.l.") || Name.startswith("cmov.w.") ||
- Name.startswith("cmov.d.") || Name.startswith("cmov.s.")) {
+ } else if (Name.starts_with("cmov.l.") || Name.starts_with("cmov.w.") ||
+ Name.starts_with("cmov.d.") || Name.starts_with("cmov.s.")) {
bool ICC = Name[5] == 'l' || Name[5] == 'w';
Mnemonic = parseCC(Name, 7, Name.size(), ICC, false, NameLoc, Operands);
- } else if (Name.startswith("cvt.w.d.sx") || Name.startswith("cvt.w.d.zx") ||
- Name.startswith("cvt.w.s.sx") || Name.startswith("cvt.w.s.zx")) {
+ } else if (Name.starts_with("cvt.w.d.sx") || Name.starts_with("cvt.w.d.zx") ||
+ Name.starts_with("cvt.w.s.sx") || Name.starts_with("cvt.w.s.zx")) {
Mnemonic = parseRD(Name, 10, NameLoc, Operands);
- } else if (Name.startswith("cvt.l.d")) {
+ } else if (Name.starts_with("cvt.l.d")) {
Mnemonic = parseRD(Name, 7, NameLoc, Operands);
- } else if (Name.startswith("vcvt.w.d.sx") || Name.startswith("vcvt.w.d.zx") ||
- Name.startswith("vcvt.w.s.sx") || Name.startswith("vcvt.w.s.zx")) {
+ } else if (Name.starts_with("vcvt.w.d.sx") ||
+ Name.starts_with("vcvt.w.d.zx") ||
+ Name.starts_with("vcvt.w.s.sx") ||
+ Name.starts_with("vcvt.w.s.zx")) {
Mnemonic = parseRD(Name, 11, NameLoc, Operands);
- } else if (Name.startswith("vcvt.l.d")) {
+ } else if (Name.starts_with("vcvt.l.d")) {
Mnemonic = parseRD(Name, 8, NameLoc, Operands);
- } else if (Name.startswith("pvcvt.w.s.lo") ||
- Name.startswith("pvcvt.w.s.up")) {
+ } else if (Name.starts_with("pvcvt.w.s.lo") ||
+ Name.starts_with("pvcvt.w.s.up")) {
Mnemonic = parseRD(Name, 12, NameLoc, Operands);
- } else if (Name.startswith("pvcvt.w.s")) {
+ } else if (Name.starts_with("pvcvt.w.s")) {
Mnemonic = parseRD(Name, 9, NameLoc, Operands);
- } else if (Name.startswith("vfmk.l.") || Name.startswith("vfmk.w.") ||
- Name.startswith("vfmk.d.") || Name.startswith("vfmk.s.")) {
+ } else if (Name.starts_with("vfmk.l.") || Name.starts_with("vfmk.w.") ||
+ Name.starts_with("vfmk.d.") || Name.starts_with("vfmk.s.")) {
bool ICC = Name[5] == 'l' || Name[5] == 'w' ? true : false;
Mnemonic = parseCC(Name, 7, Name.size(), ICC, true, NameLoc, Operands);
- } else if (Name.startswith("pvfmk.w.lo.") || Name.startswith("pvfmk.w.up.") ||
- Name.startswith("pvfmk.s.lo.") || Name.startswith("pvfmk.s.up.")) {
+ } else if (Name.starts_with("pvfmk.w.lo.") ||
+ Name.starts_with("pvfmk.w.up.") ||
+ Name.starts_with("pvfmk.s.lo.") ||
+ Name.starts_with("pvfmk.s.up.")) {
bool ICC = Name[6] == 'l' || Name[6] == 'w' ? true : false;
Mnemonic = parseCC(Name, 11, Name.size(), ICC, true, NameLoc, Operands);
} else {
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index b70fa957a859..1b92997f03f1 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -1103,7 +1103,7 @@ public:
// object writer expects each function to have its own section. This way
// The user can't forget this "convention".
auto SymName = Symbol->getName();
- if (SymName.startswith(".L"))
+ if (SymName.starts_with(".L"))
return; // Local Symbol.
// TODO: If the user explicitly creates a new function section, we ignore
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 2c1ec21ba17d..908efbb8d321 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -104,7 +104,7 @@ WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
static bool isEmscriptenInvokeName(StringRef Name) {
if (Name.front() == '"' && Name.back() == '"')
Name = Name.substr(1, Name.size() - 2);
- return Name.startswith("__invoke_");
+ return Name.starts_with("__invoke_");
}
// Returns a character that represents the given wasm value type in invoke
@@ -235,7 +235,7 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) {
return WasmSym;
}
- if (Name.startswith("GCC_except_table")) {
+ if (Name.starts_with("GCC_except_table")) {
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA);
return WasmSym;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index 5e84fff351b2..77e6640d5a82 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -623,7 +623,7 @@ static bool canLongjmp(const Value *Callee) {
return false;
// __cxa_find_matching_catch_N functions cannot longjmp
- if (Callee->getName().startswith("__cxa_find_matching_catch_"))
+ if (Callee->getName().starts_with("__cxa_find_matching_catch_"))
return false;
// Exception-catching related functions
@@ -1517,7 +1517,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
Value *Threw = nullptr;
BasicBlock *Tail;
- if (Callee->getName().startswith("__invoke_")) {
+ if (Callee->getName().starts_with("__invoke_")) {
// If invoke wrapper has already been generated for this call in
// previous EH phase, search for the load instruction
// %__THREW__.val = __THREW__;
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index 32ede8558efe..e78d16056460 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -1417,7 +1417,7 @@ bool X86AsmParser::MatchRegisterByName(MCRegister &RegNo, StringRef RegName,
// If this is "db[0-15]", match it as an alias
// for dr[0-15].
- if (RegNo == 0 && RegName.startswith("db")) {
+ if (RegNo == 0 && RegName.starts_with("db")) {
if (RegName.size() == 3) {
switch (RegName[2]) {
case '0':
@@ -2072,7 +2072,7 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
Lex(); // eat type
bool EndDot = parseOptionalToken(AsmToken::Dot);
while (EndDot || (getTok().is(AsmToken::Identifier) &&
- getTok().getString().startswith("."))) {
+ getTok().getString().starts_with("."))) {
getParser().parseIdentifier(Identifier);
if (!EndDot)
Identifier.consume_front(".");
@@ -2271,7 +2271,7 @@ bool X86AsmParser::ParseRoundingModeOp(SMLoc Start, OperandVector &Operands) {
const SMLoc consumedToken = consumeToken();
if (Tok.isNot(AsmToken::Identifier))
return Error(Tok.getLoc(), "Expected an identifier after {");
- if (Tok.getIdentifier().startswith("r")){
+ if (Tok.getIdentifier().starts_with("r")) {
int rndMode = StringSwitch<int>(Tok.getIdentifier())
.Case("rn", X86::STATIC_ROUNDING::TO_NEAREST_INT)
.Case("rd", X86::STATIC_ROUNDING::TO_NEG_INF)
@@ -2313,7 +2313,7 @@ bool X86AsmParser::ParseIntelDotOperator(IntelExprStateMachine &SM,
// Drop the optional '.'.
StringRef DotDispStr = Tok.getString();
- if (DotDispStr.startswith("."))
+ if (DotDispStr.starts_with("."))
DotDispStr = DotDispStr.drop_front(1);
StringRef TrailingDot;
@@ -2325,7 +2325,7 @@ bool X86AsmParser::ParseIntelDotOperator(IntelExprStateMachine &SM,
Info.Offset = DotDisp.getZExtValue();
} else if ((isParsingMSInlineAsm() || getParser().isParsingMasm()) &&
Tok.is(AsmToken::Identifier)) {
- if (DotDispStr.endswith(".")) {
+ if (DotDispStr.ends_with(".")) {
TrailingDot = DotDispStr.substr(DotDispStr.size() - 1);
DotDispStr = DotDispStr.drop_back(1);
}
@@ -2815,7 +2815,7 @@ bool X86AsmParser::HandleAVX512Operand(OperandVector &Operands) {
SmallVector<char, 5> BroadcastVector;
StringRef BroadcastString = (Prefix + getLexer().getTok().getIdentifier())
.toStringRef(BroadcastVector);
- if (!BroadcastString.startswith("1to"))
+ if (!BroadcastString.starts_with("1to"))
return TokError("Expected 1to<NUM> at this point");
const char *BroadcastPrimitive =
StringSwitch<const char *>(BroadcastString)
@@ -3174,7 +3174,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
if (isParsingIntelSyntax() &&
(PatchedName == "jmp" || PatchedName == "jc" || PatchedName == "jnc" ||
PatchedName == "jcxz" || PatchedName == "jecxz" ||
- (PatchedName.startswith("j") &&
+ (PatchedName.starts_with("j") &&
ParseConditionCode(PatchedName.substr(1)) != X86::COND_INVALID))) {
StringRef NextTok = Parser.getTok().getString();
if (Parser.isParsingMasm() ? NextTok.equals_insensitive("short")
@@ -3192,17 +3192,17 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
// FIXME: Hack to recognize setneb as setne.
- if (PatchedName.startswith("set") && PatchedName.endswith("b") &&
+ if (PatchedName.starts_with("set") && PatchedName.ends_with("b") &&
PatchedName != "setb" && PatchedName != "setnb")
PatchedName = PatchedName.substr(0, Name.size()-1);
unsigned ComparisonPredicate = ~0U;
// FIXME: Hack to recognize cmp<comparison code>{sh,ss,sd,ph,ps,pd}.
- if ((PatchedName.startswith("cmp") || PatchedName.startswith("vcmp")) &&
- (PatchedName.endswith("ss") || PatchedName.endswith("sd") ||
- PatchedName.endswith("sh") || PatchedName.endswith("ph") ||
- PatchedName.endswith("ps") || PatchedName.endswith("pd"))) {
+ if ((PatchedName.starts_with("cmp") || PatchedName.starts_with("vcmp")) &&
+ (PatchedName.ends_with("ss") || PatchedName.ends_with("sd") ||
+ PatchedName.ends_with("sh") || PatchedName.ends_with("ph") ||
+ PatchedName.ends_with("ps") || PatchedName.ends_with("pd"))) {
bool IsVCMP = PatchedName[0] == 'v';
unsigned CCIdx = IsVCMP ? 4 : 3;
unsigned CC = StringSwitch<unsigned>(
@@ -3257,17 +3257,17 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
.Default(~0U);
if (CC != ~0U && (IsVCMP || CC < 8) &&
(IsVCMP || PatchedName.back() != 'h')) {
- if (PatchedName.endswith("ss"))
+ if (PatchedName.ends_with("ss"))
PatchedName = IsVCMP ? "vcmpss" : "cmpss";
- else if (PatchedName.endswith("sd"))
+ else if (PatchedName.ends_with("sd"))
PatchedName = IsVCMP ? "vcmpsd" : "cmpsd";
- else if (PatchedName.endswith("ps"))
+ else if (PatchedName.ends_with("ps"))
PatchedName = IsVCMP ? "vcmpps" : "cmpps";
- else if (PatchedName.endswith("pd"))
+ else if (PatchedName.ends_with("pd"))
PatchedName = IsVCMP ? "vcmppd" : "cmppd";
- else if (PatchedName.endswith("sh"))
+ else if (PatchedName.ends_with("sh"))
PatchedName = "vcmpsh";
- else if (PatchedName.endswith("ph"))
+ else if (PatchedName.ends_with("ph"))
PatchedName = "vcmpph";
else
llvm_unreachable("Unexpected suffix!");
@@ -3277,7 +3277,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
// FIXME: Hack to recognize vpcmp<comparison code>{ub,uw,ud,uq,b,w,d,q}.
- if (PatchedName.startswith("vpcmp") &&
+ if (PatchedName.starts_with("vpcmp") &&
(PatchedName.back() == 'b' || PatchedName.back() == 'w' ||
PatchedName.back() == 'd' || PatchedName.back() == 'q')) {
unsigned SuffixSize = PatchedName.drop_back().back() == 'u' ? 2 : 1;
@@ -3306,7 +3306,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
// FIXME: Hack to recognize vpcom<comparison code>{ub,uw,ud,uq,b,w,d,q}.
- if (PatchedName.startswith("vpcom") &&
+ if (PatchedName.starts_with("vpcom") &&
(PatchedName.back() == 'b' || PatchedName.back() == 'w' ||
PatchedName.back() == 'd' || PatchedName.back() == 'q')) {
unsigned SuffixSize = PatchedName.drop_back().back() == 'u' ? 2 : 1;
@@ -3334,7 +3334,6 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
}
-
// Determine whether this is an instruction prefix.
// FIXME:
// Enhance prefixes integrity robustness. for example, following forms
@@ -3380,9 +3379,9 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
Parser.Lex(); // eat the prefix
// Hack: we could have something like "rep # some comment" or
// "lock; cmpxchg16b $1" or "lock\0A\09incl" or "lock/incl"
- while (Name.startswith(";") || Name.startswith("\n") ||
- Name.startswith("#") || Name.startswith("\t") ||
- Name.startswith("/")) {
+ while (Name.starts_with(";") || Name.starts_with("\n") ||
+ Name.starts_with("#") || Name.starts_with("\t") ||
+ Name.starts_with("/")) {
// FIXME: The mnemonic won't match correctly if its not in lower case.
Name = Parser.getTok().getString();
Parser.Lex(); // go to next prefix or instr
@@ -3541,7 +3540,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
bool HadVerifyError = false;
// Append default arguments to "ins[bwld]"
- if (Name.startswith("ins") &&
+ if (Name.starts_with("ins") &&
(Operands.size() == 1 || Operands.size() == 3) &&
(Name == "insb" || Name == "insw" || Name == "insl" || Name == "insd" ||
Name == "ins")) {
@@ -3553,7 +3552,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
// Append default arguments to "outs[bwld]"
- if (Name.startswith("outs") &&
+ if (Name.starts_with("outs") &&
(Operands.size() == 1 || Operands.size() == 3) &&
(Name == "outsb" || Name == "outsw" || Name == "outsl" ||
Name == "outsd" || Name == "outs")) {
@@ -3565,7 +3564,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// Transform "lods[bwlq]" into "lods[bwlq] ($SIREG)" for appropriate
// values of $SIREG according to the mode. It would be nice if this
// could be achieved with InstAlias in the tables.
- if (Name.startswith("lods") &&
+ if (Name.starts_with("lods") &&
(Operands.size() == 1 || Operands.size() == 2) &&
(Name == "lods" || Name == "lodsb" || Name == "lodsw" ||
Name == "lodsl" || Name == "lodsd" || Name == "lodsq")) {
@@ -3576,7 +3575,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// Transform "stos[bwlq]" into "stos[bwlq] ($DIREG)" for appropriate
// values of $DIREG according to the mode. It would be nice if this
// could be achieved with InstAlias in the tables.
- if (Name.startswith("stos") &&
+ if (Name.starts_with("stos") &&
(Operands.size() == 1 || Operands.size() == 2) &&
(Name == "stos" || Name == "stosb" || Name == "stosw" ||
Name == "stosl" || Name == "stosd" || Name == "stosq")) {
@@ -3587,7 +3586,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// Transform "scas[bwlq]" into "scas[bwlq] ($DIREG)" for appropriate
// values of $DIREG according to the mode. It would be nice if this
// could be achieved with InstAlias in the tables.
- if (Name.startswith("scas") &&
+ if (Name.starts_with("scas") &&
(Operands.size() == 1 || Operands.size() == 2) &&
(Name == "scas" || Name == "scasb" || Name == "scasw" ||
Name == "scasl" || Name == "scasd" || Name == "scasq")) {
@@ -3596,7 +3595,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
// Add default SI and DI operands to "cmps[bwlq]".
- if (Name.startswith("cmps") &&
+ if (Name.starts_with("cmps") &&
(Operands.size() == 1 || Operands.size() == 3) &&
(Name == "cmps" || Name == "cmpsb" || Name == "cmpsw" ||
Name == "cmpsl" || Name == "cmpsd" || Name == "cmpsq")) {
@@ -3606,10 +3605,10 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
// Add default SI and DI operands to "movs[bwlq]".
- if (((Name.startswith("movs") &&
+ if (((Name.starts_with("movs") &&
(Name == "movs" || Name == "movsb" || Name == "movsw" ||
Name == "movsl" || Name == "movsd" || Name == "movsq")) ||
- (Name.startswith("smov") &&
+ (Name.starts_with("smov") &&
(Name == "smov" || Name == "smovb" || Name == "smovw" ||
Name == "smovl" || Name == "smovd" || Name == "smovq"))) &&
(Operands.size() == 1 || Operands.size() == 3)) {
@@ -4472,11 +4471,11 @@ bool X86AsmParser::OmitRegisterFromClobberLists(unsigned RegNo) {
bool X86AsmParser::ParseDirective(AsmToken DirectiveID) {
MCAsmParser &Parser = getParser();
StringRef IDVal = DirectiveID.getIdentifier();
- if (IDVal.startswith(".arch"))
+ if (IDVal.starts_with(".arch"))
return parseDirectiveArch();
- if (IDVal.startswith(".code"))
+ if (IDVal.starts_with(".code"))
return ParseDirectiveCode(IDVal, DirectiveID.getLoc());
- else if (IDVal.startswith(".att_syntax")) {
+ else if (IDVal.starts_with(".att_syntax")) {
if (getLexer().isNot(AsmToken::EndOfStatement)) {
if (Parser.getTok().getString() == "prefix")
Parser.Lex();
@@ -4487,7 +4486,7 @@ bool X86AsmParser::ParseDirective(AsmToken DirectiveID) {
}
getParser().setAssemblerDialect(0);
return false;
- } else if (IDVal.startswith(".intel_syntax")) {
+ } else if (IDVal.starts_with(".intel_syntax")) {
getParser().setAssemblerDialect(1);
if (getLexer().isNot(AsmToken::EndOfStatement)) {
if (Parser.getTok().getString() == "noprefix")
diff --git a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
index d50e6514b86d..59e2008f5632 100644
--- a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
+++ b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
@@ -1330,7 +1330,8 @@ static int getInstructionID(struct InternalInstruction *insn,
// any position.
if ((insn->opcodeType == ONEBYTE && ((insn->opcode & 0xFC) == 0xA0)) ||
(insn->opcodeType == TWOBYTE && (insn->opcode == 0xAE)) ||
- (insn->opcodeType == THREEBYTE_38 && insn->opcode == 0xF8)) {
+ (insn->opcodeType == THREEBYTE_38 && insn->opcode == 0xF8) ||
+ (insn->opcodeType == MAP4 && insn->opcode == 0xF8)) {
// Make sure we observed the prefixes in any position.
if (insn->hasAdSize)
attrMask |= ATTR_ADSIZE;
diff --git a/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp b/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
index 6157dafb5c51..d7a10f45cb5f 100644
--- a/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
+++ b/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
@@ -20,6 +20,7 @@
#include "X86Subtarget.h"
#include "X86TargetMachine.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
+#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/LowLevelType.h"
@@ -116,6 +117,8 @@ private:
bool selectImplicitDefOrPHI(MachineInstr &I, MachineRegisterInfo &MRI) const;
bool selectMulDivRem(MachineInstr &I, MachineRegisterInfo &MRI,
MachineFunction &MF) const;
+ bool selectSelect(MachineInstr &I, MachineRegisterInfo &MRI,
+ MachineFunction &MF) const;
bool selectIntrinsicWSideEffects(MachineInstr &I, MachineRegisterInfo &MRI,
MachineFunction &MF) const;
@@ -429,6 +432,8 @@ bool X86InstructionSelector::select(MachineInstr &I) {
case TargetOpcode::G_SREM:
case TargetOpcode::G_UREM:
return selectMulDivRem(I, MRI, MF);
+ case TargetOpcode::G_SELECT:
+ return selectSelect(I, MRI, MF);
case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
return selectIntrinsicWSideEffects(I, MRI, MF);
}
@@ -1789,6 +1794,49 @@ bool X86InstructionSelector::selectMulDivRem(MachineInstr &I,
return true;
}
+bool X86InstructionSelector::selectSelect(MachineInstr &I,
+ MachineRegisterInfo &MRI,
+ MachineFunction &MF) const {
+ GSelect &Sel = cast<GSelect>(I);
+ unsigned DstReg = Sel.getReg(0);
+ BuildMI(*Sel.getParent(), Sel, Sel.getDebugLoc(), TII.get(X86::TEST32rr))
+ .addReg(Sel.getCondReg())
+ .addReg(Sel.getCondReg());
+
+ unsigned OpCmp;
+ LLT Ty = MRI.getType(DstReg);
+ switch (Ty.getSizeInBits()) {
+ default:
+ return false;
+ case 8:
+ OpCmp = X86::CMOV_GR8;
+ break;
+ case 16:
+ OpCmp = STI.canUseCMOV() ? X86::CMOV16rr : X86::CMOV_GR16;
+ break;
+ case 32:
+ OpCmp = STI.canUseCMOV() ? X86::CMOV32rr : X86::CMOV_GR32;
+ break;
+ case 64:
+ assert(STI.is64Bit() && STI.canUseCMOV());
+ OpCmp = X86::CMOV64rr;
+ break;
+ }
+ BuildMI(*Sel.getParent(), Sel, Sel.getDebugLoc(), TII.get(OpCmp), DstReg)
+ .addReg(Sel.getTrueReg())
+ .addReg(Sel.getFalseReg())
+ .addImm(X86::COND_E);
+
+ const TargetRegisterClass *DstRC = getRegClass(Ty, DstReg, MRI);
+ if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) {
+ LLVM_DEBUG(dbgs() << "Failed to constrain CMOV\n");
+ return false;
+ }
+
+ Sel.eraseFromParent();
+ return true;
+}
+
bool X86InstructionSelector::selectIntrinsicWSideEffects(
MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const {
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index 03af2b9e537c..27381dff338e 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -29,6 +29,7 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
: Subtarget(STI) {
bool Is64Bit = Subtarget.is64Bit();
+ bool HasCMOV = Subtarget.canUseCMOV();
bool HasSSE1 = Subtarget.hasSSE1();
bool HasSSE2 = Subtarget.hasSSE2();
bool HasSSE41 = Subtarget.hasSSE41();
@@ -521,11 +522,10 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
// todo: vectors and address spaces
getActionDefinitionsBuilder(G_SELECT)
- .legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32},
- {p0, s32}})
- .widenScalarToNextPow2(0, /*Min=*/8)
- .clampScalar(0, s8, sMaxScalar)
- .clampScalar(1, s32, s32);
+ .legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
+ .widenScalarToNextPow2(0, /*Min=*/8)
+ .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar)
+ .clampScalar(1, s32, s32);
// memory intrinsics
getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86InstComments.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86InstComments.cpp
index ee82faebb57e..20b37d5a9990 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86InstComments.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86InstComments.cpp
@@ -1285,8 +1285,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
Src2Name = getRegName(MI->getOperand(2).getReg());
break;
- case X86::VBROADCASTF128:
- case X86::VBROADCASTI128:
+ case X86::VBROADCASTF128rm:
+ case X86::VBROADCASTI128rm:
CASE_AVX512_INS_COMMON(BROADCASTF64X2, Z128, rm)
CASE_AVX512_INS_COMMON(BROADCASTI64X2, Z128, rm)
DecodeSubVectorBroadcast(4, 2, ShuffleMask);
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
index 165e9207ef1c..ed4d0a45bd8f 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
@@ -399,8 +399,8 @@ MCSubtargetInfo *X86_MC::createX86MCSubtargetInfo(const Triple &TT,
size_t posNoEVEX512 = FS.rfind("-evex512");
// Make sure we won't be cheated by "-avx512fp16".
- size_t posNoAVX512F = FS.endswith("-avx512f") ? FS.size() - 8
- : FS.rfind("-avx512f,");
+ size_t posNoAVX512F =
+ FS.ends_with("-avx512f") ? FS.size() - 8 : FS.rfind("-avx512f,");
size_t posEVEX512 = FS.rfind("+evex512");
size_t posAVX512F = FS.rfind("+avx512"); // Any AVX512XXX will enable AVX512F.
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 73c745062096..15cfd247f125 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -14,6 +14,7 @@
#include "X86AsmPrinter.h"
#include "MCTargetDesc/X86ATTInstPrinter.h"
#include "MCTargetDesc/X86BaseInfo.h"
+#include "MCTargetDesc/X86MCTargetDesc.h"
#include "MCTargetDesc/X86TargetStreamer.h"
#include "TargetInfo/X86TargetInfo.h"
#include "X86InstrInfo.h"
@@ -34,6 +35,7 @@
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCSectionCOFF.h"
#include "llvm/MC/MCSectionELF.h"
@@ -530,6 +532,86 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
O << ']';
}
+const MCSubtargetInfo *X86AsmPrinter::getIFuncMCSubtargetInfo() const {
+ assert(Subtarget);
+ return Subtarget;
+}
+
+void X86AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) {
+ // _ifunc:
+ // jmpq *lazy_pointer(%rip)
+
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::JMP32m)
+ .addReg(X86::RIP)
+ .addImm(1)
+ .addReg(0)
+ .addOperand(MCOperand::createExpr(
+ MCSymbolRefExpr::create(LazyPointer, OutContext)))
+ .addReg(0),
+ *Subtarget);
+}
+
+void X86AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
+ const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) {
+ // _ifunc.stub_helper:
+ // push %rax
+ // push %rdi
+ // push %rsi
+ // push %rdx
+ // push %rcx
+ // push %r8
+ // push %r9
+ // callq foo
+ // movq %rax,lazy_pointer(%rip)
+ // pop %r9
+ // pop %r8
+ // pop %rcx
+ // pop %rdx
+ // pop %rsi
+ // pop %rdi
+ // pop %rax
+ // jmpq *lazy_pointer(%rip)
+
+ for (int Reg :
+ {X86::RAX, X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9})
+ OutStreamer->emitInstruction(MCInstBuilder(X86::PUSH64r).addReg(Reg),
+ *Subtarget);
+
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::CALL64pcrel32)
+ .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
+ *Subtarget);
+
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::MOV64mr)
+ .addReg(X86::RIP)
+ .addImm(1)
+ .addReg(0)
+ .addOperand(MCOperand::createExpr(
+ MCSymbolRefExpr::create(LazyPointer, OutContext)))
+ .addReg(0)
+ .addReg(X86::RAX),
+ *Subtarget);
+
+ for (int Reg :
+ {X86::R9, X86::R8, X86::RCX, X86::RDX, X86::RSI, X86::RDI, X86::RAX})
+ OutStreamer->emitInstruction(MCInstBuilder(X86::POP64r).addReg(Reg),
+ *Subtarget);
+
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::JMP32m)
+ .addReg(X86::RIP)
+ .addImm(1)
+ .addReg(0)
+ .addOperand(MCOperand::createExpr(
+ MCSymbolRefExpr::create(LazyPointer, OutContext)))
+ .addReg(0),
+ *Subtarget);
+}
+
static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO,
char Mode, raw_ostream &O) {
Register Reg = MO.getReg();
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.h b/llvm/lib/Target/X86/X86AsmPrinter.h
index c81651cf7f2f..693021eca329 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.h
+++ b/llvm/lib/Target/X86/X86AsmPrinter.h
@@ -120,6 +120,11 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
const char *Modifier);
void PrintIntelMemReference(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O, const char *Modifier);
+ const MCSubtargetInfo *getIFuncMCSubtargetInfo() const override;
+ void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) override;
+ void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
+ MCSymbol *LazyPointer) override;
public:
X86AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
diff --git a/llvm/lib/Target/X86/X86FastISel.cpp b/llvm/lib/Target/X86/X86FastISel.cpp
index 068119a6332a..7f134fe1c72b 100644
--- a/llvm/lib/Target/X86/X86FastISel.cpp
+++ b/llvm/lib/Target/X86/X86FastISel.cpp
@@ -711,7 +711,12 @@ bool X86FastISel::handleConstantAddresses(const Value *V, X86AddressMode &AM) {
// Handle constant address.
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
// Can't handle alternate code models yet.
- if (TM.getCodeModel() != CodeModel::Small)
+ if (TM.getCodeModel() != CodeModel::Small &&
+ TM.getCodeModel() != CodeModel::Medium)
+ return false;
+
+ // Can't handle large objects yet.
+ if (TM.isLargeGlobalValue(GV))
return false;
// Can't handle TLS yet.
@@ -1044,7 +1049,8 @@ bool X86FastISel::X86SelectCallAddress(const Value *V, X86AddressMode &AM) {
// Handle constant address.
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
// Can't handle alternate code models yet.
- if (TM.getCodeModel() != CodeModel::Small)
+ if (TM.getCodeModel() != CodeModel::Small &&
+ TM.getCodeModel() != CodeModel::Medium)
return false;
// RIP-relative addresses can't have additional register operands.
@@ -3768,7 +3774,8 @@ unsigned X86FastISel::X86MaterializeFP(const ConstantFP *CFP, MVT VT) {
// Can't handle alternate code models yet.
CodeModel::Model CM = TM.getCodeModel();
- if (CM != CodeModel::Small && CM != CodeModel::Large)
+ if (CM != CodeModel::Small && CM != CodeModel::Medium &&
+ CM != CodeModel::Large)
return 0;
// Get opcode and regclass of the output for the given load instruction.
@@ -3806,7 +3813,7 @@ unsigned X86FastISel::X86MaterializeFP(const ConstantFP *CFP, MVT VT) {
PICBase = getInstrInfo()->getGlobalBaseReg(FuncInfo.MF);
else if (OpFlag == X86II::MO_GOTOFF)
PICBase = getInstrInfo()->getGlobalBaseReg(FuncInfo.MF);
- else if (Subtarget->is64Bit() && TM.getCodeModel() == CodeModel::Small)
+ else if (Subtarget->is64Bit() && TM.getCodeModel() != CodeModel::Large)
PICBase = X86::RIP;
// Create the load from the constant pool.
@@ -3836,8 +3843,11 @@ unsigned X86FastISel::X86MaterializeFP(const ConstantFP *CFP, MVT VT) {
}
unsigned X86FastISel::X86MaterializeGV(const GlobalValue *GV, MVT VT) {
- // Can't handle alternate code models yet.
- if (TM.getCodeModel() != CodeModel::Small)
+ // Can't handle large GlobalValues yet.
+ if (TM.getCodeModel() != CodeModel::Small &&
+ TM.getCodeModel() != CodeModel::Medium)
+ return 0;
+ if (TM.isLargeGlobalValue(GV))
return 0;
// Materialize addresses with LEA/MOV instructions.
diff --git a/llvm/lib/Target/X86/X86FixupVectorConstants.cpp b/llvm/lib/Target/X86/X86FixupVectorConstants.cpp
index 99e92bbcf996..483becebbe10 100644
--- a/llvm/lib/Target/X86/X86FixupVectorConstants.cpp
+++ b/llvm/lib/Target/X86/X86FixupVectorConstants.cpp
@@ -190,12 +190,13 @@ static Constant *rebuildSplatableConstant(const Constant *C,
Type *SclTy = OriginalType->getScalarType();
unsigned NumSclBits = SclTy->getPrimitiveSizeInBits();
NumSclBits = std::min<unsigned>(NumSclBits, SplatBitWidth);
+ LLVMContext &Ctx = OriginalType->getContext();
if (NumSclBits == 8) {
SmallVector<uint8_t> RawBits;
for (unsigned I = 0; I != SplatBitWidth; I += 8)
RawBits.push_back(Splat->extractBits(8, I).getZExtValue());
- return ConstantDataVector::get(OriginalType->getContext(), RawBits);
+ return ConstantDataVector::get(Ctx, RawBits);
}
if (NumSclBits == 16) {
@@ -204,7 +205,7 @@ static Constant *rebuildSplatableConstant(const Constant *C,
RawBits.push_back(Splat->extractBits(16, I).getZExtValue());
if (SclTy->is16bitFPTy())
return ConstantDataVector::getFP(SclTy, RawBits);
- return ConstantDataVector::get(OriginalType->getContext(), RawBits);
+ return ConstantDataVector::get(Ctx, RawBits);
}
if (NumSclBits == 32) {
@@ -213,7 +214,7 @@ static Constant *rebuildSplatableConstant(const Constant *C,
RawBits.push_back(Splat->extractBits(32, I).getZExtValue());
if (SclTy->isFloatTy())
return ConstantDataVector::getFP(SclTy, RawBits);
- return ConstantDataVector::get(OriginalType->getContext(), RawBits);
+ return ConstantDataVector::get(Ctx, RawBits);
}
// Fallback to i64 / double.
@@ -222,7 +223,7 @@ static Constant *rebuildSplatableConstant(const Constant *C,
RawBits.push_back(Splat->extractBits(64, I).getZExtValue());
if (SclTy->isDoubleTy())
return ConstantDataVector::getFP(SclTy, RawBits);
- return ConstantDataVector::get(OriginalType->getContext(), RawBits);
+ return ConstantDataVector::get(Ctx, RawBits);
}
bool X86FixupVectorConstantsPass::processInstruction(MachineFunction &MF,
@@ -285,7 +286,7 @@ bool X86FixupVectorConstantsPass::processInstruction(MachineFunction &MF,
case X86::VMOVAPSYrm:
case X86::VMOVUPDYrm:
case X86::VMOVUPSYrm:
- return ConvertToBroadcast(0, X86::VBROADCASTF128, X86::VBROADCASTSDYrm,
+ return ConvertToBroadcast(0, X86::VBROADCASTF128rm, X86::VBROADCASTSDYrm,
X86::VBROADCASTSSYrm, 0, 0, 1);
case X86::VMOVAPDZ128rm:
case X86::VMOVAPSZ128rm:
@@ -318,7 +319,7 @@ bool X86FixupVectorConstantsPass::processInstruction(MachineFunction &MF,
case X86::VMOVDQAYrm:
case X86::VMOVDQUYrm:
return ConvertToBroadcast(
- 0, HasAVX2 ? X86::VBROADCASTI128 : X86::VBROADCASTF128,
+ 0, HasAVX2 ? X86::VBROADCASTI128rm : X86::VBROADCASTF128rm,
HasAVX2 ? X86::VPBROADCASTQYrm : X86::VBROADCASTSDYrm,
HasAVX2 ? X86::VPBROADCASTDYrm : X86::VBROADCASTSSYrm,
HasAVX2 ? X86::VPBROADCASTWYrm : 0, HasAVX2 ? X86::VPBROADCASTBYrm : 0,
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index 545039b79f16..7ec59c74f5f5 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -2927,6 +2927,13 @@ bool X86DAGToDAGISel::selectAddr(SDNode *Parent, SDValue N, SDValue &Base,
}
bool X86DAGToDAGISel::selectMOV64Imm32(SDValue N, SDValue &Imm) {
+ // Cannot use 32 bit constants to reference objects in kernel code model.
+ // Cannot use 32 bit constants to reference objects in large PIC mode since
+ // GOTOFF is 64 bits.
+ if (TM.getCodeModel() == CodeModel::Kernel ||
+ (TM.getCodeModel() == CodeModel::Large && TM.isPositionIndependent()))
+ return false;
+
// In static codegen with small code model, we can get the address of a label
// into a register with 'movl'
if (N->getOpcode() != X86ISD::Wrapper)
@@ -2940,15 +2947,18 @@ bool X86DAGToDAGISel::selectMOV64Imm32(SDValue N, SDValue &Imm) {
return false;
Imm = N;
- if (N->getOpcode() != ISD::TargetGlobalAddress)
- return TM.getCodeModel() == CodeModel::Small;
+ // Small/medium code model can reference non-TargetGlobalAddress objects with
+ // 32 bit constants.
+ if (N->getOpcode() != ISD::TargetGlobalAddress) {
+ return TM.getCodeModel() == CodeModel::Small ||
+ TM.getCodeModel() == CodeModel::Medium;
+ }
- std::optional<ConstantRange> CR =
- cast<GlobalAddressSDNode>(N)->getGlobal()->getAbsoluteSymbolRange();
- if (!CR)
- return TM.getCodeModel() == CodeModel::Small;
+ const GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal();
+ if (std::optional<ConstantRange> CR = GV->getAbsoluteSymbolRange())
+ return CR->getUnsignedMax().ult(1ull << 32);
- return CR->getUnsignedMax().ult(1ull << 32);
+ return !TM.isLargeGlobalValue(GV);
}
bool X86DAGToDAGISel::selectLEA64_32Addr(SDValue N, SDValue &Base,
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index d69976342fcb..b80c766c7ffa 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -142,11 +142,11 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setLibcallName(RTLIB::POWI_F64, nullptr);
}
- // If we don't have cmpxchg8b(meaing this is a 386/486), limit atomic size to
- // 32 bits so the AtomicExpandPass will expand it so we don't need cmpxchg8b.
- // FIXME: Should we be limiting the atomic size on other configs? Default is
- // 1024.
- if (!Subtarget.canUseCMPXCHG8B())
+ if (Subtarget.canUseCMPXCHG16B())
+ setMaxAtomicSizeInBitsSupported(128);
+ else if (Subtarget.canUseCMPXCHG8B())
+ setMaxAtomicSizeInBitsSupported(64);
+ else
setMaxAtomicSizeInBitsSupported(32);
setMaxDivRemBitWidthSupported(Subtarget.is64Bit() ? 128 : 64);
@@ -7040,6 +7040,31 @@ static SDValue combineToConsecutiveLoads(EVT VT, SDValue Op, const SDLoc &DL,
IsAfterLegalize);
}
+static Constant *getConstantVector(MVT VT, ArrayRef<APInt> Bits,
+ const APInt &Undefs, LLVMContext &C) {
+ unsigned ScalarSize = VT.getScalarSizeInBits();
+ Type *Ty = EVT(VT.getScalarType()).getTypeForEVT(C);
+
+ auto getConstantScalar = [&](const APInt &Val) -> Constant * {
+ if (VT.isFloatingPoint()) {
+ if (ScalarSize == 16)
+ return ConstantFP::get(C, APFloat(APFloat::IEEEhalf(), Val));
+ if (ScalarSize == 32)
+ return ConstantFP::get(C, APFloat(APFloat::IEEEsingle(), Val));
+ assert(ScalarSize == 64 && "Unsupported floating point scalar size");
+ return ConstantFP::get(C, APFloat(APFloat::IEEEdouble(), Val));
+ }
+ return Constant::getIntegerValue(Ty, Val);
+ };
+
+ SmallVector<Constant *, 32> ConstantVec;
+ for (unsigned I = 0, E = Bits.size(); I != E; ++I)
+ ConstantVec.push_back(Undefs[I] ? UndefValue::get(Ty)
+ : getConstantScalar(Bits[I]));
+
+ return ConstantVector::get(ArrayRef<Constant *>(ConstantVec));
+}
+
static Constant *getConstantVector(MVT VT, const APInt &SplatValue,
unsigned SplatBitSize, LLVMContext &C) {
unsigned ScalarSize = VT.getScalarSizeInBits();
@@ -18304,13 +18329,6 @@ unsigned X86TargetLowering::getGlobalWrapperKind(
OpFlags == X86II::MO_DLLIMPORT))
return X86ISD::WrapperRIP;
- // In the medium model, functions can always be referenced RIP-relatively,
- // since they must be within 2GiB. This is also possible in non-PIC mode, and
- // shorter than the 64-bit absolute immediate that would otherwise be emitted.
- if (getTargetMachine().getCodeModel() == CodeModel::Medium &&
- isa_and_nonnull<Function>(GV))
- return X86ISD::WrapperRIP;
-
// GOTPCREL references must always use RIP.
if (OpFlags == X86II::MO_GOTPCREL || OpFlags == X86II::MO_GOTPCREL_NORELAX)
return X86ISD::WrapperRIP;
@@ -39562,9 +39580,21 @@ static SDValue combineCommutableSHUFP(SDValue N, MVT VT, const SDLoc &DL,
return SDValue();
}
+// TODO - move this to TLI like isBinOp?
+static bool isUnaryOp(unsigned Opcode) {
+ switch (Opcode) {
+ case ISD::CTLZ:
+ case ISD::CTTZ:
+ case ISD::CTPOP:
+ return true;
+ }
+ return false;
+}
+
+// Canonicalize SHUFFLE(UNARYOP(X)) -> UNARYOP(SHUFFLE(X)).
// Canonicalize SHUFFLE(BINOP(X,Y)) -> BINOP(SHUFFLE(X),SHUFFLE(Y)).
-static SDValue canonicalizeShuffleWithBinOps(SDValue N, SelectionDAG &DAG,
- const SDLoc &DL) {
+static SDValue canonicalizeShuffleWithOp(SDValue N, SelectionDAG &DAG,
+ const SDLoc &DL) {
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
EVT ShuffleVT = N.getValueType();
@@ -39691,6 +39721,25 @@ static SDValue canonicalizeShuffleWithBinOps(SDValue N, SelectionDAG &DAG,
DAG.getBitcast(OpVT, RHS)));
}
}
+ if (isUnaryOp(SrcOpcode) && N1.getOpcode() == SrcOpcode &&
+ N0.getValueType() == N1.getValueType() &&
+ IsSafeToMoveShuffle(N0, SrcOpcode) &&
+ IsSafeToMoveShuffle(N1, SrcOpcode)) {
+ SDValue Op00 = peekThroughOneUseBitcasts(N0.getOperand(0));
+ SDValue Op10 = peekThroughOneUseBitcasts(N1.getOperand(0));
+ SDValue Res;
+ Op00 = DAG.getBitcast(ShuffleVT, Op00);
+ Op10 = DAG.getBitcast(ShuffleVT, Op10);
+ if (N.getNumOperands() == 3) {
+ Res = DAG.getNode(Opc, DL, ShuffleVT, Op00, Op10, N.getOperand(2));
+ } else {
+ Res = DAG.getNode(Opc, DL, ShuffleVT, Op00, Op10);
+ }
+ EVT OpVT = N0.getValueType();
+ return DAG.getBitcast(
+ ShuffleVT,
+ DAG.getNode(SrcOpcode, DL, OpVT, DAG.getBitcast(OpVT, Res)));
+ }
}
break;
}
@@ -40772,10 +40821,11 @@ static SDValue combineShuffle(SDNode *N, SelectionDAG &DAG,
if (TLI.SimplifyDemandedVectorElts(Op, DemandedElts, DCI))
return SDValue(N, 0);
+ // Canonicalize SHUFFLE(UNARYOP(X)) -> UNARYOP(SHUFFLE(X)).
// Canonicalize SHUFFLE(BINOP(X,Y)) -> BINOP(SHUFFLE(X),SHUFFLE(Y)).
// Perform this after other shuffle combines to allow inner shuffles to be
// combined away first.
- if (SDValue BinOp = canonicalizeShuffleWithBinOps(Op, DAG, dl))
+ if (SDValue BinOp = canonicalizeShuffleWithOp(Op, DAG, dl))
return BinOp;
}
@@ -49894,41 +49944,35 @@ static SDValue combineLoad(SDNode *N, SelectionDAG &DAG,
Extract = DAG.getBitcast(RegVT, Extract);
return DCI.CombineTo(N, Extract, SDValue(User, 1));
}
- if (User->getOpcode() == X86ISD::VBROADCAST_LOAD &&
- getTargetConstantFromBasePtr(Ptr)) {
- // See if we are loading a constant that has also been broadcast.
- APInt Undefs, UserUndefs;
- SmallVector<APInt> Bits, UserBits;
- if (getTargetConstantBitsFromNode(SDValue(N, 0), 8, Undefs, Bits) &&
- getTargetConstantBitsFromNode(SDValue(User, 0), 8, UserUndefs,
- UserBits)) {
- UserUndefs = UserUndefs.trunc(Undefs.getBitWidth());
- UserBits.truncate(Bits.size());
- if (Bits == UserBits && UserUndefs.isSubsetOf(Undefs)) {
- SDValue Extract = extractSubVector(
- SDValue(User, 0), 0, DAG, SDLoc(N), RegVT.getSizeInBits());
- Extract = DAG.getBitcast(RegVT, Extract);
- return DCI.CombineTo(N, Extract, SDValue(User, 1));
- }
+ auto MatchingBits = [](const APInt &Undefs, const APInt &UserUndefs,
+ ArrayRef<APInt> Bits, ArrayRef<APInt> UserBits) {
+ for (unsigned I = 0, E = Undefs.getBitWidth(); I != E; ++I) {
+ if (Undefs[I])
+ continue;
+ if (UserUndefs[I] || Bits[I] != UserBits[I])
+ return false;
}
- }
- if (ISD::isNormalLoad(User)) {
- // See if we are loading a constant that matches in the lower
- // bits of a longer constant (but from a different constant pool ptr).
- SDValue UserPtr = cast<MemSDNode>(User)->getBasePtr();
- const Constant *LdC = getTargetConstantFromBasePtr(Ptr);
- const Constant *UserC = getTargetConstantFromBasePtr(UserPtr);
- if (LdC && UserC && UserPtr != Ptr &&
- LdC->getType()->getPrimitiveSizeInBits() <
- UserC->getType()->getPrimitiveSizeInBits()) {
+ return true;
+ };
+ // See if we are loading a constant that matches in the lower
+ // bits of a longer constant (but from a different constant pool ptr).
+ EVT UserVT = User->getValueType(0);
+ SDValue UserPtr = cast<MemSDNode>(User)->getBasePtr();
+ const Constant *LdC = getTargetConstantFromBasePtr(Ptr);
+ const Constant *UserC = getTargetConstantFromBasePtr(UserPtr);
+ if (LdC && UserC && UserPtr != Ptr) {
+ unsigned LdSize = LdC->getType()->getPrimitiveSizeInBits();
+ unsigned UserSize = UserC->getType()->getPrimitiveSizeInBits();
+ if (LdSize < UserSize || !ISD::isNormalLoad(User)) {
APInt Undefs, UserUndefs;
SmallVector<APInt> Bits, UserBits;
- if (getTargetConstantBitsFromNode(SDValue(N, 0), 8, Undefs, Bits) &&
- getTargetConstantBitsFromNode(SDValue(User, 0), 8, UserUndefs,
- UserBits)) {
- UserUndefs = UserUndefs.trunc(Undefs.getBitWidth());
- UserBits.truncate(Bits.size());
- if (Bits == UserBits && UserUndefs.isSubsetOf(Undefs)) {
+ unsigned NumBits = std::min(RegVT.getScalarSizeInBits(),
+ UserVT.getScalarSizeInBits());
+ if (getTargetConstantBitsFromNode(SDValue(N, 0), NumBits, Undefs,
+ Bits) &&
+ getTargetConstantBitsFromNode(SDValue(User, 0), NumBits,
+ UserUndefs, UserBits)) {
+ if (MatchingBits(Undefs, UserUndefs, Bits, UserBits)) {
SDValue Extract = extractSubVector(
SDValue(User, 0), 0, DAG, SDLoc(N), RegVT.getSizeInBits());
Extract = DAG.getBitcast(RegVT, Extract);
@@ -54483,6 +54527,7 @@ static SDValue combineConcatVectorOps(const SDLoc &DL, MVT VT,
bool IsSplat = llvm::all_equal(Ops);
unsigned NumOps = Ops.size();
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ LLVMContext &Ctx = *DAG.getContext();
// Repeated subvectors.
if (IsSplat &&
@@ -54780,7 +54825,7 @@ static SDValue combineConcatVectorOps(const SDLoc &DL, MVT VT,
Subtarget.useAVX512Regs() &&
Subtarget.getPreferVectorWidth() >= 512 &&
(SrcVT.getScalarSizeInBits() > 16 || Subtarget.useBWIRegs())) {
- EVT NewSrcVT = SrcVT.getDoubleNumVectorElementsVT(*DAG.getContext());
+ EVT NewSrcVT = SrcVT.getDoubleNumVectorElementsVT(Ctx);
return DAG.getNode(ISD::TRUNCATE, DL, VT,
ConcatSubOperand(NewSrcVT, Ops, 0));
}
@@ -54937,7 +54982,7 @@ static SDValue combineConcatVectorOps(const SDLoc &DL, MVT VT,
(EltSizeInBits >= 32 || Subtarget.hasBWI())) {
EVT SelVT = Ops[0].getOperand(0).getValueType();
if (SelVT.getVectorElementType() == MVT::i1) {
- SelVT = EVT::getVectorVT(*DAG.getContext(), MVT::i1,
+ SelVT = EVT::getVectorVT(Ctx, MVT::i1,
NumOps * SelVT.getVectorNumElements());
if (TLI.isTypeLegal(SelVT))
return DAG.getNode(Op0.getOpcode(), DL, VT,
@@ -54952,7 +54997,7 @@ static SDValue combineConcatVectorOps(const SDLoc &DL, MVT VT,
(EltSizeInBits >= 32 || Subtarget.hasInt256()) &&
IsConcatFree(VT, Ops, 1) && IsConcatFree(VT, Ops, 2)) {
EVT SelVT = Ops[0].getOperand(0).getValueType();
- SelVT = SelVT.getDoubleNumVectorElementsVT(*DAG.getContext());
+ SelVT = SelVT.getDoubleNumVectorElementsVT(Ctx);
if (TLI.isTypeLegal(SelVT))
return DAG.getNode(Op0.getOpcode(), DL, VT,
ConcatSubOperand(SelVT.getSimpleVT(), Ops, 0),
@@ -54968,7 +55013,7 @@ static SDValue combineConcatVectorOps(const SDLoc &DL, MVT VT,
if (auto *FirstLd = dyn_cast<LoadSDNode>(peekThroughBitcasts(Op0))) {
unsigned Fast;
const X86TargetLowering *TLI = Subtarget.getTargetLowering();
- if (TLI->allowsMemoryAccess(*DAG.getContext(), DAG.getDataLayout(), VT,
+ if (TLI->allowsMemoryAccess(Ctx, DAG.getDataLayout(), VT,
*FirstLd->getMemOperand(), &Fast) &&
Fast) {
if (SDValue Ld =
@@ -54977,6 +55022,32 @@ static SDValue combineConcatVectorOps(const SDLoc &DL, MVT VT,
}
}
+ // Attempt to fold target constant loads.
+ if (all_of(Ops, [](SDValue Op) { return getTargetConstantFromNode(Op); })) {
+ SmallVector<APInt> EltBits;
+ APInt UndefElts = APInt::getZero(VT.getVectorNumElements());
+ for (unsigned I = 0; I != NumOps; ++I) {
+ APInt OpUndefElts;
+ SmallVector<APInt> OpEltBits;
+ if (!getTargetConstantBitsFromNode(Ops[I], EltSizeInBits, OpUndefElts,
+ OpEltBits, true, false))
+ break;
+ EltBits.append(OpEltBits);
+ UndefElts.insertBits(OpUndefElts, I * OpUndefElts.getBitWidth());
+ }
+ if (EltBits.size() == VT.getVectorNumElements()) {
+ Constant *C = getConstantVector(VT, EltBits, UndefElts, Ctx);
+ MVT PVT = TLI.getPointerTy(DAG.getDataLayout());
+ SDValue CV = DAG.getConstantPool(C, PVT);
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachinePointerInfo MPI = MachinePointerInfo::getConstantPool(MF);
+ SDValue Ld = DAG.getLoad(VT, DL, DAG.getEntryNode(), CV, MPI);
+ SDValue Sub = extractSubVector(Ld, 0, DAG, DL, Op0.getValueSizeInBits());
+ DAG.ReplaceAllUsesOfValueWith(Op0, Sub);
+ return Ld;
+ }
+ }
+
// If this simple subvector or scalar/subvector broadcast_load is inserted
// into both halves, use a larger broadcast_load. Update other uses to use
// an extracted subvector.
@@ -54999,23 +55070,6 @@ static SDValue combineConcatVectorOps(const SDLoc &DL, MVT VT,
}
}
- // Attempt to fold target constant loads.
- if (all_of(Ops, [](SDValue Op) { return getTargetConstantFromNode(Op); })) {
- SmallVector<APInt> EltBits;
- APInt UndefElts = APInt::getZero(VT.getVectorNumElements());
- for (unsigned I = 0; I != NumOps; ++I) {
- APInt OpUndefElts;
- SmallVector<APInt> OpEltBits;
- if (!getTargetConstantBitsFromNode(Ops[I], EltSizeInBits, OpUndefElts,
- OpEltBits, true, false))
- break;
- EltBits.append(OpEltBits);
- UndefElts.insertBits(OpUndefElts, I * OpUndefElts.getBitWidth());
- }
- if (EltBits.size() == VT.getVectorNumElements())
- return getConstVector(EltBits, UndefElts, VT, DAG, DL);
- }
-
// If we're splatting a 128-bit subvector to 512-bits, use SHUF128 directly.
if (IsSplat && NumOps == 4 && VT.is512BitVector() &&
Subtarget.useAVX512Regs()) {
diff --git a/llvm/lib/Target/X86/X86InsertPrefetch.cpp b/llvm/lib/Target/X86/X86InsertPrefetch.cpp
index 3c9738be547f..3e11ab2d98a4 100644
--- a/llvm/lib/Target/X86/X86InsertPrefetch.cpp
+++ b/llvm/lib/Target/X86/X86InsertPrefetch.cpp
@@ -135,7 +135,7 @@ bool X86InsertPrefetch::findPrefetchInfo(const FunctionSamples *TopSamples,
int64_t D = static_cast<int64_t>(S_V.second);
unsigned IID = 0;
for (const auto &HintType : HintTypes) {
- if (Name.startswith(HintType.first)) {
+ if (Name.starts_with(HintType.first)) {
Name = Name.drop_front(HintType.first.size());
IID = HintType.second;
break;
diff --git a/llvm/lib/Target/X86/X86InstrAVX512.td b/llvm/lib/Target/X86/X86InstrAVX512.td
index 5eb893a82fcc..e1fe2b680b96 100644
--- a/llvm/lib/Target/X86/X86InstrAVX512.td
+++ b/llvm/lib/Target/X86/X86InstrAVX512.td
@@ -1624,19 +1624,19 @@ multiclass avx512_perm_i_sizes<bits<8> opc, string OpcodeStr,
X86FoldableSchedWrite sched,
AVX512VLVectorVTInfo VTInfo,
AVX512VLVectorVTInfo ShuffleMask> {
- defm NAME: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info512,
- ShuffleMask.info512>,
- avx512_perm_i_mb<opc, OpcodeStr, sched, VTInfo.info512,
- ShuffleMask.info512>, EVEX_V512;
+ defm NAME#Z: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info512,
+ ShuffleMask.info512>,
+ avx512_perm_i_mb<opc, OpcodeStr, sched, VTInfo.info512,
+ ShuffleMask.info512>, EVEX_V512;
let Predicates = [HasVLX] in {
- defm NAME#128: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info128,
- ShuffleMask.info128>,
- avx512_perm_i_mb<opc, OpcodeStr, sched, VTInfo.info128,
- ShuffleMask.info128>, EVEX_V128;
- defm NAME#256: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info256,
- ShuffleMask.info256>,
- avx512_perm_i_mb<opc, OpcodeStr, sched, VTInfo.info256,
- ShuffleMask.info256>, EVEX_V256;
+ defm NAME#Z128: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info128,
+ ShuffleMask.info128>,
+ avx512_perm_i_mb<opc, OpcodeStr, sched, VTInfo.info128,
+ ShuffleMask.info128>, EVEX_V128;
+ defm NAME#Z256: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info256,
+ ShuffleMask.info256>,
+ avx512_perm_i_mb<opc, OpcodeStr, sched, VTInfo.info256,
+ ShuffleMask.info256>, EVEX_V256;
}
}
@@ -1646,13 +1646,13 @@ multiclass avx512_perm_i_sizes_bw<bits<8> opc, string OpcodeStr,
AVX512VLVectorVTInfo Idx,
Predicate Prd> {
let Predicates = [Prd] in
- defm NAME: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info512,
- Idx.info512>, EVEX_V512;
+ defm NAME#Z: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info512,
+ Idx.info512>, EVEX_V512;
let Predicates = [Prd, HasVLX] in {
- defm NAME#128: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info128,
- Idx.info128>, EVEX_V128;
- defm NAME#256: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info256,
- Idx.info256>, EVEX_V256;
+ defm NAME#Z128: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info128,
+ Idx.info128>, EVEX_V128;
+ defm NAME#Z256: avx512_perm_i<opc, OpcodeStr, sched, VTInfo.info256,
+ Idx.info256>, EVEX_V256;
}
}
@@ -1702,9 +1702,9 @@ multiclass avx512_perm_i_lowering<string InstrStr, X86VectorVTInfo _,
}
// TODO: Should we add more casts? The vXi64 case is common due to ABI.
-defm : avx512_perm_i_lowering<"VPERMI2PS", v16f32_info, v16i32_info, v8i64_info>;
-defm : avx512_perm_i_lowering<"VPERMI2PS256", v8f32x_info, v8i32x_info, v4i64x_info>;
-defm : avx512_perm_i_lowering<"VPERMI2PS128", v4f32x_info, v4i32x_info, v2i64x_info>;
+defm : avx512_perm_i_lowering<"VPERMI2PSZ", v16f32_info, v16i32_info, v8i64_info>;
+defm : avx512_perm_i_lowering<"VPERMI2PSZ256", v8f32x_info, v8i32x_info, v4i64x_info>;
+defm : avx512_perm_i_lowering<"VPERMI2PSZ128", v4f32x_info, v4i32x_info, v2i64x_info>;
// VPERMT2
multiclass avx512_perm_t<bits<8> opc, string OpcodeStr,
@@ -1743,19 +1743,19 @@ multiclass avx512_perm_t_sizes<bits<8> opc, string OpcodeStr,
X86FoldableSchedWrite sched,
AVX512VLVectorVTInfo VTInfo,
AVX512VLVectorVTInfo ShuffleMask> {
- defm NAME: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info512,
- ShuffleMask.info512>,
- avx512_perm_t_mb<opc, OpcodeStr, sched, VTInfo.info512,
- ShuffleMask.info512>, EVEX_V512;
+ defm NAME#Z: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info512,
+ ShuffleMask.info512>,
+ avx512_perm_t_mb<opc, OpcodeStr, sched, VTInfo.info512,
+ ShuffleMask.info512>, EVEX_V512;
let Predicates = [HasVLX] in {
- defm NAME#128: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info128,
- ShuffleMask.info128>,
- avx512_perm_t_mb<opc, OpcodeStr, sched, VTInfo.info128,
- ShuffleMask.info128>, EVEX_V128;
- defm NAME#256: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info256,
- ShuffleMask.info256>,
- avx512_perm_t_mb<opc, OpcodeStr, sched, VTInfo.info256,
- ShuffleMask.info256>, EVEX_V256;
+ defm NAME#Z128: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info128,
+ ShuffleMask.info128>,
+ avx512_perm_t_mb<opc, OpcodeStr, sched, VTInfo.info128,
+ ShuffleMask.info128>, EVEX_V128;
+ defm NAME#Z256: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info256,
+ ShuffleMask.info256>,
+ avx512_perm_t_mb<opc, OpcodeStr, sched, VTInfo.info256,
+ ShuffleMask.info256>, EVEX_V256;
}
}
@@ -1764,13 +1764,13 @@ multiclass avx512_perm_t_sizes_bw<bits<8> opc, string OpcodeStr,
AVX512VLVectorVTInfo VTInfo,
AVX512VLVectorVTInfo Idx, Predicate Prd> {
let Predicates = [Prd] in
- defm NAME: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info512,
- Idx.info512>, EVEX_V512;
+ defm NAME#Z: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info512,
+ Idx.info512>, EVEX_V512;
let Predicates = [Prd, HasVLX] in {
- defm NAME#128: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info128,
- Idx.info128>, EVEX_V128;
- defm NAME#256: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info256,
- Idx.info256>, EVEX_V256;
+ defm NAME#Z128: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info128,
+ Idx.info128>, EVEX_V128;
+ defm NAME#Z256: avx512_perm_t<opc, OpcodeStr, sched, VTInfo.info256,
+ Idx.info256>, EVEX_V256;
}
}
diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index d6ae4971d238..bc2d5ed1e17d 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -2138,45 +2138,45 @@ static void commuteVPTERNLOG(MachineInstr &MI, unsigned SrcOpIdx1,
// commuted.
static bool isCommutableVPERMV3Instruction(unsigned Opcode) {
#define VPERM_CASES(Suffix) \
- case X86::VPERMI2##Suffix##128rr: \
- case X86::VPERMT2##Suffix##128rr: \
- case X86::VPERMI2##Suffix##256rr: \
- case X86::VPERMT2##Suffix##256rr: \
- case X86::VPERMI2##Suffix##rr: \
- case X86::VPERMT2##Suffix##rr: \
- case X86::VPERMI2##Suffix##128rm: \
- case X86::VPERMT2##Suffix##128rm: \
- case X86::VPERMI2##Suffix##256rm: \
- case X86::VPERMT2##Suffix##256rm: \
- case X86::VPERMI2##Suffix##rm: \
- case X86::VPERMT2##Suffix##rm: \
- case X86::VPERMI2##Suffix##128rrkz: \
- case X86::VPERMT2##Suffix##128rrkz: \
- case X86::VPERMI2##Suffix##256rrkz: \
- case X86::VPERMT2##Suffix##256rrkz: \
- case X86::VPERMI2##Suffix##rrkz: \
- case X86::VPERMT2##Suffix##rrkz: \
- case X86::VPERMI2##Suffix##128rmkz: \
- case X86::VPERMT2##Suffix##128rmkz: \
- case X86::VPERMI2##Suffix##256rmkz: \
- case X86::VPERMT2##Suffix##256rmkz: \
- case X86::VPERMI2##Suffix##rmkz: \
- case X86::VPERMT2##Suffix##rmkz:
+ case X86::VPERMI2##Suffix##Z128rr: \
+ case X86::VPERMT2##Suffix##Z128rr: \
+ case X86::VPERMI2##Suffix##Z256rr: \
+ case X86::VPERMT2##Suffix##Z256rr: \
+ case X86::VPERMI2##Suffix##Zrr: \
+ case X86::VPERMT2##Suffix##Zrr: \
+ case X86::VPERMI2##Suffix##Z128rm: \
+ case X86::VPERMT2##Suffix##Z128rm: \
+ case X86::VPERMI2##Suffix##Z256rm: \
+ case X86::VPERMT2##Suffix##Z256rm: \
+ case X86::VPERMI2##Suffix##Zrm: \
+ case X86::VPERMT2##Suffix##Zrm: \
+ case X86::VPERMI2##Suffix##Z128rrkz: \
+ case X86::VPERMT2##Suffix##Z128rrkz: \
+ case X86::VPERMI2##Suffix##Z256rrkz: \
+ case X86::VPERMT2##Suffix##Z256rrkz: \
+ case X86::VPERMI2##Suffix##Zrrkz: \
+ case X86::VPERMT2##Suffix##Zrrkz: \
+ case X86::VPERMI2##Suffix##Z128rmkz: \
+ case X86::VPERMT2##Suffix##Z128rmkz: \
+ case X86::VPERMI2##Suffix##Z256rmkz: \
+ case X86::VPERMT2##Suffix##Z256rmkz: \
+ case X86::VPERMI2##Suffix##Zrmkz: \
+ case X86::VPERMT2##Suffix##Zrmkz:
#define VPERM_CASES_BROADCAST(Suffix) \
VPERM_CASES(Suffix) \
- case X86::VPERMI2##Suffix##128rmb: \
- case X86::VPERMT2##Suffix##128rmb: \
- case X86::VPERMI2##Suffix##256rmb: \
- case X86::VPERMT2##Suffix##256rmb: \
- case X86::VPERMI2##Suffix##rmb: \
- case X86::VPERMT2##Suffix##rmb: \
- case X86::VPERMI2##Suffix##128rmbkz: \
- case X86::VPERMT2##Suffix##128rmbkz: \
- case X86::VPERMI2##Suffix##256rmbkz: \
- case X86::VPERMT2##Suffix##256rmbkz: \
- case X86::VPERMI2##Suffix##rmbkz: \
- case X86::VPERMT2##Suffix##rmbkz:
+ case X86::VPERMI2##Suffix##Z128rmb: \
+ case X86::VPERMT2##Suffix##Z128rmb: \
+ case X86::VPERMI2##Suffix##Z256rmb: \
+ case X86::VPERMT2##Suffix##Z256rmb: \
+ case X86::VPERMI2##Suffix##Zrmb: \
+ case X86::VPERMT2##Suffix##Zrmb: \
+ case X86::VPERMI2##Suffix##Z128rmbkz: \
+ case X86::VPERMT2##Suffix##Z128rmbkz: \
+ case X86::VPERMI2##Suffix##Z256rmbkz: \
+ case X86::VPERMT2##Suffix##Z256rmbkz: \
+ case X86::VPERMI2##Suffix##Zrmbkz: \
+ case X86::VPERMT2##Suffix##Zrmbkz:
switch (Opcode) {
default:
@@ -2197,45 +2197,45 @@ static bool isCommutableVPERMV3Instruction(unsigned Opcode) {
// from the I opcode to the T opcode and vice versa.
static unsigned getCommutedVPERMV3Opcode(unsigned Opcode) {
#define VPERM_CASES(Orig, New) \
- case X86::Orig##128rr: \
- return X86::New##128rr; \
- case X86::Orig##128rrkz: \
- return X86::New##128rrkz; \
- case X86::Orig##128rm: \
- return X86::New##128rm; \
- case X86::Orig##128rmkz: \
- return X86::New##128rmkz; \
- case X86::Orig##256rr: \
- return X86::New##256rr; \
- case X86::Orig##256rrkz: \
- return X86::New##256rrkz; \
- case X86::Orig##256rm: \
- return X86::New##256rm; \
- case X86::Orig##256rmkz: \
- return X86::New##256rmkz; \
- case X86::Orig##rr: \
- return X86::New##rr; \
- case X86::Orig##rrkz: \
- return X86::New##rrkz; \
- case X86::Orig##rm: \
- return X86::New##rm; \
- case X86::Orig##rmkz: \
- return X86::New##rmkz;
+ case X86::Orig##Z128rr: \
+ return X86::New##Z128rr; \
+ case X86::Orig##Z128rrkz: \
+ return X86::New##Z128rrkz; \
+ case X86::Orig##Z128rm: \
+ return X86::New##Z128rm; \
+ case X86::Orig##Z128rmkz: \
+ return X86::New##Z128rmkz; \
+ case X86::Orig##Z256rr: \
+ return X86::New##Z256rr; \
+ case X86::Orig##Z256rrkz: \
+ return X86::New##Z256rrkz; \
+ case X86::Orig##Z256rm: \
+ return X86::New##Z256rm; \
+ case X86::Orig##Z256rmkz: \
+ return X86::New##Z256rmkz; \
+ case X86::Orig##Zrr: \
+ return X86::New##Zrr; \
+ case X86::Orig##Zrrkz: \
+ return X86::New##Zrrkz; \
+ case X86::Orig##Zrm: \
+ return X86::New##Zrm; \
+ case X86::Orig##Zrmkz: \
+ return X86::New##Zrmkz;
#define VPERM_CASES_BROADCAST(Orig, New) \
VPERM_CASES(Orig, New) \
- case X86::Orig##128rmb: \
- return X86::New##128rmb; \
- case X86::Orig##128rmbkz: \
- return X86::New##128rmbkz; \
- case X86::Orig##256rmb: \
- return X86::New##256rmb; \
- case X86::Orig##256rmbkz: \
- return X86::New##256rmbkz; \
- case X86::Orig##rmb: \
- return X86::New##rmb; \
- case X86::Orig##rmbkz: \
- return X86::New##rmbkz;
+ case X86::Orig##Z128rmb: \
+ return X86::New##Z128rmb; \
+ case X86::Orig##Z128rmbkz: \
+ return X86::New##Z128rmbkz; \
+ case X86::Orig##Z256rmb: \
+ return X86::New##Z256rmb; \
+ case X86::Orig##Z256rmbkz: \
+ return X86::New##Z256rmbkz; \
+ case X86::Orig##Zrmb: \
+ return X86::New##Zrmb; \
+ case X86::Orig##Zrmbkz: \
+ return X86::New##Zrmbkz;
switch (Opcode) {
VPERM_CASES(VPERMI2B, VPERMT2B)
@@ -8026,9 +8026,8 @@ MachineInstr *X86InstrInfo::foldMemoryOperandImpl(
// Folding a V_SET0 or V_SETALLONES as a load, to ease register pressure.
// Create a constant-pool entry and operands to load from it.
- // Medium and large mode can't fold loads this way.
- if (MF.getTarget().getCodeModel() != CodeModel::Small &&
- MF.getTarget().getCodeModel() != CodeModel::Kernel)
+ // Large code model can't fold loads this way.
+ if (MF.getTarget().getCodeModel() == CodeModel::Large)
return nullptr;
// x86-32 PIC requires a PIC base register for constant pools.
diff --git a/llvm/lib/Target/X86/X86InstrMisc.td b/llvm/lib/Target/X86/X86InstrMisc.td
index 82c079fe2ea8..2ea10e317e12 100644
--- a/llvm/lib/Target/X86/X86InstrMisc.td
+++ b/llvm/lib/Target/X86/X86InstrMisc.td
@@ -1497,11 +1497,19 @@ let SchedRW = [WriteStore] in {
def MOVDIRI32 : I<0xF9, MRMDestMem, (outs), (ins i32mem:$dst, GR32:$src),
"movdiri\t{$src, $dst|$dst, $src}",
[(int_x86_directstore32 addr:$dst, GR32:$src)]>,
- T8PS, Requires<[HasMOVDIRI]>;
+ T8PS, Requires<[HasMOVDIRI, NoEGPR]>;
def MOVDIRI64 : RI<0xF9, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src),
"movdiri\t{$src, $dst|$dst, $src}",
[(int_x86_directstore64 addr:$dst, GR64:$src)]>,
- T8PS, Requires<[In64BitMode, HasMOVDIRI]>;
+ T8PS, Requires<[In64BitMode, HasMOVDIRI, NoEGPR]>;
+def MOVDIRI32_EVEX : I<0xF9, MRMDestMem, (outs), (ins i32mem:$dst, GR32:$src),
+ "movdiri\t{$src, $dst|$dst, $src}",
+ [(int_x86_directstore32 addr:$dst, GR32:$src)]>,
+ EVEX_NoCD8, T_MAP4PS, Requires<[In64BitMode, HasMOVDIRI, HasEGPR]>;
+def MOVDIRI64_EVEX : RI<0xF9, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src),
+ "movdiri\t{$src, $dst|$dst, $src}",
+ [(int_x86_directstore64 addr:$dst, GR64:$src)]>,
+ EVEX_NoCD8, T_MAP4PS, Requires<[In64BitMode, HasMOVDIRI, HasEGPR]>;
} // SchedRW
//===----------------------------------------------------------------------===//
@@ -1514,11 +1522,19 @@ def MOVDIR64B16 : I<0xF8, MRMSrcMem, (outs), (ins GR16:$dst, i512mem_GR16:$src),
def MOVDIR64B32 : I<0xF8, MRMSrcMem, (outs), (ins GR32:$dst, i512mem_GR32:$src),
"movdir64b\t{$src, $dst|$dst, $src}",
[(int_x86_movdir64b GR32:$dst, addr:$src)]>,
- T8PD, AdSize32, Requires<[HasMOVDIR64B]>;
+ T8PD, AdSize32, Requires<[HasMOVDIR64B, NoEGPR]>;
def MOVDIR64B64 : I<0xF8, MRMSrcMem, (outs), (ins GR64:$dst, i512mem_GR64:$src),
"movdir64b\t{$src, $dst|$dst, $src}",
[(int_x86_movdir64b GR64:$dst, addr:$src)]>,
- T8PD, AdSize64, Requires<[HasMOVDIR64B, In64BitMode]>;
+ T8PD, AdSize64, Requires<[HasMOVDIR64B, NoEGPR, In64BitMode]>;
+def MOVDIR64B32_EVEX : I<0xF8, MRMSrcMem, (outs), (ins GR32:$dst, i512mem_GR32:$src),
+ "movdir64b\t{$src, $dst|$dst, $src}",
+ [(int_x86_movdir64b GR32:$dst, addr:$src)]>,
+ EVEX_NoCD8, T_MAP4PD, AdSize32, Requires<[HasMOVDIR64B, HasEGPR, In64BitMode]>;
+def MOVDIR64B64_EVEX : I<0xF8, MRMSrcMem, (outs), (ins GR64:$dst, i512mem_GR64:$src),
+ "movdir64b\t{$src, $dst|$dst, $src}",
+ [(int_x86_movdir64b GR64:$dst, addr:$src)]>,
+ EVEX_NoCD8, T_MAP4PD, AdSize64, Requires<[HasMOVDIR64B, HasEGPR, In64BitMode]>;
} // SchedRW
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/X86/X86InstrSSE.td b/llvm/lib/Target/X86/X86InstrSSE.td
index 34eb17af1033..cf57fe562ed5 100644
--- a/llvm/lib/Target/X86/X86InstrSSE.td
+++ b/llvm/lib/Target/X86/X86InstrSSE.td
@@ -7093,35 +7093,35 @@ def VBROADCASTSDYrr : avx2_broadcast_rr<0x19, "vbroadcastsd", VR256,
// halves of a 256-bit vector.
//
let mayLoad = 1, hasSideEffects = 0, Predicates = [HasAVX2] in
-def VBROADCASTI128 : AVX8I<0x5A, MRMSrcMem, (outs VR256:$dst),
- (ins i128mem:$src),
- "vbroadcasti128\t{$src, $dst|$dst, $src}", []>,
- Sched<[WriteShuffleLd]>, VEX, VEX_L;
+def VBROADCASTI128rm : AVX8I<0x5A, MRMSrcMem, (outs VR256:$dst),
+ (ins i128mem:$src),
+ "vbroadcasti128\t{$src, $dst|$dst, $src}", []>,
+ Sched<[WriteShuffleLd]>, VEX, VEX_L;
let mayLoad = 1, hasSideEffects = 0, Predicates = [HasAVX],
ExeDomain = SSEPackedSingle in
-def VBROADCASTF128 : AVX8I<0x1A, MRMSrcMem, (outs VR256:$dst),
- (ins f128mem:$src),
- "vbroadcastf128\t{$src, $dst|$dst, $src}", []>,
- Sched<[SchedWriteFShuffle.XMM.Folded]>, VEX, VEX_L;
+def VBROADCASTF128rm : AVX8I<0x1A, MRMSrcMem, (outs VR256:$dst),
+ (ins f128mem:$src),
+ "vbroadcastf128\t{$src, $dst|$dst, $src}", []>,
+ Sched<[SchedWriteFShuffle.XMM.Folded]>, VEX, VEX_L;
let Predicates = [HasAVX, NoVLX] in {
def : Pat<(v4f64 (X86SubVBroadcastld128 addr:$src)),
- (VBROADCASTF128 addr:$src)>;
+ (VBROADCASTF128rm addr:$src)>;
def : Pat<(v8f32 (X86SubVBroadcastld128 addr:$src)),
- (VBROADCASTF128 addr:$src)>;
+ (VBROADCASTF128rm addr:$src)>;
// NOTE: We're using FP instructions here, but execution domain fixing can
// convert to integer when profitable.
def : Pat<(v4i64 (X86SubVBroadcastld128 addr:$src)),
- (VBROADCASTF128 addr:$src)>;
+ (VBROADCASTF128rm addr:$src)>;
def : Pat<(v8i32 (X86SubVBroadcastld128 addr:$src)),
- (VBROADCASTF128 addr:$src)>;
+ (VBROADCASTF128rm addr:$src)>;
def : Pat<(v16i16 (X86SubVBroadcastld128 addr:$src)),
- (VBROADCASTF128 addr:$src)>;
+ (VBROADCASTF128rm addr:$src)>;
def : Pat<(v16f16 (X86SubVBroadcastld128 addr:$src)),
- (VBROADCASTF128 addr:$src)>;
+ (VBROADCASTF128rm addr:$src)>;
def : Pat<(v32i8 (X86SubVBroadcastld128 addr:$src)),
- (VBROADCASTF128 addr:$src)>;
+ (VBROADCASTF128rm addr:$src)>;
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/X86/X86LowerAMXIntrinsics.cpp b/llvm/lib/Target/X86/X86LowerAMXIntrinsics.cpp
index e3b03e981202..591a76e6fd6c 100644
--- a/llvm/lib/Target/X86/X86LowerAMXIntrinsics.cpp
+++ b/llvm/lib/Target/X86/X86LowerAMXIntrinsics.cpp
@@ -184,9 +184,7 @@ Value *X86LowerAMXIntrinsics::createTileLoadStoreLoops(
Value *CurrentColZExt = B.CreateZExt(CurrentCol, Stride->getType());
Value *Offset =
B.CreateAdd(B.CreateMul(CurrentRowZExt, Stride), CurrentColZExt);
- unsigned AS = cast<PointerType>(Ptr->getType())->getAddressSpace();
- Value *EltBasePtr = B.CreatePointerCast(Ptr, PointerType::get(EltTy, AS));
- Value *EltPtr = B.CreateGEP(EltTy, EltBasePtr, Offset);
+ Value *EltPtr = B.CreateGEP(EltTy, Ptr, Offset);
Value *Idx = B.CreateAdd(B.CreateMul(CurrentRow, B.getInt16(16)), CurrentCol);
if (IsTileLoad) {
// tileload.scalarize.rows.header:
diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp
index cbb012161524..e1a67f61e766 100644
--- a/llvm/lib/Target/X86/X86MCInstLower.cpp
+++ b/llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -1865,8 +1865,8 @@ static void addConstantComments(const MachineInstr *MI,
// For loads from a constant pool to a vector register, print the constant
// loaded.
CASE_ALL_MOV_RM()
- case X86::VBROADCASTF128:
- case X86::VBROADCASTI128:
+ case X86::VBROADCASTF128rm:
+ case X86::VBROADCASTI128rm:
case X86::VBROADCASTF32X4Z256rm:
case X86::VBROADCASTF32X4rm:
case X86::VBROADCASTF32X8rm:
@@ -1891,8 +1891,8 @@ static void addConstantComments(const MachineInstr *MI,
CASE_128_MOV_RM() NumLanes = 1; BitWidth = 128; break;
CASE_256_MOV_RM() NumLanes = 1; BitWidth = 256; break;
CASE_512_MOV_RM() NumLanes = 1; BitWidth = 512; break;
- case X86::VBROADCASTF128: NumLanes = 2; BitWidth = 128; break;
- case X86::VBROADCASTI128: NumLanes = 2; BitWidth = 128; break;
+ case X86::VBROADCASTF128rm: NumLanes = 2; BitWidth = 128; break;
+ case X86::VBROADCASTI128rm: NumLanes = 2; BitWidth = 128; break;
case X86::VBROADCASTF32X4Z256rm: NumLanes = 2; BitWidth = 128; break;
case X86::VBROADCASTF32X4rm: NumLanes = 4; BitWidth = 128; break;
case X86::VBROADCASTF32X8rm: NumLanes = 2; BitWidth = 256; break;
diff --git a/llvm/lib/Target/X86/X86RegisterInfo.cpp b/llvm/lib/Target/X86/X86RegisterInfo.cpp
index 5c32519dab37..e76d0d7bf50e 100644
--- a/llvm/lib/Target/X86/X86RegisterInfo.cpp
+++ b/llvm/lib/Target/X86/X86RegisterInfo.cpp
@@ -1077,12 +1077,6 @@ bool X86RegisterInfo::getRegAllocationHints(Register VirtReg,
VirtReg, Order, Hints, MF, VRM, Matrix);
unsigned ID = RC.getID();
- const X86Subtarget &Subtarget = MF.getSubtarget<X86Subtarget>();
- if ((ID == X86::VK64RegClassID || ID == X86::VK64WMRegClassID) &&
- Subtarget.hasAVX512() && !Subtarget.hasEVEX512())
- report_fatal_error(
- "64-bit mask registers are not supported without EVEX512");
-
if (ID != X86::TILERegClassID)
return BaseImplRetVal;
diff --git a/llvm/lib/Target/X86/X86ReplaceableInstrs.def b/llvm/lib/Target/X86/X86ReplaceableInstrs.def
index 4798275c0519..e1383198d3fe 100644
--- a/llvm/lib/Target/X86/X86ReplaceableInstrs.def
+++ b/llvm/lib/Target/X86/X86ReplaceableInstrs.def
@@ -202,7 +202,7 @@ ENTRY(VBROADCASTSSYrr, VBROADCASTSSYrr, VPBROADCASTDYrr)
ENTRY(VBROADCASTSSYrm, VBROADCASTSSYrm, VPBROADCASTDYrm)
ENTRY(VBROADCASTSDYrr, VBROADCASTSDYrr, VPBROADCASTQYrr)
ENTRY(VBROADCASTSDYrm, VBROADCASTSDYrm, VPBROADCASTQYrm)
-ENTRY(VBROADCASTF128, VBROADCASTF128, VBROADCASTI128)
+ENTRY(VBROADCASTF128rm, VBROADCASTF128rm, VBROADCASTI128rm)
ENTRY(VBLENDPSYrri, VBLENDPSYrri, VPBLENDDYrri)
ENTRY(VBLENDPSYrmi, VBLENDPSYrmi, VPBLENDDYrmi)
ENTRY(VPERMILPSYmi, VPERMILPSYmi, VPSHUFDYmi)
diff --git a/llvm/lib/Target/X86/X86SchedAlderlakeP.td b/llvm/lib/Target/X86/X86SchedAlderlakeP.td
index 3406a28be2c2..8e3e55428264 100644
--- a/llvm/lib/Target/X86/X86SchedAlderlakeP.td
+++ b/llvm/lib/Target/X86/X86SchedAlderlakeP.td
@@ -1328,7 +1328,7 @@ def ADLPWriteResGroup117 : SchedWriteRes<[ADLPPort02_03_11]> {
let Latency = 8;
}
def : InstRW<[ADLPWriteResGroup117], (instregex "^MMX_MOV(D|Q)64rm$",
- "^VBROADCAST(F|I)128$",
+ "^VBROADCAST(F|I)128rm$",
"^VBROADCASTS(D|S)Yrm$",
"^VMOV(D|SH|SL)DUPYrm$",
"^VPBROADCAST(D|Q)Yrm$")>;
diff --git a/llvm/lib/Target/X86/X86SchedBroadwell.td b/llvm/lib/Target/X86/X86SchedBroadwell.td
index 8575f747b4d3..61a8832000e2 100644
--- a/llvm/lib/Target/X86/X86SchedBroadwell.td
+++ b/llvm/lib/Target/X86/X86SchedBroadwell.td
@@ -946,8 +946,8 @@ def BWWriteResGroup58 : SchedWriteRes<[BWPort23]> {
let ReleaseAtCycles = [1];
}
def: InstRW<[BWWriteResGroup58], (instregex "LD_F(32|64|80)m")>;
-def: InstRW<[BWWriteResGroup58], (instrs VBROADCASTF128,
- VBROADCASTI128,
+def: InstRW<[BWWriteResGroup58], (instrs VBROADCASTF128rm,
+ VBROADCASTI128rm,
VBROADCASTSDYrm,
VBROADCASTSSYrm,
VMOVDDUPYrm,
diff --git a/llvm/lib/Target/X86/X86SchedHaswell.td b/llvm/lib/Target/X86/X86SchedHaswell.td
index d10d7684ac12..8795ca95c559 100644
--- a/llvm/lib/Target/X86/X86SchedHaswell.td
+++ b/llvm/lib/Target/X86/X86SchedHaswell.td
@@ -876,8 +876,8 @@ def HWWriteResGroup0_1 : SchedWriteRes<[HWPort23]> {
let NumMicroOps = 1;
let ReleaseAtCycles = [1];
}
-def: InstRW<[HWWriteResGroup0_1], (instrs VBROADCASTF128,
- VBROADCASTI128,
+def: InstRW<[HWWriteResGroup0_1], (instrs VBROADCASTF128rm,
+ VBROADCASTI128rm,
VBROADCASTSDYrm,
VBROADCASTSSYrm,
VMOVDDUPYrm,
diff --git a/llvm/lib/Target/X86/X86SchedIceLake.td b/llvm/lib/Target/X86/X86SchedIceLake.td
index a2aa2655bca2..2c660fad2ec7 100644
--- a/llvm/lib/Target/X86/X86SchedIceLake.td
+++ b/llvm/lib/Target/X86/X86SchedIceLake.td
@@ -1274,8 +1274,8 @@ def ICXWriteResGroup89 : SchedWriteRes<[ICXPort23]> {
let ReleaseAtCycles = [1];
}
def: InstRW<[ICXWriteResGroup89], (instregex "LD_F(32|64|80)m")>;
-def: InstRW<[ICXWriteResGroup89], (instrs VBROADCASTF128,
- VBROADCASTI128,
+def: InstRW<[ICXWriteResGroup89], (instrs VBROADCASTF128rm,
+ VBROADCASTI128rm,
VBROADCASTSDYrm,
VBROADCASTSSYrm,
VMOVDDUPYrm,
@@ -1392,12 +1392,12 @@ def ICXWriteResGroup97 : SchedWriteRes<[ICXPort5,ICXPort015]> {
let NumMicroOps = 3;
let ReleaseAtCycles = [2,1];
}
-def: InstRW<[ICXWriteResGroup97], (instregex "VPERMI2W128rr",
- "VPERMI2W256rr",
- "VPERMI2Wrr",
- "VPERMT2W128rr",
- "VPERMT2W256rr",
- "VPERMT2Wrr")>;
+def: InstRW<[ICXWriteResGroup97], (instregex "VPERMI2WZ128rr",
+ "VPERMI2WZ256rr",
+ "VPERMI2WZrr",
+ "VPERMT2WZ128rr",
+ "VPERMT2WZ256rr",
+ "VPERMT2WZrr")>;
def ICXWriteResGroup99 : SchedWriteRes<[ICXPort23,ICXPort0156]> {
let Latency = 7;
@@ -1692,14 +1692,14 @@ def: InstRW<[ICXWriteResGroup136], (instregex "VALIGN(D|Q)Z128rm(b?)i",
"VFPCLASSSDZrm(b?)",
"VFPCLASSSSZrm(b?)",
"(V?)PCMPGTQrm",
- "VPERMI2D128rm(b?)",
- "VPERMI2PD128rm(b?)",
- "VPERMI2PS128rm(b?)",
- "VPERMI2Q128rm(b?)",
- "VPERMT2D128rm(b?)",
- "VPERMT2PD128rm(b?)",
- "VPERMT2PS128rm(b?)",
- "VPERMT2Q128rm(b?)",
+ "VPERMI2DZ128rm(b?)",
+ "VPERMI2PDZ128rm(b?)",
+ "VPERMI2PSZ128rm(b?)",
+ "VPERMI2QZ128rm(b?)",
+ "VPERMT2DZ128rm(b?)",
+ "VPERMT2PDZ128rm(b?)",
+ "VPERMT2PSZ128rm(b?)",
+ "VPERMT2QZ128rm(b?)",
"VPMAXSQZ128rm(b?)",
"VPMAXUQZ128rm(b?)",
"VPMINSQZ128rm(b?)",
@@ -2002,8 +2002,8 @@ def ICXWriteResGroup183 : SchedWriteRes<[ICXPort5,ICXPort23,ICXPort015]> {
let NumMicroOps = 4;
let ReleaseAtCycles = [2,1,1];
}
-def: InstRW<[ICXWriteResGroup183], (instregex "VPERMI2W128rm(b?)",
- "VPERMT2W128rm(b?)")>;
+def: InstRW<[ICXWriteResGroup183], (instregex "VPERMI2WZ128rm(b?)",
+ "VPERMT2WZ128rm(b?)")>;
def ICXWriteResGroup187 : SchedWriteRes<[ICXPort0,ICXPort5,ICXPort23]> {
let Latency = 14;
@@ -2029,10 +2029,10 @@ def ICXWriteResGroup189 : SchedWriteRes<[ICXPort5,ICXPort23,ICXPort015]> {
let NumMicroOps = 4;
let ReleaseAtCycles = [2,1,1];
}
-def: InstRW<[ICXWriteResGroup189], (instregex "VPERMI2W256rm(b?)",
- "VPERMI2Wrm(b?)",
- "VPERMT2W256rm(b?)",
- "VPERMT2Wrm(b?)")>;
+def: InstRW<[ICXWriteResGroup189], (instregex "VPERMI2WZ256rm(b?)",
+ "VPERMI2WZrm(b?)",
+ "VPERMT2WZ256rm(b?)",
+ "VPERMT2WZrm(b?)")>;
def ICXWriteResGroup190 : SchedWriteRes<[ICXPort1,ICXPort06,ICXPort15,ICXPort0156]> {
let Latency = 14;
diff --git a/llvm/lib/Target/X86/X86SchedSapphireRapids.td b/llvm/lib/Target/X86/X86SchedSapphireRapids.td
index 6a426ef4cf54..bf9e4b7dc6d9 100644
--- a/llvm/lib/Target/X86/X86SchedSapphireRapids.td
+++ b/llvm/lib/Target/X86/X86SchedSapphireRapids.td
@@ -635,10 +635,10 @@ def : InstRW<[SPRWriteResGroup10, ReadAfterVecXLd], (instregex "^(V?)PACK(S|U)S(
"^VPMULTISHIFTQBZ128rm(b?)$")>;
def : InstRW<[SPRWriteResGroup10, ReadAfterVecXLd], (instrs VFPCLASSPHZ128rm)>;
def : InstRW<[SPRWriteResGroup10, ReadAfterVecYLd], (instregex "^VFPCLASSP(D|H|S)Z((256)?)rm$",
- "^VPERM(I|T)2(D|Q|PS)128rm((b|k|bk|kz)?)$",
- "^VPERM(I|T)2(D|Q|PS)128rmbkz$",
- "^VPERM(I|T)2PD128rm((b|k|bk|kz)?)$",
- "^VPERM(I|T)2PD128rmbkz$")>;
+ "^VPERM(I|T)2(D|Q|PS)Z128rm((b|k|bk|kz)?)$",
+ "^VPERM(I|T)2(D|Q|PS)Z128rmbkz$",
+ "^VPERM(I|T)2PDZ128rm((b|k|bk|kz)?)$",
+ "^VPERM(I|T)2PDZ128rmbkz$")>;
def : InstRW<[SPRWriteResGroup10, ReadAfterVecYLd], (instrs VPERMBZ128rm)>;
def SPRWriteResGroup11 : SchedWriteRes<[SPRPort02_03_11, SPRPort05]> {
@@ -678,8 +678,8 @@ def : InstRW<[SPRWriteResGroup12], (instregex "^ADD_F(P?)rST0$",
"^VPERM(B|D|Q)Zrr$",
"^VPERM(D|Q)Z256rr((k|kz)?)$",
"^VPERM(D|Q)Zrrk(z?)$",
- "^VPERM(I|T)2(D|Q)(128|256)rr((k|kz)?)$",
- "^VPERM(I|T)2(D|Q)rr((k|kz)?)$",
+ "^VPERM(I|T)2(D|Q)Z(128|256)rr((k|kz)?)$",
+ "^VPERM(I|T)2(D|Q)Zrr((k|kz)?)$",
"^VPM(AX|IN)(S|U)QZ(128|256)rr((k|kz)?)$",
"^VPMULTISHIFTQBZ(128|256)rr$",
"^VPOPCNT(B|D|Q|W)Z(128|256)rr$",
@@ -1599,7 +1599,7 @@ def SPRWriteResGroup126 : SchedWriteRes<[SPRPort02_03_11]> {
let Latency = 8;
}
def : InstRW<[SPRWriteResGroup126], (instregex "^MMX_MOV(D|Q)64rm$",
- "^VBROADCAST(F|I)128$",
+ "^VBROADCAST(F|I)128rm$",
"^VBROADCAST(F|I)32X(2|4)Z256rm$",
"^VBROADCAST(F|I)32X(8|2Z)rm$",
"^VBROADCAST(F|I)(32|64)X4rm$",
@@ -4274,7 +4274,7 @@ def SPRWriteResGroup455 : SchedWriteRes<[SPRPort00_01_05, SPRPort02_03_11, SPRPo
}
def : InstRW<[SPRWriteResGroup455], (instregex "^VPCONFLICTQZ128rm((b|k|bk|kz)?)$")>;
def : InstRW<[SPRWriteResGroup455], (instrs VPCONFLICTQZ128rmbkz)>;
-def : InstRW<[SPRWriteResGroup455, ReadAfterVecYLd], (instregex "^VPERM(I|T)2B128rm$")>;
+def : InstRW<[SPRWriteResGroup455, ReadAfterVecYLd], (instregex "^VPERM(I|T)2BZ128rm$")>;
def SPRWriteResGroup456 : SchedWriteRes<[SPRPort00_01_05, SPRPort05]> {
let ReleaseAtCycles = [1, 2];
@@ -4325,127 +4325,127 @@ def SPRWriteResGroup462 : SchedWriteRes<[SPRPort00_01_05, SPRPort02_03_11, SPRPo
let Latency = 13;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup462, ReadAfterVecYLd], (instregex "^VPERM(I|T)2B128rmk(z?)$")>;
-def : InstRW<[SPRWriteResGroup462, ReadAfterVecYLd], (instrs VPERMT2W128rm)>;
+def : InstRW<[SPRWriteResGroup462, ReadAfterVecYLd], (instregex "^VPERM(I|T)2BZ128rmk(z?)$")>;
+def : InstRW<[SPRWriteResGroup462, ReadAfterVecYLd], (instrs VPERMT2WZ128rm)>;
def SPRWriteResGroup463 : SchedWriteRes<[SPRPort00_01_05, SPRPort05]> {
let ReleaseAtCycles = [1, 2];
let Latency = 5;
let NumMicroOps = 3;
}
-def : InstRW<[SPRWriteResGroup463], (instregex "^VPERM(I|T)2B(128|256)rr$")>;
+def : InstRW<[SPRWriteResGroup463], (instregex "^VPERM(I|T)2BZ(128|256)rr$")>;
def SPRWriteResGroup464 : SchedWriteRes<[SPRPort00_01_05, SPRPort05]> {
let ReleaseAtCycles = [1, 2];
let Latency = 7;
let NumMicroOps = 3;
}
-def : InstRW<[SPRWriteResGroup464], (instregex "^VPERM(I|T)2B(128|256)rrk(z?)$",
- "^VPERM(I|T)2W(128|256)rr$")>;
+def : InstRW<[SPRWriteResGroup464], (instregex "^VPERM(I|T)2BZ(128|256)rrk(z?)$",
+ "^VPERM(I|T)2WZ(128|256)rr$")>;
def SPRWriteResGroup465 : SchedWriteRes<[SPRPort00_01_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 12;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup465, ReadAfterVecYLd], (instregex "^VPERM(I|T)2B256rm$")>;
+def : InstRW<[SPRWriteResGroup465, ReadAfterVecYLd], (instregex "^VPERM(I|T)2BZ256rm$")>;
def SPRWriteResGroup466 : SchedWriteRes<[SPRPort00_01_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 14;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup466, ReadAfterVecYLd], (instregex "^VPERM(I|T)2B256rmk(z?)$")>;
-def : InstRW<[SPRWriteResGroup466, ReadAfterVecYLd], (instrs VPERMI2W128rm,
- VPERMT2W256rm)>;
+def : InstRW<[SPRWriteResGroup466, ReadAfterVecYLd], (instregex "^VPERM(I|T)2BZ256rmk(z?)$")>;
+def : InstRW<[SPRWriteResGroup466, ReadAfterVecYLd], (instrs VPERMI2WZ128rm,
+ VPERMT2WZ256rm)>;
def SPRWriteResGroup467 : SchedWriteRes<[SPRPort00_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 12;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup467, ReadAfterVecYLd], (instregex "^VPERM(I|T)2Brm$")>;
+def : InstRW<[SPRWriteResGroup467, ReadAfterVecYLd], (instregex "^VPERM(I|T)2BZrm$")>;
def SPRWriteResGroup468 : SchedWriteRes<[SPRPort00_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 14;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup468, ReadAfterVecYLd], (instregex "^VPERM(I|T)2Brmk(z?)$")>;
-def : InstRW<[SPRWriteResGroup468, ReadAfterVecYLd], (instrs VPERMT2Wrm)>;
+def : InstRW<[SPRWriteResGroup468, ReadAfterVecYLd], (instregex "^VPERM(I|T)2BZrmk(z?)$")>;
+def : InstRW<[SPRWriteResGroup468, ReadAfterVecYLd], (instrs VPERMT2WZrm)>;
def SPRWriteResGroup469 : SchedWriteRes<[SPRPort00_05, SPRPort05]> {
let ReleaseAtCycles = [1, 2];
let Latency = 5;
let NumMicroOps = 3;
}
-def : InstRW<[SPRWriteResGroup469], (instregex "^VPERM(I|T)2Brr$")>;
+def : InstRW<[SPRWriteResGroup469], (instregex "^VPERM(I|T)2BZrr$")>;
def SPRWriteResGroup470 : SchedWriteRes<[SPRPort00_05, SPRPort05]> {
let ReleaseAtCycles = [1, 2];
let Latency = 7;
let NumMicroOps = 3;
}
-def : InstRW<[SPRWriteResGroup470], (instregex "^VPERM(I|T)2Brrk(z?)$",
- "^VPERM(I|T)2Wrr$")>;
+def : InstRW<[SPRWriteResGroup470], (instregex "^VPERM(I|T)2BZrrk(z?)$",
+ "^VPERM(I|T)2WZrr$")>;
def SPRWriteResGroup471 : SchedWriteRes<[SPRPort00_01_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 16;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup471, ReadAfterVecYLd], (instregex "^VPERMI2W128rmk(z?)$",
- "^VPERMT2W256rmk(z?)$")>;
+def : InstRW<[SPRWriteResGroup471, ReadAfterVecYLd], (instregex "^VPERMI2WZ128rmk(z?)$",
+ "^VPERMT2WZ256rmk(z?)$")>;
def SPRWriteResGroup472 : SchedWriteRes<[SPRPort00_01_05, SPRPort05]> {
let ReleaseAtCycles = [1, 2];
let Latency = 9;
let NumMicroOps = 3;
}
-def : InstRW<[SPRWriteResGroup472], (instregex "^VPERM(I|T)2W(128|256)rrk(z?)$")>;
+def : InstRW<[SPRWriteResGroup472], (instregex "^VPERM(I|T)2WZ(128|256)rrk(z?)$")>;
def SPRWriteResGroup473 : SchedWriteRes<[SPRPort00_01_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 15;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup473, ReadAfterVecYLd], (instregex "^VPERMT2W128rmk(z?)$")>;
-def : InstRW<[SPRWriteResGroup473, ReadAfterVecYLd], (instrs VPERMI2W256rm)>;
+def : InstRW<[SPRWriteResGroup473, ReadAfterVecYLd], (instregex "^VPERMT2WZ128rmk(z?)$")>;
+def : InstRW<[SPRWriteResGroup473, ReadAfterVecYLd], (instrs VPERMI2WZ256rm)>;
def SPRWriteResGroup474 : SchedWriteRes<[SPRPort00_01_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 17;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup474, ReadAfterVecYLd], (instregex "^VPERMI2W256rmk(z?)$")>;
+def : InstRW<[SPRWriteResGroup474, ReadAfterVecYLd], (instregex "^VPERMI2WZ256rmk(z?)$")>;
def SPRWriteResGroup475 : SchedWriteRes<[SPRPort00_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 15;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup475, ReadAfterVecYLd], (instrs VPERMI2Wrm)>;
+def : InstRW<[SPRWriteResGroup475, ReadAfterVecYLd], (instrs VPERMI2WZrm)>;
def SPRWriteResGroup476 : SchedWriteRes<[SPRPort00_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 17;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup476, ReadAfterVecYLd], (instregex "^VPERMI2Wrmk(z?)$")>;
+def : InstRW<[SPRWriteResGroup476, ReadAfterVecYLd], (instregex "^VPERMI2WZrmk(z?)$")>;
def SPRWriteResGroup477 : SchedWriteRes<[SPRPort00_05, SPRPort05]> {
let ReleaseAtCycles = [1, 2];
let Latency = 9;
let NumMicroOps = 3;
}
-def : InstRW<[SPRWriteResGroup477], (instregex "^VPERM(I|T)2Wrrk(z?)$")>;
+def : InstRW<[SPRWriteResGroup477], (instregex "^VPERM(I|T)2WZrrk(z?)$")>;
def SPRWriteResGroup478 : SchedWriteRes<[SPRPort00_05, SPRPort02_03_11, SPRPort05]> {
let ReleaseAtCycles = [1, 1, 2];
let Latency = 16;
let NumMicroOps = 4;
}
-def : InstRW<[SPRWriteResGroup478, ReadAfterVecYLd], (instregex "^VPERMT2Wrmk(z?)$")>;
+def : InstRW<[SPRWriteResGroup478, ReadAfterVecYLd], (instregex "^VPERMT2WZrmk(z?)$")>;
def SPRWriteResGroup479 : SchedWriteRes<[SPRPort00_01, SPRPort02_03_11, SPRPort05]> {
let Latency = 10;
diff --git a/llvm/lib/Target/X86/X86SchedSkylakeClient.td b/llvm/lib/Target/X86/X86SchedSkylakeClient.td
index 92ed491bc296..4fa138f69fb9 100644
--- a/llvm/lib/Target/X86/X86SchedSkylakeClient.td
+++ b/llvm/lib/Target/X86/X86SchedSkylakeClient.td
@@ -1064,8 +1064,8 @@ def SKLWriteResGroup85 : SchedWriteRes<[SKLPort23]> {
let ReleaseAtCycles = [1];
}
def: InstRW<[SKLWriteResGroup85], (instregex "LD_F(32|64|80)m")>;
-def: InstRW<[SKLWriteResGroup85], (instrs VBROADCASTF128,
- VBROADCASTI128,
+def: InstRW<[SKLWriteResGroup85], (instrs VBROADCASTF128rm,
+ VBROADCASTI128rm,
VBROADCASTSDYrm,
VBROADCASTSSYrm,
VMOVDDUPYrm,
diff --git a/llvm/lib/Target/X86/X86SchedSkylakeServer.td b/llvm/lib/Target/X86/X86SchedSkylakeServer.td
index ed22f95c83e5..3da688cda2c6 100644
--- a/llvm/lib/Target/X86/X86SchedSkylakeServer.td
+++ b/llvm/lib/Target/X86/X86SchedSkylakeServer.td
@@ -1254,8 +1254,8 @@ def SKXWriteResGroup89 : SchedWriteRes<[SKXPort23]> {
let ReleaseAtCycles = [1];
}
def: InstRW<[SKXWriteResGroup89], (instregex "LD_F(32|64|80)m")>;
-def: InstRW<[SKXWriteResGroup89], (instrs VBROADCASTF128,
- VBROADCASTI128,
+def: InstRW<[SKXWriteResGroup89], (instrs VBROADCASTF128rm,
+ VBROADCASTI128rm,
VBROADCASTSDYrm,
VBROADCASTSSYrm,
VMOVDDUPYrm,
@@ -1379,12 +1379,12 @@ def SKXWriteResGroup97 : SchedWriteRes<[SKXPort5,SKXPort015]> {
let NumMicroOps = 3;
let ReleaseAtCycles = [2,1];
}
-def: InstRW<[SKXWriteResGroup97], (instregex "VPERMI2W128rr",
- "VPERMI2W256rr",
- "VPERMI2Wrr",
- "VPERMT2W128rr",
- "VPERMT2W256rr",
- "VPERMT2Wrr")>;
+def: InstRW<[SKXWriteResGroup97], (instregex "VPERMI2WZ128rr",
+ "VPERMI2WZ256rr",
+ "VPERMI2WZrr",
+ "VPERMT2WZ128rr",
+ "VPERMT2WZ256rr",
+ "VPERMT2WZrr")>;
def SKXWriteResGroup99 : SchedWriteRes<[SKXPort23,SKXPort0156]> {
let Latency = 7;
@@ -1675,14 +1675,14 @@ def: InstRW<[SKXWriteResGroup136], (instregex "VALIGN(D|Q)Z128rm(b?)i",
"VFPCLASSSDZrm(b?)",
"VFPCLASSSSZrm(b?)",
"(V?)PCMPGTQrm",
- "VPERMI2D128rm(b?)",
- "VPERMI2PD128rm(b?)",
- "VPERMI2PS128rm(b?)",
- "VPERMI2Q128rm(b?)",
- "VPERMT2D128rm(b?)",
- "VPERMT2PD128rm(b?)",
- "VPERMT2PS128rm(b?)",
- "VPERMT2Q128rm(b?)",
+ "VPERMI2DZ128rm(b?)",
+ "VPERMI2PDZ128rm(b?)",
+ "VPERMI2PSZ128rm(b?)",
+ "VPERMI2QZ128rm(b?)",
+ "VPERMT2DZ128rm(b?)",
+ "VPERMT2PDZ128rm(b?)",
+ "VPERMT2PSZ128rm(b?)",
+ "VPERMT2QZ128rm(b?)",
"VPMAXSQZ128rm(b?)",
"VPMAXUQZ128rm(b?)",
"VPMINSQZ128rm(b?)",
@@ -1983,8 +1983,8 @@ def SKXWriteResGroup183 : SchedWriteRes<[SKXPort5,SKXPort23,SKXPort015]> {
let NumMicroOps = 4;
let ReleaseAtCycles = [2,1,1];
}
-def: InstRW<[SKXWriteResGroup183], (instregex "VPERMI2W128rm(b?)",
- "VPERMT2W128rm(b?)")>;
+def: InstRW<[SKXWriteResGroup183], (instregex "VPERMI2WZ128rm(b?)",
+ "VPERMT2WZ128rm(b?)")>;
def SKXWriteResGroup187 : SchedWriteRes<[SKXPort0,SKXPort5,SKXPort23]> {
let Latency = 14;
@@ -2010,10 +2010,10 @@ def SKXWriteResGroup189 : SchedWriteRes<[SKXPort5,SKXPort23,SKXPort015]> {
let NumMicroOps = 4;
let ReleaseAtCycles = [2,1,1];
}
-def: InstRW<[SKXWriteResGroup189], (instregex "VPERMI2W256rm(b?)",
- "VPERMI2Wrm(b?)",
- "VPERMT2W256rm(b?)",
- "VPERMT2Wrm(b?)")>;
+def: InstRW<[SKXWriteResGroup189], (instregex "VPERMI2WZ256rm(b?)",
+ "VPERMI2WZrm(b?)",
+ "VPERMT2WZ256rm(b?)",
+ "VPERMT2WZrm(b?)")>;
def SKXWriteResGroup190 : SchedWriteRes<[SKXPort1,SKXPort06,SKXPort15,SKXPort0156]> {
let Latency = 14;
diff --git a/llvm/lib/Target/X86/X86ScheduleBdVer2.td b/llvm/lib/Target/X86/X86ScheduleBdVer2.td
index aeeabba45b65..c9749979576f 100644
--- a/llvm/lib/Target/X86/X86ScheduleBdVer2.td
+++ b/llvm/lib/Target/X86/X86ScheduleBdVer2.td
@@ -933,7 +933,7 @@ def PdWriteVBROADCASTF128 : SchedWriteRes<[PdFPU01, PdFPFMA]> {
let ReleaseAtCycles = [1, 3];
let NumMicroOps = 2;
}
-def : InstRW<[PdWriteVBROADCASTF128], (instrs VBROADCASTF128)>;
+def : InstRW<[PdWriteVBROADCASTF128], (instrs VBROADCASTF128rm)>;
defm : PdWriteResXMMPair<WriteFVarShuffle, [PdFPU1, PdFPXBR], 3>;
defm : PdWriteResYMMPair<WriteFVarShuffleY, [PdFPU1, PdFPXBR], 3, [2, 2], 2>;
diff --git a/llvm/lib/Target/X86/X86ScheduleBtVer2.td b/llvm/lib/Target/X86/X86ScheduleBtVer2.td
index 8b7d501981b1..9cba933e82b0 100644
--- a/llvm/lib/Target/X86/X86ScheduleBtVer2.td
+++ b/llvm/lib/Target/X86/X86ScheduleBtVer2.td
@@ -816,7 +816,7 @@ def JWriteVBROADCASTYLd: SchedWriteRes<[JLAGU, JFPU01, JFPX]> {
}
def : InstRW<[JWriteVBROADCASTYLd], (instrs VBROADCASTSDYrm,
VBROADCASTSSYrm,
- VBROADCASTF128)>;
+ VBROADCASTF128rm)>;
def JWriteJVZEROALL: SchedWriteRes<[]> {
let Latency = 90;
diff --git a/llvm/lib/Target/X86/X86ScheduleZnver1.td b/llvm/lib/Target/X86/X86ScheduleZnver1.td
index e39bcf807a0c..7ee9eadf8439 100644
--- a/llvm/lib/Target/X86/X86ScheduleZnver1.td
+++ b/llvm/lib/Target/X86/X86ScheduleZnver1.td
@@ -996,8 +996,8 @@ def ZnWriteBROADCAST : SchedWriteRes<[ZnAGU, ZnFPU13]> {
let Latency = 8;
}
// VBROADCASTF128 / VBROADCASTI128.
-def : InstRW<[ZnWriteBROADCAST], (instrs VBROADCASTF128,
- VBROADCASTI128)>;
+def : InstRW<[ZnWriteBROADCAST], (instrs VBROADCASTF128rm,
+ VBROADCASTI128rm)>;
// EXTRACTPS.
// r32,x,i.
diff --git a/llvm/lib/Target/X86/X86ScheduleZnver2.td b/llvm/lib/Target/X86/X86ScheduleZnver2.td
index ecaca70bb677..c0775847798d 100644
--- a/llvm/lib/Target/X86/X86ScheduleZnver2.td
+++ b/llvm/lib/Target/X86/X86ScheduleZnver2.td
@@ -1004,8 +1004,8 @@ def Zn2WriteBROADCAST : SchedWriteRes<[Zn2AGU, Zn2FPU13]> {
let Latency = 8;
}
// VBROADCASTF128 / VBROADCASTI128.
-def : InstRW<[Zn2WriteBROADCAST], (instrs VBROADCASTF128,
- VBROADCASTI128)>;
+def : InstRW<[Zn2WriteBROADCAST], (instrs VBROADCASTF128rm,
+ VBROADCASTI128rm)>;
// EXTRACTPS.
// r32,x,i.
diff --git a/llvm/lib/Target/X86/X86ScheduleZnver4.td b/llvm/lib/Target/X86/X86ScheduleZnver4.td
index 405000f0851e..dac4d8422582 100644
--- a/llvm/lib/Target/X86/X86ScheduleZnver4.td
+++ b/llvm/lib/Target/X86/X86ScheduleZnver4.td
@@ -1743,8 +1743,8 @@ def Zn4PERMIT2_128: SchedWriteRes<[Zn4FPFMisc12]> {
let NumMicroOps = 1;
}
def : InstRW<[Zn4PERMIT2_128], (instregex
- "VPERM(I2|T2)(PS|PD|W)128(rr|rrk|rrkz)",
- "VPERM(I2|T2)(B|D|Q)128(rr|rrk|rrkz)"
+ "VPERM(I2|T2)(PS|PD|W)Z128(rr|rrk|rrkz)",
+ "VPERM(I2|T2)(B|D|Q)Z128(rr|rrk|rrkz)"
)>;
def Zn4PERMIT2_128rr:SchedWriteRes<[Zn4FPFMisc12]> {
@@ -1763,11 +1763,11 @@ def Zn4PERMIT2_256: SchedWriteRes<[Zn4FPFMisc12]> {
let NumMicroOps = 1;
}
def : InstRW<[Zn4PERMIT2_256], (instregex
- "VPERM(I2|T2)(PS|PD|W)256(rr|rrk|rrkz)",
+ "VPERM(I2|T2)(PS|PD|W)Z256(rr|rrk|rrkz)",
"VPERMP(S|D)Z256(rr|rrk|rrkz)",
"V(P?)COMPRESS(B|W|D|Q|PD|PS|SD|SQ)Z256(rr|rrk|rrkz)",
"VPERM(B|D|Q|W)Z256(rr|rrk|rrkz)",
- "VPERM(I2|Q|T2)(B|D|Q)(Z?)256(rr|rrk|rrkz)",
+ "VPERM(I2|Q|T2)(B|D|Q)Z256(rr|rrk|rrkz)",
"VPEXPAND(B|W)Z256(rr|rrk|rrkz)"
)>;
@@ -1777,12 +1777,12 @@ def Zn4PERMIT2Z: SchedWriteRes<[Zn4FPFMisc12]> {
let NumMicroOps = 1;
}
def : InstRW<[Zn4PERMIT2Z], (instregex
- "VPERM(I2|T2)(PS|PD|W)(rr|rrk|rrkz)",
+ "VPERM(I2|T2)(PS|PD|W)Z(rr|rrk|rrkz)",
"VPERM(B|D|W)Z(rr|rrk|rrkz)",
- "VPERM(I2|Q|T2)(B|D|Q)(Z?)(rr|rrk|rrkz)",
+ "VPERM(I2|Q|T2)(B|D|Q)Z(rr|rrk|rrkz)",
"V(P?)COMPRESS(B|W|D|Q|PD|PS|SD|SQ)Z(rr|rrk|rrkz)",
"VPEXPAND(B|W)Z(rr|rrk|rrkz)",
- "VPERMP(S|D)Z(rr|rrk|rrkz)"
+ "VPERMP(S|D)Z(rr|rrk|rrkz)"
)>;
// ALU SLOW Misc Instructions
diff --git a/llvm/lib/Target/X86/X86Subtarget.cpp b/llvm/lib/Target/X86/X86Subtarget.cpp
index 328608363a8f..d63f1ca1695b 100644
--- a/llvm/lib/Target/X86/X86Subtarget.cpp
+++ b/llvm/lib/Target/X86/X86Subtarget.cpp
@@ -86,16 +86,16 @@ X86Subtarget::classifyLocalReference(const GlobalValue *GV) const {
CodeModel::Model CM = TM.getCodeModel();
assert(CM != CodeModel::Tiny &&
"Tiny codesize model not supported on X86");
- // In the large code model, even referencing a global under the large data
- // threshold which is considered "small", we need to use GOTOFF.
+ // In the large code model, all text is far from any global data, so we
+ // use GOTOFF.
if (CM == CodeModel::Large)
return X86II::MO_GOTOFF;
- // Large objects use GOTOFF, otherwise use RIP-rel access.
- if (auto *GO = dyn_cast_or_null<GlobalObject>(GV))
- return TM.isLargeGlobalObject(GO) ? X86II::MO_GOTOFF
- : X86II::MO_NO_FLAG;
- // For non-GlobalObjects, the small and medium code models treat them as
- // accessible with a RIP-rel access.
+ // Large GlobalValues use GOTOFF, otherwise use RIP-rel access.
+ if (GV)
+ return TM.isLargeGlobalValue(GV) ? X86II::MO_GOTOFF : X86II::MO_NO_FLAG;
+ // GV == nullptr is for all other non-GlobalValue global data like the
+ // constant pool, jump tables, labels, etc. The small and medium code
+ // models treat these as accessible with a RIP-rel access.
return X86II::MO_NO_FLAG;
}
@@ -267,8 +267,8 @@ void X86Subtarget::initSubtargetFeatures(StringRef CPU, StringRef TuneCPU,
if (CPU == "generic" || CPU == "pentium4" || CPU == "x86-64") {
size_t posNoEVEX512 = FS.rfind("-evex512");
// Make sure we won't be cheated by "-avx512fp16".
- size_t posNoAVX512F = FS.endswith("-avx512f") ? FS.size() - 8
- : FS.rfind("-avx512f,");
+ size_t posNoAVX512F =
+ FS.ends_with("-avx512f") ? FS.size() - 8 : FS.rfind("-avx512f,");
size_t posEVEX512 = FS.rfind("+evex512");
// Any AVX512XXX will enable AVX512F.
size_t posAVX512F = FS.rfind("+avx512");
diff --git a/llvm/lib/Target/XCore/XCoreISelLowering.cpp b/llvm/lib/Target/XCore/XCoreISelLowering.cpp
index 80edad58985b..7736adab19e8 100644
--- a/llvm/lib/Target/XCore/XCoreISelLowering.cpp
+++ b/llvm/lib/Target/XCore/XCoreISelLowering.cpp
@@ -249,7 +249,7 @@ SDValue XCoreTargetLowering::getGlobalAddressWrapper(SDValue GA,
return DAG.getNode(XCoreISD::PCRelativeWrapper, dl, MVT::i32, GA);
const auto *GVar = dyn_cast<GlobalVariable>(GV);
- if ((GV->hasSection() && GV->getSection().startswith(".cp.")) ||
+ if ((GV->hasSection() && GV->getSection().starts_with(".cp.")) ||
(GVar && GVar->isConstant() && GV->hasLocalLinkage()))
return DAG.getNode(XCoreISD::CPRelativeWrapper, dl, MVT::i32, GA);
diff --git a/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp b/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp
index 52a0a09d3ea5..ae697f43b0ee 100644
--- a/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp
+++ b/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp
@@ -98,7 +98,7 @@ MCSection *XCoreTargetObjectFile::getExplicitSectionGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
StringRef SectionName = GO->getSection();
// Infer section flags from the section name if we can.
- bool IsCPRel = SectionName.startswith(".cp.");
+ bool IsCPRel = SectionName.starts_with(".cp.");
if (IsCPRel && !Kind.isReadOnly())
report_fatal_error("Using .cp. section for writeable object.");
return getContext().getELFSection(SectionName, getXCoreSectionType(Kind),
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index 76c7328b547c..3f808298527f 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -598,8 +598,8 @@ bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic,
bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info,
StringRef Name, SMLoc NameLoc,
OperandVector &Operands) {
- if ((Name.startswith("wsr.") || Name.startswith("rsr.") ||
- Name.startswith("xsr.")) &&
+ if ((Name.starts_with("wsr.") || Name.starts_with("rsr.") ||
+ Name.starts_with("xsr.")) &&
(Name.size() > 4)) {
// Parse case when instruction name is concatenated with SR register
// name, like "wsr.sar a1"
@@ -655,8 +655,8 @@ bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info,
bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info,
StringRef Name, SMLoc NameLoc,
OperandVector &Operands) {
- if (Name.startswith("wsr") || Name.startswith("rsr") ||
- Name.startswith("xsr")) {
+ if (Name.starts_with("wsr") || Name.starts_with("rsr") ||
+ Name.starts_with("xsr")) {
return ParseInstructionWithSR(Info, Name, NameLoc, Operands);
}
diff --git a/llvm/lib/TargetParser/AArch64TargetParser.cpp b/llvm/lib/TargetParser/AArch64TargetParser.cpp
index a3f9dfa4a283..d3c72497c41c 100644
--- a/llvm/lib/TargetParser/AArch64TargetParser.cpp
+++ b/llvm/lib/TargetParser/AArch64TargetParser.cpp
@@ -75,7 +75,7 @@ StringRef AArch64::resolveCPUAlias(StringRef Name) {
}
StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
- if (ArchExt.startswith("no")) {
+ if (ArchExt.starts_with("no")) {
StringRef ArchExtBase(ArchExt.substr(2));
for (const auto &AE : Extensions) {
if (!AE.NegFeature.empty() && ArchExtBase == AE.Name)
@@ -110,7 +110,7 @@ std::optional<AArch64::ArchInfo> AArch64::parseArch(StringRef Arch) {
StringRef Syn = llvm::ARM::getArchSynonym(Arch);
for (const auto *A : ArchInfos) {
- if (A->Name.endswith(Syn))
+ if (A->Name.ends_with(Syn))
return *A;
}
return {};
diff --git a/llvm/lib/TargetParser/ARMTargetParser.cpp b/llvm/lib/TargetParser/ARMTargetParser.cpp
index d09992441909..27d168020ce6 100644
--- a/llvm/lib/TargetParser/ARMTargetParser.cpp
+++ b/llvm/lib/TargetParser/ARMTargetParser.cpp
@@ -32,7 +32,7 @@ ARM::ArchKind ARM::parseArch(StringRef Arch) {
Arch = getCanonicalArchName(Arch);
StringRef Syn = getArchSynonym(Arch);
for (const auto &A : ARMArchNames) {
- if (A.Name.endswith(Syn))
+ if (A.Name.ends_with(Syn))
return A.ID;
}
return ArchKind::INVALID;
@@ -348,7 +348,7 @@ StringRef ARM::getArchExtName(uint64_t ArchExtKind) {
}
static bool stripNegationPrefix(StringRef &Name) {
- if (Name.startswith("no")) {
+ if (Name.starts_with("no")) {
Name = Name.substr(2);
return true;
}
diff --git a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
index 907ee5957c7c..10b80cad4347 100644
--- a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
+++ b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
@@ -57,19 +57,19 @@ StringRef ARM::getCanonicalArchName(StringRef Arch) {
StringRef Error = "";
// Begins with "arm" / "thumb", move past it.
- if (A.startswith("arm64_32"))
+ if (A.starts_with("arm64_32"))
offset = 8;
- else if (A.startswith("arm64e"))
+ else if (A.starts_with("arm64e"))
offset = 6;
- else if (A.startswith("arm64"))
+ else if (A.starts_with("arm64"))
offset = 5;
- else if (A.startswith("aarch64_32"))
+ else if (A.starts_with("aarch64_32"))
offset = 10;
- else if (A.startswith("arm"))
+ else if (A.starts_with("arm"))
offset = 3;
- else if (A.startswith("thumb"))
+ else if (A.starts_with("thumb"))
offset = 5;
- else if (A.startswith("aarch64")) {
+ else if (A.starts_with("aarch64")) {
offset = 7;
// AArch64 uses "_be", not "eb" suffix.
if (A.contains("eb"))
@@ -82,7 +82,7 @@ StringRef ARM::getCanonicalArchName(StringRef Arch) {
if (offset != StringRef::npos && A.substr(offset, 2) == "eb")
offset += 2;
// Or, if it ends with eb ("armv7eb"), chop it off.
- else if (A.endswith("eb"))
+ else if (A.ends_with("eb"))
A = A.substr(0, A.size() - 2);
// Trim the head
if (offset != StringRef::npos)
@@ -116,18 +116,18 @@ ARM::ISAKind ARM::parseArchISA(StringRef Arch) {
}
ARM::EndianKind ARM::parseArchEndian(StringRef Arch) {
- if (Arch.startswith("armeb") || Arch.startswith("thumbeb") ||
- Arch.startswith("aarch64_be"))
+ if (Arch.starts_with("armeb") || Arch.starts_with("thumbeb") ||
+ Arch.starts_with("aarch64_be"))
return EndianKind::BIG;
- if (Arch.startswith("arm") || Arch.startswith("thumb")) {
- if (Arch.endswith("eb"))
+ if (Arch.starts_with("arm") || Arch.starts_with("thumb")) {
+ if (Arch.ends_with("eb"))
return EndianKind::BIG;
else
return EndianKind::LITTLE;
}
- if (Arch.startswith("aarch64") || Arch.startswith("aarch64_32"))
+ if (Arch.starts_with("aarch64") || Arch.starts_with("aarch64_32"))
return EndianKind::LITTLE;
return EndianKind::INVALID;
diff --git a/llvm/lib/TargetParser/CSKYTargetParser.cpp b/llvm/lib/TargetParser/CSKYTargetParser.cpp
index 493f253cd716..006d2bb342ac 100644
--- a/llvm/lib/TargetParser/CSKYTargetParser.cpp
+++ b/llvm/lib/TargetParser/CSKYTargetParser.cpp
@@ -150,7 +150,7 @@ StringRef CSKY::getArchExtName(uint64_t ArchExtKind) {
}
static bool stripNegationPrefix(StringRef &Name) {
- if (Name.startswith("no")) {
+ if (Name.starts_with("no")) {
Name = Name.substr(2);
return true;
}
diff --git a/llvm/lib/TargetParser/Host.cpp b/llvm/lib/TargetParser/Host.cpp
index 40f4ba0be550..e61fcb248fae 100644
--- a/llvm/lib/TargetParser/Host.cpp
+++ b/llvm/lib/TargetParser/Host.cpp
@@ -170,18 +170,18 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {
StringRef Hardware;
StringRef Part;
for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
- if (Lines[I].startswith("CPU implementer"))
+ if (Lines[I].starts_with("CPU implementer"))
Implementer = Lines[I].substr(15).ltrim("\t :");
- if (Lines[I].startswith("Hardware"))
+ if (Lines[I].starts_with("Hardware"))
Hardware = Lines[I].substr(8).ltrim("\t :");
- if (Lines[I].startswith("CPU part"))
+ if (Lines[I].starts_with("CPU part"))
Part = Lines[I].substr(8).ltrim("\t :");
}
if (Implementer == "0x41") { // ARM Ltd.
// MSM8992/8994 may give cpu part for the core that the kernel is running on,
// which is undeterministic and wrong. Always return cortex-a53 for these SoC.
- if (Hardware.endswith("MSM8994") || Hardware.endswith("MSM8996"))
+ if (Hardware.ends_with("MSM8994") || Hardware.ends_with("MSM8996"))
return "cortex-a53";
@@ -367,7 +367,7 @@ StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) {
// Look for the CPU features.
SmallVector<StringRef, 32> CPUFeatures;
for (unsigned I = 0, E = Lines.size(); I != E; ++I)
- if (Lines[I].startswith("features")) {
+ if (Lines[I].starts_with("features")) {
size_t Pos = Lines[I].find(':');
if (Pos != StringRef::npos) {
Lines[I].drop_front(Pos + 1).split(CPUFeatures, ' ');
@@ -386,7 +386,7 @@ StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) {
// Now check the processor machine type.
for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
- if (Lines[I].startswith("processor ")) {
+ if (Lines[I].starts_with("processor ")) {
size_t Pos = Lines[I].find("machine = ");
if (Pos != StringRef::npos) {
Pos += sizeof("machine = ") - 1;
@@ -409,7 +409,7 @@ StringRef sys::detail::getHostCPUNameForRISCV(StringRef ProcCpuinfoContent) {
// Look for uarch line to determine cpu name
StringRef UArch;
for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
- if (Lines[I].startswith("uarch")) {
+ if (Lines[I].starts_with("uarch")) {
UArch = Lines[I].substr(5).ltrim("\t :");
break;
}
@@ -1536,7 +1536,7 @@ StringRef sys::detail::getHostCPUNameForSPARC(StringRef ProcCpuinfoContent) {
// Look for cpu line to determine cpu name
StringRef Cpu;
for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
- if (Lines[I].startswith("cpu")) {
+ if (Lines[I].starts_with("cpu")) {
Cpu = Lines[I].substr(5).ltrim("\t :");
break;
}
@@ -1853,7 +1853,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
// Look for the CPU features.
for (unsigned I = 0, E = Lines.size(); I != E; ++I)
- if (Lines[I].startswith("Features")) {
+ if (Lines[I].starts_with("Features")) {
Lines[I].split(CPUFeatures, ' ');
break;
}
diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp
index c5e9ad43d225..ac04dab04897 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -477,7 +477,7 @@ static Triple::ArchType parseARMArch(StringRef ArchName) {
// Thumb only exists in v4+
if (ISA == ARM::ISAKind::THUMB &&
- (ArchName.startswith("v2") || ArchName.startswith("v3")))
+ (ArchName.starts_with("v2") || ArchName.starts_with("v3")))
return Triple::UnknownArch;
// Thumb only for v6m
@@ -574,10 +574,10 @@ static Triple::ArchType parseArch(StringRef ArchName) {
// Some architectures require special parsing logic just to compute the
// ArchType result.
if (AT == Triple::UnknownArch) {
- if (ArchName.startswith("arm") || ArchName.startswith("thumb") ||
- ArchName.startswith("aarch64"))
+ if (ArchName.starts_with("arm") || ArchName.starts_with("thumb") ||
+ ArchName.starts_with("aarch64"))
return parseARMArch(ArchName);
- if (ArchName.startswith("bpf"))
+ if (ArchName.starts_with("bpf"))
return parseBPFArch(ArchName);
}
@@ -706,8 +706,8 @@ static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) {
}
static Triple::SubArchType parseSubArch(StringRef SubArchName) {
- if (SubArchName.startswith("mips") &&
- (SubArchName.endswith("r6el") || SubArchName.endswith("r6")))
+ if (SubArchName.starts_with("mips") &&
+ (SubArchName.ends_with("r6el") || SubArchName.ends_with("r6")))
return Triple::MipsSubArch_r6;
if (SubArchName == "powerpcspe")
@@ -719,7 +719,7 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) {
if (SubArchName == "arm64ec")
return Triple::AArch64SubArch_arm64ec;
- if (SubArchName.startswith("spirv"))
+ if (SubArchName.starts_with("spirv"))
return StringSwitch<Triple::SubArchType>(SubArchName)
.EndsWith("v1.0", Triple::SPIRVSubArch_v10)
.EndsWith("v1.1", Triple::SPIRVSubArch_v11)
@@ -1004,8 +1004,8 @@ std::string Triple::normalize(StringRef Str) {
OSType OS = UnknownOS;
if (Components.size() > 2) {
OS = parseOS(Components[2]);
- IsCygwin = Components[2].startswith("cygwin");
- IsMinGW32 = Components[2].startswith("mingw");
+ IsCygwin = Components[2].starts_with("cygwin");
+ IsMinGW32 = Components[2].starts_with("mingw");
}
EnvironmentType Environment = UnknownEnvironment;
if (Components.size() > 3)
@@ -1049,8 +1049,8 @@ std::string Triple::normalize(StringRef Str) {
break;
case 2:
OS = parseOS(Comp);
- IsCygwin = Comp.startswith("cygwin");
- IsMinGW32 = Comp.startswith("mingw");
+ IsCygwin = Comp.starts_with("cygwin");
+ IsMinGW32 = Comp.starts_with("mingw");
Valid = OS != UnknownOS || IsCygwin || IsMinGW32;
break;
case 3:
@@ -1127,7 +1127,8 @@ std::string Triple::normalize(StringRef Str) {
// Special case logic goes here. At this point Arch, Vendor and OS have the
// correct values for the computed components.
std::string NormalizedEnvironment;
- if (Environment == Triple::Android && Components[3].startswith("androideabi")) {
+ if (Environment == Triple::Android &&
+ Components[3].starts_with("androideabi")) {
StringRef AndroidVersion = Components[3].drop_front(strlen("androideabi"));
if (AndroidVersion.empty()) {
Components[3] = "android";
@@ -1206,7 +1207,7 @@ static VersionTuple parseVersionFromName(StringRef Name) {
VersionTuple Triple::getEnvironmentVersion() const {
StringRef EnvironmentName = getEnvironmentName();
StringRef EnvironmentTypeName = getEnvironmentTypeName(getEnvironment());
- if (EnvironmentName.startswith(EnvironmentTypeName))
+ if (EnvironmentName.starts_with(EnvironmentTypeName))
EnvironmentName = EnvironmentName.substr(EnvironmentTypeName.size());
return parseVersionFromName(EnvironmentName);
@@ -1216,7 +1217,7 @@ VersionTuple Triple::getOSVersion() const {
StringRef OSName = getOSName();
// Assume that the OS portion of the triple starts with the canonical name.
StringRef OSTypeName = getOSTypeName(getOS());
- if (OSName.startswith(OSTypeName))
+ if (OSName.starts_with(OSTypeName))
OSName = OSName.substr(OSTypeName.size());
else if (getOS() == MacOSX)
OSName.consume_front("macos");
diff --git a/llvm/lib/TextAPI/Symbol.cpp b/llvm/lib/TextAPI/Symbol.cpp
index c3756fcb8435..fd395436051d 100644
--- a/llvm/lib/TextAPI/Symbol.cpp
+++ b/llvm/lib/TextAPI/Symbol.cpp
@@ -73,16 +73,16 @@ bool Symbol::operator==(const Symbol &O) const {
}
SimpleSymbol parseSymbol(StringRef SymName, const SymbolFlags Flags) {
- if (SymName.startswith(ObjC1ClassNamePrefix))
+ if (SymName.starts_with(ObjC1ClassNamePrefix))
return {SymName.drop_front(ObjC1ClassNamePrefix.size()),
SymbolKind::ObjectiveCClass};
- if (SymName.startswith(ObjC2ClassNamePrefix))
+ if (SymName.starts_with(ObjC2ClassNamePrefix))
return {SymName.drop_front(ObjC2ClassNamePrefix.size()),
SymbolKind::ObjectiveCClass};
- if (SymName.startswith(ObjC2MetaClassNamePrefix))
+ if (SymName.starts_with(ObjC2MetaClassNamePrefix))
return {SymName.drop_front(ObjC2MetaClassNamePrefix.size()),
SymbolKind::ObjectiveCClass};
- if (SymName.startswith(ObjC2EHTypePrefix)) {
+ if (SymName.starts_with(ObjC2EHTypePrefix)) {
// When classes without ehtype are used in try/catch blocks
// a weak-defined symbol is exported. In those cases, treat these as a
// global instead.
@@ -92,7 +92,7 @@ SimpleSymbol parseSymbol(StringRef SymName, const SymbolFlags Flags) {
SymbolKind::ObjectiveCClassEHType};
}
- if (SymName.startswith(ObjC2IVarPrefix))
+ if (SymName.starts_with(ObjC2IVarPrefix))
return {SymName.drop_front(ObjC2IVarPrefix.size()),
SymbolKind::ObjectiveCInstanceVariable};
return {SymName, SymbolKind::GlobalSymbol};
diff --git a/llvm/lib/TextAPI/Target.cpp b/llvm/lib/TextAPI/Target.cpp
index 7f4551973507..a50abeeca194 100644
--- a/llvm/lib/TextAPI/Target.cpp
+++ b/llvm/lib/TextAPI/Target.cpp
@@ -28,7 +28,7 @@ Expected<Target> Target::create(StringRef TargetValue) {
.Default(PLATFORM_UNKNOWN);
if (Platform == PLATFORM_UNKNOWN) {
- if (PlatformStr.startswith("<") && PlatformStr.endswith(">")) {
+ if (PlatformStr.starts_with("<") && PlatformStr.ends_with(">")) {
PlatformStr = PlatformStr.drop_front().drop_back();
unsigned long long RawValue;
if (!PlatformStr.getAsInteger(10, RawValue))
diff --git a/llvm/lib/TextAPI/TextStub.cpp b/llvm/lib/TextAPI/TextStub.cpp
index 635f6b3a3df6..9fa1459e9557 100644
--- a/llvm/lib/TextAPI/TextStub.cpp
+++ b/llvm/lib/TextAPI/TextStub.cpp
@@ -614,7 +614,7 @@ template <> struct MappingTraits<const InterfaceFile *> {
for (const auto &Symbol : Section.Symbols) {
if (Ctx->FileKind != FileType::TBD_V3 &&
- Symbol.value.startswith(ObjC2EHTypePrefix))
+ Symbol.value.starts_with(ObjC2EHTypePrefix))
File->addSymbol(SymbolKind::ObjectiveCClassEHType,
Symbol.value.drop_front(15), Targets, Flags);
else
@@ -649,7 +649,7 @@ template <> struct MappingTraits<const InterfaceFile *> {
synthesizeTargets(Section.Architectures, Platforms);
for (auto &Symbol : Section.Symbols) {
if (Ctx->FileKind != FileType::TBD_V3 &&
- Symbol.value.startswith(ObjC2EHTypePrefix))
+ Symbol.value.starts_with(ObjC2EHTypePrefix))
File->addSymbol(SymbolKind::ObjectiveCClassEHType,
Symbol.value.drop_front(15), Targets,
SymbolFlags::Undefined | Flags);
@@ -1073,23 +1073,23 @@ static void DiagHandler(const SMDiagnostic &Diag, void *Context) {
Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) {
auto TAPIFile = InputBuffer.getBuffer().trim();
- if (TAPIFile.startswith("{") && TAPIFile.endswith("}"))
+ if (TAPIFile.starts_with("{") && TAPIFile.ends_with("}"))
return FileType::TBD_V5;
- if (!TAPIFile.endswith("..."))
+ if (!TAPIFile.ends_with("..."))
return createStringError(std::errc::not_supported, "unsupported file type");
- if (TAPIFile.startswith("--- !tapi-tbd\n"))
+ if (TAPIFile.starts_with("--- !tapi-tbd\n"))
return FileType::TBD_V4;
- if (TAPIFile.startswith("--- !tapi-tbd-v3\n"))
+ if (TAPIFile.starts_with("--- !tapi-tbd-v3\n"))
return FileType::TBD_V3;
- if (TAPIFile.startswith("--- !tapi-tbd-v2\n"))
+ if (TAPIFile.starts_with("--- !tapi-tbd-v2\n"))
return FileType::TBD_V2;
- if (TAPIFile.startswith("--- !tapi-tbd-v1\n") ||
- TAPIFile.startswith("---\narchs:"))
+ if (TAPIFile.starts_with("--- !tapi-tbd-v1\n") ||
+ TAPIFile.starts_with("---\narchs:"))
return FileType::TBD_V1;
return createStringError(std::errc::not_supported, "unsupported file type");
diff --git a/llvm/lib/Transforms/CFGuard/CFGuard.cpp b/llvm/lib/Transforms/CFGuard/CFGuard.cpp
index 387734358775..4d4306576017 100644
--- a/llvm/lib/Transforms/CFGuard/CFGuard.cpp
+++ b/llvm/lib/Transforms/CFGuard/CFGuard.cpp
@@ -34,25 +34,22 @@ namespace {
/// Adds Control Flow Guard (CFG) checks on indirect function calls/invokes.
/// These checks ensure that the target address corresponds to the start of an
-/// address-taken function. X86_64 targets use the CF_Dispatch mechanism. X86,
-/// ARM, and AArch64 targets use the CF_Check machanism.
-class CFGuard : public FunctionPass {
+/// address-taken function. X86_64 targets use the Mechanism::Dispatch
+/// mechanism. X86, ARM, and AArch64 targets use the Mechanism::Check machanism.
+class CFGuardImpl {
public:
- static char ID;
-
- enum Mechanism { CF_Check, CF_Dispatch };
-
- // Default constructor required for the INITIALIZE_PASS macro.
- CFGuard() : FunctionPass(ID) {
- initializeCFGuardPass(*PassRegistry::getPassRegistry());
- // By default, use the guard check mechanism.
- GuardMechanism = CF_Check;
- }
-
- // Recommended constructor used to specify the type of guard mechanism.
- CFGuard(Mechanism Var) : FunctionPass(ID) {
- initializeCFGuardPass(*PassRegistry::getPassRegistry());
- GuardMechanism = Var;
+ using Mechanism = CFGuardPass::Mechanism;
+
+ CFGuardImpl(Mechanism M) : GuardMechanism(M) {
+ // Get or insert the guard check or dispatch global symbols.
+ switch (GuardMechanism) {
+ case Mechanism::Check:
+ GuardFnName = "__guard_check_icall_fptr";
+ break;
+ case Mechanism::Dispatch:
+ GuardFnName = "__guard_dispatch_icall_fptr";
+ break;
+ }
}
/// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
@@ -141,21 +138,37 @@ public:
/// \param CB indirect call to instrument.
void insertCFGuardDispatch(CallBase *CB);
- bool doInitialization(Module &M) override;
- bool runOnFunction(Function &F) override;
+ bool doInitialization(Module &M);
+ bool runOnFunction(Function &F);
private:
// Only add checks if the module has the cfguard=2 flag.
int cfguard_module_flag = 0;
- Mechanism GuardMechanism = CF_Check;
+ StringRef GuardFnName;
+ Mechanism GuardMechanism = Mechanism::Check;
FunctionType *GuardFnType = nullptr;
PointerType *GuardFnPtrType = nullptr;
Constant *GuardFnGlobal = nullptr;
};
+class CFGuard : public FunctionPass {
+ CFGuardImpl Impl;
+
+public:
+ static char ID;
+
+ // Default constructor required for the INITIALIZE_PASS macro.
+ CFGuard(CFGuardImpl::Mechanism M) : FunctionPass(ID), Impl(M) {
+ initializeCFGuardPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool doInitialization(Module &M) override { return Impl.doInitialization(M); }
+ bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }
+};
+
} // end anonymous namespace
-void CFGuard::insertCFGuardCheck(CallBase *CB) {
+void CFGuardImpl::insertCFGuardCheck(CallBase *CB) {
assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&
"Only applicable for Windows targets");
@@ -184,7 +197,7 @@ void CFGuard::insertCFGuardCheck(CallBase *CB) {
GuardCheck->setCallingConv(CallingConv::CFGuard_Check);
}
-void CFGuard::insertCFGuardDispatch(CallBase *CB) {
+void CFGuardImpl::insertCFGuardDispatch(CallBase *CB) {
assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&
"Only applicable for Windows targets");
@@ -218,7 +231,7 @@ void CFGuard::insertCFGuardDispatch(CallBase *CB) {
CB->eraseFromParent();
}
-bool CFGuard::doInitialization(Module &M) {
+bool CFGuardImpl::doInitialization(Module &M) {
// Check if this module has the cfguard flag and read its value.
if (auto *MD =
@@ -235,15 +248,6 @@ bool CFGuard::doInitialization(Module &M) {
{PointerType::getUnqual(M.getContext())}, false);
GuardFnPtrType = PointerType::get(GuardFnType, 0);
- // Get or insert the guard check or dispatch global symbols.
- llvm::StringRef GuardFnName;
- if (GuardMechanism == CF_Check) {
- GuardFnName = "__guard_check_icall_fptr";
- } else if (GuardMechanism == CF_Dispatch) {
- GuardFnName = "__guard_dispatch_icall_fptr";
- } else {
- assert(false && "Invalid CFGuard mechanism");
- }
GuardFnGlobal = M.getOrInsertGlobal(GuardFnName, GuardFnPtrType, [&] {
auto *Var = new GlobalVariable(M, GuardFnPtrType, false,
GlobalVariable::ExternalLinkage, nullptr,
@@ -255,7 +259,7 @@ bool CFGuard::doInitialization(Module &M) {
return true;
}
-bool CFGuard::runOnFunction(Function &F) {
+bool CFGuardImpl::runOnFunction(Function &F) {
// Skip modules for which CFGuard checks have been disabled.
if (cfguard_module_flag != 2)
@@ -283,7 +287,7 @@ bool CFGuard::runOnFunction(Function &F) {
}
// For each indirect call/invoke, add the appropriate dispatch or check.
- if (GuardMechanism == CF_Dispatch) {
+ if (GuardMechanism == Mechanism::Dispatch) {
for (CallBase *CB : IndirectCalls) {
insertCFGuardDispatch(CB);
}
@@ -296,13 +300,20 @@ bool CFGuard::runOnFunction(Function &F) {
return true;
}
+PreservedAnalyses CFGuardPass::run(Function &F, FunctionAnalysisManager &FAM) {
+ CFGuardImpl Impl(GuardMechanism);
+ bool Changed = Impl.doInitialization(*F.getParent());
+ Changed |= Impl.runOnFunction(F);
+ return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
+}
+
char CFGuard::ID = 0;
INITIALIZE_PASS(CFGuard, "CFGuard", "CFGuard", false, false)
FunctionPass *llvm::createCFGuardCheckPass() {
- return new CFGuard(CFGuard::CF_Check);
+ return new CFGuard(CFGuardPass::Mechanism::Check);
}
FunctionPass *llvm::createCFGuardDispatchPass() {
- return new CFGuard(CFGuard::CF_Dispatch);
+ return new CFGuard(CFGuardPass::Mechanism::Dispatch);
}
diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
index 1134b20880f1..f37b4dc938d3 100644
--- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
@@ -963,12 +963,18 @@ static void cacheDIVar(FrameDataInfo &FrameData,
if (DIVarCache.contains(V))
continue;
- auto DDIs = FindDbgDeclareUses(V);
- auto *I = llvm::find_if(DDIs, [](DbgDeclareInst *DDI) {
- return DDI->getExpression()->getNumElements() == 0;
- });
- if (I != DDIs.end())
- DIVarCache.insert({V, (*I)->getVariable()});
+ SmallVector<DbgDeclareInst *, 1> DDIs;
+ SmallVector<DPValue *, 1> DPVs;
+ findDbgDeclares(DDIs, V, &DPVs);
+ auto CacheIt = [&DIVarCache, V](auto &Container) {
+ auto *I = llvm::find_if(Container, [](auto *DDI) {
+ return DDI->getExpression()->getNumElements() == 0;
+ });
+ if (I != Container.end())
+ DIVarCache.insert({V, (*I)->getVariable()});
+ };
+ CacheIt(DDIs);
+ CacheIt(DPVs);
}
}
@@ -1119,15 +1125,26 @@ static void buildFrameDebugInfo(Function &F, coro::Shape &Shape,
assert(PromiseAlloca &&
"Coroutine with switch ABI should own Promise alloca");
- TinyPtrVector<DbgDeclareInst *> DIs = FindDbgDeclareUses(PromiseAlloca);
- if (DIs.empty())
+ SmallVector<DbgDeclareInst *, 1> DIs;
+ SmallVector<DPValue *, 1> DPVs;
+ findDbgDeclares(DIs, PromiseAlloca, &DPVs);
+
+ DILocalVariable *PromiseDIVariable = nullptr;
+ DILocation *DILoc = nullptr;
+ if (!DIs.empty()) {
+ DbgDeclareInst *PromiseDDI = DIs.front();
+ PromiseDIVariable = PromiseDDI->getVariable();
+ DILoc = PromiseDDI->getDebugLoc().get();
+ } else if (!DPVs.empty()) {
+ DPValue *PromiseDPV = DPVs.front();
+ PromiseDIVariable = PromiseDPV->getVariable();
+ DILoc = PromiseDPV->getDebugLoc().get();
+ } else {
return;
+ }
- DbgDeclareInst *PromiseDDI = DIs.front();
- DILocalVariable *PromiseDIVariable = PromiseDDI->getVariable();
DILocalScope *PromiseDIScope = PromiseDIVariable->getScope();
DIFile *DFile = PromiseDIScope->getFile();
- DILocation *DILoc = PromiseDDI->getDebugLoc().get();
unsigned LineNum = PromiseDIVariable->getLine();
DICompositeType *FrameDITy = DBuilder.createStructType(
@@ -1241,7 +1258,7 @@ static void buildFrameDebugInfo(Function &F, coro::Shape &Shape,
auto *FrameDIVar = DBuilder.createAutoVariable(PromiseDIScope, "__coro_frame",
DFile, LineNum, FrameDITy,
true, DINode::FlagArtificial);
- assert(FrameDIVar->isValidLocationForIntrinsic(PromiseDDI->getDebugLoc()));
+ assert(FrameDIVar->isValidLocationForIntrinsic(DILoc));
// Subprogram would have ContainedNodes field which records the debug
// variables it contained. So we need to add __coro_frame to the
@@ -1259,9 +1276,17 @@ static void buildFrameDebugInfo(Function &F, coro::Shape &Shape,
7, (MDTuple::get(F.getContext(), RetainedNodesVec)));
}
- DBuilder.insertDeclare(Shape.FramePtr, FrameDIVar,
- DBuilder.createExpression(), DILoc,
- Shape.getInsertPtAfterFramePtr());
+ if (UseNewDbgInfoFormat) {
+ DPValue *NewDPV = new DPValue(ValueAsMetadata::get(Shape.FramePtr),
+ FrameDIVar, DBuilder.createExpression(),
+ DILoc, DPValue::LocationType::Declare);
+ BasicBlock::iterator It = Shape.getInsertPtAfterFramePtr();
+ It->getParent()->insertDPValueBefore(NewDPV, It);
+ } else {
+ DBuilder.insertDeclare(Shape.FramePtr, FrameDIVar,
+ DBuilder.createExpression(), DILoc,
+ &*Shape.getInsertPtAfterFramePtr());
+ }
}
// Build a struct that will keep state for an active coroutine.
@@ -1769,7 +1794,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
if (auto *Arg = dyn_cast<Argument>(Def)) {
// For arguments, we will place the store instruction right after
// the coroutine frame pointer instruction, i.e. coro.begin.
- InsertPt = Shape.getInsertPtAfterFramePtr()->getIterator();
+ InsertPt = Shape.getInsertPtAfterFramePtr();
// If we're spilling an Argument, make sure we clear 'nocapture'
// from the coroutine function.
@@ -1786,7 +1811,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
if (!DT.dominates(CB, I)) {
// If it is not dominated by CoroBegin, then spill should be
// inserted immediately after CoroFrame is computed.
- InsertPt = Shape.getInsertPtAfterFramePtr()->getIterator();
+ InsertPt = Shape.getInsertPtAfterFramePtr();
} else if (auto *II = dyn_cast<InvokeInst>(I)) {
// If we are spilling the result of the invoke instruction, split
// the normal edge and insert the spill in the new block.
@@ -1840,7 +1865,9 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
FrameTy->getElementType(FrameData.getFieldIndex(E.first)), GEP,
SpillAlignment, E.first->getName() + Twine(".reload"));
- TinyPtrVector<DbgDeclareInst *> DIs = FindDbgDeclareUses(Def);
+ SmallVector<DbgDeclareInst *, 1> DIs;
+ SmallVector<DPValue *, 1> DPVs;
+ findDbgDeclares(DIs, Def, &DPVs);
// Try best to find dbg.declare. If the spill is a temp, there may not
// be a direct dbg.declare. Walk up the load chain to find one from an
// alias.
@@ -1854,24 +1881,37 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
CurDef = LdInst->getPointerOperand();
if (!isa<AllocaInst, LoadInst>(CurDef))
break;
- DIs = FindDbgDeclareUses(CurDef);
+ DIs.clear();
+ DPVs.clear();
+ findDbgDeclares(DIs, CurDef, &DPVs);
}
}
- for (DbgDeclareInst *DDI : DIs) {
+ auto SalvageOne = [&](auto *DDI) {
bool AllowUnresolved = false;
// This dbg.declare is preserved for all coro-split function
// fragments. It will be unreachable in the main function, and
// processed by coro::salvageDebugInfo() by CoroCloner.
- DIBuilder(*CurrentBlock->getParent()->getParent(), AllowUnresolved)
- .insertDeclare(CurrentReload, DDI->getVariable(),
- DDI->getExpression(), DDI->getDebugLoc(),
- &*Builder.GetInsertPoint());
+ if (UseNewDbgInfoFormat) {
+ DPValue *NewDPV =
+ new DPValue(ValueAsMetadata::get(CurrentReload),
+ DDI->getVariable(), DDI->getExpression(),
+ DDI->getDebugLoc(), DPValue::LocationType::Declare);
+ Builder.GetInsertPoint()->getParent()->insertDPValueBefore(
+ NewDPV, Builder.GetInsertPoint());
+ } else {
+ DIBuilder(*CurrentBlock->getParent()->getParent(), AllowUnresolved)
+ .insertDeclare(CurrentReload, DDI->getVariable(),
+ DDI->getExpression(), DDI->getDebugLoc(),
+ &*Builder.GetInsertPoint());
+ }
// This dbg.declare is for the main function entry point. It
// will be deleted in all coro-split functions.
- coro::salvageDebugInfo(ArgToAllocaMap, DDI, Shape.OptimizeFrame,
+ coro::salvageDebugInfo(ArgToAllocaMap, *DDI, Shape.OptimizeFrame,
false /*UseEntryValue*/);
- }
+ };
+ for_each(DIs, SalvageOne);
+ for_each(DPVs, SalvageOne);
}
// If we have a single edge PHINode, remove it and replace it with a
@@ -1889,6 +1929,10 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
// Replace all uses of CurrentValue in the current instruction with
// reload.
U->replaceUsesOfWith(Def, CurrentReload);
+ // Instructions are added to Def's user list if the attached
+ // debug records use Def. Update those now.
+ for (auto &DPV : U->getDbgValueRange())
+ DPV.replaceVariableLocationOp(Def, CurrentReload, true);
}
}
@@ -1939,9 +1983,12 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
G->setName(Alloca->getName() + Twine(".reload.addr"));
SmallVector<DbgVariableIntrinsic *, 4> DIs;
- findDbgUsers(DIs, Alloca);
+ SmallVector<DPValue *> DPValues;
+ findDbgUsers(DIs, Alloca, &DPValues);
for (auto *DVI : DIs)
DVI->replaceUsesOfWith(Alloca, G);
+ for (auto *DPV : DPValues)
+ DPV->replaceVariableLocationOp(Alloca, G);
for (Instruction *I : UsersToUpdate) {
// It is meaningless to retain the lifetime intrinsics refer for the
@@ -1955,7 +2002,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
I->replaceUsesOfWith(Alloca, G);
}
}
- Builder.SetInsertPoint(Shape.getInsertPtAfterFramePtr());
+ Builder.SetInsertPoint(&*Shape.getInsertPtAfterFramePtr());
for (const auto &A : FrameData.Allocas) {
AllocaInst *Alloca = A.Alloca;
if (A.MayWriteBeforeCoroBegin) {
@@ -2016,7 +2063,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
isa<BitCastInst>(Inst);
});
if (HasAccessingPromiseBeforeCB) {
- Builder.SetInsertPoint(Shape.getInsertPtAfterFramePtr());
+ Builder.SetInsertPoint(&*Shape.getInsertPtAfterFramePtr());
auto *G = GetFramePointer(PA);
auto *Value = Builder.CreateLoad(PA->getAllocatedType(), PA);
Builder.CreateStore(Value, G);
@@ -2798,21 +2845,16 @@ static void collectFrameAlloca(AllocaInst *AI, coro::Shape &Shape,
Visitor.getMayWriteBeforeCoroBegin());
}
-void coro::salvageDebugInfo(
- SmallDenseMap<Argument *, AllocaInst *, 4> &ArgToAllocaMap,
- DbgVariableIntrinsic *DVI, bool OptimizeFrame, bool UseEntryValue) {
- Function *F = DVI->getFunction();
+static std::optional<std::pair<Value &, DIExpression &>>
+salvageDebugInfoImpl(SmallDenseMap<Argument *, AllocaInst *, 4> &ArgToAllocaMap,
+ bool OptimizeFrame, bool UseEntryValue, Function *F,
+ Value *Storage, DIExpression *Expr,
+ bool SkipOutermostLoad) {
IRBuilder<> Builder(F->getContext());
auto InsertPt = F->getEntryBlock().getFirstInsertionPt();
while (isa<IntrinsicInst>(InsertPt))
++InsertPt;
Builder.SetInsertPoint(&F->getEntryBlock(), InsertPt);
- DIExpression *Expr = DVI->getExpression();
- // Follow the pointer arithmetic all the way to the incoming
- // function argument and convert into a DIExpression.
- bool SkipOutermostLoad = !isa<DbgValueInst>(DVI);
- Value *Storage = DVI->getVariableLocationOp(0);
- Value *OriginalStorage = Storage;
while (auto *Inst = dyn_cast_or_null<Instruction>(Storage)) {
if (auto *LdInst = dyn_cast<LoadInst>(Inst)) {
@@ -2844,7 +2886,7 @@ void coro::salvageDebugInfo(
SkipOutermostLoad = false;
}
if (!Storage)
- return;
+ return std::nullopt;
auto *StorageAsArg = dyn_cast<Argument>(Storage);
const bool IsSwiftAsyncArg =
@@ -2880,8 +2922,30 @@ void coro::salvageDebugInfo(
Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore);
}
- DVI->replaceVariableLocationOp(OriginalStorage, Storage);
- DVI->setExpression(Expr);
+ return {{*Storage, *Expr}};
+}
+
+void coro::salvageDebugInfo(
+ SmallDenseMap<Argument *, AllocaInst *, 4> &ArgToAllocaMap,
+ DbgVariableIntrinsic &DVI, bool OptimizeFrame, bool UseEntryValue) {
+
+ Function *F = DVI.getFunction();
+ // Follow the pointer arithmetic all the way to the incoming
+ // function argument and convert into a DIExpression.
+ bool SkipOutermostLoad = !isa<DbgValueInst>(DVI);
+ Value *OriginalStorage = DVI.getVariableLocationOp(0);
+
+ auto SalvagedInfo = ::salvageDebugInfoImpl(
+ ArgToAllocaMap, OptimizeFrame, UseEntryValue, F, OriginalStorage,
+ DVI.getExpression(), SkipOutermostLoad);
+ if (!SalvagedInfo)
+ return;
+
+ Value *Storage = &SalvagedInfo->first;
+ DIExpression *Expr = &SalvagedInfo->second;
+
+ DVI.replaceVariableLocationOp(OriginalStorage, Storage);
+ DVI.setExpression(Expr);
// We only hoist dbg.declare today since it doesn't make sense to hoist
// dbg.value since it does not have the same function wide guarantees that
// dbg.declare does.
@@ -2892,7 +2956,44 @@ void coro::salvageDebugInfo(
else if (isa<Argument>(Storage))
InsertPt = F->getEntryBlock().begin();
if (InsertPt)
- DVI->moveBefore(*(*InsertPt)->getParent(), *InsertPt);
+ DVI.moveBefore(*(*InsertPt)->getParent(), *InsertPt);
+ }
+}
+
+void coro::salvageDebugInfo(
+ SmallDenseMap<Argument *, AllocaInst *, 4> &ArgToAllocaMap, DPValue &DPV,
+ bool OptimizeFrame, bool UseEntryValue) {
+
+ Function *F = DPV.getFunction();
+ // Follow the pointer arithmetic all the way to the incoming
+ // function argument and convert into a DIExpression.
+ bool SkipOutermostLoad = DPV.getType() == DPValue::LocationType::Declare;
+ Value *OriginalStorage = DPV.getVariableLocationOp(0);
+
+ auto SalvagedInfo = ::salvageDebugInfoImpl(
+ ArgToAllocaMap, OptimizeFrame, UseEntryValue, F, OriginalStorage,
+ DPV.getExpression(), SkipOutermostLoad);
+ if (!SalvagedInfo)
+ return;
+
+ Value *Storage = &SalvagedInfo->first;
+ DIExpression *Expr = &SalvagedInfo->second;
+
+ DPV.replaceVariableLocationOp(OriginalStorage, Storage);
+ DPV.setExpression(Expr);
+ // We only hoist dbg.declare today since it doesn't make sense to hoist
+ // dbg.value since it does not have the same function wide guarantees that
+ // dbg.declare does.
+ if (DPV.getType() == DPValue::LocationType::Declare) {
+ std::optional<BasicBlock::iterator> InsertPt;
+ if (auto *I = dyn_cast<Instruction>(Storage))
+ InsertPt = I->getInsertionPointAfterDef();
+ else if (isa<Argument>(Storage))
+ InsertPt = F->getEntryBlock().begin();
+ if (InsertPt) {
+ DPV.removeFromParent();
+ (*InsertPt)->getParent()->insertDPValueBefore(&DPV, *InsertPt);
+ }
}
}
@@ -3083,10 +3184,15 @@ void coro::buildCoroutineFrame(
for (auto &Iter : FrameData.Spills) {
auto *V = Iter.first;
SmallVector<DbgValueInst *, 16> DVIs;
- findDbgValues(DVIs, V);
+ SmallVector<DPValue *, 16> DPVs;
+ findDbgValues(DVIs, V, &DPVs);
for (DbgValueInst *DVI : DVIs)
if (Checker.isDefinitionAcrossSuspend(*V, DVI))
FrameData.Spills[V].push_back(DVI);
+ // Add the instructions which carry debug info that is in the frame.
+ for (DPValue *DPV : DPVs)
+ if (Checker.isDefinitionAcrossSuspend(*V, DPV->Marker->MarkedInstr))
+ FrameData.Spills[V].push_back(DPV->Marker->MarkedInstr);
}
LLVM_DEBUG(dumpSpills("Spills", FrameData.Spills));
diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h
index 0856c4925cc5..fb16a4090689 100644
--- a/llvm/lib/Transforms/Coroutines/CoroInternal.h
+++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h
@@ -32,7 +32,10 @@ void replaceCoroFree(CoroIdInst *CoroId, bool Elide);
/// OptimizeFrame is false.
void salvageDebugInfo(
SmallDenseMap<Argument *, AllocaInst *, 4> &ArgToAllocaMap,
- DbgVariableIntrinsic *DVI, bool OptimizeFrame, bool IsEntryPoint);
+ DbgVariableIntrinsic &DVI, bool OptimizeFrame, bool IsEntryPoint);
+void salvageDebugInfo(
+ SmallDenseMap<Argument *, AllocaInst *, 4> &ArgToAllocaMap, DPValue &DPV,
+ bool OptimizeFrame, bool UseEntryValue);
// Keeps data and helper functions for lowering coroutine intrinsics.
struct LowererBase {
@@ -240,10 +243,13 @@ struct LLVM_LIBRARY_VISIBILITY Shape {
return nullptr;
}
- Instruction *getInsertPtAfterFramePtr() const {
- if (auto *I = dyn_cast<Instruction>(FramePtr))
- return I->getNextNode();
- return &cast<Argument>(FramePtr)->getParent()->getEntryBlock().front();
+ BasicBlock::iterator getInsertPtAfterFramePtr() const {
+ if (auto *I = dyn_cast<Instruction>(FramePtr)) {
+ BasicBlock::iterator It = std::next(I->getIterator());
+ It.setHeadBit(true); // Copy pre-RemoveDIs behaviour.
+ return It;
+ }
+ return cast<Argument>(FramePtr)->getParent()->getEntryBlock().begin();
}
/// Allocate memory according to the rules of the active lowering.
diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index 244580f503d5..7758b52abc20 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -725,13 +725,17 @@ static void replaceSwiftErrorOps(Function &F, coro::Shape &Shape,
}
/// Returns all DbgVariableIntrinsic in F.
-static SmallVector<DbgVariableIntrinsic *, 8>
+static std::pair<SmallVector<DbgVariableIntrinsic *, 8>, SmallVector<DPValue *>>
collectDbgVariableIntrinsics(Function &F) {
SmallVector<DbgVariableIntrinsic *, 8> Intrinsics;
- for (auto &I : instructions(F))
+ SmallVector<DPValue *> DPValues;
+ for (auto &I : instructions(F)) {
+ for (DPValue &DPV : I.getDbgValueRange())
+ DPValues.push_back(&DPV);
if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I))
Intrinsics.push_back(DVI);
- return Intrinsics;
+ }
+ return {Intrinsics, DPValues};
}
void CoroCloner::replaceSwiftErrorOps() {
@@ -739,15 +743,17 @@ void CoroCloner::replaceSwiftErrorOps() {
}
void CoroCloner::salvageDebugInfo() {
- SmallVector<DbgVariableIntrinsic *, 8> Worklist =
- collectDbgVariableIntrinsics(*NewF);
+ auto [Worklist, DPValues] = collectDbgVariableIntrinsics(*NewF);
SmallDenseMap<Argument *, AllocaInst *, 4> ArgToAllocaMap;
// Only 64-bit ABIs have a register we can refer to with the entry value.
bool UseEntryValue =
llvm::Triple(OrigF.getParent()->getTargetTriple()).isArch64Bit();
for (DbgVariableIntrinsic *DVI : Worklist)
- coro::salvageDebugInfo(ArgToAllocaMap, DVI, Shape.OptimizeFrame,
+ coro::salvageDebugInfo(ArgToAllocaMap, *DVI, Shape.OptimizeFrame,
+ UseEntryValue);
+ for (DPValue *DPV : DPValues)
+ coro::salvageDebugInfo(ArgToAllocaMap, *DPV, Shape.OptimizeFrame,
UseEntryValue);
// Remove all salvaged dbg.declare intrinsics that became
@@ -757,7 +763,7 @@ void CoroCloner::salvageDebugInfo() {
return !isPotentiallyReachable(&NewF->getEntryBlock(), BB, nullptr,
&DomTree);
};
- for (DbgVariableIntrinsic *DVI : Worklist) {
+ auto RemoveOne = [&](auto *DVI) {
if (IsUnreachableBlock(DVI->getParent()))
DVI->eraseFromParent();
else if (isa_and_nonnull<AllocaInst>(DVI->getVariableLocationOp(0))) {
@@ -770,7 +776,9 @@ void CoroCloner::salvageDebugInfo() {
if (!Uses)
DVI->eraseFromParent();
}
- }
+ };
+ for_each(Worklist, RemoveOne);
+ for_each(DPValues, RemoveOne);
}
void CoroCloner::replaceEntryBlock() {
@@ -1243,7 +1251,7 @@ static void updateCoroFrame(coro::Shape &Shape, Function *ResumeFn,
Function *DestroyFn, Function *CleanupFn) {
assert(Shape.ABI == coro::ABI::Switch);
- IRBuilder<> Builder(Shape.getInsertPtAfterFramePtr());
+ IRBuilder<> Builder(&*Shape.getInsertPtAfterFramePtr());
auto *ResumeAddr = Builder.CreateStructGEP(
Shape.FrameTy, Shape.FramePtr, coro::Shape::SwitchFieldIndex::Resume,
@@ -2039,10 +2047,13 @@ splitCoroutine(Function &F, SmallVectorImpl<Function *> &Clones,
// original function. The Cloner has already salvaged debug info in the new
// coroutine funclets.
SmallDenseMap<Argument *, AllocaInst *, 4> ArgToAllocaMap;
- for (auto *DDI : collectDbgVariableIntrinsics(F))
- coro::salvageDebugInfo(ArgToAllocaMap, DDI, Shape.OptimizeFrame,
+ auto [DbgInsts, DPValues] = collectDbgVariableIntrinsics(F);
+ for (auto *DDI : DbgInsts)
+ coro::salvageDebugInfo(ArgToAllocaMap, *DDI, Shape.OptimizeFrame,
+ false /*UseEntryValue*/);
+ for (DPValue *DPV : DPValues)
+ coro::salvageDebugInfo(ArgToAllocaMap, *DPV, Shape.OptimizeFrame,
false /*UseEntryValue*/);
-
return Shape;
}
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 889ebd7438bd..8e1f782f7cd8 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -290,20 +290,19 @@ static const Value *getPointerOperand(const Instruction *I,
return nullptr;
}
-/// Helper function to create a pointer of type \p ResTy, based on \p Ptr, and
-/// advanced by \p Offset bytes. To aid later analysis the method tries to build
+/// Helper function to create a pointer based on \p Ptr, and advanced by \p
+/// Offset bytes. To aid later analysis the method tries to build
/// getelement pointer instructions that traverse the natural type of \p Ptr if
/// possible. If that fails, the remaining offset is adjusted byte-wise, hence
/// through a cast to i8*.
///
/// TODO: This could probably live somewhere more prominantly if it doesn't
/// already exist.
-static Value *constructPointer(Type *ResTy, Type *PtrElemTy, Value *Ptr,
- int64_t Offset, IRBuilder<NoFolder> &IRB,
- const DataLayout &DL) {
+static Value *constructPointer(Type *PtrElemTy, Value *Ptr, int64_t Offset,
+ IRBuilder<NoFolder> &IRB, const DataLayout &DL) {
assert(Offset >= 0 && "Negative offset not supported yet!");
LLVM_DEBUG(dbgs() << "Construct pointer: " << *Ptr << " + " << Offset
- << "-bytes as " << *ResTy << "\n");
+ << "-bytes\n");
if (Offset) {
Type *Ty = PtrElemTy;
@@ -327,10 +326,6 @@ static Value *constructPointer(Type *ResTy, Type *PtrElemTy, Value *Ptr,
}
}
- // Ensure the result has the requested type.
- Ptr = IRB.CreatePointerBitCastOrAddrSpaceCast(Ptr, ResTy,
- Ptr->getName() + ".cast");
-
LLVM_DEBUG(dbgs() << "Constructed pointer: " << *Ptr << "\n");
return Ptr;
}
@@ -7492,19 +7487,16 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl {
if (auto *PrivStructType = dyn_cast<StructType>(PrivType)) {
const StructLayout *PrivStructLayout = DL.getStructLayout(PrivStructType);
for (unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
- Type *PointeeTy = PrivStructType->getElementType(u)->getPointerTo();
- Value *Ptr =
- constructPointer(PointeeTy, PrivType, &Base,
- PrivStructLayout->getElementOffset(u), IRB, DL);
+ Value *Ptr = constructPointer(
+ PrivType, &Base, PrivStructLayout->getElementOffset(u), IRB, DL);
new StoreInst(F.getArg(ArgNo + u), Ptr, &IP);
}
} else if (auto *PrivArrayType = dyn_cast<ArrayType>(PrivType)) {
Type *PointeeTy = PrivArrayType->getElementType();
- Type *PointeePtrTy = PointeeTy->getPointerTo();
uint64_t PointeeTySize = DL.getTypeStoreSize(PointeeTy);
for (unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
- Value *Ptr = constructPointer(PointeePtrTy, PrivType, &Base,
- u * PointeeTySize, IRB, DL);
+ Value *Ptr =
+ constructPointer(PrivType, &Base, u * PointeeTySize, IRB, DL);
new StoreInst(F.getArg(ArgNo + u), Ptr, &IP);
}
} else {
@@ -7524,19 +7516,13 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl {
IRBuilder<NoFolder> IRB(IP);
const DataLayout &DL = IP->getModule()->getDataLayout();
- Type *PrivPtrType = PrivType->getPointerTo();
- if (Base->getType() != PrivPtrType)
- Base = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
- Base, PrivPtrType, "", ACS.getInstruction());
-
// Traverse the type, build GEPs and loads.
if (auto *PrivStructType = dyn_cast<StructType>(PrivType)) {
const StructLayout *PrivStructLayout = DL.getStructLayout(PrivStructType);
for (unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
Type *PointeeTy = PrivStructType->getElementType(u);
- Value *Ptr =
- constructPointer(PointeeTy->getPointerTo(), PrivType, Base,
- PrivStructLayout->getElementOffset(u), IRB, DL);
+ Value *Ptr = constructPointer(
+ PrivType, Base, PrivStructLayout->getElementOffset(u), IRB, DL);
LoadInst *L = new LoadInst(PointeeTy, Ptr, "", IP);
L->setAlignment(Alignment);
ReplacementValues.push_back(L);
@@ -7544,10 +7530,9 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl {
} else if (auto *PrivArrayType = dyn_cast<ArrayType>(PrivType)) {
Type *PointeeTy = PrivArrayType->getElementType();
uint64_t PointeeTySize = DL.getTypeStoreSize(PointeeTy);
- Type *PointeePtrTy = PointeeTy->getPointerTo();
for (unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
- Value *Ptr = constructPointer(PointeePtrTy, PrivType, Base,
- u * PointeeTySize, IRB, DL);
+ Value *Ptr =
+ constructPointer(PrivType, Base, u * PointeeTySize, IRB, DL);
LoadInst *L = new LoadInst(PointeeTy, Ptr, "", IP);
L->setAlignment(Alignment);
ReplacementValues.push_back(L);
@@ -9066,7 +9051,8 @@ struct AAValueConstantRangeImpl : AAValueConstantRange {
if (!LVI || !CtxI)
return getWorstState(getBitWidth());
return LVI->getConstantRange(&getAssociatedValue(),
- const_cast<Instruction *>(CtxI));
+ const_cast<Instruction *>(CtxI),
+ /*UndefAllowed*/ false);
}
/// Return true if \p CtxI is valid for querying outside analyses.
diff --git a/llvm/lib/Transforms/IPO/FunctionImport.cpp b/llvm/lib/Transforms/IPO/FunctionImport.cpp
index 9c546b531dff..49b3f2b085e1 100644
--- a/llvm/lib/Transforms/IPO/FunctionImport.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionImport.cpp
@@ -37,6 +37,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/JSON.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/Internalize.h"
@@ -138,6 +139,29 @@ static cl::opt<bool>
ImportAllIndex("import-all-index",
cl::desc("Import all external functions in index."));
+/// Pass a workload description file - an example of workload would be the
+/// functions executed to satisfy a RPC request. A workload is defined by a root
+/// function and the list of functions that are (frequently) needed to satisfy
+/// it. The module that defines the root will have all those functions imported.
+/// The file contains a JSON dictionary. The keys are root functions, the values
+/// are lists of functions to import in the module defining the root. It is
+/// assumed -funique-internal-linkage-names was used, thus ensuring function
+/// names are unique even for local linkage ones.
+static cl::opt<std::string> WorkloadDefinitions(
+ "thinlto-workload-def",
+ cl::desc("Pass a workload definition. This is a file containing a JSON "
+ "dictionary. The keys are root functions, the values are lists of "
+ "functions to import in the module defining the root. It is "
+ "assumed -funique-internal-linkage-names was used, to ensure "
+ "local linkage functions have unique names. For example: \n"
+ "{\n"
+ " \"rootFunction_1\": [\"function_to_import_1\", "
+ "\"function_to_import_2\"], \n"
+ " \"rootFunction_2\": [\"function_to_import_3\", "
+ "\"function_to_import_4\"] \n"
+ "}"),
+ cl::Hidden);
+
// Load lazily a module from \p FileName in \p Context.
static std::unique_ptr<Module> loadFile(const std::string &FileName,
LLVMContext &Context) {
@@ -369,14 +393,16 @@ public:
}
};
+static const char *getFailureName(FunctionImporter::ImportFailureReason Reason);
+
/// Determine the list of imports and exports for each module.
-class ModuleImportsManager final {
+class ModuleImportsManager {
+protected:
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
IsPrevailing;
const ModuleSummaryIndex &Index;
DenseMap<StringRef, FunctionImporter::ExportSetTy> *const ExportLists;
-public:
ModuleImportsManager(
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
IsPrevailing,
@@ -384,14 +410,247 @@ public:
DenseMap<StringRef, FunctionImporter::ExportSetTy> *ExportLists = nullptr)
: IsPrevailing(IsPrevailing), Index(Index), ExportLists(ExportLists) {}
+public:
+ virtual ~ModuleImportsManager() = default;
+
/// Given the list of globals defined in a module, compute the list of imports
/// as well as the list of "exports", i.e. the list of symbols referenced from
/// another module (that may require promotion).
- void computeImportForModule(const GVSummaryMapTy &DefinedGVSummaries,
- StringRef ModName,
- FunctionImporter::ImportMapTy &ImportList);
+ virtual void
+ computeImportForModule(const GVSummaryMapTy &DefinedGVSummaries,
+ StringRef ModName,
+ FunctionImporter::ImportMapTy &ImportList);
+
+ static std::unique_ptr<ModuleImportsManager>
+ create(function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
+ IsPrevailing,
+ const ModuleSummaryIndex &Index,
+ DenseMap<StringRef, FunctionImporter::ExportSetTy> *ExportLists =
+ nullptr);
+};
+
+/// A ModuleImportsManager that operates based on a workload definition (see
+/// -thinlto-workload-def). For modules that do not define workload roots, it
+/// applies the base ModuleImportsManager import policy.
+class WorkloadImportsManager : public ModuleImportsManager {
+ // Keep a module name -> value infos to import association. We use it to
+ // determine if a module's import list should be done by the base
+ // ModuleImportsManager or by us.
+ StringMap<DenseSet<ValueInfo>> Workloads;
+
+ void
+ computeImportForModule(const GVSummaryMapTy &DefinedGVSummaries,
+ StringRef ModName,
+ FunctionImporter::ImportMapTy &ImportList) override {
+ auto SetIter = Workloads.find(ModName);
+ if (SetIter == Workloads.end()) {
+ LLVM_DEBUG(dbgs() << "[Workload] " << ModName
+ << " does not contain the root of any context.\n");
+ return ModuleImportsManager::computeImportForModule(DefinedGVSummaries,
+ ModName, ImportList);
+ }
+ LLVM_DEBUG(dbgs() << "[Workload] " << ModName
+ << " contains the root(s) of context(s).\n");
+
+ GlobalsImporter GVI(Index, DefinedGVSummaries, IsPrevailing, ImportList,
+ ExportLists);
+ auto &ValueInfos = SetIter->second;
+ SmallVector<EdgeInfo, 128> GlobWorklist;
+ for (auto &VI : llvm::make_early_inc_range(ValueInfos)) {
+ auto It = DefinedGVSummaries.find(VI.getGUID());
+ if (It != DefinedGVSummaries.end() &&
+ IsPrevailing(VI.getGUID(), It->second)) {
+ LLVM_DEBUG(
+ dbgs() << "[Workload] " << VI.name()
+ << " has the prevailing variant already in the module "
+ << ModName << ". No need to import\n");
+ continue;
+ }
+ auto Candidates =
+ qualifyCalleeCandidates(Index, VI.getSummaryList(), ModName);
+
+ const GlobalValueSummary *GVS = nullptr;
+ auto PotentialCandidates = llvm::map_range(
+ llvm::make_filter_range(
+ Candidates,
+ [&](const auto &Candidate) {
+ LLVM_DEBUG(dbgs() << "[Workflow] Candidate for " << VI.name()
+ << " from " << Candidate.second->modulePath()
+ << " ImportFailureReason: "
+ << getFailureName(Candidate.first) << "\n");
+ return Candidate.first ==
+ FunctionImporter::ImportFailureReason::None;
+ }),
+ [](const auto &Candidate) { return Candidate.second; });
+ if (PotentialCandidates.empty()) {
+ LLVM_DEBUG(dbgs() << "[Workload] Not importing " << VI.name()
+ << " because can't find eligible Callee. Guid is: "
+ << Function::getGUID(VI.name()) << "\n");
+ continue;
+ }
+ /// We will prefer importing the prevailing candidate, if not, we'll
+ /// still pick the first available candidate. The reason we want to make
+ /// sure we do import the prevailing candidate is because the goal of
+ /// workload-awareness is to enable optimizations specializing the call
+ /// graph of that workload. Suppose a function is already defined in the
+ /// module, but it's not the prevailing variant. Suppose also we do not
+ /// inline it (in fact, if it were interposable, we can't inline it),
+ /// but we could specialize it to the workload in other ways. However,
+ /// the linker would drop it in the favor of the prevailing copy.
+ /// Instead, by importing the prevailing variant (assuming also the use
+ /// of `-avail-extern-to-local`), we keep the specialization. We could
+ /// alteranatively make the non-prevailing variant local, but the
+ /// prevailing one is also the one for which we would have previously
+ /// collected profiles, making it preferrable.
+ auto PrevailingCandidates = llvm::make_filter_range(
+ PotentialCandidates, [&](const auto *Candidate) {
+ return IsPrevailing(VI.getGUID(), Candidate);
+ });
+ if (PrevailingCandidates.empty()) {
+ GVS = *PotentialCandidates.begin();
+ if (!llvm::hasSingleElement(PotentialCandidates) &&
+ GlobalValue::isLocalLinkage(GVS->linkage()))
+ LLVM_DEBUG(
+ dbgs()
+ << "[Workload] Found multiple non-prevailing candidates for "
+ << VI.name()
+ << ". This is unexpected. Are module paths passed to the "
+ "compiler unique for the modules passed to the linker?");
+ // We could in theory have multiple (interposable) copies of a symbol
+ // when there is no prevailing candidate, if say the prevailing copy was
+ // in a native object being linked in. However, we should in theory be
+ // marking all of these non-prevailing IR copies dead in that case, in
+ // which case they won't be candidates.
+ assert(GVS->isLive());
+ } else {
+ assert(llvm::hasSingleElement(PrevailingCandidates));
+ GVS = *PrevailingCandidates.begin();
+ }
+
+ auto ExportingModule = GVS->modulePath();
+ // We checked that for the prevailing case, but if we happen to have for
+ // example an internal that's defined in this module, it'd have no
+ // PrevailingCandidates.
+ if (ExportingModule == ModName) {
+ LLVM_DEBUG(dbgs() << "[Workload] Not importing " << VI.name()
+ << " because its defining module is the same as the "
+ "current module\n");
+ continue;
+ }
+ LLVM_DEBUG(dbgs() << "[Workload][Including]" << VI.name() << " from "
+ << ExportingModule << " : "
+ << Function::getGUID(VI.name()) << "\n");
+ ImportList[ExportingModule].insert(VI.getGUID());
+ GVI.onImportingSummary(*GVS);
+ if (ExportLists)
+ (*ExportLists)[ExportingModule].insert(VI);
+ }
+ LLVM_DEBUG(dbgs() << "[Workload] Done\n");
+ }
+
+public:
+ WorkloadImportsManager(
+ function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
+ IsPrevailing,
+ const ModuleSummaryIndex &Index,
+ DenseMap<StringRef, FunctionImporter::ExportSetTy> *ExportLists)
+ : ModuleImportsManager(IsPrevailing, Index, ExportLists) {
+ // Since the workload def uses names, we need a quick lookup
+ // name->ValueInfo.
+ StringMap<ValueInfo> NameToValueInfo;
+ StringSet<> AmbiguousNames;
+ for (auto &I : Index) {
+ ValueInfo VI = Index.getValueInfo(I);
+ if (!NameToValueInfo.insert(std::make_pair(VI.name(), VI)).second)
+ LLVM_DEBUG(AmbiguousNames.insert(VI.name()));
+ }
+ auto DbgReportIfAmbiguous = [&](StringRef Name) {
+ LLVM_DEBUG(if (AmbiguousNames.count(Name) > 0) {
+ dbgs() << "[Workload] Function name " << Name
+ << " present in the workload definition is ambiguous. Consider "
+ "compiling with -funique-internal-linkage-names.";
+ });
+ };
+ std::error_code EC;
+ auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(WorkloadDefinitions);
+ if (std::error_code EC = BufferOrErr.getError()) {
+ report_fatal_error("Failed to open context file");
+ return;
+ }
+ auto Buffer = std::move(BufferOrErr.get());
+ std::map<std::string, std::vector<std::string>> WorkloadDefs;
+ json::Path::Root NullRoot;
+ // The JSON is supposed to contain a dictionary matching the type of
+ // WorkloadDefs. For example:
+ // {
+ // "rootFunction_1": ["function_to_import_1", "function_to_import_2"],
+ // "rootFunction_2": ["function_to_import_3", "function_to_import_4"]
+ // }
+ auto Parsed = json::parse(Buffer->getBuffer());
+ if (!Parsed)
+ report_fatal_error(Parsed.takeError());
+ if (!json::fromJSON(*Parsed, WorkloadDefs, NullRoot))
+ report_fatal_error("Invalid thinlto contextual profile format.");
+ for (const auto &Workload : WorkloadDefs) {
+ const auto &Root = Workload.first;
+ DbgReportIfAmbiguous(Root);
+ LLVM_DEBUG(dbgs() << "[Workload] Root: " << Root << "\n");
+ const auto &AllCallees = Workload.second;
+ auto RootIt = NameToValueInfo.find(Root);
+ if (RootIt == NameToValueInfo.end()) {
+ LLVM_DEBUG(dbgs() << "[Workload] Root " << Root
+ << " not found in this linkage unit.\n");
+ continue;
+ }
+ auto RootVI = RootIt->second;
+ if (RootVI.getSummaryList().size() != 1) {
+ LLVM_DEBUG(dbgs() << "[Workload] Root " << Root
+ << " should have exactly one summary, but has "
+ << RootVI.getSummaryList().size() << ". Skipping.\n");
+ continue;
+ }
+ StringRef RootDefiningModule =
+ RootVI.getSummaryList().front()->modulePath();
+ LLVM_DEBUG(dbgs() << "[Workload] Root defining module for " << Root
+ << " is : " << RootDefiningModule << "\n");
+ auto &Set = Workloads[RootDefiningModule];
+ for (const auto &Callee : AllCallees) {
+ LLVM_DEBUG(dbgs() << "[Workload] " << Callee << "\n");
+ DbgReportIfAmbiguous(Callee);
+ auto ElemIt = NameToValueInfo.find(Callee);
+ if (ElemIt == NameToValueInfo.end()) {
+ LLVM_DEBUG(dbgs() << "[Workload] " << Callee << " not found\n");
+ continue;
+ }
+ Set.insert(ElemIt->second);
+ }
+ LLVM_DEBUG({
+ dbgs() << "[Workload] Root: " << Root << " we have " << Set.size()
+ << " distinct callees.\n";
+ for (const auto &VI : Set) {
+ dbgs() << "[Workload] Root: " << Root
+ << " Would include: " << VI.getGUID() << "\n";
+ }
+ });
+ }
+ }
};
+std::unique_ptr<ModuleImportsManager> ModuleImportsManager::create(
+ function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
+ IsPrevailing,
+ const ModuleSummaryIndex &Index,
+ DenseMap<StringRef, FunctionImporter::ExportSetTy> *ExportLists) {
+ if (WorkloadDefinitions.empty()) {
+ LLVM_DEBUG(dbgs() << "[Workload] Using the regular imports manager.\n");
+ return std::unique_ptr<ModuleImportsManager>(
+ new ModuleImportsManager(IsPrevailing, Index, ExportLists));
+ }
+ LLVM_DEBUG(dbgs() << "[Workload] Using the contextual imports manager.\n");
+ return std::make_unique<WorkloadImportsManager>(IsPrevailing, Index,
+ ExportLists);
+}
+
static const char *
getFailureName(FunctionImporter::ImportFailureReason Reason) {
switch (Reason) {
@@ -732,14 +991,14 @@ void llvm::ComputeCrossModuleImport(
isPrevailing,
DenseMap<StringRef, FunctionImporter::ImportMapTy> &ImportLists,
DenseMap<StringRef, FunctionImporter::ExportSetTy> &ExportLists) {
- ModuleImportsManager MIS(isPrevailing, Index, &ExportLists);
+ auto MIS = ModuleImportsManager::create(isPrevailing, Index, &ExportLists);
// For each module that has function defined, compute the import/export lists.
for (const auto &DefinedGVSummaries : ModuleToDefinedGVSummaries) {
auto &ImportList = ImportLists[DefinedGVSummaries.first];
LLVM_DEBUG(dbgs() << "Computing import for Module '"
<< DefinedGVSummaries.first << "'\n");
- MIS.computeImportForModule(DefinedGVSummaries.second,
- DefinedGVSummaries.first, ImportList);
+ MIS->computeImportForModule(DefinedGVSummaries.second,
+ DefinedGVSummaries.first, ImportList);
}
// When computing imports we only added the variables and functions being
@@ -855,8 +1114,8 @@ static void ComputeCrossModuleImportForModuleForTest(
// Compute the import list for this module.
LLVM_DEBUG(dbgs() << "Computing import for Module '" << ModulePath << "'\n");
- ModuleImportsManager MIS(isPrevailing, Index);
- MIS.computeImportForModule(FunctionSummaryMap, ModulePath, ImportList);
+ auto MIS = ModuleImportsManager::create(isPrevailing, Index);
+ MIS->computeImportForModule(FunctionSummaryMap, ModulePath, ImportList);
#ifndef NDEBUG
dumpImportListForModule(Index, ModulePath, ImportList);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 6002f599ca71..5e362f4117d0 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3756,6 +3756,35 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
}
}
+ /// Res, Overflow = xxx_with_overflow X, C1
+ /// Try to canonicalize the pattern "Overflow | icmp pred Res, C2" into
+ /// "Overflow | icmp pred X, C2 +/- C1".
+ const WithOverflowInst *WO;
+ const Value *WOV;
+ const APInt *C1, *C2;
+ if (match(&I, m_c_Or(m_CombineAnd(m_ExtractValue<1>(m_CombineAnd(
+ m_WithOverflowInst(WO), m_Value(WOV))),
+ m_Value(Ov)),
+ m_OneUse(m_ICmp(Pred, m_ExtractValue<0>(m_Deferred(WOV)),
+ m_APInt(C2))))) &&
+ (WO->getBinaryOp() == Instruction::Add ||
+ WO->getBinaryOp() == Instruction::Sub) &&
+ (ICmpInst::isEquality(Pred) ||
+ WO->isSigned() == ICmpInst::isSigned(Pred)) &&
+ match(WO->getRHS(), m_APInt(C1))) {
+ bool Overflow;
+ APInt NewC = WO->getBinaryOp() == Instruction::Add
+ ? (ICmpInst::isSigned(Pred) ? C2->ssub_ov(*C1, Overflow)
+ : C2->usub_ov(*C1, Overflow))
+ : (ICmpInst::isSigned(Pred) ? C2->sadd_ov(*C1, Overflow)
+ : C2->uadd_ov(*C1, Overflow));
+ if (!Overflow || ICmpInst::isEquality(Pred)) {
+ Value *NewCmp = Builder.CreateICmp(
+ Pred, WO->getLHS(), ConstantInt::get(WO->getLHS()->getType(), NewC));
+ return BinaryOperator::CreateOr(Ov, NewCmp);
+ }
+ }
+
// (~x) | y --> ~(x & (~y)) iff that gets rid of inversions
if (sinkNotIntoOtherHandOfLogicalOp(I))
return &I;
@@ -4280,6 +4309,12 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) {
if (match(NotVal, m_AShr(m_Not(m_Value(X)), m_Value(Y))))
return BinaryOperator::CreateAShr(X, Y);
+ // Treat lshr with non-negative operand as ashr.
+ // ~(~X >>u Y) --> (X >>s Y) iff X is known negative
+ if (match(NotVal, m_LShr(m_Not(m_Value(X)), m_Value(Y))) &&
+ isKnownNegative(X, SQ.getWithInstruction(NotVal)))
+ return BinaryOperator::CreateAShr(X, Y);
+
// Bit-hack form of a signbit test for iN type:
// ~(X >>s (N - 1)) --> sext i1 (X > -1) to iN
unsigned FullShift = Ty->getScalarSizeInBits() - 1;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 255ce6973a16..1539fa9a3269 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1536,6 +1536,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
}
if (II->isCommutative()) {
+ if (Instruction *I = foldCommutativeIntrinsicOverSelects(*II))
+ return I;
+
if (CallInst *NewCall = canonicalizeConstantArg0ToArg1(CI))
return NewCall;
}
@@ -4217,3 +4220,20 @@ InstCombinerImpl::transformCallThroughTrampoline(CallBase &Call,
Call.setCalledFunction(FTy, NestF);
return &Call;
}
+
+// op(select(%v, %x, %y), select(%v, %y, %x)) --> op(%x, %y)
+Instruction *
+InstCombinerImpl::foldCommutativeIntrinsicOverSelects(IntrinsicInst &II) {
+ assert(II.isCommutative());
+
+ Value *A, *B, *C;
+ if (match(II.getOperand(0), m_Select(m_Value(A), m_Value(B), m_Value(C))) &&
+ match(II.getOperand(1),
+ m_Select(m_Specific(A), m_Specific(C), m_Specific(B)))) {
+ replaceOperand(II, 0, B);
+ replaceOperand(II, 1, C);
+ return &II;
+ }
+
+ return nullptr;
+}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index e42e011bd436..289976718e52 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -23,7 +23,6 @@
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/Support/KnownBits.h"
@@ -1324,34 +1323,21 @@ Instruction *InstCombinerImpl::foldICmpWithConstant(ICmpInst &Cmp) {
/// Canonicalize icmp instructions based on dominating conditions.
Instruction *InstCombinerImpl::foldICmpWithDominatingICmp(ICmpInst &Cmp) {
- // This is a cheap/incomplete check for dominance - just match a single
- // predecessor with a conditional branch.
- BasicBlock *CmpBB = Cmp.getParent();
- BasicBlock *DomBB = CmpBB->getSinglePredecessor();
- if (!DomBB)
- return nullptr;
-
- Value *DomCond;
- BasicBlock *TrueBB, *FalseBB;
- if (!match(DomBB->getTerminator(), m_Br(m_Value(DomCond), TrueBB, FalseBB)))
- return nullptr;
-
- assert((TrueBB == CmpBB || FalseBB == CmpBB) &&
- "Predecessor block does not point to successor?");
-
- // The branch should get simplified. Don't bother simplifying this condition.
- if (TrueBB == FalseBB)
- return nullptr;
-
// We already checked simple implication in InstSimplify, only handle complex
// cases here.
-
- CmpInst::Predicate Pred = Cmp.getPredicate();
Value *X = Cmp.getOperand(0), *Y = Cmp.getOperand(1);
ICmpInst::Predicate DomPred;
- const APInt *C, *DomC;
- if (match(DomCond, m_ICmp(DomPred, m_Specific(X), m_APInt(DomC))) &&
- match(Y, m_APInt(C))) {
+ const APInt *C;
+ if (!match(Y, m_APInt(C)))
+ return nullptr;
+
+ CmpInst::Predicate Pred = Cmp.getPredicate();
+ ConstantRange CR = ConstantRange::makeExactICmpRegion(Pred, *C);
+
+ auto handleDomCond = [&](Value *DomCond, bool CondIsTrue) -> Instruction * {
+ const APInt *DomC;
+ if (!match(DomCond, m_ICmp(DomPred, m_Specific(X), m_APInt(DomC))))
+ return nullptr;
// We have 2 compares of a variable with constants. Calculate the constant
// ranges of those compares to see if we can transform the 2nd compare:
// DomBB:
@@ -1359,11 +1345,10 @@ Instruction *InstCombinerImpl::foldICmpWithDominatingICmp(ICmpInst &Cmp) {
// br DomCond, CmpBB, FalseBB
// CmpBB:
// Cmp = icmp Pred X, C
- ConstantRange CR = ConstantRange::makeExactICmpRegion(Pred, *C);
+ if (!CondIsTrue)
+ DomPred = CmpInst::getInversePredicate(DomPred);
ConstantRange DominatingCR =
- (CmpBB == TrueBB) ? ConstantRange::makeExactICmpRegion(DomPred, *DomC)
- : ConstantRange::makeExactICmpRegion(
- CmpInst::getInversePredicate(DomPred), *DomC);
+ ConstantRange::makeExactICmpRegion(DomPred, *DomC);
ConstantRange Intersection = DominatingCR.intersectWith(CR);
ConstantRange Difference = DominatingCR.difference(CR);
if (Intersection.isEmptySet())
@@ -1391,6 +1376,21 @@ Instruction *InstCombinerImpl::foldICmpWithDominatingICmp(ICmpInst &Cmp) {
return new ICmpInst(ICmpInst::ICMP_EQ, X, Builder.getInt(*EqC));
if (const APInt *NeC = Difference.getSingleElement())
return new ICmpInst(ICmpInst::ICMP_NE, X, Builder.getInt(*NeC));
+ return nullptr;
+ };
+
+ for (BranchInst *BI : DC.conditionsFor(X)) {
+ auto *Cond = BI->getCondition();
+ BasicBlockEdge Edge0(BI->getParent(), BI->getSuccessor(0));
+ if (DT.dominates(Edge0, Cmp.getParent())) {
+ if (auto *V = handleDomCond(Cond, true))
+ return V;
+ } else {
+ BasicBlockEdge Edge1(BI->getParent(), BI->getSuccessor(1));
+ if (DT.dominates(Edge1, Cmp.getParent()))
+ if (auto *V = handleDomCond(Cond, false))
+ return V;
+ }
}
return nullptr;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index bb620ad8d41c..1d50fa9b6bf7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -276,6 +276,7 @@ private:
bool transformConstExprCastCall(CallBase &Call);
Instruction *transformCallThroughTrampoline(CallBase &Call,
IntrinsicInst &Tramp);
+ Instruction *foldCommutativeIntrinsicOverSelects(IntrinsicInst &II);
Value *simplifyMaskedLoad(IntrinsicInst &II);
Instruction *simplifyMaskedStore(IntrinsicInst &II);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
index b72b68c68d98..bb2a77daa60a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
@@ -213,29 +213,10 @@ static Instruction *simplifyAllocaArraySize(InstCombinerImpl &IC,
AllocaInst *New = IC.Builder.CreateAlloca(NewTy, AI.getAddressSpace(),
nullptr, AI.getName());
New->setAlignment(AI.getAlign());
+ New->setUsedWithInAlloca(AI.isUsedWithInAlloca());
replaceAllDbgUsesWith(AI, *New, *New, DT);
-
- // Scan to the end of the allocation instructions, to skip over a block of
- // allocas if possible...also skip interleaved debug info
- //
- BasicBlock::iterator It(New);
- while (isa<AllocaInst>(*It) || isa<DbgInfoIntrinsic>(*It))
- ++It;
-
- // Now that I is pointing to the first non-allocation-inst in the block,
- // insert our getelementptr instruction...
- //
- Type *IdxTy = IC.getDataLayout().getIndexType(AI.getType());
- Value *NullIdx = Constant::getNullValue(IdxTy);
- Value *Idx[2] = {NullIdx, NullIdx};
- Instruction *GEP = GetElementPtrInst::CreateInBounds(
- NewTy, New, Idx, New->getName() + ".sub");
- IC.InsertNewInstBefore(GEP, It);
-
- // Now make everything use the getelementptr instead of the original
- // allocation.
- return IC.replaceInstUsesWith(AI, GEP);
+ return IC.replaceInstUsesWith(AI, New);
}
}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 8d5866e98a8e..e5566578869d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1205,6 +1205,38 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
}
}
+ // (X * Y) / (X * Z) --> Y / Z (and commuted variants)
+ if (match(Op0, m_Mul(m_Value(X), m_Value(Y)))) {
+ auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
+ auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
+
+ auto CreateDivOrNull = [&](Value *A, Value *B) -> Instruction * {
+ auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
+ auto OB1HasNUW =
+ cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
+ const APInt *C1, *C2;
+ if (IsSigned && OB0HasNSW) {
+ if (OB1HasNSW && match(B, m_APInt(C1)) && !C1->isAllOnes())
+ return BinaryOperator::CreateSDiv(A, B);
+ }
+ if (!IsSigned && OB0HasNUW) {
+ if (OB1HasNUW)
+ return BinaryOperator::CreateUDiv(A, B);
+ if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)) && C2->ule(*C1))
+ return BinaryOperator::CreateUDiv(A, B);
+ }
+ return nullptr;
+ };
+
+ if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
+ if (auto *Val = CreateDivOrNull(Y, Z))
+ return Val;
+ }
+ if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
+ if (auto *Val = CreateDivOrNull(X, Z))
+ return Val;
+ }
+ }
return nullptr;
}
@@ -1375,20 +1407,7 @@ Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) {
if (Instruction *NarrowDiv = narrowUDivURem(I, *this))
return NarrowDiv;
- // If the udiv operands are non-overflowing multiplies with a common operand,
- // then eliminate the common factor:
- // (A * B) / (A * X) --> B / X (and commuted variants)
- // TODO: The code would be reduced if we had m_c_NUWMul pattern matching.
- // TODO: If -reassociation handled this generally, we could remove this.
Value *A, *B;
- if (match(Op0, m_NUWMul(m_Value(A), m_Value(B)))) {
- if (match(Op1, m_NUWMul(m_Specific(A), m_Value(X))) ||
- match(Op1, m_NUWMul(m_Value(X), m_Specific(A))))
- return BinaryOperator::CreateUDiv(B, X);
- if (match(Op1, m_NUWMul(m_Specific(B), m_Value(X))) ||
- match(Op1, m_NUWMul(m_Value(X), m_Specific(B))))
- return BinaryOperator::CreateUDiv(A, X);
- }
// Look through a right-shift to find the common factor:
// ((Op1 *nuw A) >> B) / Op1 --> A >> B
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp
index 513b185c83a4..62e49469cb01 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp
@@ -43,14 +43,11 @@
#include <cassert>
#include <cstdint>
#include <functional>
-#include <tuple>
#include <type_traits>
#include <utility>
namespace llvm {
-class AssumptionCache;
class DataLayout;
-class DominatorTree;
class LLVMContext;
} // namespace llvm
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 046ce9d1207e..846116a929b1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -552,6 +552,17 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
if (DemandedFromOps.isSubsetOf(LHSKnown.Zero))
return I->getOperand(1);
+ // (add X, C) --> (xor X, C) IFF C is equal to the top bit of the DemandMask
+ {
+ const APInt *C;
+ if (match(I->getOperand(1), m_APInt(C)) &&
+ C->isOneBitSet(DemandedMask.getActiveBits() - 1)) {
+ IRBuilderBase::InsertPointGuard Guard(Builder);
+ Builder.SetInsertPoint(I);
+ return Builder.CreateXor(I->getOperand(0), ConstantInt::get(VTy, *C));
+ }
+ }
+
// Otherwise just compute the known bits of the result.
bool NSW = cast<OverflowingBinaryOperator>(I)->hasNoSignedWrap();
Known = KnownBits::computeForAddSub(true, NSW, LHSKnown, RHSKnown);
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index f072f5cec309..a7ddadc25de4 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -610,7 +610,7 @@ static Value *getIdentityValue(Instruction::BinaryOps Opcode, Value *V) {
/// allow more factorization opportunities.
static Instruction::BinaryOps
getBinOpsForFactorization(Instruction::BinaryOps TopOpcode, BinaryOperator *Op,
- Value *&LHS, Value *&RHS) {
+ Value *&LHS, Value *&RHS, BinaryOperator *OtherOp) {
assert(Op && "Expected a binary operator");
LHS = Op->getOperand(0);
RHS = Op->getOperand(1);
@@ -623,6 +623,13 @@ getBinOpsForFactorization(Instruction::BinaryOps TopOpcode, BinaryOperator *Op,
}
// TODO: We can add other conversions e.g. shr => div etc.
}
+ if (Instruction::isBitwiseLogicOp(TopOpcode)) {
+ if (OtherOp && OtherOp->getOpcode() == Instruction::AShr &&
+ match(Op, m_LShr(m_NonNegative(), m_Value()))) {
+ // lshr nneg C, X --> ashr nneg C, X
+ return Instruction::AShr;
+ }
+ }
return Op->getOpcode();
}
@@ -963,9 +970,9 @@ Value *InstCombinerImpl::tryFactorizationFolds(BinaryOperator &I) {
Instruction::BinaryOps LHSOpcode, RHSOpcode;
if (Op0)
- LHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op0, A, B);
+ LHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op0, A, B, Op1);
if (Op1)
- RHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op1, C, D);
+ RHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op1, C, D, Op0);
// The instruction has the form "(A op' B) op (C op' D)". Try to factorize
// a common term.
@@ -1132,6 +1139,14 @@ Value *InstCombinerImpl::SimplifySelectsFeedingBinaryOp(BinaryOperator &I,
};
if (LHSIsSelect && RHSIsSelect && A == D) {
+ // op(select(%v, %x, %y), select(%v, %y, %x)) --> op(%x, %y)
+ if (I.isCommutative() && B == F && C == E) {
+ Value *BI = Builder.CreateBinOp(I.getOpcode(), B, E);
+ if (auto *BO = dyn_cast<BinaryOperator>(BI))
+ BO->copyIRFlags(&I);
+ return BI;
+ }
+
// (A ? B : C) op (A ? E : F) -> A ? (B op E) : (C op F)
Cond = A;
True = simplifyBinOp(Opcode, B, E, FMF, Q);
@@ -2182,16 +2197,6 @@ Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses,
return nullptr;
}
- // Treat lshr with non-negative operand as ashr.
- if (match(V, m_LShr(m_Value(A), m_Value(B))) &&
- isKnownNonNegative(A, SQ.getWithInstruction(cast<Instruction>(V)),
- Depth)) {
- if (auto *AV = getFreelyInvertedImpl(A, A->hasOneUse(), Builder,
- DoesConsume, Depth))
- return Builder ? Builder->CreateAShr(AV, B) : NonNull;
- return nullptr;
- }
-
Value *Cond;
// LogicOps are special in that we canonicalize them at the cost of an
// instruction.
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index b175e6f93f3e..6468d07b4f4f 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -3505,7 +3505,7 @@ void FunctionStackPoisoner::processStaticAllocas() {
SplitBlockAndInsertIfThenElse(Cmp, Ret, &ThenTerm, &ElseTerm);
IRBuilder<> IRBPoison(ThenTerm);
- if (StackMallocIdx <= 4) {
+ if (ASan.MaxInlinePoisoningSize != 0 && StackMallocIdx <= 4) {
int ClassSize = kMinStackMallocSize << StackMallocIdx;
ShadowAfterReturn.resize(ClassSize / L.Granularity,
kAsanStackUseAfterReturnMagic);
diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
index d3282779d9f5..fe5a0578bd97 100644
--- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
@@ -64,10 +64,24 @@ using namespace llvm;
#define DEBUG_TYPE "instrprof"
namespace llvm {
-cl::opt<bool>
- DebugInfoCorrelate("debug-info-correlate",
- cl::desc("Use debug info to correlate profiles."),
- cl::init(false));
+// TODO: Remove -debug-info-correlate in next LLVM release, in favor of
+// -profile-correlate=debug-info.
+cl::opt<bool> DebugInfoCorrelate(
+ "debug-info-correlate",
+ cl::desc("Use debug info to correlate profiles. (Deprecated, use "
+ "-profile-correlate=debug-info)"),
+ cl::init(false));
+
+cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate(
+ "profile-correlate",
+ cl::desc("Use debug info or binary file to correlate profiles."),
+ cl::init(InstrProfCorrelator::NONE),
+ cl::values(clEnumValN(InstrProfCorrelator::NONE, "",
+ "No profile correlation"),
+ clEnumValN(InstrProfCorrelator::DEBUG_INFO, "debug-info",
+ "Use debug info to correlate"),
+ clEnumValN(InstrProfCorrelator::BINARY, "binary",
+ "Use binary to correlate")));
} // namespace llvm
namespace {
@@ -152,6 +166,155 @@ cl::opt<bool> SkipRetExitBlock(
"skip-ret-exit-block", cl::init(true),
cl::desc("Suppress counter promotion if exit blocks contain ret."));
+using LoadStorePair = std::pair<Instruction *, Instruction *>;
+
+class InstrLowerer final {
+public:
+ InstrLowerer(Module &M, const InstrProfOptions &Options,
+ std::function<const TargetLibraryInfo &(Function &F)> GetTLI,
+ bool IsCS)
+ : M(M), Options(Options), TT(Triple(M.getTargetTriple())), IsCS(IsCS),
+ GetTLI(GetTLI) {}
+
+ bool lower();
+
+private:
+ Module &M;
+ const InstrProfOptions Options;
+ const Triple TT;
+ // Is this lowering for the context-sensitive instrumentation.
+ const bool IsCS;
+
+ std::function<const TargetLibraryInfo &(Function &F)> GetTLI;
+ struct PerFunctionProfileData {
+ uint32_t NumValueSites[IPVK_Last + 1] = {};
+ GlobalVariable *RegionCounters = nullptr;
+ GlobalVariable *DataVar = nullptr;
+ GlobalVariable *RegionBitmaps = nullptr;
+ uint32_t NumBitmapBytes = 0;
+
+ PerFunctionProfileData() = default;
+ };
+ DenseMap<GlobalVariable *, PerFunctionProfileData> ProfileDataMap;
+ /// If runtime relocation is enabled, this maps functions to the load
+ /// instruction that produces the profile relocation bias.
+ DenseMap<const Function *, LoadInst *> FunctionToProfileBiasMap;
+ std::vector<GlobalValue *> CompilerUsedVars;
+ std::vector<GlobalValue *> UsedVars;
+ std::vector<GlobalVariable *> ReferencedNames;
+ GlobalVariable *NamesVar = nullptr;
+ size_t NamesSize = 0;
+
+ // vector of counter load/store pairs to be register promoted.
+ std::vector<LoadStorePair> PromotionCandidates;
+
+ int64_t TotalCountersPromoted = 0;
+
+ /// Lower instrumentation intrinsics in the function. Returns true if there
+ /// any lowering.
+ bool lowerIntrinsics(Function *F);
+
+ /// Register-promote counter loads and stores in loops.
+ void promoteCounterLoadStores(Function *F);
+
+ /// Returns true if relocating counters at runtime is enabled.
+ bool isRuntimeCounterRelocationEnabled() const;
+
+ /// Returns true if profile counter update register promotion is enabled.
+ bool isCounterPromotionEnabled() const;
+
+ /// Count the number of instrumented value sites for the function.
+ void computeNumValueSiteCounts(InstrProfValueProfileInst *Ins);
+
+ /// Replace instrprof.value.profile with a call to runtime library.
+ void lowerValueProfileInst(InstrProfValueProfileInst *Ins);
+
+ /// Replace instrprof.cover with a store instruction to the coverage byte.
+ void lowerCover(InstrProfCoverInst *Inc);
+
+ /// Replace instrprof.timestamp with a call to
+ /// INSTR_PROF_PROFILE_SET_TIMESTAMP.
+ void lowerTimestamp(InstrProfTimestampInst *TimestampInstruction);
+
+ /// Replace instrprof.increment with an increment of the appropriate value.
+ void lowerIncrement(InstrProfIncrementInst *Inc);
+
+ /// Force emitting of name vars for unused functions.
+ void lowerCoverageData(GlobalVariable *CoverageNamesVar);
+
+ /// Replace instrprof.mcdc.tvbitmask.update with a shift and or instruction
+ /// using the index represented by the a temp value into a bitmap.
+ void lowerMCDCTestVectorBitmapUpdate(InstrProfMCDCTVBitmapUpdate *Ins);
+
+ /// Replace instrprof.mcdc.temp.update with a shift and or instruction using
+ /// the corresponding condition ID.
+ void lowerMCDCCondBitmapUpdate(InstrProfMCDCCondBitmapUpdate *Ins);
+
+ /// Compute the address of the counter value that this profiling instruction
+ /// acts on.
+ Value *getCounterAddress(InstrProfCntrInstBase *I);
+
+ /// Get the region counters for an increment, creating them if necessary.
+ ///
+ /// If the counter array doesn't yet exist, the profile data variables
+ /// referring to them will also be created.
+ GlobalVariable *getOrCreateRegionCounters(InstrProfCntrInstBase *Inc);
+
+ /// Create the region counters.
+ GlobalVariable *createRegionCounters(InstrProfCntrInstBase *Inc,
+ StringRef Name,
+ GlobalValue::LinkageTypes Linkage);
+
+ /// Compute the address of the test vector bitmap that this profiling
+ /// instruction acts on.
+ Value *getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I);
+
+ /// Get the region bitmaps for an increment, creating them if necessary.
+ ///
+ /// If the bitmap array doesn't yet exist, the profile data variables
+ /// referring to them will also be created.
+ GlobalVariable *getOrCreateRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc);
+
+ /// Create the MC/DC bitmap as a byte-aligned array of bytes associated with
+ /// an MC/DC Decision region. The number of bytes required is indicated by
+ /// the intrinsic used (type InstrProfMCDCBitmapInstBase). This is called
+ /// as part of setupProfileSection() and is conceptually very similar to
+ /// what is done for profile data counters in createRegionCounters().
+ GlobalVariable *createRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc,
+ StringRef Name,
+ GlobalValue::LinkageTypes Linkage);
+
+ /// Set Comdat property of GV, if required.
+ void maybeSetComdat(GlobalVariable *GV, Function *Fn, StringRef VarName);
+
+ /// Setup the sections into which counters and bitmaps are allocated.
+ GlobalVariable *setupProfileSection(InstrProfInstBase *Inc,
+ InstrProfSectKind IPSK);
+
+ /// Create INSTR_PROF_DATA variable for counters and bitmaps.
+ void createDataVariable(InstrProfCntrInstBase *Inc);
+
+ /// Emit the section with compressed function names.
+ void emitNameData();
+
+ /// Emit value nodes section for value profiling.
+ void emitVNodes();
+
+ /// Emit runtime registration functions for each profile data variable.
+ void emitRegistration();
+
+ /// Emit the necessary plumbing to pull in the runtime initialization.
+ /// Returns true if a change was made.
+ bool emitRuntimeHook();
+
+ /// Add uses of our data variables and runtime hook.
+ void emitUses();
+
+ /// Create a static initializer for our data, on platforms that need it,
+ /// and for any profile output file that was specified.
+ void emitInitialization();
+};
+
///
/// A helper class to promote one counter RMW operation in the loop
/// into register update.
@@ -407,19 +570,21 @@ enum class ValueProfilingCallType {
} // end anonymous namespace
-PreservedAnalyses InstrProfiling::run(Module &M, ModuleAnalysisManager &AM) {
+PreservedAnalyses InstrProfilingLoweringPass::run(Module &M,
+ ModuleAnalysisManager &AM) {
FunctionAnalysisManager &FAM =
AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
return FAM.getResult<TargetLibraryAnalysis>(F);
};
- if (!run(M, GetTLI))
+ InstrLowerer Lowerer(M, Options, GetTLI, IsCS);
+ if (!Lowerer.lower())
return PreservedAnalyses::all();
return PreservedAnalyses::none();
}
-bool InstrProfiling::lowerIntrinsics(Function *F) {
+bool InstrLowerer::lowerIntrinsics(Function *F) {
bool MadeChange = false;
PromotionCandidates.clear();
for (BasicBlock &BB : *F) {
@@ -459,7 +624,7 @@ bool InstrProfiling::lowerIntrinsics(Function *F) {
return true;
}
-bool InstrProfiling::isRuntimeCounterRelocationEnabled() const {
+bool InstrLowerer::isRuntimeCounterRelocationEnabled() const {
// Mach-O don't support weak external references.
if (TT.isOSBinFormatMachO())
return false;
@@ -471,14 +636,14 @@ bool InstrProfiling::isRuntimeCounterRelocationEnabled() const {
return TT.isOSFuchsia();
}
-bool InstrProfiling::isCounterPromotionEnabled() const {
+bool InstrLowerer::isCounterPromotionEnabled() const {
if (DoCounterPromotion.getNumOccurrences() > 0)
return DoCounterPromotion;
return Options.DoCounterPromotion;
}
-void InstrProfiling::promoteCounterLoadStores(Function *F) {
+void InstrLowerer::promoteCounterLoadStores(Function *F) {
if (!isCounterPromotionEnabled())
return;
@@ -535,17 +700,7 @@ static bool containsProfilingIntrinsics(Module &M) {
containsIntrinsic(llvm::Intrinsic::instrprof_value_profile);
}
-bool InstrProfiling::run(
- Module &M, std::function<const TargetLibraryInfo &(Function &F)> GetTLI) {
- this->M = &M;
- this->GetTLI = std::move(GetTLI);
- NamesVar = nullptr;
- NamesSize = 0;
- ProfileDataMap.clear();
- CompilerUsedVars.clear();
- UsedVars.clear();
- TT = Triple(M.getTargetTriple());
-
+bool InstrLowerer::lower() {
bool MadeChange = false;
bool NeedsRuntimeHook = needsRuntimeHookUnconditionally(TT);
if (NeedsRuntimeHook)
@@ -637,7 +792,7 @@ static FunctionCallee getOrInsertValueProfilingCall(
return M.getOrInsertFunction(FuncName, ValueProfilingCallTy, AL);
}
-void InstrProfiling::computeNumValueSiteCounts(InstrProfValueProfileInst *Ind) {
+void InstrLowerer::computeNumValueSiteCounts(InstrProfValueProfileInst *Ind) {
GlobalVariable *Name = Ind->getName();
uint64_t ValueKind = Ind->getValueKind()->getZExtValue();
uint64_t Index = Ind->getIndex()->getZExtValue();
@@ -646,12 +801,12 @@ void InstrProfiling::computeNumValueSiteCounts(InstrProfValueProfileInst *Ind) {
std::max(PD.NumValueSites[ValueKind], (uint32_t)(Index + 1));
}
-void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) {
+void InstrLowerer::lowerValueProfileInst(InstrProfValueProfileInst *Ind) {
// TODO: Value profiling heavily depends on the data section which is omitted
// in lightweight mode. We need to move the value profile pointer to the
// Counter struct to get this working.
assert(
- !DebugInfoCorrelate &&
+ !DebugInfoCorrelate && ProfileCorrelate == InstrProfCorrelator::NONE &&
"Value profiling is not yet supported with lightweight instrumentation");
GlobalVariable *Name = Ind->getName();
auto It = ProfileDataMap.find(Name);
@@ -678,12 +833,12 @@ void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) {
Ind->getOperandBundlesAsDefs(OpBundles);
if (!IsMemOpSize) {
Value *Args[3] = {Ind->getTargetValue(), DataVar, Builder.getInt32(Index)};
- Call = Builder.CreateCall(getOrInsertValueProfilingCall(*M, *TLI), Args,
+ Call = Builder.CreateCall(getOrInsertValueProfilingCall(M, *TLI), Args,
OpBundles);
} else {
Value *Args[3] = {Ind->getTargetValue(), DataVar, Builder.getInt32(Index)};
Call = Builder.CreateCall(
- getOrInsertValueProfilingCall(*M, *TLI, ValueProfilingCallType::MemOp),
+ getOrInsertValueProfilingCall(M, *TLI, ValueProfilingCallType::MemOp),
Args, OpBundles);
}
if (auto AK = TLI->getExtAttrForI32Param(false))
@@ -692,7 +847,7 @@ void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) {
Ind->eraseFromParent();
}
-Value *InstrProfiling::getCounterAddress(InstrProfCntrInstBase *I) {
+Value *InstrLowerer::getCounterAddress(InstrProfCntrInstBase *I) {
auto *Counters = getOrCreateRegionCounters(I);
IRBuilder<> Builder(I);
@@ -705,18 +860,18 @@ Value *InstrProfiling::getCounterAddress(InstrProfCntrInstBase *I) {
if (!isRuntimeCounterRelocationEnabled())
return Addr;
- Type *Int64Ty = Type::getInt64Ty(M->getContext());
+ Type *Int64Ty = Type::getInt64Ty(M.getContext());
Function *Fn = I->getParent()->getParent();
LoadInst *&BiasLI = FunctionToProfileBiasMap[Fn];
if (!BiasLI) {
IRBuilder<> EntryBuilder(&Fn->getEntryBlock().front());
- auto *Bias = M->getGlobalVariable(getInstrProfCounterBiasVarName());
+ auto *Bias = M.getGlobalVariable(getInstrProfCounterBiasVarName());
if (!Bias) {
// Compiler must define this variable when runtime counter relocation
// is being used. Runtime has a weak external reference that is used
// to check whether that's the case or not.
Bias = new GlobalVariable(
- *M, Int64Ty, false, GlobalValue::LinkOnceODRLinkage,
+ M, Int64Ty, false, GlobalValue::LinkOnceODRLinkage,
Constant::getNullValue(Int64Ty), getInstrProfCounterBiasVarName());
Bias->setVisibility(GlobalVariable::HiddenVisibility);
// A definition that's weak (linkonce_odr) without being in a COMDAT
@@ -724,7 +879,7 @@ Value *InstrProfiling::getCounterAddress(InstrProfCntrInstBase *I) {
// data word from every TU but one. Putting it in COMDAT ensures there
// will be exactly one data slot in the link.
if (TT.supportsCOMDAT())
- Bias->setComdat(M->getOrInsertComdat(Bias->getName()));
+ Bias->setComdat(M.getOrInsertComdat(Bias->getName()));
}
BiasLI = EntryBuilder.CreateLoad(Int64Ty, Bias);
}
@@ -732,7 +887,7 @@ Value *InstrProfiling::getCounterAddress(InstrProfCntrInstBase *I) {
return Builder.CreateIntToPtr(Add, Addr->getType());
}
-Value *InstrProfiling::getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I) {
+Value *InstrLowerer::getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I) {
auto *Bitmaps = getOrCreateRegionBitmaps(I);
IRBuilder<> Builder(I);
@@ -740,9 +895,9 @@ Value *InstrProfiling::getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I) {
Bitmaps->getValueType(), Bitmaps, 0, I->getBitmapIndex()->getZExtValue());
if (isRuntimeCounterRelocationEnabled()) {
- LLVMContext &Ctx = M->getContext();
+ LLVMContext &Ctx = M.getContext();
Ctx.diagnose(DiagnosticInfoPGOProfile(
- M->getName().data(),
+ M.getName().data(),
Twine("Runtime counter relocation is presently not supported for MC/DC "
"bitmaps."),
DS_Warning));
@@ -751,7 +906,7 @@ Value *InstrProfiling::getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I) {
return Addr;
}
-void InstrProfiling::lowerCover(InstrProfCoverInst *CoverInstruction) {
+void InstrLowerer::lowerCover(InstrProfCoverInst *CoverInstruction) {
auto *Addr = getCounterAddress(CoverInstruction);
IRBuilder<> Builder(CoverInstruction);
// We store zero to represent that this block is covered.
@@ -759,22 +914,22 @@ void InstrProfiling::lowerCover(InstrProfCoverInst *CoverInstruction) {
CoverInstruction->eraseFromParent();
}
-void InstrProfiling::lowerTimestamp(
+void InstrLowerer::lowerTimestamp(
InstrProfTimestampInst *TimestampInstruction) {
assert(TimestampInstruction->getIndex()->isZeroValue() &&
"timestamp probes are always the first probe for a function");
- auto &Ctx = M->getContext();
+ auto &Ctx = M.getContext();
auto *TimestampAddr = getCounterAddress(TimestampInstruction);
IRBuilder<> Builder(TimestampInstruction);
auto *CalleeTy =
FunctionType::get(Type::getVoidTy(Ctx), TimestampAddr->getType(), false);
- auto Callee = M->getOrInsertFunction(
+ auto Callee = M.getOrInsertFunction(
INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_SET_TIMESTAMP), CalleeTy);
Builder.CreateCall(Callee, {TimestampAddr});
TimestampInstruction->eraseFromParent();
}
-void InstrProfiling::lowerIncrement(InstrProfIncrementInst *Inc) {
+void InstrLowerer::lowerIncrement(InstrProfIncrementInst *Inc) {
auto *Addr = getCounterAddress(Inc);
IRBuilder<> Builder(Inc);
@@ -793,7 +948,7 @@ void InstrProfiling::lowerIncrement(InstrProfIncrementInst *Inc) {
Inc->eraseFromParent();
}
-void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageNamesVar) {
+void InstrLowerer::lowerCoverageData(GlobalVariable *CoverageNamesVar) {
ConstantArray *Names =
cast<ConstantArray>(CoverageNamesVar->getInitializer());
for (unsigned I = 0, E = Names->getNumOperands(); I < E; ++I) {
@@ -810,13 +965,13 @@ void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageNamesVar) {
CoverageNamesVar->eraseFromParent();
}
-void InstrProfiling::lowerMCDCTestVectorBitmapUpdate(
+void InstrLowerer::lowerMCDCTestVectorBitmapUpdate(
InstrProfMCDCTVBitmapUpdate *Update) {
IRBuilder<> Builder(Update);
- auto *Int8Ty = Type::getInt8Ty(M->getContext());
- auto *Int8PtrTy = PointerType::getUnqual(M->getContext());
- auto *Int32Ty = Type::getInt32Ty(M->getContext());
- auto *Int64Ty = Type::getInt64Ty(M->getContext());
+ auto *Int8Ty = Type::getInt8Ty(M.getContext());
+ auto *Int8PtrTy = PointerType::getUnqual(M.getContext());
+ auto *Int32Ty = Type::getInt32Ty(M.getContext());
+ auto *Int64Ty = Type::getInt64Ty(M.getContext());
auto *MCDCCondBitmapAddr = Update->getMCDCCondBitmapAddr();
auto *BitmapAddr = getBitmapAddress(Update);
@@ -862,10 +1017,10 @@ void InstrProfiling::lowerMCDCTestVectorBitmapUpdate(
Update->eraseFromParent();
}
-void InstrProfiling::lowerMCDCCondBitmapUpdate(
+void InstrLowerer::lowerMCDCCondBitmapUpdate(
InstrProfMCDCCondBitmapUpdate *Update) {
IRBuilder<> Builder(Update);
- auto *Int32Ty = Type::getInt32Ty(M->getContext());
+ auto *Int32Ty = Type::getInt32Ty(M.getContext());
auto *MCDCCondBitmapAddr = Update->getMCDCCondBitmapAddr();
// Load the MCDC temporary value from the stack.
@@ -1045,10 +1200,10 @@ static bool needsRuntimeRegistrationOfSectionRange(const Triple &TT) {
return true;
}
-void InstrProfiling::maybeSetComdat(GlobalVariable *GV, Function *Fn,
- StringRef VarName) {
- bool DataReferencedByCode = profDataReferencedByCode(*M);
- bool NeedComdat = needsComdatForCounter(*Fn, *M);
+void InstrLowerer::maybeSetComdat(GlobalVariable *GV, Function *Fn,
+ StringRef VarName) {
+ bool DataReferencedByCode = profDataReferencedByCode(M);
+ bool NeedComdat = needsComdatForCounter(*Fn, M);
bool UseComdat = (NeedComdat || TT.isOSBinFormatELF());
if (!UseComdat)
@@ -1056,7 +1211,7 @@ void InstrProfiling::maybeSetComdat(GlobalVariable *GV, Function *Fn,
StringRef GroupName =
TT.isOSBinFormatCOFF() && DataReferencedByCode ? GV->getName() : VarName;
- Comdat *C = M->getOrInsertComdat(GroupName);
+ Comdat *C = M.getOrInsertComdat(GroupName);
if (!NeedComdat)
C->setSelectionKind(Comdat::NoDeduplicate);
GV->setComdat(C);
@@ -1067,8 +1222,8 @@ void InstrProfiling::maybeSetComdat(GlobalVariable *GV, Function *Fn,
GV->setLinkage(GlobalValue::InternalLinkage);
}
-GlobalVariable *InstrProfiling::setupProfileSection(InstrProfInstBase *Inc,
- InstrProfSectKind IPSK) {
+GlobalVariable *InstrLowerer::setupProfileSection(InstrProfInstBase *Inc,
+ InstrProfSectKind IPSK) {
GlobalVariable *NamePtr = Inc->getName();
// Match the linkage and visibility of the name global.
@@ -1078,8 +1233,9 @@ GlobalVariable *InstrProfiling::setupProfileSection(InstrProfInstBase *Inc,
// Use internal rather than private linkage so the counter variable shows up
// in the symbol table when using debug info for correlation.
- if (DebugInfoCorrelate && TT.isOSBinFormatMachO() &&
- Linkage == GlobalValue::PrivateLinkage)
+ if ((DebugInfoCorrelate ||
+ ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) &&
+ TT.isOSBinFormatMachO() && Linkage == GlobalValue::PrivateLinkage)
Linkage = GlobalValue::InternalLinkage;
// Due to the limitation of binder as of 2021/09/28, the duplicate weak
@@ -1137,19 +1293,19 @@ GlobalVariable *InstrProfiling::setupProfileSection(InstrProfInstBase *Inc,
}
GlobalVariable *
-InstrProfiling::createRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc,
- StringRef Name,
- GlobalValue::LinkageTypes Linkage) {
+InstrLowerer::createRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc,
+ StringRef Name,
+ GlobalValue::LinkageTypes Linkage) {
uint64_t NumBytes = Inc->getNumBitmapBytes()->getZExtValue();
- auto *BitmapTy = ArrayType::get(Type::getInt8Ty(M->getContext()), NumBytes);
- auto GV = new GlobalVariable(*M, BitmapTy, false, Linkage,
+ auto *BitmapTy = ArrayType::get(Type::getInt8Ty(M.getContext()), NumBytes);
+ auto GV = new GlobalVariable(M, BitmapTy, false, Linkage,
Constant::getNullValue(BitmapTy), Name);
GV->setAlignment(Align(1));
return GV;
}
GlobalVariable *
-InstrProfiling::getOrCreateRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc) {
+InstrLowerer::getOrCreateRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc) {
GlobalVariable *NamePtr = Inc->getName();
auto &PD = ProfileDataMap[NamePtr];
if (PD.RegionBitmaps)
@@ -1164,10 +1320,10 @@ InstrProfiling::getOrCreateRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc) {
}
GlobalVariable *
-InstrProfiling::createRegionCounters(InstrProfCntrInstBase *Inc, StringRef Name,
- GlobalValue::LinkageTypes Linkage) {
+InstrLowerer::createRegionCounters(InstrProfCntrInstBase *Inc, StringRef Name,
+ GlobalValue::LinkageTypes Linkage) {
uint64_t NumCounters = Inc->getNumCounters()->getZExtValue();
- auto &Ctx = M->getContext();
+ auto &Ctx = M.getContext();
GlobalVariable *GV;
if (isa<InstrProfCoverInst>(Inc)) {
auto *CounterTy = Type::getInt8Ty(Ctx);
@@ -1175,13 +1331,13 @@ InstrProfiling::createRegionCounters(InstrProfCntrInstBase *Inc, StringRef Name,
// TODO: `Constant::getAllOnesValue()` does not yet accept an array type.
std::vector<Constant *> InitialValues(NumCounters,
Constant::getAllOnesValue(CounterTy));
- GV = new GlobalVariable(*M, CounterArrTy, false, Linkage,
+ GV = new GlobalVariable(M, CounterArrTy, false, Linkage,
ConstantArray::get(CounterArrTy, InitialValues),
Name);
GV->setAlignment(Align(1));
} else {
auto *CounterTy = ArrayType::get(Type::getInt64Ty(Ctx), NumCounters);
- GV = new GlobalVariable(*M, CounterTy, false, Linkage,
+ GV = new GlobalVariable(M, CounterTy, false, Linkage,
Constant::getNullValue(CounterTy), Name);
GV->setAlignment(Align(8));
}
@@ -1189,7 +1345,7 @@ InstrProfiling::createRegionCounters(InstrProfCntrInstBase *Inc, StringRef Name,
}
GlobalVariable *
-InstrProfiling::getOrCreateRegionCounters(InstrProfCntrInstBase *Inc) {
+InstrLowerer::getOrCreateRegionCounters(InstrProfCntrInstBase *Inc) {
GlobalVariable *NamePtr = Inc->getName();
auto &PD = ProfileDataMap[NamePtr];
if (PD.RegionCounters)
@@ -1200,11 +1356,12 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfCntrInstBase *Inc) {
auto *CounterPtr = setupProfileSection(Inc, IPSK_cnts);
PD.RegionCounters = CounterPtr;
- if (DebugInfoCorrelate) {
- LLVMContext &Ctx = M->getContext();
+ if (DebugInfoCorrelate ||
+ ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) {
+ LLVMContext &Ctx = M.getContext();
Function *Fn = Inc->getParent()->getParent();
if (auto *SP = Fn->getSubprogram()) {
- DIBuilder DB(*M, true, SP->getUnit());
+ DIBuilder DB(M, true, SP->getUnit());
Metadata *FunctionNameAnnotation[] = {
MDString::get(Ctx, InstrProfCorrelator::FunctionNameAttributeName),
MDString::get(Ctx, getPGOFuncNameVarInitializer(NamePtr)),
@@ -1242,10 +1399,10 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfCntrInstBase *Inc) {
return PD.RegionCounters;
}
-void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc) {
+void InstrLowerer::createDataVariable(InstrProfCntrInstBase *Inc) {
// When debug information is correlated to profile data, a data variable
// is not needed.
- if (DebugInfoCorrelate)
+ if (DebugInfoCorrelate || ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO)
return;
GlobalVariable *NamePtr = Inc->getName();
@@ -1255,7 +1412,7 @@ void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc) {
if (PD.DataVar)
return;
- LLVMContext &Ctx = M->getContext();
+ LLVMContext &Ctx = M.getContext();
Function *Fn = Inc->getParent()->getParent();
GlobalValue::LinkageTypes Linkage = NamePtr->getLinkage();
@@ -1271,8 +1428,8 @@ void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc) {
Visibility = GlobalValue::DefaultVisibility;
}
- bool DataReferencedByCode = profDataReferencedByCode(*M);
- bool NeedComdat = needsComdatForCounter(*Fn, *M);
+ bool DataReferencedByCode = profDataReferencedByCode(M);
+ bool NeedComdat = needsComdatForCounter(*Fn, M);
bool Renamed;
// The Data Variable section is anchored to profile counters.
@@ -1292,7 +1449,7 @@ void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc) {
!needsRuntimeRegistrationOfSectionRange(TT)) {
ArrayType *ValuesTy = ArrayType::get(Type::getInt64Ty(Ctx), NS);
auto *ValuesVar = new GlobalVariable(
- *M, ValuesTy, false, Linkage, Constant::getNullValue(ValuesTy),
+ M, ValuesTy, false, Linkage, Constant::getNullValue(ValuesTy),
getVarName(Inc, getInstrProfValuesVarPrefix(), Renamed));
ValuesVar->setVisibility(Visibility);
setGlobalVariableLargeSection(TT, *ValuesVar);
@@ -1309,7 +1466,7 @@ void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc) {
uint64_t NumBitmapBytes = PD.NumBitmapBytes;
// Create data variable.
- auto *IntPtrTy = M->getDataLayout().getIntPtrType(M->getContext());
+ auto *IntPtrTy = M.getDataLayout().getIntPtrType(M.getContext());
auto *Int16Ty = Type::getInt16Ty(Ctx);
auto *Int16ArrayTy = ArrayType::get(Int16Ty, IPVK_Last + 1);
Type *DataTypes[] = {
@@ -1342,21 +1499,29 @@ void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc) {
Visibility = GlobalValue::DefaultVisibility;
}
auto *Data =
- new GlobalVariable(*M, DataTy, false, Linkage, nullptr, DataVarName);
- // Reference the counter variable with a label difference (link-time
- // constant).
- auto *RelativeCounterPtr =
- ConstantExpr::getSub(ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy),
- ConstantExpr::getPtrToInt(Data, IntPtrTy));
-
- // Bitmaps are relative to the same data variable as profile counters.
+ new GlobalVariable(M, DataTy, false, Linkage, nullptr, DataVarName);
+ Constant *RelativeCounterPtr;
GlobalVariable *BitmapPtr = PD.RegionBitmaps;
Constant *RelativeBitmapPtr = ConstantInt::get(IntPtrTy, 0);
-
- if (BitmapPtr != nullptr) {
- RelativeBitmapPtr =
- ConstantExpr::getSub(ConstantExpr::getPtrToInt(BitmapPtr, IntPtrTy),
+ InstrProfSectKind DataSectionKind;
+ // With binary profile correlation, profile data is not loaded into memory.
+ // profile data must reference profile counter with an absolute relocation.
+ if (ProfileCorrelate == InstrProfCorrelator::BINARY) {
+ DataSectionKind = IPSK_covdata;
+ RelativeCounterPtr = ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy);
+ if (BitmapPtr != nullptr)
+ RelativeBitmapPtr = ConstantExpr::getPtrToInt(BitmapPtr, IntPtrTy);
+ } else {
+ // Reference the counter variable with a label difference (link-time
+ // constant).
+ DataSectionKind = IPSK_data;
+ RelativeCounterPtr =
+ ConstantExpr::getSub(ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy),
ConstantExpr::getPtrToInt(Data, IntPtrTy));
+ if (BitmapPtr != nullptr)
+ RelativeBitmapPtr =
+ ConstantExpr::getSub(ConstantExpr::getPtrToInt(BitmapPtr, IntPtrTy),
+ ConstantExpr::getPtrToInt(Data, IntPtrTy));
}
Constant *DataVals[] = {
@@ -1366,7 +1531,8 @@ void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc) {
Data->setInitializer(ConstantStruct::get(DataTy, DataVals));
Data->setVisibility(Visibility);
- Data->setSection(getInstrProfSectionName(IPSK_data, TT.getObjectFormat()));
+ Data->setSection(
+ getInstrProfSectionName(DataSectionKind, TT.getObjectFormat()));
Data->setAlignment(Align(INSTR_PROF_DATA_ALIGNMENT));
maybeSetComdat(Data, Fn, CntsVarName);
@@ -1382,7 +1548,7 @@ void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc) {
ReferencedNames.push_back(NamePtr);
}
-void InstrProfiling::emitVNodes() {
+void InstrLowerer::emitVNodes() {
if (!ValueProfileStaticAlloc)
return;
@@ -1413,7 +1579,7 @@ void InstrProfiling::emitVNodes() {
if (NumCounters < INSTR_PROF_MIN_VAL_COUNTS)
NumCounters = std::max(INSTR_PROF_MIN_VAL_COUNTS, (int)NumCounters * 2);
- auto &Ctx = M->getContext();
+ auto &Ctx = M.getContext();
Type *VNodeTypes[] = {
#define INSTR_PROF_VALUE_NODE(Type, LLVMType, Name, Init) LLVMType,
#include "llvm/ProfileData/InstrProfData.inc"
@@ -1422,18 +1588,18 @@ void InstrProfiling::emitVNodes() {
ArrayType *VNodesTy = ArrayType::get(VNodeTy, NumCounters);
auto *VNodesVar = new GlobalVariable(
- *M, VNodesTy, false, GlobalValue::PrivateLinkage,
+ M, VNodesTy, false, GlobalValue::PrivateLinkage,
Constant::getNullValue(VNodesTy), getInstrProfVNodesVarName());
setGlobalVariableLargeSection(TT, *VNodesVar);
VNodesVar->setSection(
getInstrProfSectionName(IPSK_vnodes, TT.getObjectFormat()));
- VNodesVar->setAlignment(M->getDataLayout().getABITypeAlign(VNodesTy));
+ VNodesVar->setAlignment(M.getDataLayout().getABITypeAlign(VNodesTy));
// VNodesVar is used by runtime but not referenced via relocation by other
// sections. Conservatively make it linker retained.
UsedVars.push_back(VNodesVar);
}
-void InstrProfiling::emitNameData() {
+void InstrLowerer::emitNameData() {
std::string UncompressedData;
if (ReferencedNames.empty())
@@ -1445,16 +1611,18 @@ void InstrProfiling::emitNameData() {
report_fatal_error(Twine(toString(std::move(E))), false);
}
- auto &Ctx = M->getContext();
+ auto &Ctx = M.getContext();
auto *NamesVal =
ConstantDataArray::getString(Ctx, StringRef(CompressedNameStr), false);
- NamesVar = new GlobalVariable(*M, NamesVal->getType(), true,
+ NamesVar = new GlobalVariable(M, NamesVal->getType(), true,
GlobalValue::PrivateLinkage, NamesVal,
getInstrProfNamesVarName());
NamesSize = CompressedNameStr.size();
setGlobalVariableLargeSection(TT, *NamesVar);
NamesVar->setSection(
- getInstrProfSectionName(IPSK_name, TT.getObjectFormat()));
+ ProfileCorrelate == InstrProfCorrelator::BINARY
+ ? getInstrProfSectionName(IPSK_covname, TT.getObjectFormat())
+ : getInstrProfSectionName(IPSK_name, TT.getObjectFormat()));
// On COFF, it's important to reduce the alignment down to 1 to prevent the
// linker from inserting padding before the start of the names section or
// between names entries.
@@ -1467,14 +1635,14 @@ void InstrProfiling::emitNameData() {
NamePtr->eraseFromParent();
}
-void InstrProfiling::emitRegistration() {
+void InstrLowerer::emitRegistration() {
if (!needsRuntimeRegistrationOfSectionRange(TT))
return;
// Construct the function.
- auto *VoidTy = Type::getVoidTy(M->getContext());
- auto *VoidPtrTy = PointerType::getUnqual(M->getContext());
- auto *Int64Ty = Type::getInt64Ty(M->getContext());
+ auto *VoidTy = Type::getVoidTy(M.getContext());
+ auto *VoidPtrTy = PointerType::getUnqual(M.getContext());
+ auto *Int64Ty = Type::getInt64Ty(M.getContext());
auto *RegisterFTy = FunctionType::get(VoidTy, false);
auto *RegisterF = Function::Create(RegisterFTy, GlobalValue::InternalLinkage,
getInstrProfRegFuncsName(), M);
@@ -1487,7 +1655,7 @@ void InstrProfiling::emitRegistration() {
Function::Create(RuntimeRegisterTy, GlobalVariable::ExternalLinkage,
getInstrProfRegFuncName(), M);
- IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", RegisterF));
+ IRBuilder<> IRB(BasicBlock::Create(M.getContext(), "", RegisterF));
for (Value *Data : CompilerUsedVars)
if (!isa<Function>(Data))
IRB.CreateCall(RuntimeRegisterF, Data);
@@ -1508,20 +1676,20 @@ void InstrProfiling::emitRegistration() {
IRB.CreateRetVoid();
}
-bool InstrProfiling::emitRuntimeHook() {
+bool InstrLowerer::emitRuntimeHook() {
// We expect the linker to be invoked with -u<hook_var> flag for Linux
// in which case there is no need to emit the external variable.
if (TT.isOSLinux() || TT.isOSAIX())
return false;
// If the module's provided its own runtime, we don't need to do anything.
- if (M->getGlobalVariable(getInstrProfRuntimeHookVarName()))
+ if (M.getGlobalVariable(getInstrProfRuntimeHookVarName()))
return false;
// Declare an external variable that will pull in the runtime initialization.
- auto *Int32Ty = Type::getInt32Ty(M->getContext());
+ auto *Int32Ty = Type::getInt32Ty(M.getContext());
auto *Var =
- new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
+ new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage,
nullptr, getInstrProfRuntimeHookVarName());
Var->setVisibility(GlobalValue::HiddenVisibility);
@@ -1538,9 +1706,9 @@ bool InstrProfiling::emitRuntimeHook() {
User->addFnAttr(Attribute::NoRedZone);
User->setVisibility(GlobalValue::HiddenVisibility);
if (TT.supportsCOMDAT())
- User->setComdat(M->getOrInsertComdat(User->getName()));
+ User->setComdat(M.getOrInsertComdat(User->getName()));
- IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", User));
+ IRBuilder<> IRB(BasicBlock::Create(M.getContext(), "", User));
auto *Load = IRB.CreateLoad(Int32Ty, Var);
IRB.CreateRet(Load);
@@ -1550,7 +1718,7 @@ bool InstrProfiling::emitRuntimeHook() {
return true;
}
-void InstrProfiling::emitUses() {
+void InstrLowerer::emitUses() {
// The metadata sections are parallel arrays. Optimizers (e.g.
// GlobalOpt/ConstantMerge) may not discard associated sections as a unit, so
// we conservatively retain all unconditionally in the compiler.
@@ -1561,30 +1729,30 @@ void InstrProfiling::emitUses() {
// and ensure this GC property as well. Otherwise, we have to conservatively
// make all of the sections retained by the linker.
if (TT.isOSBinFormatELF() || TT.isOSBinFormatMachO() ||
- (TT.isOSBinFormatCOFF() && !profDataReferencedByCode(*M)))
- appendToCompilerUsed(*M, CompilerUsedVars);
+ (TT.isOSBinFormatCOFF() && !profDataReferencedByCode(M)))
+ appendToCompilerUsed(M, CompilerUsedVars);
else
- appendToUsed(*M, CompilerUsedVars);
+ appendToUsed(M, CompilerUsedVars);
// We do not add proper references from used metadata sections to NamesVar and
// VNodesVar, so we have to be conservative and place them in llvm.used
// regardless of the target,
- appendToUsed(*M, UsedVars);
+ appendToUsed(M, UsedVars);
}
-void InstrProfiling::emitInitialization() {
+void InstrLowerer::emitInitialization() {
// Create ProfileFileName variable. Don't don't this for the
// context-sensitive instrumentation lowering: This lowering is after
// LTO/ThinLTO linking. Pass PGOInstrumentationGenCreateVar should
// have already create the variable before LTO/ThinLTO linking.
if (!IsCS)
- createProfileFileNameVar(*M, Options.InstrProfileOutput);
- Function *RegisterF = M->getFunction(getInstrProfRegFuncsName());
+ createProfileFileNameVar(M, Options.InstrProfileOutput);
+ Function *RegisterF = M.getFunction(getInstrProfRegFuncsName());
if (!RegisterF)
return;
// Create the initialization function.
- auto *VoidTy = Type::getVoidTy(M->getContext());
+ auto *VoidTy = Type::getVoidTy(M.getContext());
auto *F = Function::Create(FunctionType::get(VoidTy, false),
GlobalValue::InternalLinkage,
getInstrProfInitFuncName(), M);
@@ -1594,9 +1762,9 @@ void InstrProfiling::emitInitialization() {
F->addFnAttr(Attribute::NoRedZone);
// Add the basic block and the necessary calls.
- IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", F));
+ IRBuilder<> IRB(BasicBlock::Create(M.getContext(), "", F));
IRB.CreateCall(RegisterF, {});
IRB.CreateRetVoid();
- appendToGlobalCtors(*M, F, 0);
+ appendToGlobalCtors(M, F, 0);
}
diff --git a/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp b/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp
index 199afbe966dd..b842d9eef407 100644
--- a/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp
+++ b/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp
@@ -85,10 +85,15 @@ Comdat *llvm::getOrCreateFunctionComdat(Function &F, Triple &T) {
return C;
}
-void llvm::setGlobalVariableLargeSection(Triple &TargetTriple,
+void llvm::setGlobalVariableLargeSection(const Triple &TargetTriple,
GlobalVariable &GV) {
- if (TargetTriple.getArch() == Triple::x86_64 &&
- TargetTriple.getObjectFormat() == Triple::ELF) {
- GV.setCodeModel(CodeModel::Large);
- }
+ // Limit to x86-64 ELF.
+ if (TargetTriple.getArch() != Triple::x86_64 ||
+ TargetTriple.getObjectFormat() != Triple::ELF)
+ return;
+ // Limit to medium/large code models.
+ std::optional<CodeModel::Model> CM = GV.getParent()->getCodeModel();
+ if (!CM || (*CM != CodeModel::Medium && *CM != CodeModel::Large))
+ return;
+ GV.setCodeModel(CodeModel::Large);
}
diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
index 4a5a0b25bebb..3a57709c4e8b 100644
--- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
+++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
@@ -327,6 +327,7 @@ extern cl::opt<PGOViewCountsType> PGOViewCounts;
// Defined in Analysis/BlockFrequencyInfo.cpp: -view-bfi-func-name=
extern cl::opt<std::string> ViewBlockFreqFuncName;
+extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;
} // namespace llvm
static cl::opt<bool>
@@ -381,7 +382,7 @@ static GlobalVariable *createIRLevelProfileFlagVar(Module &M, bool IsCS) {
ProfileVersion |= VARIANT_MASK_CSIR_PROF;
if (PGOInstrumentEntry)
ProfileVersion |= VARIANT_MASK_INSTR_ENTRY;
- if (DebugInfoCorrelate)
+ if (DebugInfoCorrelate || ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO)
ProfileVersion |= VARIANT_MASK_DBG_CORRELATE;
if (PGOFunctionEntryCoverage)
ProfileVersion |=
@@ -1783,6 +1784,8 @@ static bool skipPGOUse(const Function &F) {
static bool skipPGOGen(const Function &F) {
if (skipPGOUse(F))
return true;
+ if (F.hasFnAttribute(llvm::Attribute::Naked))
+ return true;
if (F.hasFnAttribute(llvm::Attribute::NoProfile))
return true;
if (F.hasFnAttribute(llvm::Attribute::SkipProfile))
diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
index 906687663519..fe672a4377a1 100644
--- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
+++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
@@ -329,8 +329,7 @@ ModuleSanitizerCoverage::CreateSecStartEnd(Module &M, const char *Section,
// Account for the fact that on windows-msvc __start_* symbols actually
// point to a uint64_t before the start of the array.
- auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, PtrTy);
- auto GEP = IRB.CreateGEP(Int8Ty, SecStartI8Ptr,
+ auto GEP = IRB.CreateGEP(Int8Ty, SecStart,
ConstantInt::get(IntptrTy, sizeof(uint64_t)));
return std::make_pair(GEP, SecEnd);
}
@@ -838,8 +837,7 @@ void ModuleSanitizerCoverage::InjectTraceForSwitch(
*CurModule, ArrayOfInt64Ty, false, GlobalVariable::InternalLinkage,
ConstantArray::get(ArrayOfInt64Ty, Initializers),
"__sancov_gen_cov_switch_values");
- IRB.CreateCall(SanCovTraceSwitchFunction,
- {Cond, IRB.CreatePointerCast(GV, PtrTy)});
+ IRB.CreateCall(SanCovTraceSwitchFunction, {Cond, GV});
}
}
}
diff --git a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp
index 3e5d979f11cc..1fb9d7fff32f 100644
--- a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp
@@ -523,7 +523,8 @@ void ConstantHoistingPass::collectConstantCandidates(Function &Fn) {
if (!DT->isReachableFromEntry(&BB))
continue;
for (Instruction &Inst : BB)
- collectConstantCandidates(ConstCandMap, &Inst);
+ if (!TTI->preferToKeepConstantsAttached(Inst, Fn))
+ collectConstantCandidates(ConstCandMap, &Inst);
}
}
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index a6fbddca5cba..18266ba07898 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -26,7 +26,6 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
-#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instructions.h"
@@ -36,7 +35,6 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DebugCounter.h"
-#include "llvm/Support/KnownBits.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
@@ -433,7 +431,7 @@ static Decomposition decomposeGEP(GEPOperator &GEP,
return &GEP;
assert(!IsSigned && "The logic below only supports decomposition for "
- "unsinged predicates at the moment.");
+ "unsigned predicates at the moment.");
const auto &[BasePtr, ConstantOffset, VariableOffsets, AllInbounds] =
collectOffsets(GEP, DL);
if (!BasePtr || !AllInbounds)
@@ -1111,6 +1109,16 @@ void State::addInfoFor(BasicBlock &BB) {
CmpI->getOperand(1)));
}
+#ifndef NDEBUG
+static void dumpUnpackedICmp(raw_ostream &OS, ICmpInst::Predicate Pred,
+ Value *LHS, Value *RHS) {
+ OS << "icmp " << Pred << ' ';
+ LHS->printAsOperand(OS, /*PrintType=*/true);
+ OS << ", ";
+ RHS->printAsOperand(OS, /*PrintType=*/false);
+}
+#endif
+
namespace {
/// Helper to keep track of a condition and if it should be treated as negated
/// for reproducer construction.
@@ -1243,10 +1251,9 @@ static void generateReproducer(CmpInst *Cond, Module *M,
if (Entry.Pred == ICmpInst::BAD_ICMP_PREDICATE)
continue;
- LLVM_DEBUG(
- dbgs() << " Materializing assumption icmp " << Entry.Pred << ' ';
- Entry.LHS->printAsOperand(dbgs(), /*PrintType=*/true); dbgs() << ", ";
- Entry.RHS->printAsOperand(dbgs(), /*PrintType=*/false); dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Materializing assumption ";
+ dumpUnpackedICmp(dbgs(), Entry.Pred, Entry.LHS, Entry.RHS);
+ dbgs() << "\n");
CloneInstructions({Entry.LHS, Entry.RHS}, CmpInst::isSigned(Entry.Pred));
auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);
@@ -1262,14 +1269,12 @@ static void generateReproducer(CmpInst *Cond, Module *M,
assert(!verifyFunction(*F, &dbgs()));
}
-static std::optional<bool> checkCondition(CmpInst *Cmp, ConstraintInfo &Info,
- unsigned NumIn, unsigned NumOut,
+static std::optional<bool> checkCondition(CmpInst::Predicate Pred, Value *A,
+ Value *B, Instruction *CheckInst,
+ ConstraintInfo &Info, unsigned NumIn,
+ unsigned NumOut,
Instruction *ContextInst) {
- LLVM_DEBUG(dbgs() << "Checking " << *Cmp << "\n");
-
- CmpInst::Predicate Pred = Cmp->getPredicate();
- Value *A = Cmp->getOperand(0);
- Value *B = Cmp->getOperand(1);
+ LLVM_DEBUG(dbgs() << "Checking " << *CheckInst << "\n");
auto R = Info.getConstraintForSolving(Pred, A, B);
if (R.empty() || !R.isValid(Info)){
@@ -1294,13 +1299,10 @@ static std::optional<bool> checkCondition(CmpInst *Cmp, ConstraintInfo &Info,
return std::nullopt;
LLVM_DEBUG({
- if (*ImpliedCondition) {
- dbgs() << "Condition " << *Cmp;
- } else {
- auto InversePred = Cmp->getInversePredicate();
- dbgs() << "Condition " << CmpInst::getPredicateName(InversePred) << " "
- << *A << ", " << *B;
- }
+ dbgs() << "Condition ";
+ dumpUnpackedICmp(
+ dbgs(), *ImpliedCondition ? Pred : CmpInst::getInversePredicate(Pred),
+ A, B);
dbgs() << " implied by dominating constraints\n";
CSToUse.dump();
});
@@ -1340,8 +1342,9 @@ static bool checkAndReplaceCondition(
return true;
};
- if (auto ImpliedCondition =
- checkCondition(Cmp, Info, NumIn, NumOut, ContextInst))
+ if (auto ImpliedCondition = checkCondition(
+ Cmp->getPredicate(), Cmp->getOperand(0), Cmp->getOperand(1), Cmp,
+ Info, NumIn, NumOut, ContextInst))
return ReplaceCmpWithConstant(Cmp, *ImpliedCondition);
return false;
}
@@ -1382,9 +1385,10 @@ static bool checkAndSecondOpImpliedByFirst(
bool Changed = false;
// Check if the second condition can be simplified now.
- if (auto ImpliedCondition =
- checkCondition(cast<ICmpInst>(And->getOperand(1)), Info, CB.NumIn,
- CB.NumOut, CB.getContextInst())) {
+ ICmpInst *Cmp = cast<ICmpInst>(And->getOperand(1));
+ if (auto ImpliedCondition = checkCondition(
+ Cmp->getPredicate(), Cmp->getOperand(0), Cmp->getOperand(1), Cmp,
+ Info, CB.NumIn, CB.NumOut, CB.getContextInst())) {
And->setOperand(1, ConstantInt::getBool(And->getType(), *ImpliedCondition));
Changed = true;
}
@@ -1410,9 +1414,8 @@ void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,
if (!R.isValid(*this) || R.isNe())
return;
- LLVM_DEBUG(dbgs() << "Adding '" << Pred << " ";
- A->printAsOperand(dbgs(), false); dbgs() << ", ";
- B->printAsOperand(dbgs(), false); dbgs() << "'\n");
+ LLVM_DEBUG(dbgs() << "Adding '"; dumpUnpackedICmp(dbgs(), Pred, A, B);
+ dbgs() << "'\n");
bool Added = false;
auto &CSToUse = getCS(R.IsSigned);
if (R.Coefficients.empty())
@@ -1618,10 +1621,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
}
auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) {
- LLVM_DEBUG(dbgs() << "fact to add to the system: "
- << CmpInst::getPredicateName(Pred) << " ";
- A->printAsOperand(dbgs()); dbgs() << ", ";
- B->printAsOperand(dbgs(), false); dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << "fact to add to the system: ";
+ dumpUnpackedICmp(dbgs(), Pred, A, B); dbgs() << "\n");
if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) {
LLVM_DEBUG(
dbgs()
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index a5cf875ef354..d2dfc764d042 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -278,8 +278,10 @@ static bool processICmp(ICmpInst *Cmp, LazyValueInfo *LVI) {
ICmpInst::Predicate UnsignedPred =
ConstantRange::getEquivalentPredWithFlippedSignedness(
Cmp->getPredicate(),
- LVI->getConstantRangeAtUse(Cmp->getOperandUse(0)),
- LVI->getConstantRangeAtUse(Cmp->getOperandUse(1)));
+ LVI->getConstantRangeAtUse(Cmp->getOperandUse(0),
+ /*UndefAllowed*/ true),
+ LVI->getConstantRangeAtUse(Cmp->getOperandUse(1),
+ /*UndefAllowed*/ true));
if (UnsignedPred == ICmpInst::Predicate::BAD_ICMP_PREDICATE)
return false;
@@ -393,8 +395,10 @@ static bool processSwitch(SwitchInst *I, LazyValueInfo *LVI,
// See if we can prove that the given binary op intrinsic will not overflow.
static bool willNotOverflow(BinaryOpIntrinsic *BO, LazyValueInfo *LVI) {
- ConstantRange LRange = LVI->getConstantRangeAtUse(BO->getOperandUse(0));
- ConstantRange RRange = LVI->getConstantRangeAtUse(BO->getOperandUse(1));
+ ConstantRange LRange =
+ LVI->getConstantRangeAtUse(BO->getOperandUse(0), /*UndefAllowed*/ false);
+ ConstantRange RRange =
+ LVI->getConstantRangeAtUse(BO->getOperandUse(1), /*UndefAllowed*/ false);
ConstantRange NWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
BO->getBinaryOp(), RRange, BO->getNoWrapKind());
return NWRegion.contains(LRange);
@@ -821,8 +825,11 @@ static bool processUDivOrURem(BinaryOperator *Instr, LazyValueInfo *LVI) {
if (Instr->getType()->isVectorTy())
return false;
- ConstantRange XCR = LVI->getConstantRangeAtUse(Instr->getOperandUse(0));
- ConstantRange YCR = LVI->getConstantRangeAtUse(Instr->getOperandUse(1));
+ ConstantRange XCR = LVI->getConstantRangeAtUse(Instr->getOperandUse(0),
+ /*UndefAllowed*/ false);
+ // Allow undef for RHS, as we can assume it is division by zero UB.
+ ConstantRange YCR = LVI->getConstantRangeAtUse(Instr->getOperandUse(1),
+ /*UndefAllowed*/ true);
if (expandUDivOrURem(Instr, XCR, YCR))
return true;
@@ -949,8 +956,11 @@ static bool processSDivOrSRem(BinaryOperator *Instr, LazyValueInfo *LVI) {
if (Instr->getType()->isVectorTy())
return false;
- ConstantRange LCR = LVI->getConstantRangeAtUse(Instr->getOperandUse(0));
- ConstantRange RCR = LVI->getConstantRangeAtUse(Instr->getOperandUse(1));
+ ConstantRange LCR =
+ LVI->getConstantRangeAtUse(Instr->getOperandUse(0), /*AllowUndef*/ false);
+ // Allow undef for RHS, as we can assume it is division by zero UB.
+ ConstantRange RCR =
+ LVI->getConstantRangeAtUse(Instr->getOperandUse(1), /*AlloweUndef*/ true);
if (Instr->getOpcode() == Instruction::SDiv)
if (processSDiv(Instr, LCR, RCR, LVI))
return true;
@@ -1048,8 +1058,10 @@ static bool processBinOp(BinaryOperator *BinOp, LazyValueInfo *LVI) {
Value *LHS = BinOp->getOperand(0);
Value *RHS = BinOp->getOperand(1);
- ConstantRange LRange = LVI->getConstantRange(LHS, BinOp);
- ConstantRange RRange = LVI->getConstantRange(RHS, BinOp);
+ ConstantRange LRange =
+ LVI->getConstantRange(LHS, BinOp, /*UndefAllowed*/ false);
+ ConstantRange RRange =
+ LVI->getConstantRange(RHS, BinOp, /*UndefAllowed*/ false);
bool Changed = false;
bool NewNUW = false, NewNSW = false;
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index dd0a290252da..008dcc53fd44 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -2170,7 +2170,7 @@ static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
auto *DeadSI = dyn_cast<StoreInst>(DeadI);
auto *KillingSI = dyn_cast<StoreInst>(KillingI);
// We are re-using tryToMergePartialOverlappingStores, which requires
- // DeadSI to dominate DeadSI.
+ // DeadSI to dominate KillingSI.
// TODO: implement tryToMergeParialOverlappingStores using MemorySSA.
if (DeadSI && KillingSI && DT.dominates(DeadSI, KillingSI)) {
if (Constant *Merged = tryToMergePartialOverlappingStores(
diff --git a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
index 5f82af1ca46d..9df28747570c 100644
--- a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
@@ -89,7 +89,6 @@
#include <algorithm>
#include <cassert>
#include <iterator>
-#include <limits>
#include <optional>
#include <utility>
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index d0afe09ce41d..9117378568b7 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -193,7 +193,7 @@ static Instruction *cloneInstructionInExitBlock(
static void eraseInstruction(Instruction &I, ICFLoopSafetyInfo &SafetyInfo,
MemorySSAUpdater &MSSAU);
-static void moveInstructionBefore(Instruction &I, Instruction &Dest,
+static void moveInstructionBefore(Instruction &I, BasicBlock::iterator Dest,
ICFLoopSafetyInfo &SafetyInfo,
MemorySSAUpdater &MSSAU, ScalarEvolution *SE);
@@ -1011,7 +1011,8 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
LLVM_DEBUG(dbgs() << "LICM rehoisting to "
<< HoistPoint->getParent()->getNameOrAsOperand()
<< ": " << *I << "\n");
- moveInstructionBefore(*I, *HoistPoint, *SafetyInfo, MSSAU, SE);
+ moveInstructionBefore(*I, HoistPoint->getIterator(), *SafetyInfo, MSSAU,
+ SE);
HoistPoint = I;
Changed = true;
}
@@ -1491,16 +1492,17 @@ static void eraseInstruction(Instruction &I, ICFLoopSafetyInfo &SafetyInfo,
I.eraseFromParent();
}
-static void moveInstructionBefore(Instruction &I, Instruction &Dest,
+static void moveInstructionBefore(Instruction &I, BasicBlock::iterator Dest,
ICFLoopSafetyInfo &SafetyInfo,
MemorySSAUpdater &MSSAU,
ScalarEvolution *SE) {
SafetyInfo.removeInstruction(&I);
- SafetyInfo.insertInstructionTo(&I, Dest.getParent());
- I.moveBefore(&Dest);
+ SafetyInfo.insertInstructionTo(&I, Dest->getParent());
+ I.moveBefore(*Dest->getParent(), Dest);
if (MemoryUseOrDef *OldMemAcc = cast_or_null<MemoryUseOrDef>(
MSSAU.getMemorySSA()->getMemoryAccess(&I)))
- MSSAU.moveToPlace(OldMemAcc, Dest.getParent(), MemorySSA::BeforeTerminator);
+ MSSAU.moveToPlace(OldMemAcc, Dest->getParent(),
+ MemorySSA::BeforeTerminator);
if (SE)
SE->forgetBlockAndLoopDispositions(&I);
}
@@ -1747,10 +1749,11 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
if (isa<PHINode>(I))
// Move the new node to the end of the phi list in the destination block.
- moveInstructionBefore(I, *Dest->getFirstNonPHI(), *SafetyInfo, MSSAU, SE);
+ moveInstructionBefore(I, Dest->getFirstNonPHIIt(), *SafetyInfo, MSSAU, SE);
else
// Move the new node to the destination block, before its terminator.
- moveInstructionBefore(I, *Dest->getTerminator(), *SafetyInfo, MSSAU, SE);
+ moveInstructionBefore(I, Dest->getTerminator()->getIterator(), *SafetyInfo,
+ MSSAU, SE);
I.updateLocationAfterHoist();
diff --git a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
index 13e06c79d0d7..9d5e6693c0e5 100644
--- a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
@@ -266,6 +266,11 @@ bool LoopVersioningLICM::legalLoopMemoryAccesses() {
for (const auto &A : AS) {
Value *Ptr = A.getValue();
// Alias tracker should have pointers of same data type.
+ //
+ // FIXME: check no longer effective since opaque pointers?
+ // If the intent is to check that the memory accesses use the
+ // same data type (such that LICM can promote them), then we
+ // can no longer see this from the pointer value types.
TypeCheck = (TypeCheck && (SomePtr->getType() == Ptr->getType()));
}
// At least one alias tracker should have pointers of same data type.
diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index 0e55249d63a8..9d058e0d2483 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -880,8 +880,11 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad,
return false;
const DataLayout &DL = cpyLoad->getModule()->getDataLayout();
- uint64_t srcSize = DL.getTypeAllocSize(srcAlloca->getAllocatedType()) *
- srcArraySize->getZExtValue();
+ TypeSize SrcAllocaSize = DL.getTypeAllocSize(srcAlloca->getAllocatedType());
+ // We can't optimize scalable types.
+ if (SrcAllocaSize.isScalable())
+ return false;
+ uint64_t srcSize = SrcAllocaSize * srcArraySize->getZExtValue();
if (cpySize < srcSize)
return false;
diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp
index 69679b608f8d..8a491e74b91c 100644
--- a/llvm/lib/Transforms/Scalar/SCCP.cpp
+++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
@@ -46,7 +46,6 @@
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/SCCPSolver.h"
-#include <cassert>
#include <utility>
using namespace llvm;
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index f578762d2b49..24da26c9f0f2 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -4838,6 +4838,36 @@ AllocaInst *SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
return NewAI;
}
+static void insertNewDbgInst(DIBuilder &DIB, DbgDeclareInst *Orig,
+ AllocaInst *NewAddr, DIExpression *NewFragmentExpr,
+ Instruction *BeforeInst) {
+ DIB.insertDeclare(NewAddr, Orig->getVariable(), NewFragmentExpr,
+ Orig->getDebugLoc(), BeforeInst);
+}
+static void insertNewDbgInst(DIBuilder &DIB, DbgAssignIntrinsic *Orig,
+ AllocaInst *NewAddr, DIExpression *NewFragmentExpr,
+ Instruction *BeforeInst) {
+ (void)BeforeInst;
+ if (!NewAddr->hasMetadata(LLVMContext::MD_DIAssignID)) {
+ NewAddr->setMetadata(LLVMContext::MD_DIAssignID,
+ DIAssignID::getDistinct(NewAddr->getContext()));
+ }
+ auto *NewAssign = DIB.insertDbgAssign(
+ NewAddr, Orig->getValue(), Orig->getVariable(), NewFragmentExpr, NewAddr,
+ Orig->getAddressExpression(), Orig->getDebugLoc());
+ LLVM_DEBUG(dbgs() << "Created new assign intrinsic: " << *NewAssign << "\n");
+ (void)NewAssign;
+}
+static void insertNewDbgInst(DIBuilder &DIB, DPValue *Orig, AllocaInst *NewAddr,
+ DIExpression *NewFragmentExpr,
+ Instruction *BeforeInst) {
+ (void)DIB;
+ DPValue *New = new DPValue(ValueAsMetadata::get(NewAddr), Orig->getVariable(),
+ NewFragmentExpr, Orig->getDebugLoc(),
+ DPValue::LocationType::Declare);
+ BeforeInst->getParent()->insertDPValueBefore(New, BeforeInst->getIterator());
+}
+
/// Walks the slices of an alloca and form partitions based on them,
/// rewriting each of their uses.
bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
@@ -4939,12 +4969,7 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
// Migrate debug information from the old alloca to the new alloca(s)
// and the individual partitions.
- TinyPtrVector<DbgVariableIntrinsic *> DbgVariables;
- for (auto *DbgDeclare : FindDbgDeclareUses(&AI))
- DbgVariables.push_back(DbgDeclare);
- for (auto *DbgAssign : at::getAssignmentMarkers(&AI))
- DbgVariables.push_back(DbgAssign);
- for (DbgVariableIntrinsic *DbgVariable : DbgVariables) {
+ auto MigrateOne = [&](auto *DbgVariable) {
auto *Expr = DbgVariable->getExpression();
DIBuilder DIB(*AI.getModule(), /*AllowUnresolved*/ false);
uint64_t AllocaSize =
@@ -4997,36 +5022,34 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
// Remove any existing intrinsics on the new alloca describing
// the variable fragment.
- for (DbgDeclareInst *OldDII : FindDbgDeclareUses(Fragment.Alloca)) {
- auto SameVariableFragment = [](const DbgVariableIntrinsic *LHS,
- const DbgVariableIntrinsic *RHS) {
+ SmallVector<DbgDeclareInst *, 1> FragDbgDeclares;
+ SmallVector<DPValue *, 1> FragDPVs;
+ findDbgDeclares(FragDbgDeclares, Fragment.Alloca, &FragDPVs);
+ auto RemoveOne = [DbgVariable](auto *OldDII) {
+ auto SameVariableFragment = [](const auto *LHS, const auto *RHS) {
return LHS->getVariable() == RHS->getVariable() &&
LHS->getDebugLoc()->getInlinedAt() ==
RHS->getDebugLoc()->getInlinedAt();
};
if (SameVariableFragment(OldDII, DbgVariable))
OldDII->eraseFromParent();
- }
+ };
+ for_each(FragDbgDeclares, RemoveOne);
+ for_each(FragDPVs, RemoveOne);
- if (auto *DbgAssign = dyn_cast<DbgAssignIntrinsic>(DbgVariable)) {
- if (!Fragment.Alloca->hasMetadata(LLVMContext::MD_DIAssignID)) {
- Fragment.Alloca->setMetadata(
- LLVMContext::MD_DIAssignID,
- DIAssignID::getDistinct(AI.getContext()));
- }
- auto *NewAssign = DIB.insertDbgAssign(
- Fragment.Alloca, DbgAssign->getValue(), DbgAssign->getVariable(),
- FragmentExpr, Fragment.Alloca, DbgAssign->getAddressExpression(),
- DbgAssign->getDebugLoc());
- NewAssign->setDebugLoc(DbgAssign->getDebugLoc());
- LLVM_DEBUG(dbgs() << "Created new assign intrinsic: " << *NewAssign
- << "\n");
- } else {
- DIB.insertDeclare(Fragment.Alloca, DbgVariable->getVariable(),
- FragmentExpr, DbgVariable->getDebugLoc(), &AI);
- }
+ insertNewDbgInst(DIB, DbgVariable, Fragment.Alloca, FragmentExpr, &AI);
}
- }
+ };
+
+ // Migrate debug information from the old alloca to the new alloca(s)
+ // and the individual partitions.
+ SmallVector<DbgDeclareInst *, 1> DbgDeclares;
+ SmallVector<DPValue *, 1> DPValues;
+ findDbgDeclares(DbgDeclares, &AI, &DPValues);
+ for_each(DbgDeclares, MigrateOne);
+ for_each(DPValues, MigrateOne);
+ for_each(at::getAssignmentMarkers(&AI), MigrateOne);
+
return Changed;
}
@@ -5147,7 +5170,12 @@ bool SROA::deleteDeadInstructions(
// not be able to find it.
if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
DeletedAllocas.insert(AI);
- for (DbgDeclareInst *OldDII : FindDbgDeclareUses(AI))
+ SmallVector<DbgDeclareInst *, 1> DbgDeclares;
+ SmallVector<DPValue *, 1> DPValues;
+ findDbgDeclares(DbgDeclares, AI, &DPValues);
+ for (DbgDeclareInst *OldDII : DbgDeclares)
+ OldDII->eraseFromParent();
+ for (DPValue *OldDII : DPValues)
OldDII->eraseFromParent();
}
diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
index b700edf8ea6c..8b5a6d618412 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -387,6 +387,18 @@ static bool DPValuesRemoveRedundantDbgInstrsUsingBackwardScan(BasicBlock *BB) {
SmallDenseSet<DebugVariable> VariableSet;
for (auto &I : reverse(*BB)) {
for (DPValue &DPV : reverse(I.getDbgValueRange())) {
+ // Skip declare-type records, as the debug intrinsic method only works
+ // on dbg.value intrinsics.
+ if (DPV.getType() == DPValue::LocationType::Declare) {
+ // The debug intrinsic method treats dbg.declares are "non-debug"
+ // instructions (i.e., a break in a consecutive range of debug
+ // intrinsics). Emulate that to create identical outputs. See
+ // "Possible improvements" above.
+ // FIXME: Delete the line below.
+ VariableSet.clear();
+ continue;
+ }
+
DebugVariable Key(DPV.getVariable(), DPV.getExpression(),
DPV.getDebugLoc()->getInlinedAt());
auto R = VariableSet.insert(Key);
@@ -478,6 +490,8 @@ static bool DPValuesRemoveRedundantDbgInstrsUsingForwardScan(BasicBlock *BB) {
VariableMap;
for (auto &I : *BB) {
for (DPValue &DPV : I.getDbgValueRange()) {
+ if (DPV.getType() == DPValue::LocationType::Declare)
+ continue;
DebugVariable Key(DPV.getVariable(), std::nullopt,
DPV.getDebugLoc()->getInlinedAt());
auto VMI = VariableMap.find(Key);
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 9c1186232e02..f5abed0dd517 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -998,6 +998,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::ByRef:
case Attribute::WriteOnly:
case Attribute::Writable:
+ case Attribute::DeadOnUnwind:
// These are not really attributes.
case Attribute::None:
case Attribute::EndAttrKinds:
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index 51f39e0ba0cc..a758fb306982 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -1724,9 +1724,11 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII,
SI->getIterator());
}
+namespace llvm {
// RemoveDIs: duplicate the getDebugValueLoc method using DPValues instead of
-// dbg.value intrinsics.
-static DebugLoc getDebugValueLocDPV(DPValue *DPV) {
+// dbg.value intrinsics. In llvm namespace so that it overloads the
+// DbgVariableIntrinsic version.
+static DebugLoc getDebugValueLoc(DPValue *DPV) {
// Original dbg.declare must have a location.
const DebugLoc &DeclareLoc = DPV->getDebugLoc();
MDNode *Scope = DeclareLoc.getScope();
@@ -1734,6 +1736,7 @@ static DebugLoc getDebugValueLocDPV(DPValue *DPV) {
// Produce an unknown location with the correct scope / inlinedAt fields.
return DILocation::get(DPV->getContext(), 0, 0, Scope, InlinedAt);
}
+} // namespace llvm
/// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value
/// that has an associated llvm.dbg.declare intrinsic.
@@ -1770,25 +1773,39 @@ void llvm::ConvertDebugDeclareToDebugValue(DPValue *DPV, StoreInst *SI,
auto *DIExpr = DPV->getExpression();
Value *DV = SI->getValueOperand();
- DebugLoc NewLoc = getDebugValueLocDPV(DPV);
+ DebugLoc NewLoc = getDebugValueLoc(DPV);
- if (!valueCoversEntireFragment(DV->getType(), DPV)) {
- // FIXME: If storing to a part of the variable described by the dbg.declare,
- // then we want to insert a DPValue.value for the corresponding fragment.
- LLVM_DEBUG(dbgs() << "Failed to convert dbg.declare to DPValue: " << *DPV
- << '\n');
- // For now, when there is a store to parts of the variable (but we do not
- // know which part) we insert an DPValue record to indicate that we know
- // nothing about the variable's content.
- DV = UndefValue::get(DV->getType());
- ValueAsMetadata *DVAM = ValueAsMetadata::get(DV);
- DPValue *NewDPV = new DPValue(DVAM, DIVar, DIExpr, NewLoc.get());
- SI->getParent()->insertDPValueBefore(NewDPV, SI->getIterator());
+ // If the alloca describes the variable itself, i.e. the expression in the
+ // dbg.declare doesn't start with a dereference, we can perform the
+ // conversion if the value covers the entire fragment of DII.
+ // If the alloca describes the *address* of DIVar, i.e. DIExpr is
+ // *just* a DW_OP_deref, we use DV as is for the dbg.value.
+ // We conservatively ignore other dereferences, because the following two are
+ // not equivalent:
+ // dbg.declare(alloca, ..., !Expr(deref, plus_uconstant, 2))
+ // dbg.value(DV, ..., !Expr(deref, plus_uconstant, 2))
+ // The former is adding 2 to the address of the variable, whereas the latter
+ // is adding 2 to the value of the variable. As such, we insist on just a
+ // deref expression.
+ bool CanConvert =
+ DIExpr->isDeref() || (!DIExpr->startsWithDeref() &&
+ valueCoversEntireFragment(DV->getType(), DPV));
+ if (CanConvert) {
+ insertDbgValueOrDPValue(Builder, DV, DIVar, DIExpr, NewLoc,
+ SI->getIterator());
return;
}
+ // FIXME: If storing to a part of the variable described by the dbg.declare,
+ // then we want to insert a dbg.value for the corresponding fragment.
+ LLVM_DEBUG(dbgs() << "Failed to convert dbg.declare to dbg.value: " << *DPV
+ << '\n');
assert(UseNewDbgInfoFormat);
- // Create a DPValue directly and insert.
+
+ // For now, when there is a store to parts of the variable (but we do not
+ // know which part) we insert an dbg.value intrinsic to indicate that we
+ // know nothing about the variable's content.
+ DV = UndefValue::get(DV->getType());
ValueAsMetadata *DVAM = ValueAsMetadata::get(DV);
DPValue *NewDPV = new DPValue(DVAM, DIVar, DIExpr, NewLoc.get());
SI->getParent()->insertDPValueBefore(NewDPV, SI->getIterator());
@@ -1842,7 +1859,7 @@ void llvm::ConvertDebugDeclareToDebugValue(DPValue *DPV, LoadInst *LI,
return;
}
- DebugLoc NewLoc = getDebugValueLocDPV(DPV);
+ DebugLoc NewLoc = getDebugValueLoc(DPV);
// We are now tracking the loaded value instead of the address. In the
// future if multi-location support is added to the IR, it might be
@@ -1887,7 +1904,7 @@ void llvm::ConvertDebugDeclareToDebugValue(DPValue *DPV, PHINode *APN,
BasicBlock *BB = APN->getParent();
auto InsertionPt = BB->getFirstInsertionPt();
- DebugLoc NewLoc = getDebugValueLocDPV(DPV);
+ DebugLoc NewLoc = getDebugValueLoc(DPV);
// The block may be a catchswitch block, which does not have a valid
// insertion point.
@@ -1903,17 +1920,24 @@ bool llvm::LowerDbgDeclare(Function &F) {
bool Changed = false;
DIBuilder DIB(*F.getParent(), /*AllowUnresolved*/ false);
SmallVector<DbgDeclareInst *, 4> Dbgs;
- for (auto &FI : F)
- for (Instruction &BI : FI)
- if (auto DDI = dyn_cast<DbgDeclareInst>(&BI))
+ SmallVector<DPValue *> DPVs;
+ for (auto &FI : F) {
+ for (Instruction &BI : FI) {
+ if (auto *DDI = dyn_cast<DbgDeclareInst>(&BI))
Dbgs.push_back(DDI);
+ for (DPValue &DPV : BI.getDbgValueRange()) {
+ if (DPV.getType() == DPValue::LocationType::Declare)
+ DPVs.push_back(&DPV);
+ }
+ }
+ }
- if (Dbgs.empty())
+ if (Dbgs.empty() && DPVs.empty())
return Changed;
- for (auto &I : Dbgs) {
- DbgDeclareInst *DDI = I;
- AllocaInst *AI = dyn_cast_or_null<AllocaInst>(DDI->getAddress());
+ auto LowerOne = [&](auto *DDI) {
+ AllocaInst *AI =
+ dyn_cast_or_null<AllocaInst>(DDI->getVariableLocationOp(0));
// If this is an alloca for a scalar variable, insert a dbg.value
// at each load and store to the alloca and erase the dbg.declare.
// The dbg.values allow tracking a variable even if it is not
@@ -1921,7 +1945,7 @@ bool llvm::LowerDbgDeclare(Function &F) {
// the stack slot (and at a lexical-scope granularity). Later
// passes will attempt to elide the stack slot.
if (!AI || isArray(AI) || isStructure(AI))
- continue;
+ return;
// A volatile load/store means that the alloca can't be elided anyway.
if (llvm::any_of(AI->users(), [](User *U) -> bool {
@@ -1931,7 +1955,7 @@ bool llvm::LowerDbgDeclare(Function &F) {
return SI->isVolatile();
return false;
}))
- continue;
+ return;
SmallVector<const Value *, 8> WorkList;
WorkList.push_back(AI);
@@ -1963,11 +1987,14 @@ bool llvm::LowerDbgDeclare(Function &F) {
}
DDI->eraseFromParent();
Changed = true;
- }
+ };
+
+ for_each(Dbgs, LowerOne);
+ for_each(DPVs, LowerOne);
if (Changed)
- for (BasicBlock &BB : F)
- RemoveRedundantDbgInstrs(&BB);
+ for (BasicBlock &BB : F)
+ RemoveRedundantDbgInstrs(&BB);
return Changed;
}
@@ -2103,19 +2130,22 @@ void llvm::insertDebugValuesForPHIs(BasicBlock *BB,
bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress,
DIBuilder &Builder, uint8_t DIExprFlags,
int Offset) {
- auto DbgDeclares = FindDbgDeclareUses(Address);
- for (DbgVariableIntrinsic *DII : DbgDeclares) {
- const DebugLoc &Loc = DII->getDebugLoc();
- auto *DIVar = DII->getVariable();
+ SmallVector<DbgDeclareInst *, 1> DbgDeclares;
+ SmallVector<DPValue *, 1> DPValues;
+ findDbgDeclares(DbgDeclares, Address, &DPValues);
+
+ auto ReplaceOne = [&](auto *DII) {
+ assert(DII->getVariable() && "Missing variable");
auto *DIExpr = DII->getExpression();
- assert(DIVar && "Missing variable");
DIExpr = DIExpression::prepend(DIExpr, DIExprFlags, Offset);
- // Insert llvm.dbg.declare immediately before DII, and remove old
- // llvm.dbg.declare.
- Builder.insertDeclare(NewAddress, DIVar, DIExpr, Loc, DII);
- DII->eraseFromParent();
- }
- return !DbgDeclares.empty();
+ DII->setExpression(DIExpr);
+ DII->replaceVariableLocationOp(Address, NewAddress);
+ };
+
+ for_each(DbgDeclares, ReplaceOne);
+ for_each(DPValues, ReplaceOne);
+
+ return !DbgDeclares.empty() || !DPValues.empty();
}
static void updateOneDbgValueForAlloca(const DebugLoc &Loc,
diff --git a/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp b/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp
index 76280ed492b3..504f4430dc2c 100644
--- a/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp
@@ -708,12 +708,13 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) {
// as U1'' and U1' scopes will not be compatible wrt to the local restrict
// Clone the llvm.experimental.noalias.decl again for the NewHeader.
- Instruction *NewHeaderInsertionPoint = &(*NewHeader->getFirstNonPHI());
+ BasicBlock::iterator NewHeaderInsertionPoint =
+ NewHeader->getFirstNonPHIIt();
for (NoAliasScopeDeclInst *NAD : NoAliasDeclInstructions) {
LLVM_DEBUG(dbgs() << " Cloning llvm.experimental.noalias.scope.decl:"
<< *NAD << "\n");
Instruction *NewNAD = NAD->clone();
- NewNAD->insertBefore(NewHeaderInsertionPoint);
+ NewNAD->insertBefore(*NewHeader, NewHeaderInsertionPoint);
}
// Scopes must now be duplicated, once for OrigHeader and once for
diff --git a/llvm/lib/Transforms/Utils/LowerSwitch.cpp b/llvm/lib/Transforms/Utils/LowerSwitch.cpp
index 227de425ff85..4131d36b572d 100644
--- a/llvm/lib/Transforms/Utils/LowerSwitch.cpp
+++ b/llvm/lib/Transforms/Utils/LowerSwitch.cpp
@@ -42,7 +42,6 @@
#include <cassert>
#include <cstdint>
#include <iterator>
-#include <limits>
#include <vector>
using namespace llvm;
@@ -413,7 +412,8 @@ void ProcessSwitchInst(SwitchInst *SI,
// TODO Shouldn't this create a signed range?
ConstantRange KnownBitsRange =
ConstantRange::fromKnownBits(Known, /*IsSigned=*/false);
- const ConstantRange LVIRange = LVI->getConstantRange(Val, SI);
+ const ConstantRange LVIRange =
+ LVI->getConstantRange(Val, SI, /*UndefAllowed*/ false);
ConstantRange ValRange = KnownBitsRange.intersectWith(LVIRange);
// We delegate removal of unreachable non-default cases to other passes. In
// the unlikely event that some of them survived, we just conservatively
diff --git a/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp b/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp
index 531b0a624daf..47c6bcbaf26e 100644
--- a/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp
+++ b/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp
@@ -321,8 +321,10 @@ void MemoryOpRemark::visitVariable(const Value *V,
bool FoundDI = false;
// Try to get an llvm.dbg.declare, which has a DILocalVariable giving us the
// real debug info name and size of the variable.
- for (const DbgVariableIntrinsic *DVI :
- FindDbgDeclareUses(const_cast<Value *>(V))) {
+ SmallVector<DbgDeclareInst *, 1> DbgDeclares;
+ SmallVector<DPValue *, 1> DPValues;
+ findDbgDeclares(DbgDeclares, const_cast<Value *>(V), &DPValues);
+ auto FindDI = [&](const auto *DVI) {
if (DILocalVariable *DILV = DVI->getVariable()) {
std::optional<uint64_t> DISize = getSizeInBytes(DILV->getSizeInBits());
VariableInfo Var{DILV->getName(), DISize};
@@ -331,7 +333,10 @@ void MemoryOpRemark::visitVariable(const Value *V,
FoundDI = true;
}
}
- }
+ };
+ for_each(DbgDeclares, FindDI);
+ for_each(DPValues, FindDI);
+
if (FoundDI) {
assert(!Result.empty());
return;
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index c09cf9c2325c..89494a7f6497 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -15,7 +15,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SetVector.h"
diff --git a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp
index c0dbd52acbab..fa2459d1ca02 100644
--- a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp
@@ -108,7 +108,6 @@
#include <cstdint>
#include <cstdlib>
#include <iterator>
-#include <limits>
#include <numeric>
#include <optional>
#include <tuple>
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index fe2aac78e5ab..9d799124074c 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -391,8 +391,10 @@ static SmallBitVector isUndefVector(const Value *V,
if (isa<T>(II->getOperand(1)))
continue;
std::optional<unsigned> Idx = getInsertIndex(II);
- if (!Idx)
- continue;
+ if (!Idx) {
+ Res.reset();
+ return Res;
+ }
if (*Idx < UseMask.size() && !UseMask.test(*Idx))
Res.reset(*Idx);
}
@@ -13680,8 +13682,10 @@ void SLPVectorizerPass::collectSeedInstructions(BasicBlock *BB) {
// constant index, or a pointer operand that doesn't point to a scalar
// type.
else if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
+ if (GEP->getNumIndices() != 1)
+ continue;
Value *Idx = GEP->idx_begin()->get();
- if (GEP->getNumIndices() > 1 || isa<Constant>(Idx))
+ if (isa<Constant>(Idx))
continue;
if (!isValidElementType(Idx->getType()))
continue;
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 263d9938d1f0..1d7df9c9575a 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -1135,16 +1135,20 @@ void VPlanIngredient::print(raw_ostream &O) const {
template void DomTreeBuilder::Calculate<VPDominatorTree>(VPDominatorTree &DT);
void VPValue::replaceAllUsesWith(VPValue *New) {
+ if (this == New)
+ return;
for (unsigned J = 0; J < getNumUsers();) {
VPUser *User = Users[J];
- unsigned NumUsers = getNumUsers();
+ bool RemovedUser = false;
for (unsigned I = 0, E = User->getNumOperands(); I < E; ++I)
- if (User->getOperand(I) == this)
+ if (User->getOperand(I) == this) {
User->setOperand(I, New);
+ RemovedUser = true;
+ }
// If a user got removed after updating the current user, the next user to
// update will be moved to the current position, so we only need to
// increment the index if the number of users did not change.
- if (NumUsers == getNumUsers())
+ if (!RemovedUser)
J++;
}
}
@@ -1152,19 +1156,22 @@ void VPValue::replaceAllUsesWith(VPValue *New) {
void VPValue::replaceUsesWithIf(
VPValue *New,
llvm::function_ref<bool(VPUser &U, unsigned Idx)> ShouldReplace) {
+ if (this == New)
+ return;
for (unsigned J = 0; J < getNumUsers();) {
VPUser *User = Users[J];
- unsigned NumUsers = getNumUsers();
+ bool RemovedUser = false;
for (unsigned I = 0, E = User->getNumOperands(); I < E; ++I) {
if (User->getOperand(I) != this || !ShouldReplace(*User, I))
continue;
+ RemovedUser = true;
User->setOperand(I, New);
}
// If a user got removed after updating the current user, the next user to
// update will be moved to the current position, so we only need to
// increment the index if the number of users did not change.
- if (NumUsers == getNumUsers())
+ if (!RemovedUser)
J++;
}
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.h b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.h
index 473a7c28e48a..7276641551ae 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.h
@@ -16,12 +16,9 @@ namespace llvm {
class LLVMContext;
class VPValue;
class VPBlendRecipe;
-class VPInterleaveRecipe;
class VPInstruction;
-class VPReductionPHIRecipe;
class VPWidenRecipe;
class VPWidenCallRecipe;
-class VPWidenCastRecipe;
class VPWidenIntOrFpInductionRecipe;
class VPWidenMemoryInstructionRecipe;
struct VPWidenSelectRecipe;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index c23428e2ba34..02e400d590be 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -44,6 +44,8 @@ extern cl::opt<bool> EnableVPlanNativePath;
bool VPRecipeBase::mayWriteToMemory() const {
switch (getVPDefID()) {
+ case VPInterleaveSC:
+ return cast<VPInterleaveRecipe>(this)->getNumStoreOperands() > 0;
case VPWidenMemoryInstructionSC: {
return cast<VPWidenMemoryInstructionRecipe>(this)->isStore();
}
@@ -146,6 +148,8 @@ bool VPRecipeBase::mayHaveSideEffects() const {
"underlying instruction has side-effects");
return false;
}
+ case VPInterleaveSC:
+ return mayWriteToMemory();
case VPWidenMemoryInstructionSC:
assert(cast<VPWidenMemoryInstructionRecipe>(this)
->getIngredient()
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index ea90ed4a21b1..33132880d5a4 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -528,12 +528,13 @@ void VPlanTransforms::optimizeInductions(VPlan &Plan, ScalarEvolution &SE) {
Plan, ID, SE, WideIV->getTruncInst(), WideIV->getPHINode()->getType(),
WideIV->getStartValue(), WideIV->getStepValue());
- // Update scalar users of IV to use Step instead. Use SetVector to ensure
- // the list of users doesn't contain duplicates.
- WideIV->replaceUsesWithIf(
- Steps, [HasOnlyVectorVFs, WideIV](VPUser &U, unsigned) {
- return !HasOnlyVectorVFs || U.usesScalars(WideIV);
- });
+ // Update scalar users of IV to use Step instead.
+ if (!HasOnlyVectorVFs)
+ WideIV->replaceAllUsesWith(Steps);
+ else
+ WideIV->replaceUsesWithIf(Steps, [WideIV](VPUser &U, unsigned) {
+ return U.usesScalars(WideIV);
+ });
}
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index e8a6da8c3205..3bf91115debb 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -22,11 +22,9 @@ class InductionDescriptor;
class Instruction;
class PHINode;
class ScalarEvolution;
-class Loop;
class PredicatedScalarEvolution;
class TargetLibraryInfo;
class VPBuilder;
-class VPRecipeBuilder;
struct VPlanTransforms {
/// Replaces the VPInstructions in \p Plan with corresponding
diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index e5ca52755dd2..116acad8e8f3 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -121,18 +121,11 @@ public:
/// Remove a single \p User from the list of users.
void removeUser(VPUser &User) {
- bool Found = false;
// The same user can be added multiple times, e.g. because the same VPValue
// is used twice by the same VPUser. Remove a single one.
- erase_if(Users, [&User, &Found](VPUser *Other) {
- if (Found)
- return false;
- if (Other == &User) {
- Found = true;
- return true;
- }
- return false;
- });
+ auto *I = find(Users, &User);
+ if (I != Users.end())
+ Users.erase(I);
}
typedef SmallVectorImpl<VPUser *>::iterator user_iterator;
diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index 34e563399813..8d906cf37287 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -249,9 +249,9 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName,
else {
// If InputFilename ends in .bc or .ll, remove it.
StringRef IFN = InputFilename;
- if (IFN.endswith(".bc") || IFN.endswith(".ll"))
+ if (IFN.ends_with(".bc") || IFN.ends_with(".ll"))
OutputFilename = std::string(IFN.drop_back(3));
- else if (IFN.endswith(".mir"))
+ else if (IFN.ends_with(".mir"))
OutputFilename = std::string(IFN.drop_back(4));
else
OutputFilename = std::string(IFN);
@@ -584,7 +584,7 @@ static int compileModule(char **argv, LLVMContext &Context) {
return Target->createDataLayout().getStringRepresentation();
};
if (InputLanguage == "mir" ||
- (InputLanguage == "" && StringRef(InputFilename).endswith(".mir"))) {
+ (InputLanguage == "" && StringRef(InputFilename).ends_with(".mir"))) {
MIR = createMIRParserFromFile(InputFilename, Err, Context,
setMIRFunctionAttributes);
if (MIR)
diff --git a/llvm/tools/lli/lli.cpp b/llvm/tools/lli/lli.cpp
index 36fca4c40ed0..5f1fd1578764 100644
--- a/llvm/tools/lli/lli.cpp
+++ b/llvm/tools/lli/lli.cpp
@@ -622,7 +622,7 @@ int main(int argc, char **argv, char * const *envp) {
} else {
// Otherwise, if there is a .bc suffix on the executable strip it off, it
// might confuse the program.
- if (StringRef(InputFile).endswith(".bc"))
+ if (StringRef(InputFile).ends_with(".bc"))
InputFile.erase(InputFile.length() - 3);
}
diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp
index 9889ad9de627..fcb6392a1d95 100644
--- a/llvm/tools/llvm-ar/llvm-ar.cpp
+++ b/llvm/tools/llvm-ar/llvm-ar.cpp
@@ -1287,7 +1287,7 @@ static const char *matchFlagWithArg(StringRef Expected,
ArrayRef<const char *> Args) {
StringRef Arg = *ArgIt;
- if (Arg.startswith("--"))
+ if (Arg.starts_with("--"))
Arg = Arg.substr(2);
size_t len = Expected.size();
@@ -1297,7 +1297,7 @@ static const char *matchFlagWithArg(StringRef Expected,
return *ArgIt;
}
- if (Arg.startswith(Expected) && Arg.size() > len && Arg[len] == '=')
+ if (Arg.starts_with(Expected) && Arg.size() > len && Arg[len] == '=')
return Arg.data() + len + 1;
return nullptr;
diff --git a/llvm/tools/llvm-as/llvm-as.cpp b/llvm/tools/llvm-as/llvm-as.cpp
index ef1c50fc2284..1c869e173931 100644
--- a/llvm/tools/llvm-as/llvm-as.cpp
+++ b/llvm/tools/llvm-as/llvm-as.cpp
@@ -75,7 +75,7 @@ static void WriteOutputFile(const Module *M, const ModuleSummaryIndex *Index) {
OutputFilename = "-";
} else {
StringRef IFN = InputFilename;
- OutputFilename = (IFN.endswith(".ll") ? IFN.drop_back(3) : IFN).str();
+ OutputFilename = (IFN.ends_with(".ll") ? IFN.drop_back(3) : IFN).str();
OutputFilename += ".bc";
}
}
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index b5d763d8643c..6405bb15e70c 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -105,6 +105,11 @@ private:
const MemoryBuffer &File,
CoverageData &CoverageInfo);
+ /// Create source views for the MCDC records.
+ void attachMCDCSubViews(SourceCoverageView &View, StringRef SourceName,
+ ArrayRef<MCDCRecord> MCDCRecords,
+ const MemoryBuffer &File, CoverageData &CoverageInfo);
+
/// Create the source view of a particular function.
std::unique_ptr<SourceCoverageView>
createFunctionView(const FunctionRecord &Function,
@@ -352,6 +357,37 @@ void CodeCoverageTool::attachBranchSubViews(SourceCoverageView &View,
}
}
+void CodeCoverageTool::attachMCDCSubViews(SourceCoverageView &View,
+ StringRef SourceName,
+ ArrayRef<MCDCRecord> MCDCRecords,
+ const MemoryBuffer &File,
+ CoverageData &CoverageInfo) {
+ if (!ViewOpts.ShowMCDC)
+ return;
+
+ const auto *NextRecord = MCDCRecords.begin();
+ const auto *EndRecord = MCDCRecords.end();
+
+ // Group and process MCDC records that have the same line number into the
+ // same subview.
+ while (NextRecord != EndRecord) {
+ std::vector<MCDCRecord> ViewMCDCRecords;
+ unsigned CurrentLine = NextRecord->getDecisionRegion().LineEnd;
+
+ while (NextRecord != EndRecord &&
+ CurrentLine == NextRecord->getDecisionRegion().LineEnd) {
+ ViewMCDCRecords.push_back(*NextRecord++);
+ }
+
+ if (ViewMCDCRecords.empty())
+ continue;
+
+ auto SubView = SourceCoverageView::create(SourceName, File, ViewOpts,
+ std::move(CoverageInfo));
+ View.addMCDCRecord(CurrentLine, ViewMCDCRecords, std::move(SubView));
+ }
+}
+
std::unique_ptr<SourceCoverageView>
CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
const CoverageMapping &Coverage) {
@@ -364,12 +400,15 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
auto Branches = FunctionCoverage.getBranches();
auto Expansions = FunctionCoverage.getExpansions();
+ auto MCDCRecords = FunctionCoverage.getMCDCRecords();
auto View = SourceCoverageView::create(DC.demangle(Function.Name),
SourceBuffer.get(), ViewOpts,
std::move(FunctionCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
attachBranchSubViews(*View, DC.demangle(Function.Name), Branches,
SourceBuffer.get(), FunctionCoverage);
+ attachMCDCSubViews(*View, DC.demangle(Function.Name), MCDCRecords,
+ SourceBuffer.get(), FunctionCoverage);
return View;
}
@@ -386,11 +425,14 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
auto Branches = FileCoverage.getBranches();
auto Expansions = FileCoverage.getExpansions();
+ auto MCDCRecords = FileCoverage.getMCDCRecords();
auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
ViewOpts, std::move(FileCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
attachBranchSubViews(*View, SourceFile, Branches, SourceBuffer.get(),
FileCoverage);
+ attachMCDCSubViews(*View, SourceFile, MCDCRecords, SourceBuffer.get(),
+ FileCoverage);
if (!ViewOpts.ShowFunctionInstantiations)
return View;
@@ -408,11 +450,14 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
auto SubViewExpansions = SubViewCoverage.getExpansions();
auto SubViewBranches = SubViewCoverage.getBranches();
+ auto SubViewMCDCRecords = SubViewCoverage.getMCDCRecords();
SubView = SourceCoverageView::create(
Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
attachBranchSubViews(*SubView, SourceFile, SubViewBranches,
SourceBuffer.get(), SubViewCoverage);
+ attachMCDCSubViews(*SubView, SourceFile, SubViewMCDCRecords,
+ SourceBuffer.get(), SubViewCoverage);
}
unsigned FileID = Function->CountedRegions.front().FileID;
@@ -502,7 +547,7 @@ void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) {
SmallString<128> NativeFilename;
sys::path::native(Filename, NativeFilename);
sys::path::remove_dots(NativeFilename, true);
- if (NativeFilename.startswith(RemapFrom)) {
+ if (NativeFilename.starts_with(RemapFrom)) {
RemappedFilenames[Filename] =
RemapTo + NativeFilename.substr(RemapFrom.size()).str();
}
@@ -752,6 +797,10 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
cl::desc("Show branch condition statistics in summary table"),
cl::init(true));
+ cl::opt<bool> MCDCSummary("show-mcdc-summary", cl::Optional,
+ cl::desc("Show MCDC statistics in summary table"),
+ cl::init(false));
+
cl::opt<bool> InstantiationSummary(
"show-instantiation-summary", cl::Optional,
cl::desc("Show instantiation statistics in summary table"));
@@ -923,6 +972,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
::exit(0);
}
+ ViewOpts.ShowMCDCSummary = MCDCSummary;
ViewOpts.ShowBranchSummary = BranchSummary;
ViewOpts.ShowRegionSummary = RegionSummary;
ViewOpts.ShowInstantiationSummary = InstantiationSummary;
@@ -968,6 +1018,11 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
"percent", "Show True/False percent")),
cl::init(CoverageViewOptions::BranchOutputType::Off));
+ cl::opt<bool> ShowMCDC(
+ "show-mcdc", cl::Optional,
+ cl::desc("Show the MCDC Coverage for each applicable boolean expression"),
+ cl::cat(ViewCategory));
+
cl::opt<bool> ShowBestLineRegionsCounts(
"show-line-counts-or-regions", cl::Optional,
cl::desc("Show the execution counts for each line, or the execution "
@@ -1063,6 +1118,7 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
ViewOpts.ShowExpandedRegions = ShowExpansions;
ViewOpts.ShowBranchCounts =
ShowBranches == CoverageViewOptions::BranchOutputType::Count;
+ ViewOpts.ShowMCDC = ShowMCDC;
ViewOpts.ShowBranchPercents =
ShowBranches == CoverageViewOptions::BranchOutputType::Percent;
ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
diff --git a/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
index 9e43377e38a8..a424bbe06e0e 100644
--- a/llvm/tools/llvm-cov/CoverageExporterJson.cpp
+++ b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
@@ -20,6 +20,8 @@
// -- File: dict => Coverage for a single file
// -- Branches: array => List of Branches in the file
// -- Branch: dict => Describes a branch of the file with counters
+// -- MCDC Records: array => List of MCDC records in the file
+// -- MCDC Values: array => List of T/F covered condition values
// -- Segments: array => List of Segments contained in the file
// -- Segment: dict => Describes a segment of the file with a counter
// -- Expansions: array => List of expansion records
@@ -34,6 +36,7 @@
// -- FunctionCoverage: dict => Object summarizing function coverage
// -- RegionCoverage: dict => Object summarizing region coverage
// -- BranchCoverage: dict => Object summarizing branch coverage
+// -- MCDCCoverage: dict => Object summarizing MC/DC coverage
// -- Functions: array => List of objects describing coverage for functions
// -- Function: dict => Coverage info for a single function
// -- Filenames: array => List of filenames that the function relates to
@@ -43,6 +46,7 @@
// -- InstantiationCoverage: dict => Object summarizing inst. coverage
// -- RegionCoverage: dict => Object summarizing region coverage
// -- BranchCoverage: dict => Object summarizing branch coverage
+// -- MCDCCoverage: dict => Object summarizing MC/DC coverage
//
//===----------------------------------------------------------------------===//
@@ -97,6 +101,20 @@ json::Array renderBranch(const coverage::CountedRegion &Region) {
Region.ExpandedFileID, int64_t(Region.Kind)});
}
+json::Array gatherConditions(const coverage::MCDCRecord &Record) {
+ json::Array Conditions;
+ for (unsigned c = 0; c < Record.getNumConditions(); c++)
+ Conditions.push_back(Record.isConditionIndependencePairCovered(c));
+ return Conditions;
+}
+
+json::Array renderMCDCRecord(const coverage::MCDCRecord &Record) {
+ const llvm::coverage::CounterMappingRegion &CMR = Record.getDecisionRegion();
+ return json::Array({CMR.LineStart, CMR.ColumnStart, CMR.LineEnd,
+ CMR.ColumnEnd, CMR.ExpandedFileID, int64_t(CMR.Kind),
+ gatherConditions(Record)});
+}
+
json::Array renderRegions(ArrayRef<coverage::CountedRegion> Regions) {
json::Array RegionArray;
for (const auto &Region : Regions)
@@ -112,6 +130,13 @@ json::Array renderBranchRegions(ArrayRef<coverage::CountedRegion> Regions) {
return RegionArray;
}
+json::Array renderMCDCRecords(ArrayRef<coverage::MCDCRecord> Records) {
+ json::Array RecordArray;
+ for (auto &Record : Records)
+ RecordArray.push_back(renderMCDCRecord(Record));
+ return RecordArray;
+}
+
std::vector<llvm::coverage::CountedRegion>
collectNestedBranches(const coverage::CoverageMapping &Coverage,
ArrayRef<llvm::coverage::ExpansionRecord> Expansions) {
@@ -178,7 +203,14 @@ json::Object renderSummary(const FileCoverageSummary &Summary) {
{"covered", int64_t(Summary.BranchCoverage.getCovered())},
{"notcovered", int64_t(Summary.BranchCoverage.getNumBranches() -
Summary.BranchCoverage.getCovered())},
- {"percent", Summary.BranchCoverage.getPercentCovered()}})}});
+ {"percent", Summary.BranchCoverage.getPercentCovered()}})},
+ {"mcdc",
+ json::Object(
+ {{"count", int64_t(Summary.MCDCCoverage.getNumPairs())},
+ {"covered", int64_t(Summary.MCDCCoverage.getCoveredPairs())},
+ {"notcovered", int64_t(Summary.MCDCCoverage.getNumPairs() -
+ Summary.MCDCCoverage.getCoveredPairs())},
+ {"percent", Summary.MCDCCoverage.getPercentCovered()}})}});
}
json::Array renderFileExpansions(const coverage::CoverageMapping &Coverage,
@@ -206,6 +238,14 @@ json::Array renderFileBranches(const coverage::CoverageData &FileCoverage,
return BranchArray;
}
+json::Array renderFileMCDC(const coverage::CoverageData &FileCoverage,
+ const FileCoverageSummary &FileReport) {
+ json::Array MCDCRecordArray;
+ for (const auto &Record : FileCoverage.getMCDCRecords())
+ MCDCRecordArray.push_back(renderMCDCRecord(Record));
+ return MCDCRecordArray;
+}
+
json::Object renderFile(const coverage::CoverageMapping &Coverage,
const std::string &Filename,
const FileCoverageSummary &FileReport,
@@ -216,6 +256,7 @@ json::Object renderFile(const coverage::CoverageMapping &Coverage,
auto FileCoverage = Coverage.getCoverageForFile(Filename);
File["segments"] = renderFileSegments(FileCoverage, FileReport);
File["branches"] = renderFileBranches(FileCoverage, FileReport);
+ File["mcdc_records"] = renderFileMCDC(FileCoverage, FileReport);
if (!Options.SkipExpansions) {
File["expansions"] =
renderFileExpansions(Coverage, FileCoverage, FileReport);
@@ -264,6 +305,7 @@ json::Array renderFunctions(
{"count", clamp_uint64_to_int64(F.ExecutionCount)},
{"regions", renderRegions(F.CountedRegions)},
{"branches", renderBranchRegions(F.CountedBranchRegions)},
+ {"mcdc_records", renderMCDCRecords(F.MCDCRecords)},
{"filenames", json::Array(F.Filenames)}}));
return FunctionArray;
}
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 060733b2d5d6..8cc073e4def8 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -86,9 +86,9 @@ Column column(StringRef Str, unsigned Width, const T &Value) {
}
// Specify the default column widths.
-size_t FileReportColumns[] = {25, 12, 18, 10, 12, 18, 10, 16,
- 16, 10, 12, 18, 10, 12, 18, 10};
-size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8, 10, 8, 8};
+size_t FileReportColumns[] = {25, 12, 18, 10, 12, 18, 10, 16, 16, 10,
+ 12, 18, 10, 12, 18, 10, 20, 21, 10};
+size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8, 10, 8, 8, 20, 8, 8};
/// Adjust column widths to fit long file paths and function names.
void adjustColumnWidths(ArrayRef<StringRef> Files,
@@ -211,7 +211,7 @@ void CoverageReport::render(const FileCoverageSummary &File,
sys::path::native(FileName);
// remove_dots will remove trailing slash, so we need to check before it.
- auto IsDir = FileName.endswith(sys::path::get_separator());
+ auto IsDir = FileName.ends_with(sys::path::get_separator());
sys::path::remove_dots(FileName, /*remove_dot_dot=*/true);
if (IsDir)
FileName += sys::path::get_separator();
@@ -291,6 +291,22 @@ void CoverageReport::render(const FileCoverageSummary &File,
OS << column("-", FileReportColumns[15], Column::RightAlignment);
}
+ if (Options.ShowMCDCSummary) {
+ OS << format("%*u", FileReportColumns[16],
+ (unsigned)File.MCDCCoverage.getNumPairs());
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*u", FileReportColumns[17],
+ (unsigned)(File.MCDCCoverage.getNumPairs() -
+ File.MCDCCoverage.getCoveredPairs()));
+ if (File.MCDCCoverage.getNumPairs())
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*.2f", FileReportColumns[18] - 1,
+ File.MCDCCoverage.getPercentCovered())
+ << '%';
+ else
+ OS << column("-", FileReportColumns[18], Column::RightAlignment);
+ }
+
OS << "\n";
}
@@ -338,6 +354,19 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
Function.BranchCoverage.getPercentCovered())
<< '%';
}
+ if (Options.ShowMCDCSummary) {
+ OS << format("%*u", FunctionReportColumns[10],
+ (unsigned)Function.MCDCCoverage.getNumPairs());
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*u", FunctionReportColumns[11],
+ (unsigned)(Function.MCDCCoverage.getNumPairs() -
+ Function.MCDCCoverage.getCoveredPairs()));
+ Options.colored_ostream(
+ OS, determineCoveragePercentageColor(Function.MCDCCoverage))
+ << format("%*.2f", FunctionReportColumns[12] - 1,
+ Function.MCDCCoverage.getPercentCovered())
+ << '%';
+ }
OS << "\n";
}
@@ -370,6 +399,11 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
OS << column("Branches", FunctionReportColumns[7], Column::RightAlignment)
<< column("Miss", FunctionReportColumns[8], Column::RightAlignment)
<< column("Cover", FunctionReportColumns[9], Column::RightAlignment);
+ if (Options.ShowMCDCSummary)
+ OS << column("MC/DC Conditions", FunctionReportColumns[10],
+ Column::RightAlignment)
+ << column("Miss", FunctionReportColumns[11], Column::RightAlignment)
+ << column("Cover", FunctionReportColumns[12], Column::RightAlignment);
OS << "\n";
renderDivider(FunctionReportColumns, OS);
OS << "\n";
@@ -380,6 +414,7 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
Totals.RegionCoverage += Function.RegionCoverage;
Totals.LineCoverage += Function.LineCoverage;
Totals.BranchCoverage += Function.BranchCoverage;
+ Totals.MCDCCoverage += Function.MCDCCoverage;
render(Function, DC, OS);
}
if (Totals.ExecutionCount) {
@@ -502,6 +537,12 @@ void CoverageReport::renderFileReports(
<< column("Missed Branches", FileReportColumns[14],
Column::RightAlignment)
<< column("Cover", FileReportColumns[15], Column::RightAlignment);
+ if (Options.ShowMCDCSummary)
+ OS << column("MC/DC Conditions", FileReportColumns[16],
+ Column::RightAlignment)
+ << column("Missed Conditions", FileReportColumns[17],
+ Column::RightAlignment)
+ << column("Cover", FileReportColumns[18], Column::RightAlignment);
OS << "\n";
renderDivider(FileReportColumns, OS);
OS << "\n";
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
index 10e059adeb7d..4f150020ee38 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -44,6 +44,21 @@ static void sumBranchExpansions(size_t &NumBranches, size_t &CoveredBranches,
}
}
+static std::pair<size_t, size_t>
+sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
+ size_t NumPairs = 0, CoveredPairs = 0;
+ for (const auto &Record : Records) {
+ const auto NumConditions = Record.getNumConditions();
+ for (unsigned C = 0; C < NumConditions; C++) {
+ if (!Record.isCondFolded(C))
+ ++NumPairs;
+ if (Record.isConditionIndependencePairCovered(C))
+ ++CoveredPairs;
+ }
+ }
+ return {NumPairs, CoveredPairs};
+}
+
FunctionCoverageSummary
FunctionCoverageSummary::get(const CoverageMapping &CM,
const coverage::FunctionRecord &Function) {
@@ -73,11 +88,15 @@ FunctionCoverageSummary::get(const CoverageMapping &CM,
sumBranches(NumBranches, CoveredBranches, CD.getBranches());
sumBranchExpansions(NumBranches, CoveredBranches, CM, CD.getExpansions());
+ size_t NumPairs = 0, CoveredPairs = 0;
+ std::tie(NumPairs, CoveredPairs) = sumMCDCPairs(CD.getMCDCRecords());
+
return FunctionCoverageSummary(
Function.Name, Function.ExecutionCount,
RegionCoverageInfo(CoveredRegions, NumCodeRegions),
LineCoverageInfo(CoveredLines, NumLines),
- BranchCoverageInfo(CoveredBranches, NumBranches));
+ BranchCoverageInfo(CoveredBranches, NumBranches),
+ MCDCCoverageInfo(CoveredPairs, NumPairs));
}
FunctionCoverageSummary
@@ -97,10 +116,12 @@ FunctionCoverageSummary::get(const InstantiationGroup &Group,
Summary.RegionCoverage = Summaries[0].RegionCoverage;
Summary.LineCoverage = Summaries[0].LineCoverage;
Summary.BranchCoverage = Summaries[0].BranchCoverage;
+ Summary.MCDCCoverage = Summaries[0].MCDCCoverage;
for (const auto &FCS : Summaries.drop_front()) {
Summary.RegionCoverage.merge(FCS.RegionCoverage);
Summary.LineCoverage.merge(FCS.LineCoverage);
Summary.BranchCoverage.merge(FCS.BranchCoverage);
+ Summary.MCDCCoverage.merge(FCS.MCDCCoverage);
}
return Summary;
}
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index 46510dc9cf3f..64c2c8406cf3 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -142,6 +142,47 @@ public:
}
};
+/// Provides information about MC/DC coverage for a function/file.
+class MCDCCoverageInfo {
+ /// The number of Independence Pairs that were covered.
+ size_t CoveredPairs;
+
+ /// The total number of Independence Pairs in a function/file.
+ size_t NumPairs;
+
+public:
+ MCDCCoverageInfo() : CoveredPairs(0), NumPairs(0) {}
+
+ MCDCCoverageInfo(size_t CoveredPairs, size_t NumPairs)
+ : CoveredPairs(CoveredPairs), NumPairs(NumPairs) {
+ assert(CoveredPairs <= NumPairs && "Covered pairs over-counted");
+ }
+
+ MCDCCoverageInfo &operator+=(const MCDCCoverageInfo &RHS) {
+ CoveredPairs += RHS.CoveredPairs;
+ NumPairs += RHS.NumPairs;
+ return *this;
+ }
+
+ void merge(const MCDCCoverageInfo &RHS) {
+ CoveredPairs = std::max(CoveredPairs, RHS.CoveredPairs);
+ NumPairs = std::max(NumPairs, RHS.NumPairs);
+ }
+
+ size_t getCoveredPairs() const { return CoveredPairs; }
+
+ size_t getNumPairs() const { return NumPairs; }
+
+ bool isFullyCovered() const { return CoveredPairs == NumPairs; }
+
+ double getPercentCovered() const {
+ assert(CoveredPairs <= NumPairs && "Covered pairs over-counted");
+ if (NumPairs == 0)
+ return 0.0;
+ return double(CoveredPairs) / double(NumPairs) * 100.0;
+ }
+};
+
/// Provides information about function coverage for a file.
class FunctionCoverageInfo {
/// The number of functions that were executed.
@@ -189,6 +230,7 @@ struct FunctionCoverageSummary {
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
BranchCoverageInfo BranchCoverage;
+ MCDCCoverageInfo MCDCCoverage;
FunctionCoverageSummary(const std::string &Name)
: Name(Name), ExecutionCount(0) {}
@@ -196,10 +238,11 @@ struct FunctionCoverageSummary {
FunctionCoverageSummary(const std::string &Name, uint64_t ExecutionCount,
const RegionCoverageInfo &RegionCoverage,
const LineCoverageInfo &LineCoverage,
- const BranchCoverageInfo &BranchCoverage)
+ const BranchCoverageInfo &BranchCoverage,
+ const MCDCCoverageInfo &MCDCCoverage)
: Name(Name), ExecutionCount(ExecutionCount),
RegionCoverage(RegionCoverage), LineCoverage(LineCoverage),
- BranchCoverage(BranchCoverage) {}
+ BranchCoverage(BranchCoverage), MCDCCoverage(MCDCCoverage) {}
/// Compute the code coverage summary for the given function coverage
/// mapping record.
@@ -219,6 +262,7 @@ struct FileCoverageSummary {
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
BranchCoverageInfo BranchCoverage;
+ MCDCCoverageInfo MCDCCoverage;
FunctionCoverageInfo FunctionCoverage;
FunctionCoverageInfo InstantiationCoverage;
@@ -230,6 +274,7 @@ struct FileCoverageSummary {
LineCoverage += RHS.LineCoverage;
FunctionCoverage += RHS.FunctionCoverage;
BranchCoverage += RHS.BranchCoverage;
+ MCDCCoverage += RHS.MCDCCoverage;
InstantiationCoverage += RHS.InstantiationCoverage;
return *this;
}
@@ -238,6 +283,7 @@ struct FileCoverageSummary {
RegionCoverage += Function.RegionCoverage;
LineCoverage += Function.LineCoverage;
BranchCoverage += Function.BranchCoverage;
+ MCDCCoverage += Function.MCDCCoverage;
FunctionCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0);
}
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index eb852859e9cb..6925cffd8246 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -30,12 +30,14 @@ struct CoverageViewOptions {
bool ShowLineNumbers;
bool ShowLineStats;
bool ShowRegionMarkers;
+ bool ShowMCDC;
bool ShowBranchCounts;
bool ShowBranchPercents;
bool ShowExpandedRegions;
bool ShowFunctionInstantiations;
bool ShowFullFilenames;
bool ShowBranchSummary;
+ bool ShowMCDCSummary;
bool ShowRegionSummary;
bool ShowInstantiationSummary;
bool ShowDirectoryCoverage;
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.cpp b/llvm/tools/llvm-cov/SourceCoverageView.cpp
index 7480b7f628a0..c910edd1db78 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageView.cpp
@@ -178,6 +178,12 @@ void SourceCoverageView::addBranch(unsigned Line,
BranchSubViews.emplace_back(Line, Regions, std::move(View));
}
+void SourceCoverageView::addMCDCRecord(
+ unsigned Line, ArrayRef<MCDCRecord> Records,
+ std::unique_ptr<SourceCoverageView> View) {
+ MCDCSubViews.emplace_back(Line, Records, std::move(View));
+}
+
void SourceCoverageView::addInstantiation(
StringRef FunctionName, unsigned Line,
std::unique_ptr<SourceCoverageView> View) {
@@ -203,12 +209,15 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
llvm::stable_sort(ExpansionSubViews);
llvm::stable_sort(InstantiationSubViews);
llvm::stable_sort(BranchSubViews);
+ llvm::stable_sort(MCDCSubViews);
auto NextESV = ExpansionSubViews.begin();
auto EndESV = ExpansionSubViews.end();
auto NextISV = InstantiationSubViews.begin();
auto EndISV = InstantiationSubViews.end();
auto NextBRV = BranchSubViews.begin();
auto EndBRV = BranchSubViews.end();
+ auto NextMSV = MCDCSubViews.begin();
+ auto EndMSV = MCDCSubViews.end();
// Get the coverage information for the file.
auto StartSegment = CoverageInfo.begin();
@@ -276,6 +285,11 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
renderBranchView(OS, *NextBRV, ViewDepth + 1);
RenderedSubView = true;
}
+ for (; NextMSV != EndMSV && NextMSV->Line == LI.line_number(); ++NextMSV) {
+ renderViewDivider(OS, ViewDepth + 1);
+ renderMCDCView(OS, *NextMSV, ViewDepth + 1);
+ RenderedSubView = true;
+ }
if (RenderedSubView)
renderViewDivider(OS, ViewDepth + 1);
renderLineSuffix(OS, ViewDepth);
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index c07595f98072..2e3fa8e627d8 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -84,6 +84,23 @@ struct BranchView {
}
};
+/// A view that represents one or more MCDC regions on a given source line.
+struct MCDCView {
+ std::vector<MCDCRecord> Records;
+ std::unique_ptr<SourceCoverageView> View;
+ unsigned Line;
+
+ MCDCView(unsigned Line, ArrayRef<MCDCRecord> Records,
+ std::unique_ptr<SourceCoverageView> View)
+ : Records(Records), View(std::move(View)), Line(Line) {}
+
+ unsigned getLine() const { return Line; }
+
+ friend bool operator<(const MCDCView &LHS, const MCDCView &RHS) {
+ return LHS.Line < RHS.Line;
+ }
+};
+
/// A file manager that handles format-aware file creation.
class CoveragePrinter {
public:
@@ -160,6 +177,9 @@ class SourceCoverageView {
/// A container for all branches in the source on display.
std::vector<BranchView> BranchSubViews;
+ /// A container for all MCDC records in the source on display.
+ std::vector<MCDCView> MCDCSubViews;
+
/// A container for all instantiations (e.g template functions) in the source
/// on display.
std::vector<InstantiationView> InstantiationSubViews;
@@ -233,6 +253,10 @@ protected:
virtual void renderBranchView(raw_ostream &OS, BranchView &BRV,
unsigned ViewDepth) = 0;
+ /// Render an MCDC view.
+ virtual void renderMCDCView(raw_ostream &OS, MCDCView &BRV,
+ unsigned ViewDepth) = 0;
+
/// Render \p Title, a project title if one is available, and the
/// created time.
virtual void renderTitle(raw_ostream &OS, StringRef CellText) = 0;
@@ -283,6 +307,10 @@ public:
void addBranch(unsigned Line, ArrayRef<CountedRegion> Regions,
std::unique_ptr<SourceCoverageView> View);
+ /// Add an MCDC subview to this view.
+ void addMCDCRecord(unsigned Line, ArrayRef<MCDCRecord> Records,
+ std::unique_ptr<SourceCoverageView> View);
+
/// Print the code coverage information for a specific portion of a
/// source file to the output stream.
void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName,
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index 79a0494815c2..b43e9e64231e 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -335,6 +335,10 @@ void emitTableRow(raw_ostream &OS, const CoverageViewOptions &Opts,
AddCoverageTripleToColumn(FCS.BranchCoverage.getCovered(),
FCS.BranchCoverage.getNumBranches(),
FCS.BranchCoverage.getPercentCovered());
+ if (Opts.ShowMCDCSummary)
+ AddCoverageTripleToColumn(FCS.MCDCCoverage.getCoveredPairs(),
+ FCS.MCDCCoverage.getNumPairs(),
+ FCS.MCDCCoverage.getPercentCovered());
if (IsTotals)
OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row-bold");
@@ -385,6 +389,8 @@ static void emitColumnLabelsForIndex(raw_ostream &OS,
Columns.emplace_back(tag("td", "Region Coverage", "column-entry-bold"));
if (Opts.ShowBranchSummary)
Columns.emplace_back(tag("td", "Branch Coverage", "column-entry-bold"));
+ if (Opts.ShowMCDCSummary)
+ Columns.emplace_back(tag("td", "MC/DC", "column-entry-bold"));
OS << tag("tr", join(Columns.begin(), Columns.end(), ""));
}
@@ -639,7 +645,7 @@ struct CoveragePrinterHTMLDirectory::Reporter : public DirectoryCoverageReport {
sys::path::native(LinkTextStr);
// remove_dots will remove trailing slash, so we need to check before it.
- auto IsDir = LinkTextStr.endswith(sys::path::get_separator());
+ auto IsDir = LinkTextStr.ends_with(sys::path::get_separator());
sys::path::remove_dots(LinkTextStr, /*remove_dot_dot=*/true);
SmallString<128> LinkTargetStr(LinkTextStr);
@@ -955,6 +961,52 @@ void SourceCoverageViewHTML::renderBranchView(raw_ostream &OS, BranchView &BRV,
OS << EndExpansionDiv;
}
+void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
+ unsigned ViewDepth) {
+ for (auto &Record : MRV.Records) {
+ OS << BeginExpansionDiv;
+ OS << BeginPre;
+ OS << " MC/DC Decision Region (";
+
+ // Display Line + Column information.
+ const CounterMappingRegion &DecisionRegion = Record.getDecisionRegion();
+ std::string LineNoStr = Twine(DecisionRegion.LineStart).str();
+ std::string ColNoStr = Twine(DecisionRegion.ColumnStart).str();
+ std::string TargetName = "L" + LineNoStr;
+ OS << tag("span",
+ a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr),
+ TargetName),
+ "line-number") +
+ ") to (";
+ LineNoStr = utostr(uint64_t(DecisionRegion.LineEnd));
+ ColNoStr = utostr(uint64_t(DecisionRegion.ColumnEnd));
+ OS << tag("span",
+ a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr),
+ TargetName),
+ "line-number") +
+ ")\n\n";
+
+ // Display MC/DC Information.
+ OS << " Number of Conditions: " << Record.getNumConditions() << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++) {
+ OS << " " << Record.getConditionHeaderString(i);
+ }
+ OS << "\n";
+ OS << " Executed MC/DC Test Vectors:\n\n ";
+ OS << Record.getTestVectorHeaderString();
+ for (unsigned i = 0; i < Record.getNumTestVectors(); i++)
+ OS << Record.getTestVectorString(i);
+ OS << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++)
+ OS << Record.getConditionCoverageString(i);
+ OS << " MC/DC Coverage for Expression: ";
+ OS << format("%0.2f", Record.getPercentCovered()) << "%\n";
+ OS << EndPre;
+ OS << EndExpansionDiv;
+ }
+ return;
+}
+
void SourceCoverageViewHTML::renderInstantiationView(raw_ostream &OS,
InstantiationView &ISV,
unsigned ViewDepth) {
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.h b/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
index c846379889cd..7b97f05b946b 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
@@ -91,6 +91,9 @@ class SourceCoverageViewHTML : public SourceCoverageView {
void renderBranchView(raw_ostream &OS, BranchView &BRV,
unsigned ViewDepth) override;
+ void renderMCDCView(raw_ostream &OS, MCDCView &BRV,
+ unsigned ViewDepth) override;
+
void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) override;
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index 44694a0426c8..73b7ffe16a96 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -337,6 +337,57 @@ void SourceCoverageViewText::renderBranchView(raw_ostream &OS, BranchView &BRV,
}
}
+void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
+ unsigned ViewDepth) {
+ for (auto &Record : MRV.Records) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << "---> MC/DC Decision Region (";
+ // Display Line + Column information.
+ const CounterMappingRegion &DecisionRegion = Record.getDecisionRegion();
+ OS << DecisionRegion.LineStart << ":";
+ OS << DecisionRegion.ColumnStart << ") to (";
+ OS << DecisionRegion.LineEnd << ":";
+ OS << DecisionRegion.ColumnEnd << ")\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+
+ // Display MC/DC Information.
+ renderLinePrefix(OS, ViewDepth);
+ OS << " Number of Conditions: " << Record.getNumConditions() << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << " " << Record.getConditionHeaderString(i);
+ }
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << " Executed MC/DC Test Vectors:\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << " ";
+ OS << Record.getTestVectorHeaderString();
+ for (unsigned i = 0; i < Record.getNumTestVectors(); i++) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << Record.getTestVectorString(i);
+ }
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << Record.getConditionCoverageString(i);
+ }
+ renderLinePrefix(OS, ViewDepth);
+ OS << " MC/DC Coverage for Decision: ";
+ colored_ostream(OS, raw_ostream::RED,
+ getOptions().Colors && Record.getPercentCovered() < 100.0,
+ /*Bold=*/false, /*BG=*/true)
+ << format("%0.2f", Record.getPercentCovered()) << "%\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ }
+}
+
void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
InstantiationView &ISV,
unsigned ViewDepth) {
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.h b/llvm/tools/llvm-cov/SourceCoverageViewText.h
index ade47ed3b5f5..7cb47fcbf42b 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.h
@@ -77,6 +77,9 @@ class SourceCoverageViewText : public SourceCoverageView {
void renderBranchView(raw_ostream &OS, BranchView &BRV,
unsigned ViewDepth) override;
+ void renderMCDCView(raw_ostream &OS, MCDCView &BRV,
+ unsigned ViewDepth) override;
+
void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) override;
diff --git a/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp b/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
index f35f62632763..c04aec19174b 100644
--- a/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
+++ b/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
@@ -217,7 +217,7 @@ static void dumpCXXData(const ObjectFile *Obj) {
// VFTables in the MS-ABI start with '??_7' and are contained within their
// own COMDAT section. We then determine the contents of the VFTable by
// looking at each relocation in the section.
- if (SymName.startswith("??_7")) {
+ if (SymName.starts_with("??_7")) {
// Each relocation either names a virtual method or a thunk. We note the
// offset into the section and the symbol used for the relocation.
collectRelocationOffsets(Obj, Sec, SecAddress, SecAddress, SecSize,
@@ -225,14 +225,14 @@ static void dumpCXXData(const ObjectFile *Obj) {
}
// VBTables in the MS-ABI start with '??_8' and are filled with 32-bit
// offsets of virtual bases.
- else if (SymName.startswith("??_8")) {
+ else if (SymName.starts_with("??_8")) {
ArrayRef<little32_t> VBTableData(
reinterpret_cast<const little32_t *>(SymContents.data()),
SymContents.size() / sizeof(little32_t));
VBTables[SymName] = VBTableData;
}
// Complete object locators in the MS-ABI start with '??_R4'
- else if (SymName.startswith("??_R4")) {
+ else if (SymName.starts_with("??_R4")) {
CompleteObjectLocator COL;
COL.Data =
ArrayRef(reinterpret_cast<const little32_t *>(SymContents.data()), 3);
@@ -241,7 +241,7 @@ static void dumpCXXData(const ObjectFile *Obj) {
COLs[SymName] = COL;
}
// Class hierarchy descriptors in the MS-ABI start with '??_R3'
- else if (SymName.startswith("??_R3")) {
+ else if (SymName.starts_with("??_R3")) {
ClassHierarchyDescriptor CHD;
CHD.Data =
ArrayRef(reinterpret_cast<const little32_t *>(SymContents.data()), 3);
@@ -250,14 +250,14 @@ static void dumpCXXData(const ObjectFile *Obj) {
CHDs[SymName] = CHD;
}
// Class hierarchy descriptors in the MS-ABI start with '??_R2'
- else if (SymName.startswith("??_R2")) {
+ else if (SymName.starts_with("??_R2")) {
// Each relocation names a base class descriptor. We note the offset into
// the section and the symbol used for the relocation.
collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
SymName, BCAEntries);
}
// Base class descriptors in the MS-ABI start with '??_R1'
- else if (SymName.startswith("??_R1")) {
+ else if (SymName.starts_with("??_R1")) {
BaseClassDescriptor BCD;
BCD.Data = ArrayRef(
reinterpret_cast<const little32_t *>(SymContents.data()) + 1, 5);
@@ -266,7 +266,7 @@ static void dumpCXXData(const ObjectFile *Obj) {
BCDs[SymName] = BCD;
}
// Type descriptors in the MS-ABI start with '??_R0'
- else if (SymName.startswith("??_R0")) {
+ else if (SymName.starts_with("??_R0")) {
const char *DataPtr = SymContents.drop_front(BytesInAddress).data();
TypeDescriptor TD;
if (BytesInAddress == 8)
@@ -279,7 +279,7 @@ static void dumpCXXData(const ObjectFile *Obj) {
TDs[SymName] = TD;
}
// Throw descriptors in the MS-ABI start with '_TI'
- else if (SymName.startswith("_TI") || SymName.startswith("__TI")) {
+ else if (SymName.starts_with("_TI") || SymName.starts_with("__TI")) {
ThrowInfo TI;
TI.Flags = *reinterpret_cast<const little32_t *>(SymContents.data());
collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
@@ -287,7 +287,7 @@ static void dumpCXXData(const ObjectFile *Obj) {
TIs[SymName] = TI;
}
// Catchable type arrays in the MS-ABI start with _CTA or __CTA.
- else if (SymName.startswith("_CTA") || SymName.startswith("__CTA")) {
+ else if (SymName.starts_with("_CTA") || SymName.starts_with("__CTA")) {
CatchableTypeArray CTA;
CTA.NumEntries =
*reinterpret_cast<const little32_t *>(SymContents.data());
@@ -296,7 +296,7 @@ static void dumpCXXData(const ObjectFile *Obj) {
CTAs[SymName] = CTA;
}
// Catchable types in the MS-ABI start with _CT or __CT.
- else if (SymName.startswith("_CT") || SymName.startswith("__CT")) {
+ else if (SymName.starts_with("_CT") || SymName.starts_with("__CT")) {
const little32_t *DataPtr =
reinterpret_cast<const little32_t *>(SymContents.data());
CatchableType CT;
@@ -310,16 +310,16 @@ static void dumpCXXData(const ObjectFile *Obj) {
CTs[SymName] = CT;
}
// Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'.
- else if (SymName.startswith("_ZTT") || SymName.startswith("__ZTT")) {
+ else if (SymName.starts_with("_ZTT") || SymName.starts_with("__ZTT")) {
collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
SymName, VTTEntries);
}
// Typeinfo names in the Itanium ABI start with '_ZTS' or '__ZTS'.
- else if (SymName.startswith("_ZTS") || SymName.startswith("__ZTS")) {
+ else if (SymName.starts_with("_ZTS") || SymName.starts_with("__ZTS")) {
TINames[SymName] = SymContents.slice(0, SymContents.find('\0'));
}
// Vtables in the Itanium ABI start with '_ZTV' or '__ZTV'.
- else if (SymName.startswith("_ZTV") || SymName.startswith("__ZTV")) {
+ else if (SymName.starts_with("_ZTV") || SymName.starts_with("__ZTV")) {
collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
SymName, VTableSymEntries);
for (uint64_t SymOffI = 0; SymOffI < SymSize; SymOffI += BytesInAddress) {
@@ -337,7 +337,7 @@ static void dumpCXXData(const ObjectFile *Obj) {
}
}
// Typeinfo structures in the Itanium ABI start with '_ZTI' or '__ZTI'.
- else if (SymName.startswith("_ZTI") || SymName.startswith("__ZTI")) {
+ else if (SymName.starts_with("_ZTI") || SymName.starts_with("__ZTI")) {
// FIXME: Do something with these!
}
}
diff --git a/llvm/tools/llvm-diff/llvm-diff.cpp b/llvm/tools/llvm-diff/llvm-diff.cpp
index 7349469c80d6..6fe18a51c9f5 100644
--- a/llvm/tools/llvm-diff/llvm-diff.cpp
+++ b/llvm/tools/llvm-diff/llvm-diff.cpp
@@ -42,7 +42,8 @@ static std::unique_ptr<Module> readModule(LLVMContext &Context,
static void diffGlobal(DifferenceEngine &Engine, Module &L, Module &R,
StringRef Name) {
// Drop leading sigils from the global name.
- if (Name.startswith("@")) Name = Name.substr(1);
+ if (Name.starts_with("@"))
+ Name = Name.substr(1);
Function *LFn = L.getFunction(Name);
Function *RFn = R.getFunction(Name);
diff --git a/llvm/tools/llvm-dis/llvm-dis.cpp b/llvm/tools/llvm-dis/llvm-dis.cpp
index 4996fc12ae32..06fc669390bf 100644
--- a/llvm/tools/llvm-dis/llvm-dis.cpp
+++ b/llvm/tools/llvm-dis/llvm-dis.cpp
@@ -225,7 +225,7 @@ int main(int argc, char **argv) {
FinalFilename = "-";
} else {
StringRef IFN = InputFilename;
- FinalFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str();
+ FinalFilename = (IFN.ends_with(".bc") ? IFN.drop_back(3) : IFN).str();
if (N > 1)
FinalFilename += std::string(".") + std::to_string(I);
FinalFilename += ".ll";
diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
index d9d99ffc8747..77cb8bb1aa7d 100644
--- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
+++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
@@ -18,7 +18,7 @@ namespace llvm {
namespace dwarfutil {
inline bool isDebugSection(StringRef SecName) {
- return SecName.startswith(".debug") || SecName.startswith(".zdebug") ||
+ return SecName.starts_with(".debug") || SecName.starts_with(".zdebug") ||
SecName == ".gdb_index";
}
diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp
index fede89e9c116..19ee5374979c 100644
--- a/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -900,7 +900,7 @@ static char getSymbolNMTypeChar(ELFObjectFileBase &Obj,
consumeError(NameOrErr.takeError());
return '?';
}
- if ((*NameOrErr).startswith(".debug"))
+ if ((*NameOrErr).starts_with(".debug"))
return 'N';
if (!(Flags & ELF::SHF_WRITE))
return 'n';
@@ -939,7 +939,7 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
const coff_section *Section = Obj.getCOFFSection(*SecI);
Characteristics = Section->Characteristics;
if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section))
- if (NameOrErr->startswith(".idata"))
+ if (NameOrErr->starts_with(".idata"))
return 'i';
}
@@ -1738,13 +1738,13 @@ static void getXCOFFExports(XCOFFObjectFile *XCOFFObj,
StringRef SymName = cantFail(Sym.getName());
if (SymName.empty())
continue;
- if (SymName.startswith("__sinit") || SymName.startswith("__sterm") ||
+ if (SymName.starts_with("__sinit") || SymName.starts_with("__sterm") ||
SymName.front() == '.' || SymName.front() == '(')
continue;
// Check the SymName regex matching with "^__[0-9]+__".
- if (SymName.size() > 4 && SymName.startswith("__") &&
- SymName.endswith("__")) {
+ if (SymName.size() > 4 && SymName.starts_with("__") &&
+ SymName.ends_with("__")) {
if (std::all_of(SymName.begin() + 2, SymName.end() - 2, isDigit))
continue;
}
@@ -1752,9 +1752,9 @@ static void getXCOFFExports(XCOFFObjectFile *XCOFFObj,
if (SymName == "__rsrc" && NoRsrc)
continue;
- if (SymName.startswith("__tf1"))
+ if (SymName.starts_with("__tf1"))
SymName = SymName.substr(6);
- else if (SymName.startswith("__tf9"))
+ else if (SymName.starts_with("__tf9"))
SymName = SymName.substr(14);
NMSymbol S = {};
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 571290253944..f15307181fad 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -315,7 +315,7 @@ getOutputTargetInfoByTargetName(StringRef TargetName) {
MI.OSABI = ELF::ELFOSABI_FREEBSD;
FileFormat Format;
- if (TargetName.startswith("elf"))
+ if (TargetName.starts_with("elf"))
Format = FileFormat::ELF;
else
// This should never happen because `TargetName` is valid (it certainly
@@ -737,6 +737,35 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
Config.ExtractPartition = Arg->getValue();
+ if (const auto *A = InputArgs.getLastArg(OBJCOPY_gap_fill)) {
+ if (Config.OutputFormat != FileFormat::Binary)
+ return createStringError(
+ errc::invalid_argument,
+ "'--gap-fill' is only supported for binary output");
+ ErrorOr<uint64_t> Val = getAsInteger<uint64_t>(A->getValue());
+ if (!Val)
+ return createStringError(Val.getError(), "--gap-fill: bad number: %s",
+ A->getValue());
+ uint8_t ByteVal = Val.get();
+ if (ByteVal != Val.get())
+ return createStringError(std::errc::value_too_large,
+ "gap-fill value %s is out of range (0 to 0xff)",
+ A->getValue());
+ Config.GapFill = ByteVal;
+ }
+
+ if (const auto *A = InputArgs.getLastArg(OBJCOPY_pad_to)) {
+ if (Config.OutputFormat != FileFormat::Binary)
+ return createStringError(
+ errc::invalid_argument,
+ "'--pad-to' is only supported for binary output");
+ ErrorOr<uint64_t> Addr = getAsInteger<uint64_t>(A->getValue());
+ if (!Addr)
+ return createStringError(Addr.getError(), "--pad-to: bad number: %s",
+ A->getValue());
+ Config.PadTo = *Addr;
+ }
+
for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
if (!StringRef(Arg->getValue()).contains('='))
return createStringError(errc::invalid_argument,
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index ea8828637222..ead8cd28d387 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -230,3 +230,15 @@ defm add_symbol
defm update_section
: Eq<"update-section", "Replace the contents of section <name> with contents from a file <file>">,
MetaVarName<"name=file">;
+
+defm gap_fill
+ : Eq<"gap-fill", "Fill the gaps between sections with <value> instead of zero. "
+ "<value> must be an unsigned 8-bit integer. "
+ "This option is only supported for ELF input and binary output">,
+ MetaVarName<"value">;
+
+defm pad_to
+ : Eq<"pad-to", "Pad the output up to the load address <address>, using a value "
+ "of zero or the value specified by the --gap-fill option. "
+ "This option is only supported for ELF input and binary output">,
+ MetaVarName<"address">;
diff --git a/llvm/tools/llvm-objdump/COFFDump.cpp b/llvm/tools/llvm-objdump/COFFDump.cpp
index 8f685a21505c..71697fa01e62 100644
--- a/llvm/tools/llvm-objdump/COFFDump.cpp
+++ b/llvm/tools/llvm-objdump/COFFDump.cpp
@@ -857,7 +857,7 @@ void objdump::printCOFFSymbolTable(const COFFObjectFile &coff) {
<< "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
<< "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
<< Name;
- if (Demangle && Name.startswith("?")) {
+ if (Demangle && Name.starts_with("?")) {
int Status = -1;
char *DemangledSymbol = microsoftDemangle(Name, nullptr, &Status);
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index f80a12d2f84b..0e6935c0ac58 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -290,7 +290,7 @@ static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
const StringRef FileName = MachOObj->getFileName();
for (const SymbolRef &Symbol : MachOObj->symbols()) {
StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
- if (!SymName.startswith("ltmp"))
+ if (!SymName.starts_with("ltmp"))
Symbols.push_back(Symbol);
}
@@ -1482,7 +1482,7 @@ static void CreateSymbolAddressMap(MachOObjectFile *O,
ST == SymbolRef::ST_Other) {
uint64_t Address = cantFail(Symbol.getValue());
StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
- if (!SymName.startswith(".objc"))
+ if (!SymName.starts_with(".objc"))
(*AddrMap)[Address] = SymName;
}
}
diff --git a/llvm/tools/llvm-objdump/SourcePrinter.cpp b/llvm/tools/llvm-objdump/SourcePrinter.cpp
index b2fe56cf2e1c..76da86587586 100644
--- a/llvm/tools/llvm-objdump/SourcePrinter.cpp
+++ b/llvm/tools/llvm-objdump/SourcePrinter.cpp
@@ -436,7 +436,7 @@ void SourcePrinter::printLines(formatted_raw_ostream &OS,
OS << Delimiter << LineInfo.FunctionName;
// If demangling is successful, FunctionName will end with "()". Print it
// only if demangling did not run or was unsuccessful.
- if (!StringRef(LineInfo.FunctionName).endswith("()"))
+ if (!StringRef(LineInfo.FunctionName).ends_with("()"))
OS << "()";
OS << ":\n";
}
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 631ca955776d..12bb70d5537d 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -1538,7 +1538,7 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
// __mh_(execute|dylib|dylinker|bundle|preload|object)_header are special
// symbols that support MachO header introspection. They do not bind to
// code locations and are irrelevant for disassembly.
- if (NameOrErr->startswith("__mh_") && NameOrErr->endswith("_header"))
+ if (NameOrErr->starts_with("__mh_") && NameOrErr->ends_with("_header"))
continue;
// Don't ask a Mach-O STAB symbol for its section unless you know that
// STAB symbol's section field refers to a valid section index. Otherwise
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 63e34d81f189..322b7da2678f 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -46,6 +46,7 @@
#include <queue>
using namespace llvm;
+using ProfCorrelatorKind = InstrProfCorrelator::ProfCorrelatorKind;
// https://llvm.org/docs/CommandGuide/llvm-profdata.html has documentations
// on each subcommand.
@@ -124,6 +125,11 @@ cl::opt<std::string> DebugInfoFilename(
"the functions it found. For merge, use the provided debug info to "
"correlate the raw profile."),
cl::sub(ShowSubcommand), cl::sub(MergeSubcommand));
+cl::opt<std::string>
+ BinaryFilename("binary-file", cl::init(""),
+ cl::desc("For merge, use the provided unstripped bianry to "
+ "correlate the raw profile."),
+ cl::sub(MergeSubcommand));
cl::opt<std::string> FuncNameFilter(
"function",
cl::desc("Details for matching functions. For overlapping CSSPGO, this "
@@ -787,14 +793,27 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
OutputFormat != PF_Text)
exitWithError("unknown format is specified");
- std::unique_ptr<InstrProfCorrelator> Correlator;
+ // TODO: Maybe we should support correlation with mixture of different
+ // correlation modes(w/wo debug-info/object correlation).
+ if (!DebugInfoFilename.empty() && !BinaryFilename.empty())
+ exitWithError("Expected only one of -debug-info, -binary-file");
+ std::string CorrelateFilename;
+ ProfCorrelatorKind CorrelateKind = ProfCorrelatorKind::NONE;
if (!DebugInfoFilename.empty()) {
- if (auto Err = InstrProfCorrelator::get(DebugInfoFilename,
- InstrProfCorrelator::DEBUG_INFO)
+ CorrelateFilename = DebugInfoFilename;
+ CorrelateKind = ProfCorrelatorKind::DEBUG_INFO;
+ } else if (!BinaryFilename.empty()) {
+ CorrelateFilename = BinaryFilename;
+ CorrelateKind = ProfCorrelatorKind::BINARY;
+ }
+
+ std::unique_ptr<InstrProfCorrelator> Correlator;
+ if (CorrelateKind != InstrProfCorrelator::NONE) {
+ if (auto Err = InstrProfCorrelator::get(CorrelateFilename, CorrelateKind)
.moveInto(Correlator))
- exitWithError(std::move(Err), DebugInfoFilename);
+ exitWithError(std::move(Err), CorrelateFilename);
if (auto Err = Correlator->correlateProfileData(MaxDbgCorrelationWarnings))
- exitWithError(std::move(Err), DebugInfoFilename);
+ exitWithError(std::move(Err), CorrelateFilename);
}
std::mutex ErrorLock;
@@ -1514,7 +1533,7 @@ static void parseInputFilenamesFile(MemoryBuffer *Buffer,
for (const StringRef &FileWeightEntry : Entries) {
StringRef SanitizedEntry = FileWeightEntry.trim(" \t\v\f\r");
// Skip comments.
- if (SanitizedEntry.startswith("#"))
+ if (SanitizedEntry.starts_with("#"))
continue;
// If there's no comma, it's an unweighted profile.
else if (!SanitizedEntry.contains(','))
diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
index cf5c77cf107c..b77839c2c57c 100644
--- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
+++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -1476,7 +1476,7 @@ Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
if (!NameOrErr)
return NameOrErr.takeError();
- if (NameOrErr->startswith(".pdata"))
+ if (NameOrErr->starts_with(".pdata"))
dumpProcedureData(COFF, Section);
}
return Error::success();
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 3ad40dc35510..32b1d6a2089c 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -1946,7 +1946,7 @@ void COFFDumper::printCOFFResources() {
ListScope ResourcesD(W, "Resources");
for (const SectionRef &S : Obj->sections()) {
StringRef Name = unwrapOrError(Obj->getFileName(), S.getName());
- if (!Name.startswith(".rsrc"))
+ if (!Name.starts_with(".rsrc"))
continue;
StringRef Ref = unwrapOrError(Obj->getFileName(), S.getContents());
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 85d5ab68b495..f2851a52671b 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -57,6 +57,7 @@
#include "llvm/Support/RISCVAttributeParser.h"
#include "llvm/Support/RISCVAttributes.h"
#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cinttypes>
@@ -1500,7 +1501,7 @@ static std::string getGNUPtType(unsigned Arch, unsigned Type) {
return Seg.str();
// E.g. "PT_LOAD" -> "LOAD".
- assert(Seg.startswith("PT_"));
+ assert(Seg.starts_with("PT_"));
return Seg.drop_front(3).str();
}
@@ -1692,6 +1693,19 @@ const EnumEntry<unsigned> ElfHeaderAMDGPUFlagsABIVersion4[] = {
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_ON_V4),
};
+const EnumEntry<unsigned> ElfHeaderNVPTXFlags[] = {
+ ENUM_ENT(EF_CUDA_SM20, "sm_20"), ENUM_ENT(EF_CUDA_SM21, "sm_21"),
+ ENUM_ENT(EF_CUDA_SM30, "sm_30"), ENUM_ENT(EF_CUDA_SM32, "sm_32"),
+ ENUM_ENT(EF_CUDA_SM35, "sm_35"), ENUM_ENT(EF_CUDA_SM37, "sm_37"),
+ ENUM_ENT(EF_CUDA_SM50, "sm_50"), ENUM_ENT(EF_CUDA_SM52, "sm_52"),
+ ENUM_ENT(EF_CUDA_SM53, "sm_53"), ENUM_ENT(EF_CUDA_SM60, "sm_60"),
+ ENUM_ENT(EF_CUDA_SM61, "sm_61"), ENUM_ENT(EF_CUDA_SM62, "sm_62"),
+ ENUM_ENT(EF_CUDA_SM70, "sm_70"), ENUM_ENT(EF_CUDA_SM72, "sm_72"),
+ ENUM_ENT(EF_CUDA_SM75, "sm_75"), ENUM_ENT(EF_CUDA_SM80, "sm_80"),
+ ENUM_ENT(EF_CUDA_SM86, "sm_86"), ENUM_ENT(EF_CUDA_SM87, "sm_87"),
+ ENUM_ENT(EF_CUDA_SM89, "sm_89"), ENUM_ENT(EF_CUDA_SM90, "sm_90"),
+};
+
const EnumEntry<unsigned> ElfHeaderRISCVFlags[] = {
ENUM_ENT(EF_RISCV_RVC, "RVC"),
ENUM_ENT(EF_RISCV_FLOAT_ABI_SINGLE, "single-float ABI"),
@@ -2581,7 +2595,7 @@ template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() {
llvm::sort(Libs);
for (StringRef L : Libs)
- W.startLine() << L << "\n";
+ W.printString(L);
}
template <class ELFT>
@@ -3629,6 +3643,9 @@ template <class ELFT> void GNUELFDumper<ELFT>::printFileHeaders() {
else if (e.e_machine == EM_XTENSA)
ElfFlags = printFlags(e.e_flags, ArrayRef(ElfHeaderXtensaFlags),
unsigned(ELF::EF_XTENSA_MACH));
+ else if (e.e_machine == EM_CUDA)
+ ElfFlags = printFlags(e.e_flags, ArrayRef(ElfHeaderNVPTXFlags),
+ unsigned(ELF::EF_CUDA_SM));
Str = "0x" + utohexstr(e.e_flags);
if (!ElfFlags.empty())
Str = Str + ", " + ElfFlags;
@@ -5129,6 +5146,7 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
if (Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_BTI, "BTI");
DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_PAC, "PAC");
+ DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_GCS, "GCS");
} else {
DumpBit(GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT");
DumpBit(GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK");
@@ -5862,13 +5880,13 @@ StringRef getNoteTypeName(const typename ELFT::Note &Note, unsigned ELFType) {
return FindNote(FreeBSDNoteTypes);
}
}
- if (ELFType == ELF::ET_CORE && Name.startswith("NetBSD-CORE")) {
+ if (ELFType == ELF::ET_CORE && Name.starts_with("NetBSD-CORE")) {
StringRef Result = FindNote(NetBSDCoreNoteTypes);
if (!Result.empty())
return Result;
return FindNote(CoreNoteTypes);
}
- if (ELFType == ELF::ET_CORE && Name.startswith("OpenBSD")) {
+ if (ELFType == ELF::ET_CORE && Name.starts_with("OpenBSD")) {
// OpenBSD also places the generic core notes in the OpenBSD namespace.
StringRef Result = FindNote(OpenBSDCoreNoteTypes);
if (!Result.empty())
@@ -6910,6 +6928,9 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printFileHeaders() {
else if (E.e_machine == EM_XTENSA)
W.printFlags("Flags", E.e_flags, ArrayRef(ElfHeaderXtensaFlags),
unsigned(ELF::EF_XTENSA_MACH));
+ else if (E.e_machine == EM_CUDA)
+ W.printFlags("Flags", E.e_flags, ArrayRef(ElfHeaderNVPTXFlags),
+ unsigned(ELF::EF_CUDA_SM));
else
W.printFlags("Flags", E.e_flags);
W.printNumber("HeaderSize", E.e_ehsize);
diff --git a/llvm/tools/llvm-readobj/ObjDumper.cpp b/llvm/tools/llvm-readobj/ObjDumper.cpp
index 6dde3725b4d6..59060ac217e3 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.cpp
+++ b/llvm/tools/llvm-readobj/ObjDumper.cpp
@@ -18,6 +18,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
diff --git a/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/llvm/tools/llvm-readobj/Win64EHDumper.cpp
index 2896f20336c5..e4bd77219151 100644
--- a/llvm/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/llvm/tools/llvm-readobj/Win64EHDumper.cpp
@@ -397,7 +397,7 @@ void Dumper::printData(const Context &Ctx) {
else
consumeError(NameOrErr.takeError());
- if (Name != ".pdata" && !Name.startswith(".pdata$"))
+ if (Name != ".pdata" && !Name.starts_with(".pdata$"))
continue;
const coff_section *PData = Ctx.COFF.getCOFFSection(Section);
diff --git a/llvm/tools/llvm-stress/llvm-stress.cpp b/llvm/tools/llvm-stress/llvm-stress.cpp
index 783316d67655..8cb7fce5c366 100644
--- a/llvm/tools/llvm-stress/llvm-stress.cpp
+++ b/llvm/tools/llvm-stress/llvm-stress.cpp
@@ -175,7 +175,7 @@ public:
Ty = Type::getPPC_FP128Ty(Context);
else if (Arg == "x86_mmx")
Ty = Type::getX86_MMXTy(Context);
- else if (Arg.startswith("i")) {
+ else if (Arg.starts_with("i")) {
unsigned N = 0;
Arg.drop_front().getAsInteger(10, N);
if (N > 0)
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 447c18abadc1..74cc2da4e1ca 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -159,7 +159,7 @@ static Error makeStringError(StringRef Msg) {
static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
StringRef InputString, Command &Cmd,
std::string &ModuleName, object::BuildID &BuildID,
- StringRef &Symbol, uint64_t &ModuleOffset) {
+ StringRef &Symbol, uint64_t &Offset) {
ModuleName = BinaryName;
if (InputString.consume_front("CODE ")) {
Cmd = Command::Code;
@@ -224,25 +224,51 @@ static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
return makeStringError("no input filename has been specified");
}
- // Parse module offset, which can be specified as a number or as a symbol.
- InputString = InputString.ltrim();
+ // Parse address specification, which can be an offset in module or a
+ // symbol with optional offset.
+ InputString = InputString.trim();
if (InputString.empty())
return makeStringError("no module offset has been specified");
// If input string contains a space, ignore everything after it. This behavior
// is consistent with GNU addr2line.
- int OffsetLength = InputString.find_first_of(" \n\r");
- StringRef Offset = InputString.substr(0, OffsetLength);
+ int AddrSpecLength = InputString.find_first_of(" \n\r");
+ StringRef AddrSpec = InputString.substr(0, AddrSpecLength);
+ bool StartsWithDigit = std::isdigit(AddrSpec.front());
- // GNU addr2line assumes the offset is hexadecimal and allows a redundant
+ // GNU addr2line assumes the address is hexadecimal and allows a redundant
// "0x" or "0X" prefix; do the same for compatibility.
if (IsAddr2Line)
- Offset.consume_front("0x") || Offset.consume_front("0X");
+ AddrSpec.consume_front("0x") || AddrSpec.consume_front("0X");
- // If the input is not a number, treat it is a symbol.
- if (Offset.getAsInteger(IsAddr2Line ? 16 : 0, ModuleOffset)) {
- Symbol = Offset;
- ModuleOffset = 0;
+ // If address specification is a number, treat it as a module offset.
+ if (!AddrSpec.getAsInteger(IsAddr2Line ? 16 : 0, Offset)) {
+ // Module offset is an address.
+ Symbol = StringRef();
+ return Error::success();
+ }
+
+ // If address specification starts with a digit, but is not a number, consider
+ // it as invalid.
+ if (StartsWithDigit || AddrSpec.empty())
+ return makeStringError("expected a number as module offset");
+
+ // Otherwise it is a symbol name, potentially with an offset.
+ Symbol = AddrSpec;
+ Offset = 0;
+
+ // If the address specification contains '+', try treating it as
+ // "symbol + offset".
+ size_t Plus = AddrSpec.rfind('+');
+ if (Plus != StringRef::npos) {
+ StringRef SymbolStr = AddrSpec.take_front(Plus);
+ StringRef OffsetStr = AddrSpec.substr(Plus + 1);
+ if (!SymbolStr.empty() && !OffsetStr.empty() &&
+ !OffsetStr.getAsInteger(0, Offset)) {
+ Symbol = SymbolStr;
+ return Error::success();
+ }
+ // The found '+' is not an offset delimiter.
}
return Error::success();
@@ -268,7 +294,7 @@ void executeCommand(StringRef ModuleName, const T &ModuleSpec, Command Cmd,
print(SymRequest, ResOrErr, Printer);
} else if (!Symbol.empty()) {
Expected<std::vector<DILineInfo>> ResOrErr =
- Symbolizer.findSymbol(ModuleSpec, Symbol);
+ Symbolizer.findSymbol(ModuleSpec, Symbol, Offset);
print(SymRequest, ResOrErr, Printer);
} else if (ShouldInline) {
Expected<DIInliningInfo> ResOrErr =
@@ -430,7 +456,7 @@ static void filterMarkup(const opt::InputArgList &Args, LLVMSymbolizer &Symboliz
std::string InputString;
while (std::getline(std::cin, InputString)) {
InputString += '\n';
- Filter.filter(InputString);
+ Filter.filter(std::move(InputString));
}
Filter.finish();
}
diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp
index 5e5e5ce233f3..b6068513d230 100644
--- a/llvm/tools/opt/opt.cpp
+++ b/llvm/tools/opt/opt.cpp
@@ -339,7 +339,7 @@ static bool shouldPinPassToLegacyPM(StringRef Pass) {
"nvptx-", "mips-", "lanai-", "hexagon-", "bpf-", "avr-",
"thumb2-", "arm-", "si-", "gcn-", "amdgpu-", "aarch64-",
"amdgcn-", "polly-", "riscv-", "dxil-"};
- std::vector<StringRef> PassNameContain = {"ehprepare"};
+ std::vector<StringRef> PassNameContain = {"-eh-prepare"};
std::vector<StringRef> PassNameExact = {
"safe-stack",
"cost-model",
@@ -356,14 +356,14 @@ static bool shouldPinPassToLegacyPM(StringRef Pass) {
"expand-reductions",
"indirectbr-expand",
"generic-to-nvvm",
- "expandmemcmp",
+ "expand-memcmp",
"loop-reduce",
"lower-amx-type",
"lower-amx-intrinsics",
"polyhedral-info",
"print-polyhedral-info",
"replace-with-veclib",
- "jmc-instrument",
+ "jmc-instrumenter",
"dot-regions",
"dot-regions-only",
"view-regions",
@@ -376,7 +376,7 @@ static bool shouldPinPassToLegacyPM(StringRef Pass) {
"callbrprepare",
};
for (const auto &P : PassNamePrefix)
- if (Pass.startswith(P))
+ if (Pass.starts_with(P))
return true;
for (const auto &P : PassNameContain)
if (Pass.contains(P))
@@ -422,7 +422,7 @@ int main(int argc, char **argv) {
// supported.
initializeExpandLargeDivRemLegacyPassPass(Registry);
initializeExpandLargeFpConvertLegacyPassPass(Registry);
- initializeExpandMemCmpPassPass(Registry);
+ initializeExpandMemCmpLegacyPassPass(Registry);
initializeScalarizeMaskedMemIntrinLegacyPassPass(Registry);
initializeSelectOptimizePass(Registry);
initializeCallBrPreparePass(Registry);
@@ -434,7 +434,7 @@ int main(int argc, char **argv) {
initializeSjLjEHPreparePass(Registry);
initializePreISelIntrinsicLoweringLegacyPassPass(Registry);
initializeGlobalMergePass(Registry);
- initializeIndirectBrExpandPassPass(Registry);
+ initializeIndirectBrExpandLegacyPassPass(Registry);
initializeInterleavedLoadCombinePass(Registry);
initializeInterleavedAccessPass(Registry);
initializeUnreachableBlockElimLegacyPassPass(Registry);
diff --git a/llvm/utils/TableGen/DAGISelMatcher.cpp b/llvm/utils/TableGen/DAGISelMatcher.cpp
index 0609f006763b..1a5c728fafd9 100644
--- a/llvm/utils/TableGen/DAGISelMatcher.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcher.cpp
@@ -145,6 +145,10 @@ void MoveChildMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
OS.indent(indent) << "MoveChild " << ChildNo << '\n';
}
+void MoveSiblingMatcher::printImpl(raw_ostream &OS, unsigned Indent) const {
+ OS.indent(Indent) << "MoveSibling " << SiblingNo << '\n';
+}
+
void MoveParentMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
OS.indent(indent) << "MoveParent\n";
}
diff --git a/llvm/utils/TableGen/DAGISelMatcher.h b/llvm/utils/TableGen/DAGISelMatcher.h
index e3cf847edd12..0e8a948ec8a9 100644
--- a/llvm/utils/TableGen/DAGISelMatcher.h
+++ b/llvm/utils/TableGen/DAGISelMatcher.h
@@ -33,161 +33,167 @@ namespace llvm {
class TreePredicateFn;
class TreePattern;
-Matcher *ConvertPatternToMatcher(const PatternToMatch &Pattern,unsigned Variant,
- const CodeGenDAGPatterns &CGP);
-void OptimizeMatcher(std::unique_ptr<Matcher> &Matcher,
- const CodeGenDAGPatterns &CGP);
-void EmitMatcherTable(Matcher *Matcher, const CodeGenDAGPatterns &CGP,
- raw_ostream &OS);
-
-
-/// Matcher - Base class for all the DAG ISel Matcher representation
-/// nodes.
-class Matcher {
- // The next matcher node that is executed after this one. Null if this is the
- // last stage of a match.
- std::unique_ptr<Matcher> Next;
- size_t Size = 0; // Size in bytes of matcher and all its children (if any).
- virtual void anchor();
-public:
- enum KindTy {
- // Matcher state manipulation.
- Scope, // Push a checking scope.
- RecordNode, // Record the current node.
- RecordChild, // Record a child of the current node.
- RecordMemRef, // Record the memref in the current node.
- CaptureGlueInput, // If the current node has an input glue, save it.
- MoveChild, // Move current node to specified child.
- MoveParent, // Move current node to parent.
-
- // Predicate checking.
- CheckSame, // Fail if not same as prev match.
- CheckChildSame, // Fail if child not same as prev match.
- CheckPatternPredicate,
- CheckPredicate, // Fail if node predicate fails.
- CheckOpcode, // Fail if not opcode.
- SwitchOpcode, // Dispatch based on opcode.
- CheckType, // Fail if not correct type.
- SwitchType, // Dispatch based on type.
- CheckChildType, // Fail if child has wrong type.
- CheckInteger, // Fail if wrong val.
- CheckChildInteger, // Fail if child is wrong val.
- CheckCondCode, // Fail if not condcode.
- CheckChild2CondCode, // Fail if child is wrong condcode.
- CheckValueType,
- CheckComplexPat,
- CheckAndImm,
- CheckOrImm,
- CheckImmAllOnesV,
- CheckImmAllZerosV,
- CheckFoldableChainNode,
-
- // Node creation/emisssion.
- EmitInteger, // Create a TargetConstant
- EmitStringInteger, // Create a TargetConstant from a string.
- EmitRegister, // Create a register.
- EmitConvertToTarget, // Convert a imm/fpimm to target imm/fpimm
- EmitMergeInputChains, // Merge together a chains for an input.
- EmitCopyToReg, // Emit a copytoreg into a physreg.
- EmitNode, // Create a DAG node
- EmitNodeXForm, // Run a SDNodeXForm
- CompleteMatch, // Finish a match and update the results.
- MorphNodeTo, // Build a node, finish a match and update results.
-
- // Highest enum value; watch out when adding more.
- HighestKind = MorphNodeTo
- };
- const KindTy Kind;
+ Matcher *ConvertPatternToMatcher(const PatternToMatch &Pattern,
+ unsigned Variant,
+ const CodeGenDAGPatterns &CGP);
+ void OptimizeMatcher(std::unique_ptr<Matcher> &Matcher,
+ const CodeGenDAGPatterns &CGP);
+ void EmitMatcherTable(Matcher *Matcher, const CodeGenDAGPatterns &CGP,
+ raw_ostream &OS);
+
+ /// Matcher - Base class for all the DAG ISel Matcher representation
+ /// nodes.
+ class Matcher {
+ // The next matcher node that is executed after this one. Null if this is
+ // the last stage of a match.
+ std::unique_ptr<Matcher> Next;
+ size_t Size = 0; // Size in bytes of matcher and all its children (if any).
+ virtual void anchor();
+
+ public:
+ enum KindTy {
+ // Matcher state manipulation.
+ Scope, // Push a checking scope.
+ RecordNode, // Record the current node.
+ RecordChild, // Record a child of the current node.
+ RecordMemRef, // Record the memref in the current node.
+ CaptureGlueInput, // If the current node has an input glue, save it.
+ MoveChild, // Move current node to specified child.
+ MoveSibling, // Move current node to specified sibling.
+ MoveParent, // Move current node to parent.
+
+ // Predicate checking.
+ CheckSame, // Fail if not same as prev match.
+ CheckChildSame, // Fail if child not same as prev match.
+ CheckPatternPredicate,
+ CheckPredicate, // Fail if node predicate fails.
+ CheckOpcode, // Fail if not opcode.
+ SwitchOpcode, // Dispatch based on opcode.
+ CheckType, // Fail if not correct type.
+ SwitchType, // Dispatch based on type.
+ CheckChildType, // Fail if child has wrong type.
+ CheckInteger, // Fail if wrong val.
+ CheckChildInteger, // Fail if child is wrong val.
+ CheckCondCode, // Fail if not condcode.
+ CheckChild2CondCode, // Fail if child is wrong condcode.
+ CheckValueType,
+ CheckComplexPat,
+ CheckAndImm,
+ CheckOrImm,
+ CheckImmAllOnesV,
+ CheckImmAllZerosV,
+ CheckFoldableChainNode,
+
+ // Node creation/emisssion.
+ EmitInteger, // Create a TargetConstant
+ EmitStringInteger, // Create a TargetConstant from a string.
+ EmitRegister, // Create a register.
+ EmitConvertToTarget, // Convert a imm/fpimm to target imm/fpimm
+ EmitMergeInputChains, // Merge together a chains for an input.
+ EmitCopyToReg, // Emit a copytoreg into a physreg.
+ EmitNode, // Create a DAG node
+ EmitNodeXForm, // Run a SDNodeXForm
+ CompleteMatch, // Finish a match and update the results.
+ MorphNodeTo, // Build a node, finish a match and update results.
+
+ // Highest enum value; watch out when adding more.
+ HighestKind = MorphNodeTo
+ };
+ const KindTy Kind;
+
+ protected:
+ Matcher(KindTy K) : Kind(K) {}
+
+ public:
+ virtual ~Matcher() {}
+
+ unsigned getSize() const { return Size; }
+ void setSize(unsigned sz) { Size = sz; }
+ KindTy getKind() const { return Kind; }
+
+ Matcher *getNext() { return Next.get(); }
+ const Matcher *getNext() const { return Next.get(); }
+ void setNext(Matcher *C) { Next.reset(C); }
+ Matcher *takeNext() { return Next.release(); }
+
+ std::unique_ptr<Matcher> &getNextPtr() { return Next; }
+
+ bool isEqual(const Matcher *M) const {
+ if (getKind() != M->getKind())
+ return false;
+ return isEqualImpl(M);
+ }
-protected:
- Matcher(KindTy K) : Kind(K) {}
-public:
- virtual ~Matcher() {}
-
- unsigned getSize() const { return Size; }
- void setSize(unsigned sz) { Size = sz; }
- KindTy getKind() const { return Kind; }
-
- Matcher *getNext() { return Next.get(); }
- const Matcher *getNext() const { return Next.get(); }
- void setNext(Matcher *C) { Next.reset(C); }
- Matcher *takeNext() { return Next.release(); }
-
- std::unique_ptr<Matcher> &getNextPtr() { return Next; }
-
- bool isEqual(const Matcher *M) const {
- if (getKind() != M->getKind()) return false;
- return isEqualImpl(M);
- }
-
- /// isSimplePredicateNode - Return true if this is a simple predicate that
- /// operates on the node or its children without potential side effects or a
- /// change of the current node.
- bool isSimplePredicateNode() const {
- switch (getKind()) {
- default: return false;
- case CheckSame:
- case CheckChildSame:
- case CheckPatternPredicate:
- case CheckPredicate:
- case CheckOpcode:
- case CheckType:
- case CheckChildType:
- case CheckInteger:
- case CheckChildInteger:
- case CheckCondCode:
- case CheckChild2CondCode:
- case CheckValueType:
- case CheckAndImm:
- case CheckOrImm:
- case CheckImmAllOnesV:
- case CheckImmAllZerosV:
- case CheckFoldableChainNode:
- return true;
+ /// isSimplePredicateNode - Return true if this is a simple predicate that
+ /// operates on the node or its children without potential side effects or a
+ /// change of the current node.
+ bool isSimplePredicateNode() const {
+ switch (getKind()) {
+ default:
+ return false;
+ case CheckSame:
+ case CheckChildSame:
+ case CheckPatternPredicate:
+ case CheckPredicate:
+ case CheckOpcode:
+ case CheckType:
+ case CheckChildType:
+ case CheckInteger:
+ case CheckChildInteger:
+ case CheckCondCode:
+ case CheckChild2CondCode:
+ case CheckValueType:
+ case CheckAndImm:
+ case CheckOrImm:
+ case CheckImmAllOnesV:
+ case CheckImmAllZerosV:
+ case CheckFoldableChainNode:
+ return true;
+ }
}
- }
- /// isSimplePredicateOrRecordNode - Return true if this is a record node or
- /// a simple predicate.
- bool isSimplePredicateOrRecordNode() const {
- return isSimplePredicateNode() ||
- getKind() == RecordNode || getKind() == RecordChild;
- }
-
- /// unlinkNode - Unlink the specified node from this chain. If Other == this,
- /// we unlink the next pointer and return it. Otherwise we unlink Other from
- /// the list and return this.
- Matcher *unlinkNode(Matcher *Other);
-
- /// canMoveBefore - Return true if this matcher is the same as Other, or if
- /// we can move this matcher past all of the nodes in-between Other and this
- /// node. Other must be equal to or before this.
- bool canMoveBefore(const Matcher *Other) const;
-
- /// canMoveBeforeNode - Return true if it is safe to move the current matcher
- /// across the specified one.
- bool canMoveBeforeNode(const Matcher *Other) const;
-
- /// isContradictory - Return true of these two matchers could never match on
- /// the same node.
- bool isContradictory(const Matcher *Other) const {
- // Since this predicate is reflexive, we canonicalize the ordering so that
- // we always match a node against nodes with kinds that are greater or equal
- // to them. For example, we'll pass in a CheckType node as an argument to
- // the CheckOpcode method, not the other way around.
- if (getKind() < Other->getKind())
- return isContradictoryImpl(Other);
- return Other->isContradictoryImpl(this);
- }
-
- void print(raw_ostream &OS, unsigned indent = 0) const;
- void printOne(raw_ostream &OS) const;
- void dump() const;
-protected:
- virtual void printImpl(raw_ostream &OS, unsigned indent) const = 0;
- virtual bool isEqualImpl(const Matcher *M) const = 0;
- virtual bool isContradictoryImpl(const Matcher *M) const { return false; }
-};
+ /// isSimplePredicateOrRecordNode - Return true if this is a record node or
+ /// a simple predicate.
+ bool isSimplePredicateOrRecordNode() const {
+ return isSimplePredicateNode() || getKind() == RecordNode ||
+ getKind() == RecordChild;
+ }
+
+ /// unlinkNode - Unlink the specified node from this chain. If Other ==
+ /// this, we unlink the next pointer and return it. Otherwise we unlink
+ /// Other from the list and return this.
+ Matcher *unlinkNode(Matcher *Other);
+
+ /// canMoveBefore - Return true if this matcher is the same as Other, or if
+ /// we can move this matcher past all of the nodes in-between Other and this
+ /// node. Other must be equal to or before this.
+ bool canMoveBefore(const Matcher *Other) const;
+
+ /// canMoveBeforeNode - Return true if it is safe to move the current
+ /// matcher across the specified one.
+ bool canMoveBeforeNode(const Matcher *Other) const;
+
+ /// isContradictory - Return true of these two matchers could never match on
+ /// the same node.
+ bool isContradictory(const Matcher *Other) const {
+ // Since this predicate is reflexive, we canonicalize the ordering so that
+ // we always match a node against nodes with kinds that are greater or
+ // equal to them. For example, we'll pass in a CheckType node as an
+ // argument to the CheckOpcode method, not the other way around.
+ if (getKind() < Other->getKind())
+ return isContradictoryImpl(Other);
+ return Other->isContradictoryImpl(this);
+ }
+
+ void print(raw_ostream &OS, unsigned indent = 0) const;
+ void printOne(raw_ostream &OS) const;
+ void dump() const;
+
+ protected:
+ virtual void printImpl(raw_ostream &OS, unsigned indent) const = 0;
+ virtual bool isEqualImpl(const Matcher *M) const = 0;
+ virtual bool isContradictoryImpl(const Matcher *M) const { return false; }
+ };
/// ScopeMatcher - This attempts to match each of its children to find the first
/// one that successfully matches. If one child fails, it tries the next child.
@@ -342,6 +348,26 @@ private:
}
};
+/// MoveSiblingMatcher - This tells the interpreter to move into the
+/// specified sibling node.
+class MoveSiblingMatcher : public Matcher {
+ unsigned SiblingNo;
+
+public:
+ MoveSiblingMatcher(unsigned SiblingNo)
+ : Matcher(MoveSibling), SiblingNo(SiblingNo) {}
+
+ unsigned getSiblingNo() const { return SiblingNo; }
+
+ static bool classof(const Matcher *N) { return N->getKind() == MoveSibling; }
+
+private:
+ void printImpl(raw_ostream &OS, unsigned Indent) const override;
+ bool isEqualImpl(const Matcher *M) const override {
+ return cast<MoveSiblingMatcher>(M)->getSiblingNo() == getSiblingNo();
+ }
+};
+
/// MoveParentMatcher - This tells the interpreter to move to the parent
/// of the current node.
class MoveParentMatcher : public Matcher {
diff --git a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
index ed4be74ad0d4..94799267e896 100644
--- a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -456,6 +456,17 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
return (MCM->getChildNo() >= 8) ? 2 : 1;
}
+ case Matcher::MoveSibling: {
+ const auto *MSM = cast<MoveSiblingMatcher>(N);
+
+ OS << "OPC_MoveSibling";
+ // Handle the specialized forms.
+ if (MSM->getSiblingNo() >= 8)
+ OS << ", ";
+ OS << MSM->getSiblingNo() << ",\n";
+ return (MSM->getSiblingNo() >= 8) ? 2 : 1;
+ }
+
case Matcher::MoveParent:
OS << "OPC_MoveParent,\n";
return 1;
@@ -576,21 +587,37 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
return CurrentIdx - StartIdx + 1;
}
- case Matcher::CheckType:
+ case Matcher::CheckType:
if (cast<CheckTypeMatcher>(N)->getResNo() == 0) {
- OS << "OPC_CheckType, "
- << getEnumName(cast<CheckTypeMatcher>(N)->getType()) << ",\n";
- return 2;
+ MVT::SimpleValueType VT = cast<CheckTypeMatcher>(N)->getType();
+ switch (VT) {
+ case MVT::i32:
+ case MVT::i64:
+ OS << "OPC_CheckTypeI" << MVT(VT).getSizeInBits() << ",\n";
+ return 1;
+ default:
+ OS << "OPC_CheckType, " << getEnumName(VT) << ",\n";
+ return 2;
+ }
}
- OS << "OPC_CheckTypeRes, " << cast<CheckTypeMatcher>(N)->getResNo()
- << ", " << getEnumName(cast<CheckTypeMatcher>(N)->getType()) << ",\n";
+ OS << "OPC_CheckTypeRes, " << cast<CheckTypeMatcher>(N)->getResNo() << ", "
+ << getEnumName(cast<CheckTypeMatcher>(N)->getType()) << ",\n";
return 3;
- case Matcher::CheckChildType:
- OS << "OPC_CheckChild"
- << cast<CheckChildTypeMatcher>(N)->getChildNo() << "Type, "
- << getEnumName(cast<CheckChildTypeMatcher>(N)->getType()) << ",\n";
- return 2;
+ case Matcher::CheckChildType: {
+ MVT::SimpleValueType VT = cast<CheckChildTypeMatcher>(N)->getType();
+ switch (VT) {
+ case MVT::i32:
+ case MVT::i64:
+ OS << "OPC_CheckChild" << cast<CheckChildTypeMatcher>(N)->getChildNo()
+ << "TypeI" << MVT(VT).getSizeInBits() << ",\n";
+ return 1;
+ default:
+ OS << "OPC_CheckChild" << cast<CheckChildTypeMatcher>(N)->getChildNo()
+ << "Type, " << getEnumName(VT) << ",\n";
+ return 2;
+ }
+ }
case Matcher::CheckInteger: {
OS << "OPC_CheckInteger, ";
@@ -677,7 +704,7 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
case MVT::i32:
case MVT::i64:
OpBytes = 1;
- OS << "OPC_EmitInteger" << MVT(VT).getScalarSizeInBits() << ", ";
+ OS << "OPC_EmitInteger" << MVT(VT).getSizeInBits() << ", ";
break;
default:
OpBytes = 2;
@@ -696,7 +723,7 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
switch (VT) {
case MVT::i32:
OpBytes = 1;
- OS << "OPC_EmitStringInteger" << MVT(VT).getScalarSizeInBits() << ", ";
+ OS << "OPC_EmitStringInteger" << MVT(VT).getSizeInBits() << ", ";
break;
default:
OpBytes = 2;
@@ -730,10 +757,15 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
}
}
- case Matcher::EmitConvertToTarget:
- OS << "OPC_EmitConvertToTarget, "
- << cast<EmitConvertToTargetMatcher>(N)->getSlot() << ",\n";
+ case Matcher::EmitConvertToTarget: {
+ unsigned Slot = cast<EmitConvertToTargetMatcher>(N)->getSlot();
+ if (Slot < 8) {
+ OS << "OPC_EmitConvertToTarget" << Slot << ",\n";
+ return 1;
+ }
+ OS << "OPC_EmitConvertToTarget, " << Slot << ",\n";
return 2;
+ }
case Matcher::EmitMergeInputChains: {
const EmitMergeInputChainsMatcher *MN =
@@ -755,14 +787,20 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
const auto *C2RMatcher = cast<EmitCopyToRegMatcher>(N);
int Bytes = 3;
const CodeGenRegister *Reg = C2RMatcher->getDestPhysReg();
+ unsigned Slot = C2RMatcher->getSrcSlot();
if (Reg->EnumValue > 255) {
assert(isUInt<16>(Reg->EnumValue) && "not handled");
- OS << "OPC_EmitCopyToReg2, " << C2RMatcher->getSrcSlot() << ", "
+ OS << "OPC_EmitCopyToRegTwoByte, " << Slot << ", "
<< "TARGET_VAL(" << getQualifiedName(Reg->TheDef) << "),\n";
++Bytes;
} else {
- OS << "OPC_EmitCopyToReg, " << C2RMatcher->getSrcSlot() << ", "
- << getQualifiedName(Reg->TheDef) << ",\n";
+ if (Slot < 8) {
+ OS << "OPC_EmitCopyToReg" << Slot << ", "
+ << getQualifiedName(Reg->TheDef) << ",\n";
+ --Bytes;
+ } else
+ OS << "OPC_EmitCopyToReg, " << Slot << ", "
+ << getQualifiedName(Reg->TheDef) << ",\n";
}
return Bytes;
@@ -797,21 +835,50 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
}
}
const EmitNodeMatcherCommon *EN = cast<EmitNodeMatcherCommon>(N);
- OS << (isa<EmitNodeMatcher>(EN) ? "OPC_EmitNode" : "OPC_MorphNodeTo");
+ bool IsEmitNode = isa<EmitNodeMatcher>(EN);
+ OS << (IsEmitNode ? "OPC_EmitNode" : "OPC_MorphNodeTo");
bool CompressVTs = EN->getNumVTs() < 3;
- if (CompressVTs)
+ bool CompressNodeInfo = false;
+ if (CompressVTs) {
OS << EN->getNumVTs();
+ if (!EN->hasChain() && !EN->hasInGlue() && !EN->hasOutGlue() &&
+ !EN->hasMemRefs() && EN->getNumFixedArityOperands() == -1) {
+ CompressNodeInfo = true;
+ OS << "None";
+ } else if (EN->hasChain() && !EN->hasInGlue() && !EN->hasOutGlue() &&
+ !EN->hasMemRefs() && EN->getNumFixedArityOperands() == -1) {
+ CompressNodeInfo = true;
+ OS << "Chain";
+ } else if (!IsEmitNode && !EN->hasChain() && EN->hasInGlue() &&
+ !EN->hasOutGlue() && !EN->hasMemRefs() &&
+ EN->getNumFixedArityOperands() == -1) {
+ CompressNodeInfo = true;
+ OS << "GlueInput";
+ } else if (!IsEmitNode && !EN->hasChain() && !EN->hasInGlue() &&
+ EN->hasOutGlue() && !EN->hasMemRefs() &&
+ EN->getNumFixedArityOperands() == -1) {
+ CompressNodeInfo = true;
+ OS << "GlueOutput";
+ }
+ }
const CodeGenInstruction &CGI = EN->getInstruction();
OS << ", TARGET_VAL(" << CGI.Namespace << "::" << CGI.TheDef->getName()
- << "), 0";
-
- if (EN->hasChain()) OS << "|OPFL_Chain";
- if (EN->hasInGlue()) OS << "|OPFL_GlueInput";
- if (EN->hasOutGlue()) OS << "|OPFL_GlueOutput";
- if (EN->hasMemRefs()) OS << "|OPFL_MemRefs";
- if (EN->getNumFixedArityOperands() != -1)
- OS << "|OPFL_Variadic" << EN->getNumFixedArityOperands();
+ << ")";
+
+ if (!CompressNodeInfo) {
+ OS << ", 0";
+ if (EN->hasChain())
+ OS << "|OPFL_Chain";
+ if (EN->hasInGlue())
+ OS << "|OPFL_GlueInput";
+ if (EN->hasOutGlue())
+ OS << "|OPFL_GlueOutput";
+ if (EN->hasMemRefs())
+ OS << "|OPFL_MemRefs";
+ if (EN->getNumFixedArityOperands() != -1)
+ OS << "|OPFL_Variadic" << EN->getNumFixedArityOperands();
+ }
OS << ",\n";
OS.indent(FullIndexWidth + Indent+4);
@@ -854,8 +921,8 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
} else
OS << '\n';
- return 5 + !CompressVTs + EN->getNumVTs() + NumOperandBytes +
- NumCoveredBytes;
+ return 4 + !CompressVTs + !CompressNodeInfo + EN->getNumVTs() +
+ NumOperandBytes + NumCoveredBytes;
}
case Matcher::CompleteMatch: {
const CompleteMatchMatcher *CM = cast<CompleteMatchMatcher>(N);
@@ -1072,6 +1139,8 @@ static StringRef getOpcodeString(Matcher::KindTy Kind) {
return "OPC_CaptureGlueInput";
case Matcher::MoveChild:
return "OPC_MoveChild";
+ case Matcher::MoveSibling:
+ return "OPC_MoveSibling";
case Matcher::MoveParent:
return "OPC_MoveParent";
case Matcher::CheckSame:
diff --git a/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/llvm/utils/TableGen/DAGISelMatcherGen.cpp
index d08f57b84b95..3526e97c8e08 100644
--- a/llvm/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherGen.cpp
@@ -147,13 +147,14 @@ namespace {
MatcherGen::MatcherGen(const PatternToMatch &pattern,
const CodeGenDAGPatterns &cgp)
-: Pattern(pattern), CGP(cgp), NextRecordedOperandNo(0),
- TheMatcher(nullptr), CurPredicate(nullptr) {
- // We need to produce the matcher tree for the patterns source pattern. To do
- // this we need to match the structure as well as the types. To do the type
- // matching, we want to figure out the fewest number of type checks we need to
- // emit. For example, if there is only one integer type supported by a
- // target, there should be no type comparisons at all for integer patterns!
+ : Pattern(pattern), CGP(cgp), NextRecordedOperandNo(0), TheMatcher(nullptr),
+ CurPredicate(nullptr) {
+ // We need to produce the matcher tree for the patterns source pattern. To
+ // do this we need to match the structure as well as the types. To do the
+ // type matching, we want to figure out the fewest number of type checks we
+ // need to emit. For example, if there is only one integer type supported
+ // by a target, there should be no type comparisons at all for integer
+ // patterns!
//
// To figure out the fewest number of type checks needed, clone the pattern,
// remove the types, then perform type inference on the pattern as a whole.
diff --git a/llvm/utils/TableGen/DAGISelMatcherOpt.cpp b/llvm/utils/TableGen/DAGISelMatcherOpt.cpp
index bf2a24241e84..c4c25dc1a5fd 100644
--- a/llvm/utils/TableGen/DAGISelMatcherOpt.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherOpt.cpp
@@ -155,6 +155,30 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr,
CheckType->setNext(Tail);
return ContractNodes(MatcherPtr, CGP);
}
+
+ // If we have a MoveParent followed by a MoveChild, we convert it to
+ // MoveSibling.
+ if (auto *MP = dyn_cast<MoveParentMatcher>(N)) {
+ if (auto *MC = dyn_cast<MoveChildMatcher>(MP->getNext())) {
+ auto *MS = new MoveSiblingMatcher(MC->getChildNo());
+ MS->setNext(MC->takeNext());
+ MatcherPtr.reset(MS);
+ return ContractNodes(MatcherPtr, CGP);
+ }
+ if (auto *RC = dyn_cast<RecordChildMatcher>(MP->getNext())) {
+ if (auto *MC = dyn_cast<MoveChildMatcher>(RC->getNext())) {
+ if (RC->getChildNo() == MC->getChildNo()) {
+ auto *MS = new MoveSiblingMatcher(MC->getChildNo());
+ auto *RM = new RecordMatcher(RC->getWhatFor(), RC->getResultNo());
+ // Insert the new node.
+ RM->setNext(MC->takeNext());
+ MS->setNext(RM);
+ MatcherPtr.reset(MS);
+ return ContractNodes(MatcherPtr, CGP);
+ }
+ }
+ }
+ }
}
/// FindNodeWithKind - Scan a series of matchers looking for a matcher with a
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 8d9ded1b2ac5..c204b9819dc2 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -282,6 +282,10 @@ static std::string getScopedName(unsigned Scope, const std::string &Name) {
return ("pred:" + Twine(Scope) + ":" + Name).str();
}
+static std::string getMangledRootDefName(StringRef DefOperandName) {
+ return ("DstI[" + DefOperandName + "]").str();
+}
+
//===- GlobalISelEmitter class --------------------------------------------===//
static Expected<LLTCodeGen> getInstResultType(const TreePatternNode *Dst) {
@@ -404,7 +408,7 @@ private:
const TreePatternNode *DstChild, const TreePatternNode *Src);
Error importDefaultOperandRenderers(action_iterator InsertPt, RuleMatcher &M,
BuildMIAction &DstMIBuilder,
- DagInit *DefaultOps) const;
+ const DAGDefaultOperand &DefaultOp) const;
Error
importImplicitDefRenderers(BuildMIAction &DstMIBuilder,
const std::vector<Record *> &ImplicitDefs) const;
@@ -1499,8 +1503,13 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
if (DstNumDefs == 0)
return InsertPt;
- for (unsigned I = 0; I < SrcNumDefs; ++I)
- DstMIBuilder.addRenderer<CopyRenderer>(DstI->Operands[I].Name);
+ for (unsigned I = 0; I < SrcNumDefs; ++I) {
+ std::string OpName = getMangledRootDefName(DstI->Operands[I].Name);
+ // CopyRenderer saves a StringRef, so cannot pass OpName itself -
+ // let's use a string with an appropriate lifetime.
+ StringRef PermanentRef = M.getOperandMatcher(OpName).getSymbolicName();
+ DstMIBuilder.addRenderer<CopyRenderer>(PermanentRef);
+ }
// Some instructions have multiple defs, but are missing a type entry
// (e.g. s_cc_out operands).
@@ -1672,11 +1681,11 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
// overridden, or which we aren't letting it override; emit the 'default
// ops' operands.
- const CGIOperandList::OperandInfo &DstIOperand = DstI->Operands[InstOpNo];
- DagInit *DefaultOps = DstIOperand.Rec->getValueAsDag("DefaultOps");
- if (auto Error = importDefaultOperandRenderers(InsertPt, M, DstMIBuilder,
- DefaultOps))
+ Record *OperandNode = DstI->Operands[InstOpNo].Rec;
+ if (auto Error = importDefaultOperandRenderers(
+ InsertPt, M, DstMIBuilder, CGP.getDefaultOperand(OperandNode)))
return std::move(Error);
+
++NumDefaultOps;
continue;
}
@@ -1701,22 +1710,16 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
Error GlobalISelEmitter::importDefaultOperandRenderers(
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
- DagInit *DefaultOps) const {
- for (const auto *DefaultOp : DefaultOps->getArgs()) {
- std::optional<LLTCodeGen> OpTyOrNone;
+ const DAGDefaultOperand &DefaultOp) const {
+ for (const auto &Op : DefaultOp.DefaultOps) {
+ const auto *N = Op.get();
+ if (!N->isLeaf())
+ return failedImport("Could not add default op");
- // Look through ValueType operators.
- if (const DagInit *DefaultDagOp = dyn_cast<DagInit>(DefaultOp)) {
- if (const DefInit *DefaultDagOperator =
- dyn_cast<DefInit>(DefaultDagOp->getOperator())) {
- if (DefaultDagOperator->getDef()->isSubClassOf("ValueType")) {
- OpTyOrNone = MVTToLLT(getValueType(DefaultDagOperator->getDef()));
- DefaultOp = DefaultDagOp->getArg(0);
- }
- }
- }
+ const auto *DefaultOp = N->getLeafValue();
if (const DefInit *DefaultDefOp = dyn_cast<DefInit>(DefaultOp)) {
+ std::optional<LLTCodeGen> OpTyOrNone = MVTToLLT(N->getSimpleType(0));
auto Def = DefaultDefOp->getDef();
if (Def->getName() == "undef_tied_input") {
unsigned TempRegID = M.allocateTempRegID();
@@ -2013,16 +2016,17 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
const TypeSetByHwMode &VTy = Src->getExtType(I);
const auto &DstIOperand = DstI.Operands[OpIdx];
- Record *DstIOpRec = DstIOperand.Rec;
+ PointerUnion<Record *, const CodeGenRegisterClass *> MatchedRC =
+ DstIOperand.Rec;
if (DstIName == "COPY_TO_REGCLASS") {
- DstIOpRec = getInitValueAsRegClass(Dst->getChild(1)->getLeafValue());
+ MatchedRC = getInitValueAsRegClass(Dst->getChild(1)->getLeafValue());
- if (DstIOpRec == nullptr)
+ if (MatchedRC.isNull())
return failedImport(
"COPY_TO_REGCLASS operand #1 isn't a register class");
} else if (DstIName == "REG_SEQUENCE") {
- DstIOpRec = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
- if (DstIOpRec == nullptr)
+ MatchedRC = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
+ if (MatchedRC.isNull())
return failedImport("REG_SEQUENCE operand #0 isn't a register class");
} else if (DstIName == "EXTRACT_SUBREG") {
auto InferredClass = inferRegClassFromPattern(Dst->getChild(0));
@@ -2032,7 +2036,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// We can assume that a subregister is in the same bank as it's super
// register.
- DstIOpRec = (*InferredClass)->getDef();
+ MatchedRC = (*InferredClass)->getDef();
} else if (DstIName == "INSERT_SUBREG") {
auto MaybeSuperClass = inferSuperRegisterClassForNode(
VTy, Dst->getChild(0), Dst->getChild(2));
@@ -2042,34 +2046,30 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// Move to the next pattern here, because the register class we found
// doesn't necessarily have a record associated with it. So, we can't
// set DstIOpRec using this.
- OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
- OM.setSymbolicName(DstIOperand.Name);
- M.defineOperand(OM.getSymbolicName(), OM);
- OM.addPredicate<RegisterBankOperandMatcher>(**MaybeSuperClass);
- ++OpIdx;
- continue;
+ MatchedRC = *MaybeSuperClass;
} else if (DstIName == "SUBREG_TO_REG") {
auto MaybeRegClass = inferSuperRegisterClass(VTy, Dst->getChild(2));
if (!MaybeRegClass)
return failedImport(
"Cannot infer register class for SUBREG_TO_REG operand #0");
- OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
- OM.setSymbolicName(DstIOperand.Name);
- M.defineOperand(OM.getSymbolicName(), OM);
- OM.addPredicate<RegisterBankOperandMatcher>(**MaybeRegClass);
- ++OpIdx;
- continue;
- } else if (DstIOpRec->isSubClassOf("RegisterOperand"))
- DstIOpRec = DstIOpRec->getValueAsDef("RegClass");
- else if (!DstIOpRec->isSubClassOf("RegisterClass"))
+ MatchedRC = *MaybeRegClass;
+ } else if (MatchedRC.get<Record *>()->isSubClassOf("RegisterOperand"))
+ MatchedRC = MatchedRC.get<Record *>()->getValueAsDef("RegClass");
+ else if (!MatchedRC.get<Record *>()->isSubClassOf("RegisterClass"))
return failedImport("Dst MI def isn't a register class" +
to_string(*Dst));
OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
- OM.setSymbolicName(DstIOperand.Name);
+ // The operand names declared in the DstI instruction are unrelated to
+ // those used in pattern's source and destination DAGs, so mangle the
+ // former to prevent implicitly adding unexpected
+ // GIM_CheckIsSameOperand predicates by the defineOperand method.
+ OM.setSymbolicName(getMangledRootDefName(DstIOperand.Name));
M.defineOperand(OM.getSymbolicName(), OM);
+ if (MatchedRC.is<Record *>())
+ MatchedRC = &Target.getRegisterClass(MatchedRC.get<Record *>());
OM.addPredicate<RegisterBankOperandMatcher>(
- Target.getRegisterClass(DstIOpRec));
+ *MatchedRC.get<const CodeGenRegisterClass *>());
++OpIdx;
}
diff --git a/llvm/utils/TableGen/GlobalISelMatchTable.cpp b/llvm/utils/TableGen/GlobalISelMatchTable.cpp
index 481f3f16e013..349598266aa9 100644
--- a/llvm/utils/TableGen/GlobalISelMatchTable.cpp
+++ b/llvm/utils/TableGen/GlobalISelMatchTable.cpp
@@ -11,6 +11,7 @@
#include "CodeGenRegisters.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
@@ -39,10 +40,46 @@ std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) {
std::string getMatchOpcodeForImmPredicate(const TreePredicateFn &Predicate) {
return "GIM_Check" + Predicate.getImmTypeIdentifier().str() + "ImmPredicate";
}
+
+// GIMT_Encode2/4/8
+constexpr StringLiteral EncodeMacroName = "GIMT_Encode";
+
} // namespace
//===- Helpers ------------------------------------------------------------===//
+void emitEncodingMacrosDef(raw_ostream &OS) {
+ OS << "#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n"
+ << "#define " << EncodeMacroName << "2(Val)"
+ << " uint8_t(Val), uint8_t((uint16_t)Val >> 8)\n"
+ << "#define " << EncodeMacroName << "4(Val)"
+ << " uint8_t(Val), uint8_t((uint32_t)Val >> 8), "
+ "uint8_t((uint32_t)Val >> 16), uint8_t((uint32_t)Val >> 24)\n"
+ << "#define " << EncodeMacroName << "8(Val)"
+ << " uint8_t(Val), uint8_t((uint64_t)Val >> 8), "
+ "uint8_t((uint64_t)Val >> 16), uint8_t((uint64_t)Val >> 24), "
+ "uint8_t((uint64_t)Val >> 32), uint8_t((uint64_t)Val >> 40), "
+ "uint8_t((uint64_t)Val >> 48), uint8_t((uint64_t)Val >> 56)\n"
+ << "#else\n"
+ << "#define " << EncodeMacroName << "2(Val)"
+ << " uint8_t((uint16_t)Val >> 8), uint8_t(Val)\n"
+ << "#define " << EncodeMacroName << "4(Val)"
+ << " uint8_t((uint32_t)Val >> 24), uint8_t((uint32_t)Val >> 16), "
+ "uint8_t((uint32_t)Val >> 8), uint8_t(Val)\n"
+ << "#define " << EncodeMacroName << "8(Val)"
+ << " uint8_t((uint64_t)Val >> 56), uint8_t((uint64_t)Val >> 48), "
+ "uint8_t((uint64_t)Val >> 40), uint8_t((uint64_t)Val >> 32), "
+ "uint8_t((uint64_t)Val >> 24), uint8_t((uint64_t)Val >> 16), "
+ "uint8_t((uint64_t)Val >> 8), uint8_t(Val)\n"
+ << "#endif\n";
+}
+
+void emitEncodingMacrosUndef(raw_ostream &OS) {
+ OS << "#undef " << EncodeMacroName << "2\n"
+ << "#undef " << EncodeMacroName << "4\n"
+ << "#undef " << EncodeMacroName << "8\n";
+}
+
std::string getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset,
int HwModeIdx) {
std::string Name = "GIFBS";
@@ -111,6 +148,12 @@ template std::vector<Matcher *> optimizeRules<SwitchMatcher>(
ArrayRef<Matcher *> Rules,
std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
+static std::string getEncodedEmitStr(StringRef NamedValue, unsigned NumBytes) {
+ if (NumBytes == 2 || NumBytes == 4 || NumBytes == 8)
+ return (EncodeMacroName + Twine(NumBytes) + "(" + NamedValue + ")").str();
+ llvm_unreachable("Unsupported number of bytes!");
+}
+
//===- Global Data --------------------------------------------------------===//
std::set<LLTCodeGen> KnownTypes;
@@ -127,7 +170,11 @@ void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
if (Flags & MTRF_Comment)
OS << (UseLineComment ? "// " : "/*");
- OS << EmitStr;
+ if (NumElements > 1 && !(Flags & (MTRF_PreEncoded | MTRF_Comment)))
+ OS << getEncodedEmitStr(EmitStr, NumElements);
+ else
+ OS << EmitStr;
+
if (Flags & MTRF_Label)
OS << ": @" << Table.getLabelIndex(LabelID);
@@ -137,7 +184,9 @@ void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
if (Flags & MTRF_JumpTarget) {
if (Flags & MTRF_Comment)
OS << " ";
- OS << Table.getLabelIndex(LabelID);
+ // TODO: Could encode this AOT to speed up build of generated file
+ OS << getEncodedEmitStr(llvm::to_string(Table.getLabelIndex(LabelID)),
+ NumElements);
}
if (Flags & MTRF_CommaFollows) {
@@ -172,33 +221,66 @@ MatchTableRecord MatchTable::Opcode(StringRef Opcode, int IndentAdjust) {
MatchTableRecord::MTRF_CommaFollows | ExtraFlags);
}
-MatchTableRecord MatchTable::NamedValue(StringRef NamedValue) {
- return MatchTableRecord(std::nullopt, NamedValue, 1,
+MatchTableRecord MatchTable::NamedValue(unsigned NumBytes,
+ StringRef NamedValue) {
+ return MatchTableRecord(std::nullopt, NamedValue, NumBytes,
MatchTableRecord::MTRF_CommaFollows);
}
-MatchTableRecord MatchTable::NamedValue(StringRef NamedValue,
+MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef NamedValue,
int64_t RawValue) {
- return MatchTableRecord(std::nullopt, NamedValue, 1,
+ return MatchTableRecord(std::nullopt, NamedValue, NumBytes,
MatchTableRecord::MTRF_CommaFollows, RawValue);
}
-MatchTableRecord MatchTable::NamedValue(StringRef Namespace,
+MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef Namespace,
StringRef NamedValue) {
return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
- 1, MatchTableRecord::MTRF_CommaFollows);
+ NumBytes, MatchTableRecord::MTRF_CommaFollows);
}
-MatchTableRecord MatchTable::NamedValue(StringRef Namespace,
+MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef Namespace,
StringRef NamedValue,
int64_t RawValue) {
return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
- 1, MatchTableRecord::MTRF_CommaFollows, RawValue);
+ NumBytes, MatchTableRecord::MTRF_CommaFollows,
+ RawValue);
+}
+
+MatchTableRecord MatchTable::IntValue(unsigned NumBytes, int64_t IntValue) {
+ assert(isUIntN(NumBytes * 8, IntValue) || isIntN(NumBytes * 8, IntValue));
+ auto Str = llvm::to_string(IntValue);
+ if (NumBytes == 1 && IntValue < 0)
+ Str = "uint8_t(" + Str + ")";
+ // TODO: Could optimize this directly to save the compiler some work when
+ // building the file
+ return MatchTableRecord(std::nullopt, Str, NumBytes,
+ MatchTableRecord::MTRF_CommaFollows);
}
-MatchTableRecord MatchTable::IntValue(int64_t IntValue) {
- return MatchTableRecord(std::nullopt, llvm::to_string(IntValue), 1,
- MatchTableRecord::MTRF_CommaFollows);
+MatchTableRecord MatchTable::ULEB128Value(uint64_t IntValue) {
+ uint8_t Buffer[10];
+ unsigned Len = encodeULEB128(IntValue, Buffer);
+
+ // Simple case (most common)
+ if (Len == 1) {
+ return MatchTableRecord(std::nullopt, llvm::to_string((unsigned)Buffer[0]),
+ 1, MatchTableRecord::MTRF_CommaFollows);
+ }
+
+ // Print it as, e.g. /* -123456 (*/, 0xC0, 0xBB, 0x78 /*)*/
+ std::string Str;
+ raw_string_ostream OS(Str);
+ OS << "/* " << llvm::to_string(IntValue) << "(*/";
+ for (unsigned K = 0; K < Len; ++K) {
+ if (K)
+ OS << ", ";
+ OS << "0x" << llvm::toHex({Buffer[K]});
+ }
+ OS << "/*)*/";
+ return MatchTableRecord(std::nullopt, Str, Len,
+ MatchTableRecord::MTRF_CommaFollows |
+ MatchTableRecord::MTRF_PreEncoded);
}
MatchTableRecord MatchTable::Label(unsigned LabelID) {
@@ -209,7 +291,7 @@ MatchTableRecord MatchTable::Label(unsigned LabelID) {
}
MatchTableRecord MatchTable::JumpTarget(unsigned LabelID) {
- return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 1,
+ return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 4,
MatchTableRecord::MTRF_JumpTarget |
MatchTableRecord::MTRF_Comment |
MatchTableRecord::MTRF_CommaFollows);
@@ -219,7 +301,7 @@ void MatchTable::emitUse(raw_ostream &OS) const { OS << "MatchTable" << ID; }
void MatchTable::emitDeclaration(raw_ostream &OS) const {
unsigned Indentation = 4;
- OS << " constexpr static int64_t MatchTable" << ID << "[] = {";
+ OS << " constexpr static uint8_t MatchTable" << ID << "[] = {";
LineBreak.emit(OS, true, *this);
OS << std::string(Indentation, ' ');
@@ -243,7 +325,7 @@ void MatchTable::emitDeclaration(raw_ostream &OS) const {
if (I->Flags & MatchTableRecord::MTRF_Outdent)
Indentation -= 2;
}
- OS << "}; // Size: " << (CurrentSize * 8) << " bytes\n";
+ OS << "}; // Size: " << CurrentSize << " bytes\n";
}
MatchTable MatchTable::buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage,
@@ -542,14 +624,14 @@ void SwitchMatcher::emitPredicateSpecificOpcodes(const PredicateMatcher &P,
if (const auto *Condition = dyn_cast<InstructionOpcodeMatcher>(&P)) {
Table << MatchTable::Opcode("GIM_SwitchOpcode") << MatchTable::Comment("MI")
- << MatchTable::IntValue(Condition->getInsnVarID());
+ << MatchTable::ULEB128Value(Condition->getInsnVarID());
return;
}
if (const auto *Condition = dyn_cast<LLTOperandMatcher>(&P)) {
Table << MatchTable::Opcode("GIM_SwitchType") << MatchTable::Comment("MI")
- << MatchTable::IntValue(Condition->getInsnVarID())
+ << MatchTable::ULEB128Value(Condition->getInsnVarID())
<< MatchTable::Comment("Op")
- << MatchTable::IntValue(Condition->getOpIdx());
+ << MatchTable::ULEB128Value(Condition->getOpIdx());
return;
}
@@ -574,8 +656,8 @@ void SwitchMatcher::emit(MatchTable &Table) {
emitPredicateSpecificOpcodes(*Condition, Table);
- Table << MatchTable::Comment("[") << MatchTable::IntValue(LowerBound)
- << MatchTable::IntValue(UpperBound) << MatchTable::Comment(")")
+ Table << MatchTable::Comment("[") << MatchTable::IntValue(2, LowerBound)
+ << MatchTable::IntValue(2, UpperBound) << MatchTable::Comment(")")
<< MatchTable::Comment("default:") << MatchTable::JumpTarget(Default);
int64_t J = LowerBound;
@@ -583,7 +665,7 @@ void SwitchMatcher::emit(MatchTable &Table) {
for (unsigned I = 0, E = Values.size(); I < E; ++I) {
auto V = *VI++;
while (J++ < V.getRawValue())
- Table << MatchTable::IntValue(0);
+ Table << MatchTable::IntValue(4, 0);
V.turnIntoComment();
Table << MatchTable::LineBreak << V << MatchTable::JumpTarget(LabelIDs[I]);
}
@@ -865,14 +947,14 @@ void RuleMatcher::emit(MatchTable &Table) {
if (!RequiredFeatures.empty() || HwModeIdx >= 0) {
Table << MatchTable::Opcode("GIM_CheckFeatures")
<< MatchTable::NamedValue(
- getNameForFeatureBitset(RequiredFeatures, HwModeIdx))
+ 2, getNameForFeatureBitset(RequiredFeatures, HwModeIdx))
<< MatchTable::LineBreak;
}
if (!RequiredSimplePredicates.empty()) {
for (const auto &Pred : RequiredSimplePredicates) {
Table << MatchTable::Opcode("GIM_CheckSimplePredicate")
- << MatchTable::NamedValue(Pred) << MatchTable::LineBreak;
+ << MatchTable::NamedValue(2, Pred) << MatchTable::LineBreak;
}
}
@@ -899,7 +981,7 @@ void RuleMatcher::emit(MatchTable &Table) {
for (const auto &InsnID : InsnIDs) {
// Reject the difficult cases until we have a more accurate check.
Table << MatchTable::Opcode("GIM_CheckIsSafeToFold")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
<< MatchTable::LineBreak;
// FIXME: Emit checks to determine it's _actually_ safe to fold and/or
@@ -948,8 +1030,8 @@ void RuleMatcher::emit(MatchTable &Table) {
assert((Table.isWithCoverage() ? !Table.isCombiner() : true) &&
"Combiner tables don't support coverage!");
if (Table.isWithCoverage())
- Table << MatchTable::Opcode("GIR_Coverage") << MatchTable::IntValue(RuleID)
- << MatchTable::LineBreak;
+ Table << MatchTable::Opcode("GIR_Coverage")
+ << MatchTable::IntValue(4, RuleID) << MatchTable::LineBreak;
else if (!Table.isCombiner())
Table << MatchTable::Comment(("GIR_Coverage, " + Twine(RuleID) + ",").str())
<< MatchTable::LineBreak;
@@ -1035,12 +1117,13 @@ void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
Table << MatchTable::Opcode(IgnoreCopies
? "GIM_CheckIsSameOperandIgnoreCopies"
: "GIM_CheckIsSameOperand")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(OpIdx)
<< MatchTable::Comment("OtherMI")
- << MatchTable::IntValue(OtherInsnVarID)
+ << MatchTable::ULEB128Value(OtherInsnVarID)
<< MatchTable::Comment("OtherOpIdx")
- << MatchTable::IntValue(OtherOM.getOpIdx()) << MatchTable::LineBreak;
+ << MatchTable::ULEB128Value(OtherOM.getOpIdx())
+ << MatchTable::LineBreak;
}
//===- LLTOperandMatcher --------------------------------------------------===//
@@ -1050,8 +1133,8 @@ std::map<LLTCodeGen, unsigned> LLTOperandMatcher::TypeIDValues;
MatchTableRecord LLTOperandMatcher::getValue() const {
const auto VI = TypeIDValues.find(Ty);
if (VI == TypeIDValues.end())
- return MatchTable::NamedValue(getTy().getCxxEnumValue());
- return MatchTable::NamedValue(getTy().getCxxEnumValue(), VI->second);
+ return MatchTable::NamedValue(1, getTy().getCxxEnumValue());
+ return MatchTable::NamedValue(1, getTy().getCxxEnumValue(), VI->second);
}
bool LLTOperandMatcher::hasValue() const {
@@ -1063,8 +1146,8 @@ bool LLTOperandMatcher::hasValue() const {
void LLTOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckType") << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
- << MatchTable::IntValue(OpIdx) << MatchTable::Comment("Type")
+ << MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")
+ << MatchTable::ULEB128Value(OpIdx) << MatchTable::Comment("Type")
<< getValue() << MatchTable::LineBreak;
}
@@ -1073,10 +1156,10 @@ void LLTOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
void PointerToAnyOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckPointerToAny")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("SizeInBits") << MatchTable::IntValue(SizeInBits)
- << MatchTable::LineBreak;
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
+ << MatchTable::Comment("SizeInBits")
+ << MatchTable::ULEB128Value(SizeInBits) << MatchTable::LineBreak;
}
//===- RecordNamedOperandMatcher ------------------------------------------===//
@@ -1084,9 +1167,9 @@ void PointerToAnyOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
void RecordNamedOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_RecordNamedOperand")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("StoreIdx") << MatchTable::IntValue(StoreIdx)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
+ << MatchTable::Comment("StoreIdx") << MatchTable::ULEB128Value(StoreIdx)
<< MatchTable::Comment("Name : " + Name) << MatchTable::LineBreak;
}
@@ -1096,9 +1179,9 @@ void RecordRegisterType::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
assert(Idx < 0 && "Temp types always have negative indexes!");
Table << MatchTable::Opcode("GIM_RecordRegType") << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
- << MatchTable::IntValue(OpIdx) << MatchTable::Comment("TempTypeIdx")
- << MatchTable::IntValue(Idx) << MatchTable::LineBreak;
+ << MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")
+ << MatchTable::ULEB128Value(OpIdx) << MatchTable::Comment("TempTypeIdx")
+ << MatchTable::IntValue(1, Idx) << MatchTable::LineBreak;
}
//===- ComplexPatternOperandMatcher ---------------------------------------===//
@@ -1107,10 +1190,10 @@ void ComplexPatternOperandMatcher::emitPredicateOpcodes(
MatchTable &Table, RuleMatcher &Rule) const {
unsigned ID = getAllocatedTemporariesBaseID();
Table << MatchTable::Opcode("GIM_CheckComplexPattern")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("Renderer") << MatchTable::IntValue(ID)
- << MatchTable::NamedValue(("GICP_" + TheDef.getName()).str())
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
+ << MatchTable::Comment("Renderer") << MatchTable::IntValue(2, ID)
+ << MatchTable::NamedValue(2, ("GICP_" + TheDef.getName()).str())
<< MatchTable::LineBreak;
}
@@ -1128,10 +1211,10 @@ bool RegisterBankOperandMatcher::isIdentical(const PredicateMatcher &B) const {
void RegisterBankOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckRegBankForClass")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
<< MatchTable::Comment("RC")
- << MatchTable::NamedValue(RC.getQualifiedIdName())
+ << MatchTable::NamedValue(2, RC.getQualifiedIdName())
<< MatchTable::LineBreak;
}
@@ -1140,8 +1223,8 @@ void RegisterBankOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
void MBBOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckIsMBB") << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
- << MatchTable::IntValue(OpIdx) << MatchTable::LineBreak;
+ << MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")
+ << MatchTable::ULEB128Value(OpIdx) << MatchTable::LineBreak;
}
//===- ImmOperandMatcher --------------------------------------------------===//
@@ -1149,18 +1232,20 @@ void MBBOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
void ImmOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckIsImm") << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
- << MatchTable::IntValue(OpIdx) << MatchTable::LineBreak;
+ << MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")
+ << MatchTable::ULEB128Value(OpIdx) << MatchTable::LineBreak;
}
//===- ConstantIntOperandMatcher ------------------------------------------===//
void ConstantIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
- Table << MatchTable::Opcode("GIM_CheckConstantInt")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::IntValue(Value) << MatchTable::LineBreak;
+ const bool IsInt8 = isInt<8>(Value);
+ Table << MatchTable::Opcode(IsInt8 ? "GIM_CheckConstantInt8"
+ : "GIM_CheckConstantInt")
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
+ << MatchTable::IntValue(IsInt8 ? 1 : 8, Value) << MatchTable::LineBreak;
}
//===- LiteralIntOperandMatcher -------------------------------------------===//
@@ -1168,9 +1253,9 @@ void ConstantIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
void LiteralIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckLiteralInt")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::IntValue(Value) << MatchTable::LineBreak;
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
+ << MatchTable::IntValue(8, Value) << MatchTable::LineBreak;
}
//===- CmpPredicateOperandMatcher -----------------------------------------===//
@@ -1178,10 +1263,11 @@ void LiteralIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
void CmpPredicateOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckCmpPredicate")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
<< MatchTable::Comment("Predicate")
- << MatchTable::NamedValue("CmpInst", PredName) << MatchTable::LineBreak;
+ << MatchTable::NamedValue(2, "CmpInst", PredName)
+ << MatchTable::LineBreak;
}
//===- IntrinsicIDOperandMatcher ------------------------------------------===//
@@ -1189,9 +1275,9 @@ void CmpPredicateOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
void IntrinsicIDOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckIntrinsicID")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::NamedValue("Intrinsic::" + II->EnumName)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
+ << MatchTable::NamedValue(2, "Intrinsic::" + II->EnumName)
<< MatchTable::LineBreak;
}
@@ -1200,10 +1286,10 @@ void IntrinsicIDOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
void OperandImmPredicateMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckImmOperandPredicate")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("MO") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("MO") << MatchTable::ULEB128Value(OpIdx)
<< MatchTable::Comment("Predicate")
- << MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
+ << MatchTable::NamedValue(2, getEnumNameForPredicate(Predicate))
<< MatchTable::LineBreak;
}
@@ -1304,9 +1390,9 @@ MatchTableRecord
InstructionOpcodeMatcher::getInstValue(const CodeGenInstruction *I) const {
const auto VI = OpcodeValues.find(I);
if (VI != OpcodeValues.end())
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(),
+ return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName(),
VI->second);
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName());
+ return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName());
}
void InstructionOpcodeMatcher::initOpcodeValuesMap(
@@ -1324,9 +1410,9 @@ MatchTableRecord InstructionOpcodeMatcher::getValue() const {
const CodeGenInstruction *I = Insts[0];
const auto VI = OpcodeValues.find(I);
if (VI != OpcodeValues.end())
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(),
+ return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName(),
VI->second);
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName());
+ return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName());
}
void InstructionOpcodeMatcher::emitPredicateOpcodes(MatchTable &Table,
@@ -1334,7 +1420,7 @@ void InstructionOpcodeMatcher::emitPredicateOpcodes(MatchTable &Table,
StringRef CheckType =
Insts.size() == 1 ? "GIM_CheckOpcode" : "GIM_CheckOpcodeIsEither";
Table << MatchTable::Opcode(CheckType) << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID);
+ << MatchTable::ULEB128Value(InsnVarID);
for (const CodeGenInstruction *I : Insts)
Table << getInstValue(I);
@@ -1381,9 +1467,9 @@ StringRef InstructionOpcodeMatcher::getOperandType(unsigned OpIdx) const {
void InstructionNumOperandsMatcher::emitPredicateOpcodes(
MatchTable &Table, RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckNumOperands")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Expected") << MatchTable::IntValue(NumOperands)
- << MatchTable::LineBreak;
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("Expected")
+ << MatchTable::ULEB128Value(NumOperands) << MatchTable::LineBreak;
}
//===- InstructionImmPredicateMatcher -------------------------------------===//
@@ -1399,9 +1485,9 @@ bool InstructionImmPredicateMatcher::isIdentical(
void InstructionImmPredicateMatcher::emitPredicateOpcodes(
MatchTable &Table, RuleMatcher &Rule) const {
Table << MatchTable::Opcode(getMatchOpcodeForImmPredicate(Predicate))
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
<< MatchTable::Comment("Predicate")
- << MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
+ << MatchTable::NamedValue(2, getEnumNameForPredicate(Predicate))
<< MatchTable::LineBreak;
}
@@ -1425,8 +1511,9 @@ void AtomicOrderingMMOPredicateMatcher::emitPredicateOpcodes(
Opcode = "GIM_CheckAtomicOrderingWeakerThan";
Table << MatchTable::Opcode(Opcode) << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Order")
- << MatchTable::NamedValue(("(int64_t)AtomicOrdering::" + Order).str())
+ << MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Order")
+ << MatchTable::NamedValue(1,
+ ("(uint8_t)AtomicOrdering::" + Order).str())
<< MatchTable::LineBreak;
}
@@ -1435,9 +1522,9 @@ void AtomicOrderingMMOPredicateMatcher::emitPredicateOpcodes(
void MemorySizePredicateMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckMemorySizeEqualTo")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
- << MatchTable::Comment("Size") << MatchTable::IntValue(Size)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)
+ << MatchTable::Comment("Size") << MatchTable::IntValue(4, Size)
<< MatchTable::LineBreak;
}
@@ -1454,14 +1541,14 @@ bool MemoryAddressSpacePredicateMatcher::isIdentical(
void MemoryAddressSpacePredicateMatcher::emitPredicateOpcodes(
MatchTable &Table, RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckMemoryAddressSpace")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
<< MatchTable::Comment("MMO")
- << MatchTable::IntValue(MMOIdx)
+ << MatchTable::ULEB128Value(MMOIdx)
// Encode number of address spaces to expect.
<< MatchTable::Comment("NumAddrSpace")
- << MatchTable::IntValue(AddrSpaces.size());
+ << MatchTable::ULEB128Value(AddrSpaces.size());
for (unsigned AS : AddrSpaces)
- Table << MatchTable::Comment("AddrSpace") << MatchTable::IntValue(AS);
+ Table << MatchTable::Comment("AddrSpace") << MatchTable::ULEB128Value(AS);
Table << MatchTable::LineBreak;
}
@@ -1479,9 +1566,9 @@ bool MemoryAlignmentPredicateMatcher::isIdentical(
void MemoryAlignmentPredicateMatcher::emitPredicateOpcodes(
MatchTable &Table, RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckMemoryAlignment")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
- << MatchTable::Comment("MinAlign") << MatchTable::IntValue(MinAlign)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)
+ << MatchTable::Comment("MinAlign") << MatchTable::ULEB128Value(MinAlign)
<< MatchTable::LineBreak;
}
@@ -1501,9 +1588,9 @@ void MemoryVsLLTSizePredicateMatcher::emitPredicateOpcodes(
Relation == EqualTo ? "GIM_CheckMemorySizeEqualToLLT"
: Relation == GreaterThan ? "GIM_CheckMemorySizeGreaterThanLLT"
: "GIM_CheckMemorySizeLessThanLLT")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
- << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)
+ << MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(OpIdx)
<< MatchTable::LineBreak;
}
@@ -1516,7 +1603,7 @@ void VectorSplatImmPredicateMatcher::emitPredicateOpcodes(
else
Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllZeros");
- Table << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID);
+ Table << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID);
Table << MatchTable::LineBreak;
}
@@ -1536,8 +1623,8 @@ bool GenericInstructionPredicateMatcher::isIdentical(
void GenericInstructionPredicateMatcher::emitPredicateOpcodes(
MatchTable &Table, RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIM_CheckCxxInsnPredicate")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("FnId") << MatchTable::NamedValue(EnumVal)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::Comment("FnId") << MatchTable::NamedValue(2, EnumVal)
<< MatchTable::LineBreak;
}
@@ -1555,8 +1642,9 @@ bool MIFlagsInstructionPredicateMatcher::isIdentical(
void MIFlagsInstructionPredicateMatcher::emitPredicateOpcodes(
MatchTable &Table, RuleMatcher &Rule) const {
Table << MatchTable::Opcode(CheckNot ? "GIM_MIFlagsNot" : "GIM_MIFlags")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::NamedValue(join(Flags, " | ")) << MatchTable::LineBreak;
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
+ << MatchTable::NamedValue(4, join(Flags, " | "))
+ << MatchTable::LineBreak;
}
//===- InstructionMatcher -------------------------------------------------===//
@@ -1700,9 +1788,10 @@ void InstructionOperandMatcher::emitCaptureOpcodes(MatchTable &Table,
const bool IgnoreCopies = Flags & GISF_IgnoreCopies;
Table << MatchTable::Opcode(IgnoreCopies ? "GIM_RecordInsnIgnoreCopies"
: "GIM_RecordInsn")
- << MatchTable::Comment("DefineMI") << MatchTable::IntValue(NewInsnVarID)
- << MatchTable::Comment("MI") << MatchTable::IntValue(getInsnVarID())
- << MatchTable::Comment("OpIdx") << MatchTable::IntValue(getOpIdx())
+ << MatchTable::Comment("DefineMI")
+ << MatchTable::ULEB128Value(NewInsnVarID) << MatchTable::Comment("MI")
+ << MatchTable::ULEB128Value(getInsnVarID())
+ << MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(getOpIdx())
<< MatchTable::Comment("MIs[" + llvm::to_string(NewInsnVarID) + "]")
<< MatchTable::LineBreak;
}
@@ -1732,9 +1821,11 @@ void CopyRenderer::emitRenderOpcodes(MatchTable &Table,
const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
- << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::ULEB128Value(NewInsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::ULEB128Value(OldInsnVarID)
+ << MatchTable::Comment("OpIdx")
+ << MatchTable::ULEB128Value(Operand.getOpIdx())
<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
@@ -1745,9 +1836,11 @@ void CopyPhysRegRenderer::emitRenderOpcodes(MatchTable &Table,
const OperandMatcher &Operand = Rule.getPhysRegOperandMatcher(PhysReg);
unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
- << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::ULEB128Value(NewInsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::ULEB128Value(OldInsnVarID)
+ << MatchTable::Comment("OpIdx")
+ << MatchTable::ULEB128Value(Operand.getOpIdx())
<< MatchTable::Comment(PhysReg->getName()) << MatchTable::LineBreak;
}
@@ -1758,11 +1851,14 @@ void CopyOrAddZeroRegRenderer::emitRenderOpcodes(MatchTable &Table,
const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
Table << MatchTable::Opcode("GIR_CopyOrAddZeroReg")
- << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
+ << MatchTable::Comment("NewInsnID")
+ << MatchTable::ULEB128Value(NewInsnID)
<< MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::ULEB128Value(OldInsnVarID)
+ << MatchTable::Comment("OpIdx")
+ << MatchTable::ULEB128Value(Operand.getOpIdx())
<< MatchTable::NamedValue(
+ 2,
(ZeroRegisterDef->getValue("Namespace")
? ZeroRegisterDef->getValueAsString("Namespace")
: ""),
@@ -1778,9 +1874,10 @@ void CopyConstantAsImmRenderer::emitRenderOpcodes(MatchTable &Table,
unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
Table << MatchTable::Opcode(Signed ? "GIR_CopyConstantAsSImm"
: "GIR_CopyConstantAsUImm")
- << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
+ << MatchTable::Comment("NewInsnID")
+ << MatchTable::ULEB128Value(NewInsnID)
<< MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID)
+ << MatchTable::ULEB128Value(OldInsnVarID)
<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
@@ -1791,9 +1888,10 @@ void CopyFConstantAsFPImmRenderer::emitRenderOpcodes(MatchTable &Table,
InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
Table << MatchTable::Opcode("GIR_CopyFConstantAsFPImm")
- << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
+ << MatchTable::Comment("NewInsnID")
+ << MatchTable::ULEB128Value(NewInsnID)
<< MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID)
+ << MatchTable::ULEB128Value(OldInsnVarID)
<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
@@ -1804,12 +1902,14 @@ void CopySubRegRenderer::emitRenderOpcodes(MatchTable &Table,
const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
Table << MatchTable::Opcode("GIR_CopySubReg")
- << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
+ << MatchTable::Comment("NewInsnID")
+ << MatchTable::ULEB128Value(NewInsnID)
<< MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::ULEB128Value(OldInsnVarID)
+ << MatchTable::Comment("OpIdx")
+ << MatchTable::ULEB128Value(Operand.getOpIdx())
<< MatchTable::Comment("SubRegIdx")
- << MatchTable::IntValue(SubReg->EnumValue)
+ << MatchTable::IntValue(2, SubReg->EnumValue)
<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
@@ -1818,15 +1918,16 @@ void CopySubRegRenderer::emitRenderOpcodes(MatchTable &Table,
void AddRegisterRenderer::emitRenderOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIR_AddRegister")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID);
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID);
if (RegisterDef->getName() != "zero_reg") {
Table << MatchTable::NamedValue(
+ 2,
(RegisterDef->getValue("Namespace")
? RegisterDef->getValueAsString("Namespace")
: ""),
RegisterDef->getName());
} else {
- Table << MatchTable::NamedValue(Target.getRegNamespace(), "NoRegister");
+ Table << MatchTable::NamedValue(2, Target.getRegNamespace(), "NoRegister");
}
Table << MatchTable::Comment("AddRegisterRegFlags");
@@ -1834,9 +1935,9 @@ void AddRegisterRenderer::emitRenderOpcodes(MatchTable &Table,
// really needed for a physical register reference. We can pack the
// register and flags in a single field.
if (IsDef)
- Table << MatchTable::NamedValue("RegState::Define");
+ Table << MatchTable::NamedValue(2, "RegState::Define");
else
- Table << MatchTable::IntValue(0);
+ Table << MatchTable::IntValue(2, 0);
Table << MatchTable::LineBreak;
}
@@ -1844,37 +1945,69 @@ void AddRegisterRenderer::emitRenderOpcodes(MatchTable &Table,
void TempRegRenderer::emitRenderOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
+ const bool NeedsFlags = (SubRegIdx || IsDef);
if (SubRegIdx) {
assert(!IsDef);
Table << MatchTable::Opcode("GIR_AddTempSubRegister");
} else
- Table << MatchTable::Opcode("GIR_AddTempRegister");
+ Table << MatchTable::Opcode(NeedsFlags ? "GIR_AddTempRegister"
+ : "GIR_AddSimpleTempRegister");
- Table << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
- << MatchTable::Comment("TempRegFlags");
+ Table << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
+ << MatchTable::Comment("TempRegID")
+ << MatchTable::ULEB128Value(TempRegID);
+ if (!NeedsFlags) {
+ Table << MatchTable::LineBreak;
+ return;
+ }
+
+ Table << MatchTable::Comment("TempRegFlags");
if (IsDef) {
SmallString<32> RegFlags;
RegFlags += "RegState::Define";
if (IsDead)
RegFlags += "|RegState::Dead";
- Table << MatchTable::NamedValue(RegFlags);
+ Table << MatchTable::NamedValue(2, RegFlags);
} else
- Table << MatchTable::IntValue(0);
+ Table << MatchTable::IntValue(2, 0);
if (SubRegIdx)
- Table << MatchTable::NamedValue(SubRegIdx->getQualifiedName());
+ Table << MatchTable::NamedValue(2, SubRegIdx->getQualifiedName());
Table << MatchTable::LineBreak;
}
+//===- ImmRenderer --------------------------------------------------------===//
+
+void ImmRenderer::emitAddImm(MatchTable &Table, RuleMatcher &RM,
+ unsigned InsnID, int64_t Imm, StringRef ImmName) {
+ const bool IsInt8 = isInt<8>(Imm);
+
+ Table << MatchTable::Opcode(IsInt8 ? "GIR_AddImm8" : "GIR_AddImm")
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
+ << MatchTable::Comment(ImmName)
+ << MatchTable::IntValue(IsInt8 ? 1 : 8, Imm) << MatchTable::LineBreak;
+}
+
+void ImmRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ if (CImmLLT) {
+ assert(Table.isCombiner() &&
+ "ConstantInt immediate are only for combiners!");
+ Table << MatchTable::Opcode("GIR_AddCImm") << MatchTable::Comment("InsnID")
+ << MatchTable::ULEB128Value(InsnID) << MatchTable::Comment("Type")
+ << *CImmLLT << MatchTable::Comment("Imm")
+ << MatchTable::IntValue(8, Imm) << MatchTable::LineBreak;
+ } else
+ emitAddImm(Table, Rule, InsnID, Imm);
+}
+
//===- SubRegIndexRenderer ------------------------------------------------===//
void SubRegIndexRenderer::emitRenderOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
- Table << MatchTable::Opcode("GIR_AddImm") << MatchTable::Comment("InsnID")
- << MatchTable::IntValue(InsnID) << MatchTable::Comment("SubRegIndex")
- << MatchTable::IntValue(SubRegIdx->EnumValue) << MatchTable::LineBreak;
+ ImmRenderer::emitAddImm(Table, Rule, InsnID, SubRegIdx->EnumValue,
+ "SubRegIndex");
}
//===- RenderComplexPatternOperand ----------------------------------------===//
@@ -1885,15 +2018,15 @@ void RenderComplexPatternOperand::emitRenderOpcodes(MatchTable &Table,
SubOperand ? (SubReg ? "GIR_ComplexSubOperandSubRegRenderer"
: "GIR_ComplexSubOperandRenderer")
: "GIR_ComplexRenderer")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
<< MatchTable::Comment("RendererID")
- << MatchTable::IntValue(RendererID);
+ << MatchTable::IntValue(2, RendererID);
if (SubOperand)
Table << MatchTable::Comment("SubOperand")
- << MatchTable::IntValue(*SubOperand);
+ << MatchTable::ULEB128Value(*SubOperand);
if (SubReg)
Table << MatchTable::Comment("SubRegIdx")
- << MatchTable::IntValue(SubReg->EnumValue);
+ << MatchTable::IntValue(2, SubReg->EnumValue);
Table << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
@@ -1904,11 +2037,12 @@ void CustomRenderer::emitRenderOpcodes(MatchTable &Table,
InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
Table << MatchTable::Opcode("GIR_CustomRenderer")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
<< MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("Renderer")
- << MatchTable::NamedValue("GICR_" +
- Renderer.getValueAsString("RendererFn").str())
+ << MatchTable::ULEB128Value(OldInsnVarID)
+ << MatchTable::Comment("Renderer")
+ << MatchTable::NamedValue(
+ 2, "GICR_" + Renderer.getValueAsString("RendererFn").str())
<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
@@ -1918,14 +2052,14 @@ void CustomOperandRenderer::emitRenderOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
const OperandMatcher &OpdMatcher = Rule.getOperandMatcher(SymbolicName);
Table << MatchTable::Opcode("GIR_CustomOperandRenderer")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
<< MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OpdMatcher.getInsnVarID())
+ << MatchTable::ULEB128Value(OpdMatcher.getInsnVarID())
<< MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(OpdMatcher.getOpIdx())
+ << MatchTable::ULEB128Value(OpdMatcher.getOpIdx())
<< MatchTable::Comment("OperandRenderer")
- << MatchTable::NamedValue("GICR_" +
- Renderer.getValueAsString("RendererFn").str())
+ << MatchTable::NamedValue(
+ 2, "GICR_" + Renderer.getValueAsString("RendererFn").str())
<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
@@ -1934,7 +2068,7 @@ void CustomOperandRenderer::emitRenderOpcodes(MatchTable &Table,
void CustomCXXAction::emitActionOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIR_CustomAction")
- << MatchTable::NamedValue(FnEnumName) << MatchTable::LineBreak;
+ << MatchTable::NamedValue(2, FnEnumName) << MatchTable::LineBreak;
}
//===- BuildMIAction ------------------------------------------------------===//
@@ -1977,23 +2111,23 @@ void BuildMIAction::emitActionOpcodes(MatchTable &Table,
const auto AddMIFlags = [&]() {
for (const InstructionMatcher *IM : CopiedFlags) {
Table << MatchTable::Opcode("GIR_CopyMIFlags")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
<< MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(IM->getInsnVarID())
+ << MatchTable::ULEB128Value(IM->getInsnVarID())
<< MatchTable::LineBreak;
}
if (!SetFlags.empty()) {
Table << MatchTable::Opcode("GIR_SetMIFlags")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::NamedValue(join(SetFlags, " | "))
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
+ << MatchTable::NamedValue(4, join(SetFlags, " | "))
<< MatchTable::LineBreak;
}
if (!UnsetFlags.empty()) {
Table << MatchTable::Opcode("GIR_UnsetMIFlags")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::NamedValue(join(UnsetFlags, " | "))
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
+ << MatchTable::NamedValue(4, join(UnsetFlags, " | "))
<< MatchTable::LineBreak;
}
};
@@ -2004,11 +2138,11 @@ void BuildMIAction::emitActionOpcodes(MatchTable &Table,
unsigned RecycleInsnID = Rule.getInsnVarID(*Matched);
Table << MatchTable::Opcode("GIR_MutateOpcode")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
<< MatchTable::Comment("RecycleInsnID")
- << MatchTable::IntValue(RecycleInsnID)
+ << MatchTable::ULEB128Value(RecycleInsnID)
<< MatchTable::Comment("Opcode")
- << MatchTable::NamedValue(I->Namespace, I->TheDef->getName())
+ << MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName())
<< MatchTable::LineBreak;
if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) {
@@ -2018,10 +2152,11 @@ void BuildMIAction::emitActionOpcodes(MatchTable &Table,
: "";
const bool IsDead = DeadImplicitDefs.contains(Def);
Table << MatchTable::Opcode("GIR_AddImplicitDef")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::NamedValue(Namespace, Def->getName())
- << (IsDead ? MatchTable::NamedValue("RegState", "Dead")
- : MatchTable::IntValue(0))
+ << MatchTable::Comment("InsnID")
+ << MatchTable::ULEB128Value(InsnID)
+ << MatchTable::NamedValue(2, Namespace, Def->getName())
+ << (IsDead ? MatchTable::NamedValue(2, "RegState", "Dead")
+ : MatchTable::IntValue(2, 0))
<< MatchTable::LineBreak;
}
for (auto *Use : I->ImplicitUses) {
@@ -2029,8 +2164,9 @@ void BuildMIAction::emitActionOpcodes(MatchTable &Table,
? Use->getValueAsString("Namespace")
: "";
Table << MatchTable::Opcode("GIR_AddImplicitUse")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::NamedValue(Namespace, Use->getName())
+ << MatchTable::Comment("InsnID")
+ << MatchTable::ULEB128Value(InsnID)
+ << MatchTable::NamedValue(2, Namespace, Use->getName())
<< MatchTable::LineBreak;
}
}
@@ -2043,8 +2179,8 @@ void BuildMIAction::emitActionOpcodes(MatchTable &Table,
// mutation due to commutative operations.
Table << MatchTable::Opcode("GIR_BuildMI") << MatchTable::Comment("InsnID")
- << MatchTable::IntValue(InsnID) << MatchTable::Comment("Opcode")
- << MatchTable::NamedValue(I->Namespace, I->TheDef->getName())
+ << MatchTable::ULEB128Value(InsnID) << MatchTable::Comment("Opcode")
+ << MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName())
<< MatchTable::LineBreak;
for (const auto &Renderer : OperandRenderers)
Renderer->emitRenderOpcodes(Table, Rule);
@@ -2055,17 +2191,14 @@ void BuildMIAction::emitActionOpcodes(MatchTable &Table,
if (DeadImplicitDefs.contains(Def)) {
Table
<< MatchTable::Opcode("GIR_SetImplicitDefDead")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
<< MatchTable::Comment(
("OpIdx for " + Namespace + "::" + Def->getName() + "").str())
- << MatchTable::IntValue(OpIdx) << MatchTable::LineBreak;
+ << MatchTable::ULEB128Value(OpIdx) << MatchTable::LineBreak;
}
}
if (I->mayLoad || I->mayStore) {
- Table << MatchTable::Opcode("GIR_MergeMemOperands")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("MergeInsnID's");
// Emit the ID's for all the instructions that are matched by this rule.
// TODO: Limit this to matched instructions that mayLoad/mayStore or have
// some other means of having a memoperand. Also limit this to
@@ -2073,14 +2206,20 @@ void BuildMIAction::emitActionOpcodes(MatchTable &Table,
// example, (G_SEXT (G_LOAD x)) that results in separate load and
// sign-extend instructions shouldn't put the memoperand on the
// sign-extend since it has no effect there.
+
std::vector<unsigned> MergeInsnIDs;
for (const auto &IDMatcherPair : Rule.defined_insn_vars())
MergeInsnIDs.push_back(IDMatcherPair.second);
llvm::sort(MergeInsnIDs);
+
+ Table << MatchTable::Opcode("GIR_MergeMemOperands")
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
+ << MatchTable::Comment("NumInsns")
+ << MatchTable::IntValue(1, MergeInsnIDs.size())
+ << MatchTable::Comment("MergeInsnID's");
for (const auto &MergeInsnID : MergeInsnIDs)
- Table << MatchTable::IntValue(MergeInsnID);
- Table << MatchTable::NamedValue("GIU_MergeMemOperands_EndOfList")
- << MatchTable::LineBreak;
+ Table << MatchTable::ULEB128Value(MergeInsnID);
+ Table << MatchTable::LineBreak;
}
AddMIFlags();
@@ -2097,9 +2236,9 @@ void BuildMIAction::emitActionOpcodes(MatchTable &Table,
void BuildConstantAction::emitActionOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIR_BuildConstant")
- << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
- << MatchTable::Comment("Val") << MatchTable::IntValue(Val)
- << MatchTable::LineBreak;
+ << MatchTable::Comment("TempRegID")
+ << MatchTable::ULEB128Value(TempRegID) << MatchTable::Comment("Val")
+ << MatchTable::IntValue(8, Val) << MatchTable::LineBreak;
}
//===- EraseInstAction ----------------------------------------------------===//
@@ -2111,7 +2250,7 @@ void EraseInstAction::emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule,
return;
Table << MatchTable::Opcode("GIR_EraseFromParent")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
<< MatchTable::LineBreak;
}
@@ -2128,10 +2267,12 @@ void ReplaceRegAction::emitAdditionalPredicates(MatchTable &Table,
return;
Table << MatchTable::Opcode("GIM_CheckCanReplaceReg")
- << MatchTable::Comment("OldInsnID") << MatchTable::IntValue(OldInsnID)
- << MatchTable::Comment("OldOpIdx") << MatchTable::IntValue(OldOpIdx)
- << MatchTable::Comment("NewInsnId") << MatchTable::IntValue(NewInsnId)
- << MatchTable::Comment("NewOpIdx") << MatchTable::IntValue(NewOpIdx)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::ULEB128Value(OldInsnID)
+ << MatchTable::Comment("OldOpIdx") << MatchTable::ULEB128Value(OldOpIdx)
+ << MatchTable::Comment("NewInsnId")
+ << MatchTable::ULEB128Value(NewInsnId)
+ << MatchTable::Comment("NewOpIdx") << MatchTable::ULEB128Value(NewOpIdx)
<< MatchTable::LineBreak;
}
@@ -2139,17 +2280,22 @@ void ReplaceRegAction::emitActionOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
if (TempRegID != (unsigned)-1) {
Table << MatchTable::Opcode("GIR_ReplaceRegWithTempReg")
- << MatchTable::Comment("OldInsnID") << MatchTable::IntValue(OldInsnID)
- << MatchTable::Comment("OldOpIdx") << MatchTable::IntValue(OldOpIdx)
- << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
- << MatchTable::LineBreak;
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::ULEB128Value(OldInsnID)
+ << MatchTable::Comment("OldOpIdx")
+ << MatchTable::ULEB128Value(OldOpIdx)
+ << MatchTable::Comment("TempRegID")
+ << MatchTable::ULEB128Value(TempRegID) << MatchTable::LineBreak;
} else {
Table << MatchTable::Opcode("GIR_ReplaceReg")
- << MatchTable::Comment("OldInsnID") << MatchTable::IntValue(OldInsnID)
- << MatchTable::Comment("OldOpIdx") << MatchTable::IntValue(OldOpIdx)
- << MatchTable::Comment("NewInsnId") << MatchTable::IntValue(NewInsnId)
- << MatchTable::Comment("NewOpIdx") << MatchTable::IntValue(NewOpIdx)
- << MatchTable::LineBreak;
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::ULEB128Value(OldInsnID)
+ << MatchTable::Comment("OldOpIdx")
+ << MatchTable::ULEB128Value(OldOpIdx)
+ << MatchTable::Comment("NewInsnId")
+ << MatchTable::ULEB128Value(NewInsnId)
+ << MatchTable::Comment("NewOpIdx")
+ << MatchTable::ULEB128Value(NewOpIdx) << MatchTable::LineBreak;
}
}
@@ -2158,9 +2304,9 @@ void ReplaceRegAction::emitActionOpcodes(MatchTable &Table,
void ConstrainOperandToRegClassAction::emitActionOpcodes(
MatchTable &Table, RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIR_ConstrainOperandRC")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::NamedValue(RC.getQualifiedIdName())
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
+ << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
+ << MatchTable::NamedValue(2, RC.getQualifiedIdName())
<< MatchTable::LineBreak;
}
@@ -2169,8 +2315,9 @@ void ConstrainOperandToRegClassAction::emitActionOpcodes(
void MakeTempRegisterAction::emitActionOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIR_MakeTempReg")
- << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
- << MatchTable::Comment("TypeID") << Ty << MatchTable::LineBreak;
+ << MatchTable::Comment("TempRegID")
+ << MatchTable::ULEB128Value(TempRegID) << MatchTable::Comment("TypeID")
+ << Ty << MatchTable::LineBreak;
}
} // namespace gi
diff --git a/llvm/utils/TableGen/GlobalISelMatchTable.h b/llvm/utils/TableGen/GlobalISelMatchTable.h
index 469390d73123..7cb5345f51f8 100644
--- a/llvm/utils/TableGen/GlobalISelMatchTable.h
+++ b/llvm/utils/TableGen/GlobalISelMatchTable.h
@@ -59,6 +59,9 @@ using GISelFlags = std::uint16_t;
//===- Helper functions ---------------------------------------------------===//
+void emitEncodingMacrosDef(raw_ostream &OS);
+void emitEncodingMacrosUndef(raw_ostream &OS);
+
std::string getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset,
int HwModeIdx);
@@ -119,6 +122,9 @@ struct MatchTableRecord {
/// Causes the formatter to remove a level of indentation after emitting the
/// record.
MTRF_Outdent = 0x40,
+ /// Causes the formatter to not use encoding macros to emit this multi-byte
+ /// value.
+ MTRF_PreEncoded = 0x80,
};
/// When MTRF_Label or MTRF_JumpTarget is used, indicates a label id to
@@ -194,12 +200,15 @@ public:
static MatchTableRecord LineBreak;
static MatchTableRecord Comment(StringRef Comment);
static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0);
- static MatchTableRecord NamedValue(StringRef NamedValue);
- static MatchTableRecord NamedValue(StringRef NamedValue, int64_t RawValue);
- static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue);
- static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue,
+ static MatchTableRecord NamedValue(unsigned NumBytes, StringRef NamedValue);
+ static MatchTableRecord NamedValue(unsigned NumBytes, StringRef NamedValue,
int64_t RawValue);
- static MatchTableRecord IntValue(int64_t IntValue);
+ static MatchTableRecord NamedValue(unsigned NumBytes, StringRef Namespace,
+ StringRef NamedValue);
+ static MatchTableRecord NamedValue(unsigned NumBytes, StringRef Namespace,
+ StringRef NamedValue, int64_t RawValue);
+ static MatchTableRecord IntValue(unsigned NumBytes, int64_t IntValue);
+ static MatchTableRecord ULEB128Value(uint64_t IntValue);
static MatchTableRecord Label(unsigned LabelID);
static MatchTableRecord JumpTarget(unsigned LabelID);
@@ -301,9 +310,9 @@ private:
inline MatchTable &operator<<(MatchTable &Table,
const LLTCodeGenOrTempType &Ty) {
if (Ty.isLLTCodeGen())
- Table << MatchTable::NamedValue(Ty.getLLTCodeGen().getCxxEnumValue());
+ Table << MatchTable::NamedValue(1, Ty.getLLTCodeGen().getCxxEnumValue());
else
- Table << MatchTable::IntValue(Ty.getTempTypeIdx());
+ Table << MatchTable::IntValue(1, Ty.getTempTypeIdx());
return Table;
}
@@ -1669,7 +1678,7 @@ public:
void emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIM_CheckHasNoUse")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
<< MatchTable::LineBreak;
}
};
@@ -2066,21 +2075,10 @@ public:
return R->getKind() == OR_Imm;
}
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- if (CImmLLT) {
- assert(Table.isCombiner() &&
- "ConstantInt immediate are only for combiners!");
- Table << MatchTable::Opcode("GIR_AddCImm")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("Type") << *CImmLLT
- << MatchTable::Comment("Imm") << MatchTable::IntValue(Imm)
- << MatchTable::LineBreak;
- } else {
- Table << MatchTable::Opcode("GIR_AddImm") << MatchTable::Comment("InsnID")
- << MatchTable::IntValue(InsnID) << MatchTable::Comment("Imm")
- << MatchTable::IntValue(Imm) << MatchTable::LineBreak;
- }
- }
+ static void emitAddImm(MatchTable &Table, RuleMatcher &RM, unsigned InsnID,
+ int64_t Imm, StringRef ImmName = "Imm");
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
};
/// Adds an enum value for a subreg index to the instruction being built.
@@ -2366,7 +2364,7 @@ public:
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIR_ConstrainSelectedInstOperands")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
<< MatchTable::LineBreak;
}
};
diff --git a/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
index c6cd3240a94e..5697899a915a 100644
--- a/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
@@ -164,11 +164,14 @@ void GlobalISelMatchTableExecutorEmitter::emitTypeObjects(
void GlobalISelMatchTableExecutorEmitter::emitMatchTable(
raw_ostream &OS, const MatchTable &Table) {
- OS << "const int64_t *" << getClassName() << "::getMatchTable() const {\n";
+ emitEncodingMacrosDef(OS);
+ OS << "const uint8_t *" << getClassName() << "::getMatchTable() const {\n";
Table.emitDeclaration(OS);
OS << " return ";
Table.emitUse(OS);
OS << ";\n}\n";
+ emitEncodingMacrosUndef(OS);
+ OS << "\n";
}
void GlobalISelMatchTableExecutorEmitter::emitExecutorImpl(
@@ -187,7 +190,9 @@ void GlobalISelMatchTableExecutorEmitter::emitExecutorImpl(
emitCustomOperandRenderers(OS, CustomOperandRenderers);
emitAdditionalImpl(OS);
emitRunCustomAction(OS);
+
emitMatchTable(OS, Table);
+
OS << "#endif // ifdef " << IfDefName << "\n\n";
}
@@ -226,7 +231,7 @@ void GlobalISelMatchTableExecutorEmitter::emitTemporariesDecl(
"const override;\n"
<< " bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat "
"&Imm) const override;\n"
- << " const int64_t *getMatchTable() const override;\n"
+ << " const uint8_t *getMatchTable() const override;\n"
<< " bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI"
", const MatcherState &State) "
"const override;\n"
diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp
index 959e0fda50b8..06e7ec3b9230 100644
--- a/llvm/utils/TableGen/X86DisassemblerTables.cpp
+++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp
@@ -213,6 +213,8 @@ static inline bool inheritsFrom(InstructionContext child,
(WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_OPSIZE)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_OPSIZE));
+ case IC_EVEX_OPSIZE_ADSIZE:
+ return false;
case IC_EVEX_K:
return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_K)) ||
(VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_K)) ||
@@ -885,7 +887,9 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
for (unsigned index = 0; index < ATTR_max; ++index) {
o.indent(i * 2);
- if ((index & ATTR_EVEX) || (index & ATTR_VEX) || (index & ATTR_VEXL)) {
+ if ((index & ATTR_EVEX) && (index & ATTR_OPSIZE) && (index & ATTR_ADSIZE))
+ o << "IC_EVEX_OPSIZE_ADSIZE";
+ else if ((index & ATTR_EVEX) || (index & ATTR_VEX) || (index & ATTR_VEXL)) {
if (index & ATTR_EVEX)
o << "IC_EVEX";
else
@@ -906,7 +910,7 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
else if (index & ATTR_XS)
o << "_XS";
- if ((index & ATTR_EVEX)) {
+ if (index & ATTR_EVEX) {
if (index & ATTR_EVEXKZ)
o << "_KZ";
else if (index & ATTR_EVEXK)
diff --git a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
index 5fb6b048542b..83025205310e 100644
--- a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
+++ b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
@@ -530,26 +530,17 @@ void X86FoldTablesEmitter::addBroadcastEntry(
StringRef MemInstName = MemInst->TheDef->getName();
Record *Domain = RegRec->getValueAsDef("ExeDomain");
bool IsSSEPackedInt = Domain->getName() == "SSEPackedInt";
- // TODO: Rename AVX512 instructions to simplify conditions, e.g.
- // D128 -> DZ128
- // D256 -> DZ256
- // VPERMI2Drr -> VPERMI2DZrr
- // VPERMI2Drmb -> VPERMI2DZrmb
if ((RegInstName.contains("DZ") || RegInstName.contains("DWZ") ||
- RegInstName.contains("D128") || RegInstName.contains("D256") ||
RegInstName.contains("Dr") || RegInstName.contains("I32")) &&
IsSSEPackedInt) {
assert((MemInstName.contains("DZ") || RegInstName.contains("DWZ") ||
- MemInstName.contains("D128") || MemInstName.contains("D256") ||
MemInstName.contains("Dr") || MemInstName.contains("I32")) &&
"Unmatched names for broadcast");
Result.BroadcastKind = X86FoldTableEntry::BCAST_D;
} else if ((RegInstName.contains("QZ") || RegInstName.contains("QBZ") ||
- RegInstName.contains("Q128") || RegInstName.contains("Q256") ||
RegInstName.contains("Qr") || RegInstName.contains("I64")) &&
IsSSEPackedInt) {
assert((MemInstName.contains("QZ") || MemInstName.contains("QBZ") ||
- MemInstName.contains("Q128") || MemInstName.contains("Q256") ||
MemInstName.contains("Qr") || MemInstName.contains("I64")) &&
"Unmatched names for broadcast");
Result.BroadcastKind = X86FoldTableEntry::BCAST_Q;
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index 6e03fc11d6d9..47ee9544f323 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -265,9 +265,12 @@ InstructionContext RecognizableInstr::insnContext() const {
}
}
// No L, no W
- else if (OpPrefix == X86Local::PD)
- insnContext = EVEX_KB(IC_EVEX_OPSIZE);
- else if (OpPrefix == X86Local::XD)
+ else if (OpPrefix == X86Local::PD) {
+ if (AdSize == X86Local::AdSize32)
+ insnContext = IC_EVEX_OPSIZE_ADSIZE;
+ else
+ insnContext = EVEX_KB(IC_EVEX_OPSIZE);
+ } else if (OpPrefix == X86Local::XD)
insnContext = EVEX_KB(IC_EVEX_XD);
else if (OpPrefix == X86Local::XS)
insnContext = EVEX_KB(IC_EVEX_XS);
diff --git a/llvm/utils/split-file/split-file.cpp b/llvm/utils/split-file/split-file.cpp
index 4a92c1be78a2..2ad04d6e42f2 100644
--- a/llvm/utils/split-file/split-file.cpp
+++ b/llvm/utils/split-file/split-file.cpp
@@ -75,9 +75,9 @@ static int handle(MemoryBuffer &inputBuf, StringRef input) {
for (line_iterator i(inputBuf, /*SkipBlanks=*/false, '\0'); !i.is_at_eof();) {
const int64_t lineNo = i.line_number();
const StringRef line = *i++;
- const size_t markerLen = line.startswith("//") ? 6 : 5;
+ const size_t markerLen = line.starts_with("//") ? 6 : 5;
if (!(line.size() >= markerLen &&
- line.substr(markerLen - 4).startswith("--- ")))
+ line.substr(markerLen - 4).starts_with("--- ")))
continue;
separator = line.substr(0, markerLen);
const StringRef partName = line.substr(markerLen);
diff --git a/openmp/runtime/src/kmp.h b/openmp/runtime/src/kmp.h
index d34adf7cbf8a..3dbf8c71c48d 100644
--- a/openmp/runtime/src/kmp.h
+++ b/openmp/runtime/src/kmp.h
@@ -63,7 +63,15 @@
#undef KMP_CANCEL_THREADS
#endif
+// Some WASI targets (e.g., wasm32-wasi-threads) do not support thread
+// cancellation.
+#if KMP_OS_WASI
+#undef KMP_CANCEL_THREADS
+#endif
+
+#if !KMP_OS_WASI
#include <signal.h>
+#endif
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
@@ -124,7 +132,7 @@ class kmp_stats_list;
#endif
#include "kmp_i18n.h"
-#define KMP_HANDLE_SIGNALS (KMP_OS_UNIX || KMP_OS_WINDOWS)
+#define KMP_HANDLE_SIGNALS ((KMP_OS_UNIX && !KMP_OS_WASI) || KMP_OS_WINDOWS)
#include "kmp_wrapper_malloc.h"
#if KMP_OS_UNIX
@@ -601,7 +609,9 @@ typedef int PACKED_REDUCTION_METHOD_T;
#endif
#if KMP_OS_UNIX
+#if !KMP_OS_WASI
#include <dlfcn.h>
+#endif
#include <pthread.h>
#endif
@@ -1340,6 +1350,10 @@ extern kmp_uint64 __kmp_now_nsec();
/* TODO: tune for KMP_OS_SOLARIS */
#define KMP_INIT_WAIT 1024U /* initial number of spin-tests */
#define KMP_NEXT_WAIT 512U /* susequent number of spin-tests */
+#elif KMP_OS_WASI
+/* TODO: tune for KMP_OS_WASI */
+#define KMP_INIT_WAIT 1024U /* initial number of spin-tests */
+#define KMP_NEXT_WAIT 512U /* susequent number of spin-tests */
#endif
#if KMP_ARCH_X86 || KMP_ARCH_X86_64
diff --git a/openmp/runtime/src/kmp_ftn_entry.h b/openmp/runtime/src/kmp_ftn_entry.h
index ad19079cb650..d54c5bfd10fe 100644
--- a/openmp/runtime/src/kmp_ftn_entry.h
+++ b/openmp/runtime/src/kmp_ftn_entry.h
@@ -593,7 +593,7 @@ int FTN_STDCALL KMP_EXPAND_NAME(FTN_GET_THREAD_NUM)(void) {
return 0;
}
--gtid; // We keep (gtid+1) in TLS
-#elif KMP_OS_LINUX
+#elif KMP_OS_LINUX || KMP_OS_WASI
#ifdef KMP_TDATA_GTID
if (__kmp_gtid_mode >= 3) {
if ((gtid = __kmp_gtid) == KMP_GTID_DNE) {
@@ -1043,7 +1043,7 @@ void FTN_STDCALL KMP_EXPAND_NAME(FTN_SET_DEFAULT_DEVICE)(int KMP_DEREF arg) {
int FTN_STDCALL KMP_EXPAND_NAME(FTN_GET_NUM_DEVICES)(void)
KMP_WEAK_ATTRIBUTE_EXTERNAL;
int FTN_STDCALL KMP_EXPAND_NAME(FTN_GET_NUM_DEVICES)(void) {
-#if KMP_MIC || KMP_OS_DARWIN || defined(KMP_STUB)
+#if KMP_MIC || KMP_OS_DARWIN || KMP_OS_WASI || defined(KMP_STUB)
return 0;
#else
int (*fptr)();
@@ -1558,7 +1558,7 @@ typedef void *omp_interop_t;
// libomptarget, if loaded, provides this function
int FTN_STDCALL FTN_GET_NUM_INTEROP_PROPERTIES(const omp_interop_t interop) {
-#if KMP_OS_DARWIN || defined(KMP_STUB)
+#if KMP_OS_DARWIN || KMP_OS_WASI || defined(KMP_STUB)
return 0;
#else
int (*fptr)(const omp_interop_t);
@@ -1573,7 +1573,7 @@ int FTN_STDCALL FTN_GET_NUM_INTEROP_PROPERTIES(const omp_interop_t interop) {
intptr_t FTN_STDCALL FTN_GET_INTEROP_INT(const omp_interop_t interop,
omp_interop_property_t property_id,
int *err) {
-#if KMP_OS_DARWIN || defined(KMP_STUB)
+#if KMP_OS_DARWIN || KMP_OS_WASI || defined(KMP_STUB)
return 0;
#else
intptr_t (*fptr)(const omp_interop_t, omp_interop_property_t, int *);
@@ -1587,7 +1587,7 @@ intptr_t FTN_STDCALL FTN_GET_INTEROP_INT(const omp_interop_t interop,
void *FTN_STDCALL FTN_GET_INTEROP_PTR(const omp_interop_t interop,
omp_interop_property_t property_id,
int *err) {
-#if KMP_OS_DARWIN || defined(KMP_STUB)
+#if KMP_OS_DARWIN || KMP_OS_WASI || defined(KMP_STUB)
return nullptr;
#else
void *(*fptr)(const omp_interop_t, omp_interop_property_t, int *);
@@ -1601,7 +1601,7 @@ void *FTN_STDCALL FTN_GET_INTEROP_PTR(const omp_interop_t interop,
const char *FTN_STDCALL FTN_GET_INTEROP_STR(const omp_interop_t interop,
omp_interop_property_t property_id,
int *err) {
-#if KMP_OS_DARWIN || defined(KMP_STUB)
+#if KMP_OS_DARWIN || KMP_OS_WASI || defined(KMP_STUB)
return nullptr;
#else
const char *(*fptr)(const omp_interop_t, omp_interop_property_t, int *);
@@ -1614,7 +1614,7 @@ const char *FTN_STDCALL FTN_GET_INTEROP_STR(const omp_interop_t interop,
// libomptarget, if loaded, provides this function
const char *FTN_STDCALL FTN_GET_INTEROP_NAME(
const omp_interop_t interop, omp_interop_property_t property_id) {
-#if KMP_OS_DARWIN || defined(KMP_STUB)
+#if KMP_OS_DARWIN || KMP_OS_WASI || defined(KMP_STUB)
return nullptr;
#else
const char *(*fptr)(const omp_interop_t, omp_interop_property_t);
@@ -1627,7 +1627,7 @@ const char *FTN_STDCALL FTN_GET_INTEROP_NAME(
// libomptarget, if loaded, provides this function
const char *FTN_STDCALL FTN_GET_INTEROP_TYPE_DESC(
const omp_interop_t interop, omp_interop_property_t property_id) {
-#if KMP_OS_DARWIN || defined(KMP_STUB)
+#if KMP_OS_DARWIN || KMP_OS_WASI || defined(KMP_STUB)
return nullptr;
#else
const char *(*fptr)(const omp_interop_t, omp_interop_property_t);
@@ -1640,7 +1640,7 @@ const char *FTN_STDCALL FTN_GET_INTEROP_TYPE_DESC(
// libomptarget, if loaded, provides this function
const char *FTN_STDCALL FTN_GET_INTEROP_RC_DESC(
const omp_interop_t interop, omp_interop_property_t property_id) {
-#if KMP_OS_DARWIN || defined(KMP_STUB)
+#if KMP_OS_DARWIN || KMP_OS_WASI || defined(KMP_STUB)
return nullptr;
#else
const char *(*fptr)(const omp_interop_t, omp_interop_property_t);
diff --git a/openmp/runtime/src/kmp_gsupport.cpp b/openmp/runtime/src/kmp_gsupport.cpp
index d77d4809a7e9..78af39533549 100644
--- a/openmp/runtime/src/kmp_gsupport.cpp
+++ b/openmp/runtime/src/kmp_gsupport.cpp
@@ -12,6 +12,7 @@
#include "kmp.h"
#include "kmp_atomic.h"
+#include "kmp_utils.h"
#if OMPT_SUPPORT
#include "ompt-specific.h"
@@ -356,7 +357,7 @@ void KMP_EXPAND_NAME(KMP_API_NAME_GOMP_ORDERED_END)(void) {
// They come in two flavors: 64-bit unsigned, and either 32-bit signed
// (IA-32 architecture) or 64-bit signed (Intel(R) 64).
-#if KMP_ARCH_X86 || KMP_ARCH_ARM || KMP_ARCH_MIPS
+#if KMP_ARCH_X86 || KMP_ARCH_ARM || KMP_ARCH_MIPS || KMP_ARCH_WASM
#define KMP_DISPATCH_INIT __kmp_aux_dispatch_init_4
#define KMP_DISPATCH_FINI_CHUNK __kmp_aux_dispatch_fini_chunk_4
#define KMP_DISPATCH_NEXT __kmpc_dispatch_next_4
@@ -1280,7 +1281,7 @@ void KMP_EXPAND_NAME(KMP_API_NAME_GOMP_TASK)(void (*func)(void *), void *data,
KMP_ASSERT(depend);
kmp_gomp_depends_info_t gomp_depends(depend);
kmp_int32 ndeps = gomp_depends.get_num_deps();
- kmp_depend_info_t dep_list[ndeps];
+ SimpleVLA<kmp_depend_info_t> dep_list(ndeps);
for (kmp_int32 i = 0; i < ndeps; i++)
dep_list[i] = gomp_depends.get_kmp_depend(i);
kmp_int32 ndeps_cnv;
@@ -1309,7 +1310,7 @@ void KMP_EXPAND_NAME(KMP_API_NAME_GOMP_TASK)(void (*func)(void *), void *data,
KMP_ASSERT(depend);
kmp_gomp_depends_info_t gomp_depends(depend);
kmp_int32 ndeps = gomp_depends.get_num_deps();
- kmp_depend_info_t dep_list[ndeps];
+ SimpleVLA<kmp_depend_info_t> dep_list(ndeps);
for (kmp_int32 i = 0; i < ndeps; i++)
dep_list[i] = gomp_depends.get_kmp_depend(i);
__kmpc_omp_wait_deps(&loc, gtid, ndeps, dep_list, 0, NULL);
@@ -1993,7 +1994,7 @@ void KMP_EXPAND_NAME(KMP_API_NAME_GOMP_TASKWAIT_DEPEND)(void **depend) {
KA_TRACE(20, ("GOMP_taskwait_depend: T#%d\n", gtid));
kmp_gomp_depends_info_t gomp_depends(depend);
kmp_int32 ndeps = gomp_depends.get_num_deps();
- kmp_depend_info_t dep_list[ndeps];
+ SimpleVLA<kmp_depend_info_t> dep_list(ndeps);
for (kmp_int32 i = 0; i < ndeps; i++)
dep_list[i] = gomp_depends.get_kmp_depend(i);
#if OMPT_SUPPORT
diff --git a/openmp/runtime/src/kmp_os.h b/openmp/runtime/src/kmp_os.h
index beb8d0197ddf..4ffe9f2d8c95 100644
--- a/openmp/runtime/src/kmp_os.h
+++ b/openmp/runtime/src/kmp_os.h
@@ -75,7 +75,7 @@
#error Unknown compiler
#endif
-#if (KMP_OS_LINUX || KMP_OS_WINDOWS || KMP_OS_FREEBSD)
+#if (KMP_OS_LINUX || KMP_OS_WINDOWS || KMP_OS_FREEBSD) && !KMP_OS_WASI
#define KMP_AFFINITY_SUPPORTED 1
#if KMP_OS_WINDOWS && KMP_ARCH_X86_64
#define KMP_GROUP_AFFINITY 1
@@ -176,7 +176,7 @@ typedef unsigned long long kmp_uint64;
#define KMP_UINT64_SPEC "llu"
#endif /* KMP_OS_UNIX */
-#if KMP_ARCH_X86 || KMP_ARCH_ARM || KMP_ARCH_MIPS
+#if KMP_ARCH_X86 || KMP_ARCH_ARM || KMP_ARCH_MIPS || KMP_ARCH_WASM
#define KMP_SIZE_T_SPEC KMP_UINT32_SPEC
#elif KMP_ARCH_X86_64 || KMP_ARCH_PPC64 || KMP_ARCH_AARCH64 || \
KMP_ARCH_MIPS64 || KMP_ARCH_RISCV64 || KMP_ARCH_LOONGARCH64 || \
@@ -186,7 +186,7 @@ typedef unsigned long long kmp_uint64;
#error "Can't determine size_t printf format specifier."
#endif
-#if KMP_ARCH_X86 || KMP_ARCH_ARM
+#if KMP_ARCH_X86 || KMP_ARCH_ARM || KMP_ARCH_WASM
#define KMP_SIZE_T_MAX (0xFFFFFFFF)
#else
#define KMP_SIZE_T_MAX (0xFFFFFFFFFFFFFFFF)
@@ -215,8 +215,8 @@ typedef kmp_uint32 kmp_uint;
#define KMP_INT_MIN ((kmp_int32)0x80000000)
// stdarg handling
-#if (KMP_ARCH_ARM || KMP_ARCH_X86_64 || KMP_ARCH_AARCH64) && \
- (KMP_OS_FREEBSD || KMP_OS_LINUX)
+#if (KMP_ARCH_ARM || KMP_ARCH_X86_64 || KMP_ARCH_AARCH64 || KMP_ARCH_WASM) && \
+ (KMP_OS_FREEBSD || KMP_OS_LINUX || KMP_OS_WASI)
typedef va_list *kmp_va_list;
#define kmp_va_deref(ap) (*(ap))
#define kmp_va_addr_of(ap) (&(ap))
@@ -1146,7 +1146,7 @@ extern kmp_real64 __kmp_xchg_real64(volatile kmp_real64 *p, kmp_real64 v);
KMP_COMPARE_AND_STORE_REL64((volatile kmp_int64 *)(volatile void *)&(a), \
(kmp_int64)(b), (kmp_int64)(c))
-#if KMP_ARCH_X86 || KMP_ARCH_MIPS
+#if KMP_ARCH_X86 || KMP_ARCH_MIPS || KMP_ARCH_WASM
// What about ARM?
#define TCR_PTR(a) ((void *)TCR_4(a))
#define TCW_PTR(a, b) TCW_4((a), (b))
@@ -1288,6 +1288,9 @@ bool __kmp_atomic_compare_store_rel(std::atomic<T> *p, T expected, T desired) {
extern void *__kmp_lookup_symbol(const char *name, bool next = false);
#define KMP_DLSYM(name) __kmp_lookup_symbol(name)
#define KMP_DLSYM_NEXT(name) __kmp_lookup_symbol(name, true)
+#elif KMP_OS_WASI
+#define KMP_DLSYM(name) nullptr
+#define KMP_DLSYM_NEXT(name) nullptr
#else
#define KMP_DLSYM(name) dlsym(RTLD_DEFAULT, name)
#define KMP_DLSYM_NEXT(name) dlsym(RTLD_NEXT, name)
diff --git a/openmp/runtime/src/kmp_platform.h b/openmp/runtime/src/kmp_platform.h
index b7972c7248dd..45f411b9c219 100644
--- a/openmp/runtime/src/kmp_platform.h
+++ b/openmp/runtime/src/kmp_platform.h
@@ -24,6 +24,7 @@
#define KMP_OS_WINDOWS 0
#define KMP_OS_HURD 0
#define KMP_OS_SOLARIS 0
+#define KMP_OS_WASI 0
#define KMP_OS_UNIX 0 /* disjunction of KMP_OS_LINUX, KMP_OS_DARWIN etc. */
#ifdef _WIN32
@@ -76,14 +77,20 @@
#define KMP_OS_SOLARIS 1
#endif
+#if (defined __wasi__) || (defined __EMSCRIPTEN__)
+#undef KMP_OS_WASI
+#define KMP_OS_WASI 1
+#endif
+
#if (1 != KMP_OS_LINUX + KMP_OS_DRAGONFLY + KMP_OS_FREEBSD + KMP_OS_NETBSD + \
KMP_OS_OPENBSD + KMP_OS_DARWIN + KMP_OS_WINDOWS + KMP_OS_HURD + \
- KMP_OS_SOLARIS)
+ KMP_OS_SOLARIS + KMP_OS_WASI)
#error Unknown OS
#endif
#if KMP_OS_LINUX || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || \
- KMP_OS_OPENBSD || KMP_OS_DARWIN || KMP_OS_HURD || KMP_OS_SOLARIS
+ KMP_OS_OPENBSD || KMP_OS_DARWIN || KMP_OS_HURD || KMP_OS_SOLARIS || \
+ KMP_OS_WASI
#undef KMP_OS_UNIX
#define KMP_OS_UNIX 1
#endif
@@ -196,6 +203,10 @@
#define KMP_ARCH_ARM 1
#endif
+#if defined(__wasm32__)
+#define KMP_ARCH_WASM 1
+#endif
+
#if defined(__MIC__) || defined(__MIC2__)
#define KMP_MIC 1
#if __MIC2__ || __KNC__
@@ -212,7 +223,8 @@
#endif
/* Specify 32 bit architectures here */
-#define KMP_32_BIT_ARCH (KMP_ARCH_X86 || KMP_ARCH_ARM || KMP_ARCH_MIPS)
+#define KMP_32_BIT_ARCH \
+ (KMP_ARCH_X86 || KMP_ARCH_ARM || KMP_ARCH_MIPS || KMP_ARCH_WASM)
// Platforms which support Intel(R) Many Integrated Core Architecture
#define KMP_MIC_SUPPORTED \
@@ -222,7 +234,7 @@
#if (1 != KMP_ARCH_X86 + KMP_ARCH_X86_64 + KMP_ARCH_ARM + KMP_ARCH_PPC64 + \
KMP_ARCH_AARCH64 + KMP_ARCH_MIPS + KMP_ARCH_MIPS64 + \
KMP_ARCH_RISCV64 + KMP_ARCH_LOONGARCH64 + KMP_ARCH_VE + \
- KMP_ARCH_S390X)
+ KMP_ARCH_S390X + KMP_ARCH_WASM)
#error Unknown or unsupported architecture
#endif
diff --git a/openmp/runtime/src/kmp_runtime.cpp b/openmp/runtime/src/kmp_runtime.cpp
index 25136691bc72..4e1074a893a2 100644
--- a/openmp/runtime/src/kmp_runtime.cpp
+++ b/openmp/runtime/src/kmp_runtime.cpp
@@ -24,6 +24,7 @@
#include "kmp_wait_release.h"
#include "kmp_wrapper_getpid.h"
#include "kmp_dispatch.h"
+#include "kmp_utils.h"
#if KMP_USE_HIER_SCHED
#include "kmp_dispatch_hier.h"
#endif
@@ -47,8 +48,9 @@ static char *ProfileTraceFile = nullptr;
#include <process.h>
#endif
-#if KMP_OS_WINDOWS
-// windows does not need include files as it doesn't use shared memory
+#ifndef KMP_USE_SHM
+// Windows and WASI do not need these include files as they don't use shared
+// memory.
#else
#include <sys/mman.h>
#include <sys/stat.h>
@@ -446,26 +448,26 @@ void __kmp_abort_process() {
__kmp_dump_debug_buffer();
}
- if (KMP_OS_WINDOWS) {
- // Let other threads know of abnormal termination and prevent deadlock
- // if abort happened during library initialization or shutdown
- __kmp_global.g.g_abort = SIGABRT;
-
- /* On Windows* OS by default abort() causes pop-up error box, which stalls
- nightly testing. Unfortunately, we cannot reliably suppress pop-up error
- boxes. _set_abort_behavior() works well, but this function is not
- available in VS7 (this is not problem for DLL, but it is a problem for
- static OpenMP RTL). SetErrorMode (and so, timelimit utility) does not
- help, at least in some versions of MS C RTL.
-
- It seems following sequence is the only way to simulate abort() and
- avoid pop-up error box. */
- raise(SIGABRT);
- _exit(3); // Just in case, if signal ignored, exit anyway.
- } else {
- __kmp_unregister_library();
- abort();
- }
+#if KMP_OS_WINDOWS
+ // Let other threads know of abnormal termination and prevent deadlock
+ // if abort happened during library initialization or shutdown
+ __kmp_global.g.g_abort = SIGABRT;
+
+ /* On Windows* OS by default abort() causes pop-up error box, which stalls
+ nightly testing. Unfortunately, we cannot reliably suppress pop-up error
+ boxes. _set_abort_behavior() works well, but this function is not
+ available in VS7 (this is not problem for DLL, but it is a problem for
+ static OpenMP RTL). SetErrorMode (and so, timelimit utility) does not
+ help, at least in some versions of MS C RTL.
+
+ It seems following sequence is the only way to simulate abort() and
+ avoid pop-up error box. */
+ raise(SIGABRT);
+ _exit(3); // Just in case, if signal ignored, exit anyway.
+#else
+ __kmp_unregister_library();
+ abort();
+#endif
__kmp_infinite_loop();
__kmp_release_bootstrap_lock(&__kmp_exit_lock);
@@ -1652,7 +1654,7 @@ __kmp_serial_fork_call(ident_t *loc, int gtid, enum fork_context_e call_context,
/* josh todo: hypothetical question: what do we do for OS X*? */
#if KMP_OS_LINUX && \
(KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
- void *args[argc];
+ SimpleVLA<void *> args(argc);
#else
void **args = (void **)KMP_ALLOCA(argc * sizeof(void *));
#endif /* KMP_OS_LINUX && ( KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || \
@@ -8895,11 +8897,11 @@ __kmp_determine_reduction_method(
#if KMP_ARCH_X86_64 || KMP_ARCH_PPC64 || KMP_ARCH_AARCH64 || \
KMP_ARCH_MIPS64 || KMP_ARCH_RISCV64 || KMP_ARCH_LOONGARCH64 || \
- KMP_ARCH_VE || KMP_ARCH_S390X
+ KMP_ARCH_VE || KMP_ARCH_S390X || KMP_ARCH_WASM
#if KMP_OS_LINUX || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || \
KMP_OS_OPENBSD || KMP_OS_WINDOWS || KMP_OS_DARWIN || KMP_OS_HURD || \
- KMP_OS_SOLARIS
+ KMP_OS_SOLARIS || KMP_OS_WASI
int teamsize_cutoff = 4;
@@ -8924,12 +8926,14 @@ __kmp_determine_reduction_method(
#error "Unknown or unsupported OS"
#endif // KMP_OS_LINUX || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD ||
// KMP_OS_OPENBSD || KMP_OS_WINDOWS || KMP_OS_DARWIN || KMP_OS_HURD ||
- // KMP_OS_SOLARIS
+ // KMP_OS_SOLARIS || KMP_OS_WASI
-#elif KMP_ARCH_X86 || KMP_ARCH_ARM || KMP_ARCH_AARCH || KMP_ARCH_MIPS
+#elif KMP_ARCH_X86 || KMP_ARCH_ARM || KMP_ARCH_AARCH || KMP_ARCH_MIPS || \
+ KMP_ARCH_WASM
#if KMP_OS_LINUX || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || \
- KMP_OS_OPENBSD || KMP_OS_WINDOWS || KMP_OS_HURD || KMP_OS_SOLARIS
+ KMP_OS_OPENBSD || KMP_OS_WINDOWS || KMP_OS_HURD || KMP_OS_SOLARIS || \
+ KMP_OS_WASI
// basic tuning
diff --git a/openmp/runtime/src/kmp_utility.cpp b/openmp/runtime/src/kmp_utility.cpp
index 3174bbb7a5b7..f901eaca92f4 100644
--- a/openmp/runtime/src/kmp_utility.cpp
+++ b/openmp/runtime/src/kmp_utility.cpp
@@ -294,6 +294,8 @@ void __kmp_expand_host_name(char *buffer, size_t size) {
if (!GetComputerNameA(buffer, &s))
KMP_STRCPY_S(buffer, size, unknown);
}
+#elif KMP_OS_WASI
+ KMP_STRCPY_S(buffer, size, unknown);
#else
buffer[size - 2] = 0;
if (gethostname(buffer, size) || buffer[size - 2] != 0)
diff --git a/openmp/runtime/src/kmp_utils.h b/openmp/runtime/src/kmp_utils.h
new file mode 100644
index 000000000000..a557f929e6e7
--- /dev/null
+++ b/openmp/runtime/src/kmp_utils.h
@@ -0,0 +1,55 @@
+/*
+ * kmp_utils.h -- Utilities that used internally
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef __KMP_UTILS_H__
+#define __KMP_UTILS_H__
+
+#include <cstddef>
+
+#include "kmp.h"
+
+/// A simple pure header implementation of VLA that aims to replace uses of
+/// actual VLA, which can cause compile warning. This class by default creates a
+/// stack buffer that can accomodate \p N elements. If the number of elements is
+/// greater than \p N, then a heap buffer will be allocated and used to
+/// accomodate the elements. Similar to the actual VLA, we don't check boundary
+/// (for now), so we will not store the number of elements. We can always revise
+/// it later.
+template <typename T, unsigned N = 8> class SimpleVLA final {
+ T StackBuffer[N];
+ T *HeapBuffer = nullptr;
+ T *Ptr = StackBuffer;
+
+public:
+ SimpleVLA() = delete;
+ SimpleVLA(const SimpleVLA &) = delete;
+ SimpleVLA(SimpleVLA &&) = delete;
+ SimpleVLA &operator=(const SimpleVLA &) = delete;
+ SimpleVLA &operator=(SimpleVLA &&) = delete;
+
+ explicit SimpleVLA(unsigned NumOfElements) noexcept {
+ if (NumOfElements > N) {
+ HeapBuffer =
+ reinterpret_cast<T *>(__kmp_allocate(NumOfElements * sizeof(T)));
+ Ptr = HeapBuffer;
+ }
+ }
+
+ ~SimpleVLA() {
+ if (HeapBuffer)
+ __kmp_free(HeapBuffer);
+ }
+
+ operator T *() noexcept { return Ptr; }
+ operator const T *() const noexcept { return Ptr; }
+};
+
+#endif
diff --git a/openmp/runtime/src/z_Linux_asm.S b/openmp/runtime/src/z_Linux_asm.S
index a72705528d41..14987c298fa5 100644
--- a/openmp/runtime/src/z_Linux_asm.S
+++ b/openmp/runtime/src/z_Linux_asm.S
@@ -2441,7 +2441,27 @@ KMP_PREFIX_UNDERSCORE(__kmp_unnamed_critical_addr):
#if KMP_OS_LINUX
# if KMP_ARCH_ARM || KMP_ARCH_AARCH64
.section .note.GNU-stack,"",%progbits
-# else
+# elif !KMP_ARCH_WASM
.section .note.GNU-stack,"",@progbits
# endif
#endif
+
+#if KMP_ARCH_WASM
+.data
+.global .gomp_critical_user_
+.global .gomp_critical_user_.var
+.global .gomp_critical_user_.reduction.var
+.global __kmp_unnamed_critical_addr
+.gomp_critical_user_:
+.zero 4
+.size .gomp_critical_user_, 4
+.gomp_critical_user_.var:
+.zero 4
+.size .gomp_critical_user_.var, 4
+.gomp_critical_user_.reduction.var:
+.zero 4
+.size .gomp_critical_user_.reduction.var, 4
+__kmp_unnamed_critical_addr:
+ .4byte .gomp_critical_user_
+ .size __kmp_unnamed_critical_addr, 4
+#endif
diff --git a/openmp/runtime/src/z_Linux_util.cpp b/openmp/runtime/src/z_Linux_util.cpp
index 72da0f79865d..c2df8895e887 100644
--- a/openmp/runtime/src/z_Linux_util.cpp
+++ b/openmp/runtime/src/z_Linux_util.cpp
@@ -72,7 +72,7 @@ struct kmp_sys_timer {
struct timespec start;
};
-#if KMP_OS_SOLARIS
+#ifndef TIMEVAL_TO_TIMESPEC
// Convert timeval to timespec.
#define TIMEVAL_TO_TIMESPEC(tv, ts) \
do { \
@@ -277,7 +277,7 @@ int __kmp_futex_determine_capable() {
#endif // KMP_USE_FUTEX
-#if (KMP_ARCH_X86 || KMP_ARCH_X86_64) && (!KMP_ASM_INTRINS)
+#if (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_WASM) && (!KMP_ASM_INTRINS)
/* Only 32-bit "add-exchange" instruction on IA-32 architecture causes us to
use compare_and_store for these routines */
@@ -337,7 +337,7 @@ kmp_uint32 __kmp_test_then_and32(volatile kmp_uint32 *p, kmp_uint32 d) {
return old_value;
}
-#if KMP_ARCH_X86
+#if KMP_ARCH_X86 || KMP_ARCH_WASM
kmp_int8 __kmp_test_then_add8(volatile kmp_int8 *p, kmp_int8 d) {
kmp_int8 old_value, new_value;
@@ -985,7 +985,11 @@ retry:
#endif // KMP_USE_MONITOR
void __kmp_exit_thread(int exit_status) {
+#if KMP_OS_WASI
+// TODO: the wasm32-wasi-threads target does not yet support pthread_exit.
+#else
pthread_exit((void *)(intptr_t)exit_status);
+#endif
} // __kmp_exit_thread
#if KMP_USE_MONITOR
@@ -1330,9 +1334,11 @@ static void __kmp_atfork_child(void) {
void __kmp_register_atfork(void) {
if (__kmp_need_register_atfork) {
+#if !KMP_OS_WASI
int status = pthread_atfork(__kmp_atfork_prepare, __kmp_atfork_parent,
__kmp_atfork_child);
KMP_CHECK_SYSFAIL("pthread_atfork", status);
+#endif
__kmp_need_register_atfork = FALSE;
}
}
@@ -1774,6 +1780,7 @@ int __kmp_read_system_info(struct kmp_sys_info *info) {
status = getrusage(RUSAGE_SELF, &r_usage);
KMP_CHECK_SYSFAIL_ERRNO("getrusage", status);
+#if !KMP_OS_WASI
// The maximum resident set size utilized (in kilobytes)
info->maxrss = r_usage.ru_maxrss;
// The number of page faults serviced without any I/O
@@ -1790,6 +1797,7 @@ int __kmp_read_system_info(struct kmp_sys_info *info) {
info->nvcsw = r_usage.ru_nvcsw;
// The number of times a context switch was forced
info->nivcsw = r_usage.ru_nivcsw;
+#endif
return (status != 0);
}
@@ -1824,7 +1832,7 @@ static int __kmp_get_xproc(void) {
__kmp_type_convert(sysconf(_SC_NPROCESSORS_CONF), &(r));
#elif KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_OPENBSD || \
- KMP_OS_HURD || KMP_OS_SOLARIS
+ KMP_OS_HURD || KMP_OS_SOLARIS || KMP_OS_WASI
__kmp_type_convert(sysconf(_SC_NPROCESSORS_ONLN), &(r));
@@ -2200,6 +2208,8 @@ int __kmp_is_address_mapped(void *addr) {
}
kiv.kve_start += 1;
}
+#elif KMP_OS_WASI
+ found = (int)addr < (__builtin_wasm_memory_size(0) * PAGESIZE);
#elif KMP_OS_DRAGONFLY || KMP_OS_SOLARIS
// FIXME(DragonFly, Solaris): Implement this