aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-27 19:50:45 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-27 19:50:54 +0000
commit08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (patch)
tree041e72e32710b1e742516d8c9f1575bf0116d3e3
parent4b4fe385e49bd883fd183b5f21c1ea486c722e61 (diff)
downloadsrc-08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014.tar.gz
src-08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014.zip
-rw-r--r--clang/include/clang/Analysis/CFG.h3
-rw-r--r--clang/include/clang/Analysis/ConstructionContext.h72
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h4
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h15
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/MapLattice.h9
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/Transfer.h9
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h11
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/Value.h59
-rw-r--r--clang/include/clang/Basic/AttrDocs.td6
-rw-r--r--clang/include/clang/Basic/DiagnosticIDs.h24
-rw-r--r--clang/include/clang/Basic/DiagnosticParseKinds.td6
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td8
-rw-r--r--clang/include/clang/Basic/LangOptions.def1
-rw-r--r--clang/include/clang/Basic/TokenKinds.def3
-rw-r--r--clang/include/clang/Basic/riscv_vector.td103
-rw-r--r--clang/include/clang/CodeGen/ModuleBuilder.h8
-rw-r--r--clang/include/clang/Driver/Driver.h2
-rw-r--r--clang/include/clang/Driver/Options.td4
-rw-r--r--clang/include/clang/Frontend/Utils.h4
-rw-r--r--clang/include/clang/Lex/PreprocessingRecord.h1
-rw-r--r--clang/include/clang/Lex/Preprocessor.h1
-rw-r--r--clang/include/clang/Parse/Parser.h3
-rw-r--r--clang/include/clang/Sema/Overload.h4
-rw-r--r--clang/include/clang/Sema/RISCVIntrinsicManager.h36
-rw-r--r--clang/include/clang/Sema/Scope.h38
-rw-r--r--clang/include/clang/Sema/Sema.h14
-rw-r--r--clang/include/clang/Sema/Template.h34
-rw-r--r--clang/include/clang/Serialization/ASTWriter.h4
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h2
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h19
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h2
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h1
-rw-r--r--clang/include/clang/Support/RISCVVIntrinsicUtils.h100
-rw-r--r--clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h2
-rw-r--r--clang/include/clang/Tooling/Refactoring/RefactoringActionRules.h4
-rw-r--r--clang/include/clang/Tooling/Refactoring/RefactoringOptions.h4
-rw-r--r--clang/lib/AST/ASTImporter.cpp52
-rw-r--r--clang/lib/AST/Decl.cpp14
-rw-r--r--clang/lib/AST/ExprConstant.cpp10
-rw-r--r--clang/lib/Analysis/CFG.cpp45
-rw-r--r--clang/lib/Analysis/ConstructionContext.cpp11
-rw-r--r--clang/lib/Analysis/ExprMutationAnalyzer.cpp18
-rw-r--r--clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp71
-rw-r--r--clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp48
-rw-r--r--clang/lib/Analysis/FlowSensitive/DebugSupport.cpp14
-rw-r--r--clang/lib/Analysis/FlowSensitive/Transfer.cpp48
-rw-r--r--clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp20
-rw-r--r--clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp110
-rw-r--r--clang/lib/Analysis/LiveVariables.cpp27
-rw-r--r--clang/lib/Basic/Targets/CSKY.h2
-rw-r--r--clang/lib/Basic/Targets/PPC.cpp3
-rw-r--r--clang/lib/Basic/Targets/X86.h4
-rw-r--r--clang/lib/CodeGen/ABIInfo.h2
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h2
-rw-r--r--clang/lib/CodeGen/CGCall.cpp19
-rw-r--r--clang/lib/CodeGen/CGClass.cpp14
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.cpp8
-rw-r--r--clang/lib/CodeGen/CGObjCGNU.cpp12
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntimeGPU.h23
-rw-r--r--clang/lib/CodeGen/CodeGenAction.cpp25
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp39
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h11
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp6
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp2
-rw-r--r--clang/lib/CodeGen/ModuleBuilder.cpp24
-rw-r--r--clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp4
-rw-r--r--clang/lib/CodeGen/SanitizerMetadata.h1
-rw-r--r--clang/lib/Driver/ToolChains/Arch/ARM.cpp5
-rw-r--r--clang/lib/Driver/ToolChains/Arch/PPC.cpp4
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp7
-rw-r--r--clang/lib/Driver/ToolChains/FreeBSD.cpp6
-rw-r--r--clang/lib/Edit/EditedSource.cpp4
-rw-r--r--clang/lib/Format/FormatTokenLexer.cpp159
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp6
-rw-r--r--clang/lib/Headers/stdatomic.h3
-rw-r--r--clang/lib/Interpreter/IncrementalExecutor.h1
-rw-r--r--clang/lib/Parse/ParseDecl.cpp36
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp594
-rw-r--r--clang/lib/Parse/ParsePragma.cpp52
-rw-r--r--clang/lib/Parse/Parser.cpp4
-rw-r--r--clang/lib/Sema/Scope.cpp82
-rw-r--r--clang/lib/Sema/Sema.cpp7
-rw-r--r--clang/lib/Sema/SemaDecl.cpp20
-rw-r--r--clang/lib/Sema/SemaExpr.cpp37
-rw-r--r--clang/lib/Sema/SemaLookup.cpp45
-rw-r--r--clang/lib/Sema/SemaOverload.cpp26
-rw-r--r--clang/lib/Sema/SemaRISCVVectorLookup.cpp395
-rw-r--r--clang/lib/Sema/SemaStmt.cpp10
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp55
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp3
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp100
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp11
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp20
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp26
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp23
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp91
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp124
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp28
-rw-r--r--clang/lib/StaticAnalyzer/Core/RegionStore.cpp69
-rw-r--r--clang/lib/Support/RISCVVIntrinsicUtils.cpp88
-rw-r--r--clang/utils/TableGen/RISCVVEmitter.cpp417
-rw-r--r--clang/utils/TableGen/TableGen.cpp6
-rw-r--r--clang/utils/TableGen/TableGenBackends.h1
-rw-r--r--compiler-rt/lib/builtins/int_types.h2
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_common.h5
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_win.cpp11
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_flags.inc4
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_platform.h1
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.cpp63
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.h40
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl_access.cpp9
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp44
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_shadow.h10
-rw-r--r--libcxx/include/__algorithm/copy.h16
-rw-r--r--libcxx/include/__algorithm/copy_backward.h42
-rw-r--r--libcxx/include/__algorithm/equal_range.h1
-rw-r--r--libcxx/include/__algorithm/includes.h19
-rw-r--r--libcxx/include/__algorithm/inplace_merge.h4
-rw-r--r--libcxx/include/__algorithm/is_heap.h2
-rw-r--r--libcxx/include/__algorithm/is_heap_until.h4
-rw-r--r--libcxx/include/__algorithm/ranges_copy_backward.h7
-rw-r--r--libcxx/include/__algorithm/ranges_generate.h24
-rw-r--r--libcxx/include/__algorithm/ranges_generate_n.h14
-rw-r--r--libcxx/include/__algorithm/ranges_includes.h8
-rw-r--r--libcxx/include/__algorithm/ranges_is_heap.h23
-rw-r--r--libcxx/include/__algorithm/ranges_is_heap_until.h20
-rw-r--r--libcxx/include/__assert6
-rw-r--r--libcxx/include/__concepts/arithmetic.h2
-rw-r--r--libcxx/include/__format/formatter_integer.h1
-rw-r--r--libcxx/include/__functional/invoke.h11
-rw-r--r--libcxx/include/__hash_table1
-rw-r--r--libcxx/include/__iterator/incrementable_traits.h1
-rw-r--r--libcxx/include/__iterator/iterator_traits.h6
-rw-r--r--libcxx/include/__iterator/reverse_iterator.h184
-rw-r--r--libcxx/include/__memory/swap_allocator.h53
-rw-r--r--libcxx/include/__memory/temporary_buffer.h1
-rw-r--r--libcxx/include/__memory/uninitialized_algorithms.h144
-rw-r--r--libcxx/include/__split_buffer1
-rw-r--r--libcxx/include/__tree1
-rw-r--r--libcxx/include/__type_traits/aligned_storage.h142
-rw-r--r--libcxx/include/__type_traits/aligned_union.h55
-rw-r--r--libcxx/include/__type_traits/common_reference.h188
-rw-r--r--libcxx/include/__type_traits/common_type.h138
-rw-r--r--libcxx/include/__type_traits/copy_cv.h54
-rw-r--r--libcxx/include/__type_traits/copy_cvref.h46
-rw-r--r--libcxx/include/__type_traits/is_nothrow_convertible.h53
-rw-r--r--libcxx/include/__type_traits/is_primary_template.h34
-rw-r--r--libcxx/include/__type_traits/is_signed_integer.h33
-rw-r--r--libcxx/include/__type_traits/is_unsigned_integer.h33
-rw-r--r--libcxx/include/__type_traits/is_valid_expansion.h31
-rw-r--r--libcxx/include/__type_traits/lazy.h25
-rw-r--r--libcxx/include/__type_traits/make_32_64_or_128_bit.h48
-rw-r--r--libcxx/include/__type_traits/make_signed.h76
-rw-r--r--libcxx/include/__type_traits/make_unsigned.h89
-rw-r--r--libcxx/include/__type_traits/nat.h32
-rw-r--r--libcxx/include/__type_traits/promote.h95
-rw-r--r--libcxx/include/__type_traits/remove_cvref.h41
-rw-r--r--libcxx/include/__type_traits/type_list.h44
-rw-r--r--libcxx/include/__utility/transaction.h5
-rw-r--r--libcxx/include/algorithm33
-rw-r--r--libcxx/include/charconv1
-rw-r--r--libcxx/include/forward_list1
-rw-r--r--libcxx/include/list1
-rw-r--r--libcxx/include/math.h1
-rw-r--r--libcxx/include/memory118
-rw-r--r--libcxx/include/module.modulemap.in20
-rw-r--r--libcxx/include/string1
-rw-r--r--libcxx/include/type_traits787
-rw-r--r--libcxx/include/vector19
-rw-r--r--libcxx/src/assert.cpp47
-rw-r--r--lld/ELF/Driver.cpp15
-rw-r--r--lld/ELF/DriverUtils.cpp20
-rw-r--r--lld/ELF/InputFiles.cpp4
-rw-r--r--lld/ELF/LinkerScript.cpp12
-rw-r--r--lld/ELF/Options.td14
-rw-r--r--lld/ELF/ScriptParser.cpp7
-rw-r--r--lld/ELF/SyntheticSections.cpp12
-rw-r--r--lld/ELF/Writer.cpp30
-rw-r--r--lld/MachO/Driver.cpp20
-rw-r--r--lld/MachO/DriverUtils.cpp1
-rw-r--r--lld/MachO/InputFiles.cpp60
-rw-r--r--lld/MachO/InputFiles.h12
-rw-r--r--lld/MachO/InputSection.cpp2
-rw-r--r--lld/MachO/Options.td10
-rw-r--r--lld/MachO/SyntheticSections.h6
-rw-r--r--lldb/include/lldb/Core/Disassembler.h8
-rw-r--r--lldb/include/lldb/Target/MemoryTagManager.h15
-rw-r--r--lldb/include/lldb/Target/Process.h4
-rw-r--r--lldb/include/lldb/Target/TraceCursor.h36
-rw-r--r--lldb/include/lldb/Target/TraceDumper.h7
-rw-r--r--lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h4
-rw-r--r--lldb/include/lldb/lldb-enumerations.h8
-rw-r--r--lldb/source/Commands/CommandObjectDisassemble.cpp3
-rw-r--r--lldb/source/Commands/CommandObjectExpression.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectMemory.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp2
-rw-r--r--lldb/source/Commands/Options.td10
-rw-r--r--lldb/source/Core/Disassembler.cpp385
-rw-r--r--lldb/source/Host/common/Host.cpp2
-rw-r--r--lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp331
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp10
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp5
-rw-r--r--lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp4
-rw-r--r--lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp85
-rw-r--r--lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h7
-rw-r--r--lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp4
-rw-r--r--lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp65
-rw-r--r--lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h6
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/ThreadMemory.cpp3
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp72
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.h14
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp18
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h2
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp68
-rw-r--r--lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp3
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp2
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp198
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/DecodedThread.h180
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp57
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h10
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp19
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h6
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp89
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h46
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp50
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h9
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp26
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h6
-rw-r--r--lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp2
-rw-r--r--lldb/source/Symbol/Type.cpp4
-rw-r--r--lldb/source/Target/Process.cpp15
-rw-r--r--lldb/source/Target/RegisterContextUnwind.cpp4
-rw-r--r--lldb/source/Target/StackFrame.cpp42
-rw-r--r--lldb/source/Target/ThreadPlanCallFunction.cpp10
-rw-r--r--lldb/source/Target/ThreadPlanTracer.cpp4
-rw-r--r--lldb/source/Target/TraceCursor.cpp2
-rw-r--r--lldb/source/Target/TraceDumper.cpp58
-rw-r--r--llvm/include/llvm/ADT/DenseMap.h2
-rw-r--r--llvm/include/llvm/ADT/Optional.h7
-rw-r--r--llvm/include/llvm/Analysis/DDG.h23
-rw-r--r--llvm/include/llvm/Analysis/MemoryBuiltins.h1
-rw-r--r--llvm/include/llvm/Analysis/TargetTransformInfo.h1
-rw-r--r--llvm/include/llvm/BinaryFormat/ELF.h22
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h4
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h2
-rw-r--r--llvm/include/llvm/CodeGen/LiveIntervals.h1
-rw-r--r--llvm/include/llvm/CodeGen/SelectionDAGNodes.h6
-rw-r--r--llvm/include/llvm/CodeGen/TargetInstrInfo.h1
-rw-r--r--llvm/include/llvm/DWARFLinker/DWARFLinker.h2
-rw-r--r--llvm/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h11
-rw-r--r--llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h23
-rw-r--r--llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h6
-rw-r--r--llvm/include/llvm/IR/Instructions.h2
-rw-r--r--llvm/include/llvm/IR/IntrinsicInst.h11
-rw-r--r--llvm/include/llvm/IR/Intrinsics.td6
-rw-r--r--llvm/include/llvm/IR/ModuleSummaryIndex.h6
-rw-r--r--llvm/include/llvm/IR/PrintPasses.h15
-rw-r--r--llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h4
-rw-r--r--llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h23
-rw-r--r--llvm/include/llvm/Passes/StandardInstrumentations.h10
-rw-r--r--llvm/include/llvm/ProfileData/SampleProfReader.h37
-rw-r--r--llvm/include/llvm/ProfileData/SampleProfWriter.h45
-rw-r--r--llvm/include/llvm/Support/BinaryByteStream.h4
-rw-r--r--llvm/include/llvm/Support/DXILOperationCommon.h63
-rw-r--r--llvm/include/llvm/Support/Error.h2
-rw-r--r--llvm/include/llvm/Support/MathExtras.h6
-rw-r--r--llvm/include/llvm/Support/raw_ostream.h4
-rw-r--r--llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td2
-rw-r--r--llvm/include/llvm/Transforms/IPO.h2
-rw-r--r--llvm/include/llvm/Transforms/IPO/Attributor.h2
-rw-r--r--llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h4
-rw-r--r--llvm/include/llvm/Transforms/Utils/MatrixUtils.h47
-rw-r--r--llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h6
-rw-r--r--llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h2
-rw-r--r--llvm/lib/Analysis/CodeMetrics.cpp3
-rw-r--r--llvm/lib/Analysis/InlineCost.cpp4
-rw-r--r--llvm/lib/Analysis/InstructionSimplify.cpp12
-rw-r--r--llvm/lib/Analysis/LoopAccessAnalysis.cpp4
-rw-r--r--llvm/lib/Analysis/MemoryBuiltins.cpp7
-rw-r--r--llvm/lib/Analysis/ModuleSummaryAnalysis.cpp3
-rw-r--r--llvm/lib/Analysis/PHITransAddr.cpp17
-rw-r--r--llvm/lib/Analysis/ScalarEvolution.cpp26
-rw-r--r--llvm/lib/Analysis/TypeMetadataUtils.cpp4
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp43
-rw-r--r--llvm/lib/Bitcode/Reader/BitcodeReader.cpp2
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp7
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/WasmException.h2
-rw-r--r--llvm/lib/CodeGen/AtomicExpandPass.cpp7
-rw-r--r--llvm/lib/CodeGen/CodeGenPrepare.cpp4
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp3
-rw-r--r--llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp10
-rw-r--r--llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp5
-rw-r--r--llvm/lib/CodeGen/LiveRangeEdit.cpp16
-rw-r--r--llvm/lib/CodeGen/MachineFunctionPass.cpp29
-rw-r--r--llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp7
-rw-r--r--llvm/lib/CodeGen/ProcessImplicitDefs.cpp2
-rw-r--r--llvm/lib/CodeGen/RegAllocGreedy.cpp19
-rw-r--r--llvm/lib/CodeGen/RegAllocGreedy.h2
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp90
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp41
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h2
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp17
-rw-r--r--llvm/lib/DWARFLinker/DWARFLinker.cpp53
-rw-r--r--llvm/lib/DWP/DWP.cpp7
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp124
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h10
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp179
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/SEHFrameSupport.h61
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/x86_64.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp38
-rw-r--r--llvm/lib/FileCheck/FileCheck.cpp2
-rw-r--r--llvm/lib/IR/Instructions.cpp4
-rw-r--r--llvm/lib/IR/IntrinsicInst.cpp33
-rw-r--r--llvm/lib/IR/ModuleSummaryIndex.cpp8
-rw-r--r--llvm/lib/IR/PrintPasses.cpp44
-rw-r--r--llvm/lib/LTO/LTO.cpp4
-rw-r--r--llvm/lib/LTO/LTOBackend.cpp3
-rw-r--r--llvm/lib/LTO/LTOCodeGenerator.cpp12
-rw-r--r--llvm/lib/LTO/ThinLTOCodeGenerator.cpp6
-rw-r--r--llvm/lib/MC/ELFObjectWriter.cpp5
-rw-r--r--llvm/lib/MC/MCDisassembler/MCDisassembler.cpp5
-rw-r--r--llvm/lib/MC/XCOFFObjectWriter.cpp2
-rw-r--r--llvm/lib/ObjCopy/ELF/ELFObject.cpp52
-rw-r--r--llvm/lib/ObjCopy/ELF/ELFObject.h14
-rw-r--r--llvm/lib/ObjectYAML/ELFYAML.cpp8
-rw-r--r--llvm/lib/Passes/PassBuilderPipelines.cpp3
-rw-r--r--llvm/lib/Passes/StandardInstrumentations.cpp58
-rw-r--r--llvm/lib/Support/ARMAttributeParser.cpp2
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.cpp144
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.td6
-rw-r--r--llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td32
-rw-r--r--llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp8
-rw-r--r--llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h3
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64O0PreLegalizerCombiner.cpp4
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp4
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp4
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp4
-rw-r--r--llvm/lib/Target/AArch64/SVEInstrFormats.td12
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp212
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUMIRFormatter.h2
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUPreLegalizerCombiner.cpp4
-rw-r--r--llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp826
-rw-r--r--llvm/lib/Target/AMDGPU/GCNSchedStrategy.h233
-rw-r--r--llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp16
-rw-r--r--llvm/lib/Target/AMDGPU/R600ISelLowering.h4
-rw-r--r--llvm/lib/Target/AMDGPU/SIISelLowering.cpp6
-rw-r--r--llvm/lib/Target/AMDGPU/SIISelLowering.h8
-rw-r--r--llvm/lib/Target/AMDGPU/SIRegisterInfo.td56
-rw-r--r--llvm/lib/Target/AMDGPU/VOPCInstructions.td2
-rw-r--r--llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp30
-rw-r--r--llvm/lib/Target/DirectX/DXILOpBuilder.cpp324
-rw-r--r--llvm/lib/Target/DirectX/DXILOpBuilder.h46
-rw-r--r--llvm/lib/Target/DirectX/DXILOpLowering.cpp167
-rw-r--r--llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp4
-rw-r--r--llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h1
-rw-r--r--llvm/lib/Target/Hexagon/HexagonISelLowering.h3
-rw-r--r--llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp46
-rw-r--r--llvm/lib/Target/Hexagon/HexagonInstrInfo.h4
-rw-r--r--llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp2
-rw-r--r--llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArch.h2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchFrameLowering.h2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchISelLowering.h2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchRegisterInfo.h2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchSubtarget.h2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp2
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h2
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp4
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h4
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp2
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.h2
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.h2
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp2
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp2
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.h2
-rw-r--r--llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.h4
-rw-r--r--llvm/lib/Target/LoongArch/TargetInfo/LoongArchTargetInfo.h2
-rw-r--r--llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp4
-rw-r--r--llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp15
-rw-r--r--llvm/lib/Target/RISCV/RISCVISelLowering.cpp53
-rw-r--r--llvm/lib/Target/RISCV/RISCVISelLowering.h1
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfo.h21
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfoC.td56
-rw-r--r--llvm/lib/Target/RISCV/RISCVTargetMachine.h3
-rw-r--r--llvm/lib/Target/SystemZ/SystemZRegisterInfo.h34
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp30
-rw-r--r--llvm/lib/Target/X86/X86ISelLowering.cpp84
-rw-r--r--llvm/lib/Target/X86/X86ISelLowering.h2
-rw-r--r--llvm/lib/Target/X86/X86InstrInfo.h2
-rw-r--r--llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp55
-rw-r--r--llvm/lib/Transforms/IPO/ArgumentPromotion.cpp6
-rw-r--r--llvm/lib/Transforms/IPO/AttributorAttributes.cpp28
-rw-r--r--llvm/lib/Transforms/IPO/FunctionAttrs.cpp61
-rw-r--r--llvm/lib/Transforms/IPO/GlobalOpt.cpp3
-rw-r--r--llvm/lib/Transforms/IPO/LowerTypeTests.cpp61
-rw-r--r--llvm/lib/Transforms/IPO/OpenMPOpt.cpp12
-rw-r--r--llvm/lib/Transforms/IPO/SCCP.cpp2
-rw-r--r--llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp8
-rw-r--r--llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp35
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineInternal.h7
-rw-r--r--llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp4
-rw-r--r--llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp8
-rw-r--r--llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp25
-rw-r--r--llvm/lib/Transforms/Scalar/Reassociate.cpp24
-rw-r--r--llvm/lib/Transforms/Utils/InlineFunction.cpp59
-rw-r--r--llvm/lib/Transforms/Utils/MatrixUtils.cpp42
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp137
-rw-r--r--llvm/lib/Transforms/Vectorize/LoopVectorize.cpp9
-rw-r--r--llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp4
-rw-r--r--llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp49
-rw-r--r--llvm/tools/llvm-dwarfutil/DebugInfoLinker.h4
-rw-r--r--llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp22
-rw-r--r--llvm/tools/llvm-lto/llvm-lto.cpp7
-rw-r--r--llvm/tools/llvm-mca/CodeRegionGenerator.cpp4
-rw-r--r--llvm/tools/llvm-objcopy/ObjcopyOptions.cpp27
-rw-r--r--llvm/tools/llvm-objcopy/ObjcopyOpts.td11
-rw-r--r--llvm/tools/llvm-objdump/llvm-objdump.cpp152
-rw-r--r--llvm/tools/llvm-profdata/llvm-profdata.cpp3
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp15
-rw-r--r--llvm/tools/llvm-xray/xray-graph.cpp9
-rw-r--r--llvm/utils/TableGen/DXILEmitter.cpp107
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h6
428 files changed, 9643 insertions, 4688 deletions
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index d8e7e1e43d81..4f16a6361950 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -202,7 +202,8 @@ public:
isa<ReturnedValueConstructionContext>(C) ||
isa<VariableConstructionContext>(C) ||
isa<ConstructorInitializerConstructionContext>(C) ||
- isa<ArgumentConstructionContext>(C)));
+ isa<ArgumentConstructionContext>(C) ||
+ isa<LambdaCaptureConstructionContext>(C)));
Data2.setPointer(const_cast<ConstructionContext *>(C));
}
diff --git a/clang/include/clang/Analysis/ConstructionContext.h b/clang/include/clang/Analysis/ConstructionContext.h
index a437160e0778..67a091199b91 100644
--- a/clang/include/clang/Analysis/ConstructionContext.h
+++ b/clang/include/clang/Analysis/ConstructionContext.h
@@ -36,13 +36,14 @@ public:
ElidedDestructorKind,
ElidableConstructorKind,
ArgumentKind,
- STATEMENT_WITH_INDEX_KIND_BEGIN=ArgumentKind,
- STATEMENT_WITH_INDEX_KIND_END=ArgumentKind,
+ LambdaCaptureKind,
+ STATEMENT_WITH_INDEX_KIND_BEGIN = ArgumentKind,
+ STATEMENT_WITH_INDEX_KIND_END = LambdaCaptureKind,
STATEMENT_KIND_BEGIN = VariableKind,
- STATEMENT_KIND_END = ArgumentKind,
+ STATEMENT_KIND_END = LambdaCaptureKind,
InitializerKind,
- INITIALIZER_KIND_BEGIN=InitializerKind,
- INITIALIZER_KIND_END=InitializerKind
+ INITIALIZER_KIND_BEGIN = InitializerKind,
+ INITIALIZER_KIND_END = InitializerKind
};
LLVM_DUMP_METHOD static StringRef getKindAsString(ItemKind K) {
@@ -55,6 +56,8 @@ public:
case ElidedDestructorKind: return "elide destructor";
case ElidableConstructorKind: return "elide constructor";
case ArgumentKind: return "construct into argument";
+ case LambdaCaptureKind:
+ return "construct into lambda captured variable";
case InitializerKind: return "construct into member variable";
};
llvm_unreachable("Unknown ItemKind");
@@ -72,7 +75,7 @@ private:
bool hasIndex() const {
return Kind >= STATEMENT_WITH_INDEX_KIND_BEGIN &&
- Kind >= STATEMENT_WITH_INDEX_KIND_END;
+ Kind <= STATEMENT_WITH_INDEX_KIND_END;
}
bool hasInitializer() const {
@@ -127,6 +130,9 @@ public:
ConstructionContextItem(const CXXCtorInitializer *Init)
: Data(Init), Kind(InitializerKind), Index(0) {}
+ ConstructionContextItem(const LambdaExpr *LE, unsigned Index)
+ : Data(LE), Kind(LambdaCaptureKind), Index(Index) {}
+
ItemKind getKind() const { return Kind; }
LLVM_DUMP_METHOD StringRef getKindAsString() const {
@@ -254,7 +260,8 @@ public:
CXX17ElidedCopyReturnedValueKind,
RETURNED_VALUE_BEGIN = SimpleReturnedValueKind,
RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind,
- ArgumentKind
+ ArgumentKind,
+ LambdaCaptureKind
};
protected:
@@ -298,6 +305,11 @@ public:
const ConstructionContextLayer *TopLayer);
Kind getKind() const { return K; }
+
+ virtual const ArrayInitLoopExpr *getArrayInitLoop() const { return nullptr; }
+
+ // Only declared to silence -Wnon-virtual-dtor warnings.
+ virtual ~ConstructionContext() = default;
};
/// An abstract base class for local variable constructors.
@@ -314,6 +326,12 @@ protected:
public:
const DeclStmt *getDeclStmt() const { return DS; }
+ const ArrayInitLoopExpr *getArrayInitLoop() const override {
+ const auto *Var = cast<VarDecl>(DS->getSingleDecl());
+
+ return dyn_cast<ArrayInitLoopExpr>(Var->getInit());
+ }
+
static bool classof(const ConstructionContext *CC) {
return CC->getKind() >= VARIABLE_BEGIN &&
CC->getKind() <= VARIABLE_END;
@@ -381,6 +399,10 @@ protected:
public:
const CXXCtorInitializer *getCXXCtorInitializer() const { return I; }
+ const ArrayInitLoopExpr *getArrayInitLoop() const override {
+ return dyn_cast<ArrayInitLoopExpr>(I->getInit());
+ }
+
static bool classof(const ConstructionContext *CC) {
return CC->getKind() >= INITIALIZER_BEGIN &&
CC->getKind() <= INITIALIZER_END;
@@ -659,6 +681,42 @@ public:
}
};
+class LambdaCaptureConstructionContext : public ConstructionContext {
+ // The lambda of which the initializer we capture.
+ const LambdaExpr *LE;
+
+ // Index of the captured element in the captured list.
+ unsigned Index;
+
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit LambdaCaptureConstructionContext(const LambdaExpr *LE,
+ unsigned Index)
+ : ConstructionContext(LambdaCaptureKind), LE(LE), Index(Index) {}
+
+public:
+ const LambdaExpr *getLambdaExpr() const { return LE; }
+ unsigned getIndex() const { return Index; }
+
+ const Expr *getInitializer() const {
+ return *(LE->capture_init_begin() + Index);
+ }
+
+ const FieldDecl *getFieldDecl() const {
+ auto It = LE->getLambdaClass()->field_begin();
+ std::advance(It, Index);
+ return *It;
+ }
+
+ const ArrayInitLoopExpr *getArrayInitLoop() const override {
+ return dyn_cast_or_null<ArrayInitLoopExpr>(getInitializer());
+ }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == LambdaCaptureKind;
+ }
+};
+
} // end namespace clang
#endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index abc3183e1b0b..b3e725ad3f6a 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -340,6 +340,10 @@ private:
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, DisjunctionValue *>
DisjunctionVals;
llvm::DenseMap<BoolValue *, NegationValue *> NegationVals;
+ llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, ImplicationValue *>
+ ImplicationVals;
+ llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, BiconditionalValue *>
+ BiconditionalVals;
// Flow conditions are tracked symbolically: each unique flow condition is
// associated with a fresh symbolic variable (token), bound to the clause that
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index f17df36f6a4a..2e9c088d0e5c 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -128,6 +128,21 @@ public:
/// with a symbolic representation of the `this` pointee.
Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
+ /// Creates and returns an environment to use for an inline analysis of the
+ /// callee. Uses the storage location from each argument in the `Call` as the
+ /// storage location for the corresponding parameter in the callee.
+ ///
+ /// Requirements:
+ ///
+ /// The callee of `Call` must be a `FunctionDecl` with a body.
+ ///
+ /// The body of the callee must not reference globals.
+ ///
+ /// The arguments of `Call` must map 1:1 to the callee's parameters.
+ ///
+ /// Each argument of `Call` must already have a `StorageLocation`.
+ Environment pushCall(const CallExpr *Call) const;
+
/// Returns true if and only if the environment is equivalent to `Other`, i.e
/// the two environments:
/// - have the same mappings from declarations to storage locations,
diff --git a/clang/include/clang/Analysis/FlowSensitive/MapLattice.h b/clang/include/clang/Analysis/FlowSensitive/MapLattice.h
index 014cd60841ee..16b0c978779a 100644
--- a/clang/include/clang/Analysis/FlowSensitive/MapLattice.h
+++ b/clang/include/clang/Analysis/FlowSensitive/MapLattice.h
@@ -54,10 +54,13 @@ public:
// The `bottom` element is the empty map.
static MapLattice bottom() { return MapLattice(); }
- void insert(const std::pair<const key_type, mapped_type> &P) { C.insert(P); }
+ std::pair<iterator, bool>
+ insert(const std::pair<const key_type, mapped_type> &P) {
+ return C.insert(P);
+ }
- void insert(std::pair<const key_type, mapped_type> &&P) {
- C.insert(std::move(P));
+ std::pair<iterator, bool> insert(std::pair<const key_type, mapped_type> &&P) {
+ return C.insert(std::move(P));
}
unsigned size() const { return C.size(); }
diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h
index 25afa01f307c..cbb625487c1e 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h
@@ -20,6 +20,12 @@
namespace clang {
namespace dataflow {
+struct TransferOptions {
+ /// Determines whether to analyze function bodies when present in the
+ /// translation unit.
+ bool ContextSensitive = false;
+};
+
/// Maps statements to the environments of basic blocks that contain them.
class StmtToEnvMap {
public:
@@ -36,7 +42,8 @@ public:
/// Requirements:
///
/// `S` must not be `ParenExpr` or `ExprWithCleanups`.
-void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env);
+void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
+ TransferOptions Options);
} // namespace dataflow
} // namespace clang
diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
index b043062459e4..92700f164e7b 100644
--- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
+++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
@@ -23,6 +23,7 @@
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/Transfer.h"
#include "llvm/ADT/Any.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Error.h"
@@ -36,6 +37,9 @@ struct DataflowAnalysisOptions {
// (at which point the built-in transfer functions can be simply a standalone
// analysis).
bool ApplyBuiltinTransfer = true;
+
+ /// Only has an effect if `ApplyBuiltinTransfer` is true.
+ TransferOptions BuiltinTransferOptions;
};
/// Type-erased lattice element container.
@@ -57,7 +61,7 @@ public:
/// Deprecated. Use the `DataflowAnalysisOptions` constructor instead.
TypeErasedDataflowAnalysis(bool ApplyBuiltinTransfer)
- : Options({ApplyBuiltinTransfer}) {}
+ : Options({ApplyBuiltinTransfer, TransferOptions{}}) {}
TypeErasedDataflowAnalysis(DataflowAnalysisOptions Options)
: Options(Options) {}
@@ -90,6 +94,11 @@ public:
/// Determines whether to apply the built-in transfer functions, which model
/// the heap and stack in the `Environment`.
bool applyBuiltinTransfer() const { return Options.ApplyBuiltinTransfer; }
+
+ /// Returns the options to be passed to the built-in transfer functions.
+ TransferOptions builtinTransferOptions() const {
+ return Options.BuiltinTransferOptions;
+ }
};
/// Type-erased model of the program at a given program point.
diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h
index 70348f874543..c63799fe6a46 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Value.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Value.h
@@ -37,12 +37,13 @@ public:
Pointer,
Struct,
- // Synthetic boolean values are either atomic values or composites that
- // represent conjunctions, disjunctions, and negations.
+ // Synthetic boolean values are either atomic values or logical connectives.
AtomicBool,
Conjunction,
Disjunction,
- Negation
+ Negation,
+ Implication,
+ Biconditional,
};
explicit Value(Kind ValKind) : ValKind(ValKind) {}
@@ -84,7 +85,9 @@ public:
return Val->getKind() == Kind::AtomicBool ||
Val->getKind() == Kind::Conjunction ||
Val->getKind() == Kind::Disjunction ||
- Val->getKind() == Kind::Negation;
+ Val->getKind() == Kind::Negation ||
+ Val->getKind() == Kind::Implication ||
+ Val->getKind() == Kind::Biconditional;
}
};
@@ -162,6 +165,54 @@ private:
BoolValue &SubVal;
};
+/// Models a boolean implication.
+///
+/// Equivalent to `!LHS v RHS`.
+class ImplicationValue : public BoolValue {
+public:
+ explicit ImplicationValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
+ : BoolValue(Kind::Implication), LeftSubVal(LeftSubVal),
+ RightSubVal(RightSubVal) {}
+
+ static bool classof(const Value *Val) {
+ return Val->getKind() == Kind::Implication;
+ }
+
+ /// Returns the left sub-value of the implication.
+ BoolValue &getLeftSubValue() const { return LeftSubVal; }
+
+ /// Returns the right sub-value of the implication.
+ BoolValue &getRightSubValue() const { return RightSubVal; }
+
+private:
+ BoolValue &LeftSubVal;
+ BoolValue &RightSubVal;
+};
+
+/// Models a boolean biconditional.
+///
+/// Equivalent to `(LHS ^ RHS) v (!LHS ^ !RHS)`.
+class BiconditionalValue : public BoolValue {
+public:
+ explicit BiconditionalValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
+ : BoolValue(Kind::Biconditional), LeftSubVal(LeftSubVal),
+ RightSubVal(RightSubVal) {}
+
+ static bool classof(const Value *Val) {
+ return Val->getKind() == Kind::Biconditional;
+ }
+
+ /// Returns the left sub-value of the biconditional.
+ BoolValue &getLeftSubValue() const { return LeftSubVal; }
+
+ /// Returns the right sub-value of the biconditional.
+ BoolValue &getRightSubValue() const { return RightSubVal; }
+
+private:
+ BoolValue &LeftSubVal;
+ BoolValue &RightSubVal;
+};
+
/// Models an integer.
class IntegerValue : public Value {
public:
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index aff0dbbdd94d..5c84e2fc5b77 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -5040,6 +5040,12 @@ general this requires the template to be declared at least twice. For example:
clang::preferred_name(wstring)]] basic_string {
// ...
};
+
+
+Note that the ``preferred_name`` attribute will be ignored when the compiler
+writes a C++20 Module interface now. This is due to a compiler issue
+(https://github.com/llvm/llvm-project/issues/56490) that blocks users to modularize
+declarations with `preferred_name`. This is intended to be fixed in the future.
}];
}
diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h
index 709d5e1dc80d..91b180f8004d 100644
--- a/clang/include/clang/Basic/DiagnosticIDs.h
+++ b/clang/include/clang/Basic/DiagnosticIDs.h
@@ -45,18 +45,18 @@ namespace clang {
// Start position for diagnostics.
enum {
DIAG_START_COMMON = 0,
- DIAG_START_DRIVER = DIAG_START_COMMON + DIAG_SIZE_COMMON,
- DIAG_START_FRONTEND = DIAG_START_DRIVER + DIAG_SIZE_DRIVER,
- DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + DIAG_SIZE_FRONTEND,
- DIAG_START_LEX = DIAG_START_SERIALIZATION + DIAG_SIZE_SERIALIZATION,
- DIAG_START_PARSE = DIAG_START_LEX + DIAG_SIZE_LEX,
- DIAG_START_AST = DIAG_START_PARSE + DIAG_SIZE_PARSE,
- DIAG_START_COMMENT = DIAG_START_AST + DIAG_SIZE_AST,
- DIAG_START_CROSSTU = DIAG_START_COMMENT + DIAG_SIZE_COMMENT,
- DIAG_START_SEMA = DIAG_START_CROSSTU + DIAG_SIZE_CROSSTU,
- DIAG_START_ANALYSIS = DIAG_START_SEMA + DIAG_SIZE_SEMA,
- DIAG_START_REFACTORING = DIAG_START_ANALYSIS + DIAG_SIZE_ANALYSIS,
- DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + DIAG_SIZE_REFACTORING
+ DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
+ DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
+ DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
+ DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
+ DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
+ DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
+ DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
+ DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
+ DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
+ DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
+ DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
+ DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING)
};
class CustomDiagInfo;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 352a050ba5cf..18adb21e2be0 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -282,7 +282,7 @@ def err_inline_nested_namespace_definition : Error<
def err_expected_semi_after_attribute_list : Error<
"expected ';' after attribute list">;
def err_expected_semi_after_static_assert : Error<
- "expected ';' after static_assert">;
+ "expected ';' after '%0'">;
def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">;
def err_single_decl_assign_in_for_range : Error<
"range-based 'for' statement uses ':', not '='">;
@@ -425,7 +425,7 @@ def err_unexpected_token_in_nested_name_spec : Error<
def err_bool_redeclaration : Error<
"redeclaration of C++ built-in type 'bool'">;
def warn_cxx98_compat_static_assert : Warning<
- "static_assert declarations are incompatible with C++98">,
+ "'static_assert' declarations are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def ext_ms_static_assert : ExtWarn<
"use of 'static_assert' without inclusion of <assert.h> is a Microsoft "
@@ -538,6 +538,8 @@ def err_invalid_operator_on_type : Error<
"cannot use %select{dot|arrow}0 operator on a type">;
def err_expected_unqualified_id : Error<
"expected %select{identifier|unqualified-id}0">;
+def err_while_loop_outside_of_a_function : Error<
+ "while loop outside of a function">;
def err_brackets_go_after_unqualified_id : Error<
"brackets are not allowed here; to declare an array, "
"place the brackets after the %select{identifier|name}0">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 756102720049..6ff5b8de57fd 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1526,12 +1526,12 @@ def err_messaging_class_with_direct_method : Error<
// C++ declarations
def err_static_assert_expression_is_not_constant : Error<
- "static_assert expression is not an integral constant expression">;
+ "static assertion expression is not an integral constant expression">;
def err_constexpr_if_condition_expression_is_not_constant : Error<
"constexpr if condition is not a constant expression">;
-def err_static_assert_failed : Error<"static_assert failed%select{: %1|}0">;
+def err_static_assert_failed : Error<"static assertion failed%select{: %1|}0">;
def err_static_assert_requirement_failed : Error<
- "static_assert failed due to requirement '%0'%select{: %2|}1">;
+ "static assertion failed due to requirement '%0'%select{: %2|}1">;
def warn_consteval_if_always_true : Warning<
"consteval if is always true in an %select{unevaluated|immediate}0 context">,
@@ -5774,6 +5774,8 @@ def warn_forward_class_redefinition : Warning<
def err_redefinition_different_typedef : Error<
"%select{typedef|type alias|type alias template}0 "
"redefinition with different types%diff{ ($ vs $)|}1,2">;
+def err_redefinition_different_concept : Error<
+ "redefinition of concept %0 with different template parameters or requirements">;
def err_tag_reference_non_tag : Error<
"%select{non-struct type|non-class type|non-union type|non-enum "
"type|typedef|type alias|template|type alias template|template "
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 6fb31c5655ab..ad366821f3cb 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -195,6 +195,7 @@ VALUE_LANGOPT(DoubleSize , 32, 0, "width of double")
VALUE_LANGOPT(LongDoubleSize , 32, 0, "width of long double")
LANGOPT(PPCIEEELongDouble , 1, 0, "use IEEE 754 quadruple-precision for long double")
LANGOPT(EnableAIXExtendedAltivecABI , 1, 0, "__EXTABI__ predefined macro")
+LANGOPT(EnableAIXQuadwordAtomicsABI , 1, 0, "Use 16-byte atomic lock free semantics")
COMPATIBLE_VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level")
COMPATIBLE_VALUE_LANGOPT(PIE , 1, 0, "is pie")
LANGOPT(ROPI , 1, 0, "Read-only position independence")
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 7b65a1537805..84fc0893c8b5 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -908,6 +908,9 @@ PRAGMA_ANNOTATION(pragma_fp)
// Annotation for the attribute pragma directives - #pragma clang attribute ...
PRAGMA_ANNOTATION(pragma_attribute)
+// Annotation for the riscv pragma directives - #pragma clang riscv intrinsic ...
+PRAGMA_ANNOTATION(pragma_riscv)
+
// Annotations for module import translated from #include etc.
ANNOTATION(module_include)
ANNOTATION(module_begin)
diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td
index d96020ee40d0..6b21f48110de 100644
--- a/clang/include/clang/Basic/riscv_vector.td
+++ b/clang/include/clang/Basic/riscv_vector.td
@@ -186,7 +186,7 @@ class RVVBuiltin<string suffix, string prototype, string type_range,
// HasPolicyOperand: Has a policy operand. 0 is tail and mask undisturbed, 1 is
// tail agnostic, 2 is mask undisturbed, and 3 is tail and mask agnostic. The
// policy operand is located at the last position.
- Policy MaskedPolicy = HasPolicyOperand;
+ Policy MaskedPolicyScheme = HasPolicyOperand;
// The policy scheme for unmasked intrinsic IR.
// It could be NonePolicy, HasPassthruOperand or HasPolicyOperand.
@@ -194,7 +194,7 @@ class RVVBuiltin<string suffix, string prototype, string type_range,
// undef, tail policy is tail agnostic, otherwise policy is tail undisturbed.
// HasPolicyOperand: Has a policy operand. 1 is tail agnostic and 0 is tail
// undisturbed.
- Policy UnMaskedPolicy = NonePolicy;
+ Policy UnMaskedPolicyScheme = NonePolicy;
// This builtin supports non-masked function overloading api.
// All masked operations support overloading api.
@@ -443,7 +443,7 @@ class RVVMaskOp0Builtin<string prototype> : RVVOp0Builtin<"m", prototype, "c"> {
let HasMaskedOffOperand = false;
}
-let UnMaskedPolicy = HasPolicyOperand,
+let UnMaskedPolicyScheme = HasPolicyOperand,
HasMaskedOffOperand = false in {
multiclass RVVSlideBuiltinSet {
defm "" : RVVOutBuiltinSet<NAME, "csilxfd",
@@ -582,7 +582,7 @@ class IsFloat<string type> {
}
let HasUnMaskedOverloaded = false,
- MaskedPolicy = NonePolicy in {
+ MaskedPolicyScheme = NonePolicy in {
class RVVVLEMaskBuiltin : RVVOutBuiltin<"m", "mPCUe", "c"> {
let Name = "vlm_v";
let IRName = "vlm";
@@ -591,7 +591,7 @@ let HasUnMaskedOverloaded = false,
}
let HasUnMaskedOverloaded = false,
- UnMaskedPolicy = HasPassthruOperand in {
+ UnMaskedPolicyScheme = HasPassthruOperand in {
multiclass RVVVLEBuiltin<list<string> types> {
let Name = NAME # "_v",
IRName = "vle",
@@ -664,7 +664,7 @@ multiclass RVVVLSEBuiltin<list<string> types> {
IRName = "vlse",
MaskedIRName ="vlse_mask",
HasUnMaskedOverloaded = false,
- UnMaskedPolicy = HasPassthruOperand in {
+ UnMaskedPolicyScheme = HasPassthruOperand in {
foreach type = types in {
def : RVVOutBuiltin<"v", "vPCet", type>;
if !not(IsFloat<type>.val) then {
@@ -675,7 +675,7 @@ multiclass RVVVLSEBuiltin<list<string> types> {
}
multiclass RVVIndexedLoad<string op> {
- let UnMaskedPolicy = HasPassthruOperand in {
+ let UnMaskedPolicyScheme = HasPassthruOperand in {
foreach type = TypeList in {
foreach eew_list = EEWList[0-2] in {
defvar eew = eew_list[0];
@@ -701,7 +701,7 @@ multiclass RVVIndexedLoad<string op> {
}
let HasMaskedOffOperand = false,
- MaskedPolicy = NonePolicy,
+ MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
// Builtin: (ptr, value, vl). Intrinsic: (value, ptr, vl)
std::swap(Ops[0], Ops[1]);
@@ -738,7 +738,7 @@ multiclass RVVVSSEBuiltin<list<string> types> {
IRName = "vsse",
MaskedIRName = "vsse_mask",
HasMaskedOffOperand = false,
- MaskedPolicy = NonePolicy,
+ MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
// Builtin: (ptr, stride, value, vl). Intrinsic: (value, ptr, stride, vl)
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
@@ -762,7 +762,7 @@ multiclass RVVVSSEBuiltin<list<string> types> {
multiclass RVVIndexedStore<string op> {
let HasMaskedOffOperand = false,
- MaskedPolicy = NonePolicy,
+ MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
// Builtin: (ptr, index, value, vl). Intrinsic: (value, ptr, index, vl)
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
@@ -1141,7 +1141,7 @@ multiclass RVVUnitStridedSegStore<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
HasMaskedOffOperand = false,
- MaskedPolicy = NonePolicy,
+ MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
// Builtin: (ptr, val0, val1, ..., vl)
@@ -1187,7 +1187,7 @@ multiclass RVVStridedSegStore<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
HasMaskedOffOperand = false,
- MaskedPolicy = NonePolicy,
+ MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
// Builtin: (ptr, stride, val0, val1, ..., vl).
@@ -1229,7 +1229,7 @@ multiclass RVVIndexedSegStore<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
HasMaskedOffOperand = false,
- MaskedPolicy = NonePolicy,
+ MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
// Builtin: (ptr, index, val0, val1, ..., vl)
@@ -1568,7 +1568,7 @@ def vsetvl_macro: RVVHeader;
let HasBuiltinAlias = false,
HasVL = false,
HasMasked = false,
- MaskedPolicy = NonePolicy,
+ MaskedPolicyScheme = NonePolicy,
Log2LMUL = [0],
ManualCodegen = [{IntrinsicTypes = {ResultType};}] in // Set XLEN type
{
@@ -1627,7 +1627,7 @@ defm : RVVIndexedSegStore<"vsoxseg">;
// 12. Vector Integer Arithmetic Instructions
// 12.1. Vector Single-Width Integer Add and Subtract
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vadd : RVVIntBinBuiltinSet;
defm vsub : RVVIntBinBuiltinSet;
defm vrsub : RVVOutOp1BuiltinSet<"vrsub", "csil",
@@ -1638,7 +1638,7 @@ defm vneg_v : RVVPseudoUnaryBuiltin<"vrsub", "csil">;
// 12.2. Vector Widening Integer Add/Subtract
// Widening unsigned integer add/subtract, 2*SEW = SEW +/- SEW
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vwaddu : RVVUnsignedWidenBinBuiltinSet;
defm vwsubu : RVVUnsignedWidenBinBuiltinSet;
// Widening signed integer add/subtract, 2*SEW = SEW +/- SEW
@@ -1657,7 +1657,7 @@ defm vwcvt_x_x_v : RVVPseudoVWCVTBuiltin<"vwadd", "vwcvt_x", "csi",
[["w", "wv"]]>;
// 12.3. Vector Integer Extension
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
def vsext_vf2 : RVVIntExt<"vsext", "w", "wv", "csi">;
def vzext_vf2 : RVVIntExt<"vzext", "Uw", "UwUv", "csi">;
@@ -1673,8 +1673,8 @@ let Log2LMUL = [-3, -2, -1, 0] in {
}
// 12.4. Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions
-let HasMasked = false, MaskedPolicy = NonePolicy in {
- let UnMaskedPolicy = HasPassthruOperand in {
+let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
+ let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vadc : RVVCarryinBuiltinSet;
defm vsbc : RVVCarryinBuiltinSet;
}
@@ -1685,7 +1685,7 @@ let HasMasked = false, MaskedPolicy = NonePolicy in {
}
// 12.5. Vector Bitwise Logical Instructions
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vand : RVVIntBinBuiltinSet;
defm vxor : RVVIntBinBuiltinSet;
defm vor : RVVIntBinBuiltinSet;
@@ -1693,7 +1693,7 @@ defm vor : RVVIntBinBuiltinSet;
defm vnot_v : RVVPseudoVNotBuiltin<"vxor", "csil">;
// 12.6. Vector Single-Width Bit Shift Instructions
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vsll : RVVShiftBuiltinSet;
defm vsrl : RVVUnsignedShiftBuiltinSet;
defm vsra : RVVSignedShiftBuiltinSet;
@@ -1707,7 +1707,7 @@ defm vncvt_x_x_w : RVVPseudoVNCVTBuiltin<"vnsrl", "vncvt_x", "csi",
["Uv", "UvUw"]]>;
// 12.8. Vector Integer Comparison Instructions
-let MaskedPolicy = NonePolicy in {
+let MaskedPolicyScheme = NonePolicy in {
defm vmseq : RVVIntMaskOutBuiltinSet;
defm vmsne : RVVIntMaskOutBuiltinSet;
defm vmsltu : RVVUnsignedMaskOutBuiltinSet;
@@ -1721,7 +1721,7 @@ defm vmsge : RVVSignedMaskOutBuiltinSet;
}
// 12.9. Vector Integer Min/Max Instructions
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vminu : RVVUnsignedBinBuiltinSet;
defm vmin : RVVSignedBinBuiltinSet;
defm vmaxu : RVVUnsignedBinBuiltinSet;
@@ -1745,7 +1745,7 @@ defm vrem : RVVSignedBinBuiltinSet;
}
// 12.12. Vector Widening Integer Multiply Instructions
-let Log2LMUL = [-3, -2, -1, 0, 1, 2], UnMaskedPolicy = HasPassthruOperand in {
+let Log2LMUL = [-3, -2, -1, 0, 1, 2], UnMaskedPolicyScheme = HasPassthruOperand in {
defm vwmul : RVVOutOp0Op1BuiltinSet<"vwmul", "csi",
[["vv", "w", "wvv"],
["vx", "w", "wve"]]>;
@@ -1758,7 +1758,7 @@ defm vwmulsu : RVVOutOp0Op1BuiltinSet<"vwmulsu", "csi",
}
// 12.13. Vector Single-Width Integer Multiply-Add Instructions
-let UnMaskedPolicy = HasPolicyOperand in {
+let UnMaskedPolicyScheme = HasPolicyOperand in {
defm vmacc : RVVIntTerBuiltinSet;
defm vnmsac : RVVIntTerBuiltinSet;
defm vmadd : RVVIntTerBuiltinSet;
@@ -1783,7 +1783,7 @@ defm vwmaccus : RVVOutOp1Op2BuiltinSet<"vwmaccus", "csi",
// 12.15. Vector Integer Merge Instructions
// C/C++ Operand: (mask, op1, op2, vl), Intrinsic: (op1, op2, mask, vl)
-let HasMasked = false, MaskedPolicy = NonePolicy,
+let HasMasked = false, MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3);
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType()};
@@ -1798,7 +1798,9 @@ let HasMasked = false, MaskedPolicy = NonePolicy,
}
// 12.16. Vector Integer Move Instructions
-let HasMasked = false, UnMaskedPolicy = HasPassthruOperand, MaskedPolicy = NonePolicy in {
+let HasMasked = false,
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ MaskedPolicyScheme = NonePolicy in {
let OverloadedName = "vmv_v" in {
defm vmv_v : RVVOutBuiltinSet<"vmv_v_v", "csil",
[["v", "Uv", "UvUv"]]>;
@@ -1813,7 +1815,7 @@ let HasMasked = false, UnMaskedPolicy = HasPassthruOperand, MaskedPolicy = NoneP
// 13. Vector Fixed-Point Arithmetic Instructions
// 13.1. Vector Single-Width Saturating Add and Subtract
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vsaddu : RVVUnsignedBinBuiltinSet;
defm vsadd : RVVSignedBinBuiltinSet;
defm vssubu : RVVUnsignedBinBuiltinSet;
@@ -1866,7 +1868,7 @@ let Log2LMUL = [-2, -1, 0, 1, 2] in {
}
// 14.6. Vector Single-Width Floating-Point Fused Multiply-Add Instructions
-let UnMaskedPolicy = HasPolicyOperand in {
+let UnMaskedPolicyScheme = HasPolicyOperand in {
defm vfmacc : RVVFloatingTerBuiltinSet;
defm vfnmacc : RVVFloatingTerBuiltinSet;
defm vfmsac : RVVFloatingTerBuiltinSet;
@@ -1884,7 +1886,7 @@ defm vfwnmsac : RVVFloatingWidenTerBuiltinSet;
}
// 14.8. Vector Floating-Point Square-Root Instruction
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
def vfsqrt : RVVFloatingUnaryVVBuiltin;
// 14.9. Vector Floating-Point Reciprocal Square-Root Estimate Instruction
@@ -1906,7 +1908,7 @@ defm vfneg_v : RVVPseudoVFUnaryBuiltin<"vfsgnjn", "xfd">;
defm vfabs_v : RVVPseudoVFUnaryBuiltin<"vfsgnjx", "xfd">;
// 14.13. Vector Floating-Point Compare Instructions
-let MaskedPolicy = NonePolicy in {
+let MaskedPolicyScheme = NonePolicy in {
defm vmfeq : RVVFloatingMaskOutBuiltinSet;
defm vmfne : RVVFloatingMaskOutBuiltinSet;
defm vmflt : RVVFloatingMaskOutBuiltinSet;
@@ -1916,12 +1918,12 @@ defm vmfge : RVVFloatingMaskOutBuiltinSet;
}
// 14.14. Vector Floating-Point Classify Instruction
-let Name = "vfclass_v", UnMaskedPolicy = HasPassthruOperand in
+let Name = "vfclass_v", UnMaskedPolicyScheme = HasPassthruOperand in
def vfclass : RVVOp0Builtin<"Uv", "Uvv", "xfd">;
// 14.15. Vector Floating-Point Merge Instructio
// C/C++ Operand: (mask, op1, op2, vl), Builtin: (op1, op2, mask, vl)
-let HasMasked = false, MaskedPolicy = NonePolicy,
+let HasMasked = false, MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3);
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType()};
@@ -1935,13 +1937,13 @@ let HasMasked = false, MaskedPolicy = NonePolicy,
}
// 14.16. Vector Floating-Point Move Instruction
-let HasMasked = false, UnMaskedPolicy = HasPassthruOperand,
- HasUnMaskedOverloaded = false, MaskedPolicy = NonePolicy in
+let HasMasked = false, UnMaskedPolicyScheme = HasPassthruOperand,
+ HasUnMaskedOverloaded = false, MaskedPolicyScheme = NonePolicy in
defm vfmv_v : RVVOutBuiltinSet<"vfmv_v_f", "xfd",
[["f", "v", "ve"]]>;
// 14.17. Single-Width Floating-Point/Integer Type-Convert Instructions
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
def vfcvt_xu_f_v : RVVConvToUnsignedBuiltin<"vfcvt_xu">;
def vfcvt_x_f_v : RVVConvToSignedBuiltin<"vfcvt_x">;
def vfcvt_rtz_xu_f_v : RVVConvToUnsignedBuiltin<"vfcvt_rtz_xu">;
@@ -1975,7 +1977,7 @@ let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
// 15. Vector Reduction Operations
// 15.1. Vector Single-Width Integer Reduction Instructions
-let MaskedPolicy = NonePolicy in {
+let MaskedPolicyScheme = NonePolicy in {
defm vredsum : RVVIntReductionBuiltinSet;
defm vredmaxu : RVVUnsignedReductionBuiltin;
defm vredmax : RVVSignedReductionBuiltin;
@@ -2021,7 +2023,7 @@ def vmset : RVVMaskNullaryBuiltin;
defm vmmv_m : RVVPseudoMaskBuiltin<"vmand", "c">;
defm vmnot_m : RVVPseudoMaskBuiltin<"vmnand", "c">;
-let MaskedPolicy = NonePolicy in {
+let MaskedPolicyScheme = NonePolicy in {
// 16.2. Vector count population in mask vcpop.m
def vcpop : RVVMaskOp0Builtin<"um">;
@@ -2038,7 +2040,7 @@ def vmsif : RVVMaskUnaryBuiltin;
def vmsof : RVVMaskUnaryBuiltin;
}
-let UnMaskedPolicy = HasPassthruOperand, HasUnMaskedOverloaded = false in {
+let UnMaskedPolicyScheme = HasPassthruOperand, HasUnMaskedOverloaded = false in {
// 16.8. Vector Iota Instruction
defm viota : RVVOutBuiltinSet<"viota", "csil", [["m", "Uv", "Uvm"]]>;
@@ -2049,7 +2051,7 @@ let UnMaskedPolicy = HasPassthruOperand, HasUnMaskedOverloaded = false in {
// 17. Vector Permutation Instructions
// 17.1. Integer Scalar Move Instructions
-let HasMasked = false, MaskedPolicy = NonePolicy in {
+let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
let HasVL = false, OverloadedName = "vmv_x" in
defm vmv_x : RVVOp0BuiltinSet<"vmv_x_s", "csil",
[["s", "ve", "ev"],
@@ -2061,7 +2063,7 @@ let HasMasked = false, MaskedPolicy = NonePolicy in {
}
// 17.2. Floating-Point Scalar Move Instructions
-let HasMasked = false, MaskedPolicy = NonePolicy in {
+let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
let HasVL = false, OverloadedName = "vfmv_f" in
defm vfmv_f : RVVOp0BuiltinSet<"vfmv_f_s", "xfd",
[["s", "ve", "ev"]]>;
@@ -2078,7 +2080,7 @@ defm vslideup : RVVSlideBuiltinSet;
defm vslidedown : RVVSlideBuiltinSet;
// 17.3.3. Vector Slide1up Instructions
-let UnMaskedPolicy = HasPassthruOperand in {
+let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vslide1up : RVVSlideOneBuiltinSet;
defm vfslide1up : RVVFloatingBinVFBuiltinSet;
@@ -2104,7 +2106,7 @@ defm vrgatherei16 : RVVOutBuiltinSet<"vrgatherei16_vv", "csil",
}
// 17.5. Vector Compress Instruction
-let HasMasked = false, MaskedPolicy = NonePolicy,
+let HasMasked = false, MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3);
IntrinsicTypes = {ResultType, Ops[3]->getType()};
@@ -2119,7 +2121,7 @@ let HasMasked = false, MaskedPolicy = NonePolicy,
// Miscellaneous
let HasMasked = false, HasVL = false, IRName = "" in {
- let Name = "vreinterpret_v", MaskedPolicy = NonePolicy,
+ let Name = "vreinterpret_v", MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
return Builder.CreateBitCast(Ops[0], ResultType);
}] in {
@@ -2141,7 +2143,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
}
}
- let Name = "vundefined", HasUnMaskedOverloaded = false, MaskedPolicy = NonePolicy,
+ let Name = "vundefined", HasUnMaskedOverloaded = false,
+ MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
return llvm::UndefValue::get(ResultType);
}] in {
@@ -2151,7 +2154,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
// LMUL truncation
// C/C++ Operand: VecTy, IR Operand: VecTy, Index
- let Name = "vlmul_trunc_v", OverloadedName = "vlmul_trunc", MaskedPolicy = NonePolicy,
+ let Name = "vlmul_trunc_v", OverloadedName = "vlmul_trunc",
+ MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{ {
ID = Intrinsic::vector_extract;
IntrinsicTypes = {ResultType, Ops[0]->getType()};
@@ -2169,7 +2173,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
// LMUL extension
// C/C++ Operand: SubVecTy, IR Operand: VecTy, SubVecTy, Index
- let Name = "vlmul_ext_v", OverloadedName = "vlmul_ext", MaskedPolicy = NonePolicy,
+ let Name = "vlmul_ext_v", OverloadedName = "vlmul_ext",
+ MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
ID = Intrinsic::vector_insert;
IntrinsicTypes = {ResultType, Ops[0]->getType()};
@@ -2187,7 +2192,7 @@ let HasMasked = false, HasVL = false, IRName = "" in {
}
}
- let Name = "vget_v", MaskedPolicy = NonePolicy,
+ let Name = "vget_v", MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
ID = Intrinsic::vector_extract;
@@ -2211,7 +2216,7 @@ let HasMasked = false, HasVL = false, IRName = "" in {
}
}
- let Name = "vset_v", Log2LMUL = [0, 1, 2], MaskedPolicy = NonePolicy,
+ let Name = "vset_v", Log2LMUL = [0, 1, 2], MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
ID = Intrinsic::vector_insert;
diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h
index 26587e73bf6c..edacd82bf899 100644
--- a/clang/include/clang/CodeGen/ModuleBuilder.h
+++ b/clang/include/clang/CodeGen/ModuleBuilder.h
@@ -14,12 +14,17 @@
#define LLVM_CLANG_CODEGEN_MODULEBUILDER_H
#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/LLVM.h"
namespace llvm {
class Constant;
class LLVMContext;
class Module;
class StringRef;
+
+ namespace vfs {
+ class FileSystem;
+ }
}
namespace clang {
@@ -98,10 +103,11 @@ public:
/// the allocated CodeGenerator instance.
CodeGenerator *CreateLLVMCodeGen(DiagnosticsEngine &Diags,
llvm::StringRef ModuleName,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PreprocessorOpts,
const CodeGenOptions &CGO,
- llvm::LLVMContext& C,
+ llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr);
} // end namespace clang
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index 774eac613a10..0781d476ec4a 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -44,9 +44,7 @@ typedef SmallVector<InputInfo, 4> InputInfoList;
class Command;
class Compilation;
-class JobList;
class JobAction;
-class SanitizerArgs;
class ToolChain;
/// Describes the kind of LTO mode selected via -f(no-)?lto(=.*)? options.
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index b9c2e4d528e4..3cab37b21aaf 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3679,6 +3679,10 @@ def mabi_EQ_vec_extabi : Flag<["-"], "mabi=vec-extabi">, Group<m_Group>, Flags<[
MarshallingInfoFlag<LangOpts<"EnableAIXExtendedAltivecABI">>;
def mabi_EQ_vec_default : Flag<["-"], "mabi=vec-default">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Enable the default Altivec ABI on AIX (AIX only). Uses only volatile vector registers.">;
+def mabi_EQ_quadword_atomics : Flag<["-"], "mabi=quadword-atomics">,
+ Group<m_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable quadword atomics ABI on AIX (AIX PPC64 only). Uses lqarx/stqcx. instructions.">,
+ MarshallingInfoFlag<LangOpts<"EnableAIXQuadwordAtomicsABI">>;
def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>;
def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>;
def msecure_plt : Flag<["-"], "msecure-plt">, Group<m_ppc_Features_Group>;
diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h
index 240624d5408f..143cf4359f00 100644
--- a/clang/include/clang/Frontend/Utils.h
+++ b/clang/include/clang/Frontend/Utils.h
@@ -107,10 +107,10 @@ public:
void finishedMainFile(DiagnosticsEngine &Diags) override;
- bool needSystemDependencies() final override { return IncludeSystemHeaders; }
+ bool needSystemDependencies() final { return IncludeSystemHeaders; }
bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem,
- bool IsModuleFile, bool IsMissing) final override;
+ bool IsModuleFile, bool IsMissing) final;
protected:
void outputDependencyFile(llvm::raw_ostream &OS);
diff --git a/clang/include/clang/Lex/PreprocessingRecord.h b/clang/include/clang/Lex/PreprocessingRecord.h
index 063929dd8f96..c97ca8628e14 100644
--- a/clang/include/clang/Lex/PreprocessingRecord.h
+++ b/clang/include/clang/Lex/PreprocessingRecord.h
@@ -49,7 +49,6 @@ void operator delete(void *ptr, clang::PreprocessingRecord &PR,
namespace clang {
-class FileEntry;
class IdentifierInfo;
class MacroInfo;
class SourceManager;
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 8fc24c731035..79454b5addea 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -67,7 +67,6 @@ namespace clang {
class CodeCompletionHandler;
class CommentHandler;
class DirectoryEntry;
-class DirectoryLookup;
class EmptylineHandler;
class ExternalPreprocessorSource;
class FileEntry;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 76e1c9db5284..41bfc9f48ecc 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -215,6 +215,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> AttributePragmaHandler;
std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
+ std::unique_ptr<PragmaHandler> RISCVPragmaHandler;
std::unique_ptr<CommentHandler> CommentSemaHandler;
@@ -1043,7 +1044,7 @@ private:
/// If the next token is not a semicolon, this emits the specified diagnostic,
/// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior
/// to the semicolon, consumes that extra token.
- bool ExpectAndConsumeSemi(unsigned DiagID);
+ bool ExpectAndConsumeSemi(unsigned DiagID , StringRef TokenUsed = "");
/// The kind of extra semi diagnostic to emit.
enum ExtraSemiKind {
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 48997e186ef6..fb4812675d9a 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -795,6 +795,10 @@ class Sema;
/// This candidate was not viable because its associated constraints were
/// not satisfied.
ovl_fail_constraints_not_satisfied,
+
+ /// This candidate was not viable because it has internal linkage and is
+ /// from a different module unit than the use.
+ ovl_fail_module_mismatched,
};
/// A list of implicit conversion sequences for the arguments of an
diff --git a/clang/include/clang/Sema/RISCVIntrinsicManager.h b/clang/include/clang/Sema/RISCVIntrinsicManager.h
new file mode 100644
index 000000000000..505100249d6f
--- /dev/null
+++ b/clang/include/clang/Sema/RISCVIntrinsicManager.h
@@ -0,0 +1,36 @@
+//===- RISCVIntrinsicManager.h - RISC-V Intrinsic Handler -------*- 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 the RISCVIntrinsicManager, which handles RISC-V vector
+// intrinsic functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H
+#define LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H
+
+namespace clang {
+class Sema;
+class LookupResult;
+class IdentifierInfo;
+class Preprocessor;
+
+namespace sema {
+class RISCVIntrinsicManager {
+public:
+ virtual ~RISCVIntrinsicManager() = default;
+
+ // Create RISC-V intrinsic and insert into symbol table and return true if
+ // found, otherwise return false.
+ virtual bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II,
+ Preprocessor &PP) = 0;
+};
+} // end namespace sema
+} // end namespace clang
+
+#endif
diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index f4c50864f51c..3749d925b106 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -210,9 +210,19 @@ private:
/// Used to determine if errors occurred in this scope.
DiagnosticErrorTrap ErrorTrap;
- /// A lattice consisting of undefined, a single NRVO candidate variable in
- /// this scope, or over-defined. The bit is true when over-defined.
- llvm::PointerIntPair<VarDecl *, 1, bool> NRVO;
+ /// A single NRVO candidate variable in this scope.
+ /// There are three possible values:
+ /// 1) pointer to VarDecl that denotes NRVO candidate itself.
+ /// 2) nullptr value means that NRVO is not allowed in this scope
+ /// (e.g. return a function parameter).
+ /// 3) None value means that there is no NRVO candidate in this scope
+ /// (i.e. there are no return statements in this scope).
+ Optional<VarDecl *> NRVO;
+
+ /// Represents return slots for NRVO candidates in the current scope.
+ /// If a variable is present in this set, it means that a return slot is
+ /// available for this variable in the current scope.
+ llvm::SmallPtrSet<VarDecl *, 8> ReturnSlots;
void setFlags(Scope *Parent, unsigned F);
@@ -304,6 +314,10 @@ public:
bool decl_empty() const { return DeclsInScope.empty(); }
void AddDecl(Decl *D) {
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ if (!isa<ParmVarDecl>(VD))
+ ReturnSlots.insert(VD);
+
DeclsInScope.insert(D);
}
@@ -527,23 +541,9 @@ public:
UsingDirectives.end());
}
- void addNRVOCandidate(VarDecl *VD) {
- if (NRVO.getInt())
- return;
- if (NRVO.getPointer() == nullptr) {
- NRVO.setPointer(VD);
- return;
- }
- if (NRVO.getPointer() != VD)
- setNoNRVO();
- }
-
- void setNoNRVO() {
- NRVO.setInt(true);
- NRVO.setPointer(nullptr);
- }
+ void updateNRVOCandidate(VarDecl *VD);
- void mergeNRVOIntoParent();
+ void applyNRVO();
/// Init - This is used by the parser to implement scope caching.
void Init(Scope *parent, unsigned flags);
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index a33d85cc954d..06ea0b417cb3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -226,6 +226,7 @@ namespace sema {
class FunctionScopeInfo;
class LambdaScopeInfo;
class PossiblyUnreachableDiag;
+ class RISCVIntrinsicManager;
class SemaPPCallbacks;
class TemplateDeductionInfo;
}
@@ -1587,7 +1588,12 @@ public:
/// assignment.
llvm::DenseMap<const VarDecl *, int> RefsMinusAssignments;
+ /// Indicate RISC-V vector builtin functions enabled or not.
+ bool DeclareRISCVVBuiltins = false;
+
private:
+ std::unique_ptr<sema::RISCVIntrinsicManager> RVIntrinsicManager;
+
Optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo;
bool WarnedDarwinSDKInfoMissing = false;
@@ -8260,6 +8266,9 @@ public:
Scope *S, MultiTemplateParamsArg TemplateParameterLists,
IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr);
+ void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous,
+ bool &AddToScope);
+
RequiresExprBodyDecl *
ActOnStartRequiresExpr(SourceLocation RequiresKWLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
@@ -12170,7 +12179,8 @@ public:
// For simple assignment, pass both expressions and a null converted type.
// For compound assignment, pass both expressions and the converted type.
QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
- Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType);
+ Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType,
+ BinaryOperatorKind Opc);
ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc,
UnaryOperatorKind Opcode, Expr *Op);
@@ -13586,6 +13596,8 @@ void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation,
llvm::StringRef StackSlotLabel,
AlignPackInfo Value);
+std::unique_ptr<sema::RISCVIntrinsicManager>
+CreateRISCVIntrinsicManager(Sema &S);
} // end namespace clang
namespace llvm {
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 5dcde77b5dd3..8df92b7000f3 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -75,6 +75,8 @@ enum class TemplateSubstitutionKind : char {
class MultiLevelTemplateArgumentList {
/// The template argument list at a certain template depth
using ArgList = ArrayRef<TemplateArgument>;
+ using ArgListsIterator = SmallVector<ArgList, 4>::iterator;
+ using ConstArgListsIterator = SmallVector<ArgList, 4>::const_iterator;
/// The template argument lists, stored from the innermost template
/// argument list (first) to the outermost template argument list (last).
@@ -121,6 +123,12 @@ enum class TemplateSubstitutionKind : char {
return TemplateArgumentLists.size();
}
+ // Determine the number of substituted args at 'Depth'.
+ unsigned getNumSubsitutedArgs(unsigned Depth) const {
+ assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
+ return TemplateArgumentLists[getNumLevels() - Depth - 1].size();
+ }
+
unsigned getNumRetainedOuterLevels() const {
return NumRetainedOuterLevels;
}
@@ -158,6 +166,14 @@ enum class TemplateSubstitutionKind : char {
return !(*this)(Depth, Index).isNull();
}
+ bool isAnyArgInstantiationDependent() const {
+ for (ArgList List : TemplateArgumentLists)
+ for (const TemplateArgument &TA : List)
+ if (TA.isInstantiationDependent())
+ return true;
+ return false;
+ }
+
/// Clear out a specific template argument.
void setArgument(unsigned Depth, unsigned Index,
TemplateArgument Arg) {
@@ -183,6 +199,14 @@ enum class TemplateSubstitutionKind : char {
TemplateArgumentLists.push_back(Args);
}
+ /// Replaces the current 'innermost' level with the provided argument list.
+ /// This is useful for type deduction cases where we need to get the entire
+ /// list from the AST, but then add the deduced innermost list.
+ void replaceInnermostTemplateArguments(ArgList Args) {
+ assert(TemplateArgumentLists.size() > 0 && "Replacing in an empty list?");
+ TemplateArgumentLists[0] = Args;
+ }
+
/// Add an outermost level that we are not substituting. We have no
/// arguments at this level, and do not remove it from the depth of inner
/// template parameters that we instantiate.
@@ -197,6 +221,16 @@ enum class TemplateSubstitutionKind : char {
const ArgList &getInnermost() const {
return TemplateArgumentLists.front();
}
+ /// Retrieve the outermost template argument list.
+ const ArgList &getOutermost() const {
+ return TemplateArgumentLists.back();
+ }
+ ArgListsIterator begin() { return TemplateArgumentLists.begin(); }
+ ConstArgListsIterator begin() const {
+ return TemplateArgumentLists.begin();
+ }
+ ArgListsIterator end() { return TemplateArgumentLists.end(); }
+ ConstArgListsIterator end() const { return TemplateArgumentLists.end(); }
};
/// The context in which partial ordering of function templates occurs.
diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h
index 6a3532d7272d..83bc7dcdfde3 100644
--- a/clang/include/clang/Serialization/ASTWriter.h
+++ b/clang/include/clang/Serialization/ASTWriter.h
@@ -703,6 +703,10 @@ public:
bool hasChain() const { return Chain; }
ASTReader *getChain() const { return Chain; }
+ bool isWritingNamedModules() const {
+ return WritingModule && WritingModule->isModulePurview();
+ }
+
private:
// ASTDeserializationListener implementation
void ReaderInitialized(ASTReader *Reader) override;
diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index 685dc66182ef..48da56c00f7a 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -731,7 +731,7 @@ public:
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BR,
- PathSensitiveBugReport &R) override final;
+ PathSensitiveBugReport &R) final;
};
} // namespace ento
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 116a5970c341..8773e171369f 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -622,6 +622,11 @@ public:
getIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E,
const LocationContext *LCtx);
+ /// Retreives the size of the array in the pending ArrayInitLoopExpr.
+ static Optional<unsigned> getPendingInitLoop(ProgramStateRef State,
+ const CXXConstructExpr *E,
+ const LocationContext *LCtx);
+
/// By looking at a certain item that may be potentially part of an object's
/// ConstructionContext, retrieve such object's location. A particular
/// statement can be transparently passed as \p Item in most cases.
@@ -816,7 +821,9 @@ private:
/// Checks whether our policies allow us to inline a non-POD type array
/// construction.
- bool shouldInlineArrayConstruction(const ArrayType *Type);
+ bool shouldInlineArrayConstruction(const ProgramStateRef State,
+ const CXXConstructExpr *CE,
+ const LocationContext *LCtx);
/// Checks whether we construct an array of non-POD type, and decides if the
/// constructor should be inkoved once again.
@@ -916,6 +923,16 @@ private:
const CXXConstructExpr *E,
const LocationContext *LCtx);
+ /// Sets the size of the array in a pending ArrayInitLoopExpr.
+ static ProgramStateRef setPendingInitLoop(ProgramStateRef State,
+ const CXXConstructExpr *E,
+ const LocationContext *LCtx,
+ unsigned Idx);
+
+ static ProgramStateRef removePendingInitLoop(ProgramStateRef State,
+ const CXXConstructExpr *E,
+ const LocationContext *LCtx);
+
/// Store the location of a C++ object corresponding to a statement
/// until the statement is actually encountered. For example, if a DeclStmt
/// has CXXConstructExpr as its initializer, the object would be considered
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 1092d1292255..9927b6340793 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -55,8 +55,6 @@ template <typename T> struct ProgramStateTrait {
}
};
-class RangeSet;
-
/// \class ProgramState
/// ProgramState - This class encapsulates:
///
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index c9c21fcf230e..2ae811ee3365 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -40,7 +40,6 @@ class LabelDecl;
namespace ento {
-class BasicValueFactory;
class CompoundValData;
class LazyCompoundValData;
class MemRegion;
diff --git a/clang/include/clang/Support/RISCVVIntrinsicUtils.h b/clang/include/clang/Support/RISCVVIntrinsicUtils.h
index a5e7e6d35cc8..7ee4896eea09 100644
--- a/clang/include/clang/Support/RISCVVIntrinsicUtils.h
+++ b/clang/include/clang/Support/RISCVVIntrinsicUtils.h
@@ -18,6 +18,10 @@
#include <string>
#include <vector>
+namespace llvm {
+class raw_ostream;
+} // end namespace llvm
+
namespace clang {
namespace RISCV {
@@ -104,12 +108,14 @@ struct PrototypeDescriptor {
uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier);
bool operator!=(const PrototypeDescriptor &PD) const {
- return PD.PT != PT || PD.VTM != VTM || PD.TM != TM;
+ return !(*this == PD);
}
- bool operator>(const PrototypeDescriptor &PD) const {
- return !(PD.PT <= PT && PD.VTM <= VTM && PD.TM <= TM);
+ bool operator==(const PrototypeDescriptor &PD) const {
+ return PD.PT == PT && PD.VTM == VTM && PD.TM == TM;
+ }
+ bool operator<(const PrototypeDescriptor &PD) const {
+ return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM);
}
-
static const PrototypeDescriptor Mask;
static const PrototypeDescriptor Vector;
static const PrototypeDescriptor VL;
@@ -224,8 +230,12 @@ public:
bool isFloat(unsigned Width) const {
return isFloat() && ElementBitwidth == Width;
}
-
+ bool isConstant() const { return IsConstant; }
bool isPointer() const { return IsPointer; }
+ unsigned getElementBitwidth() const { return ElementBitwidth; }
+
+ ScalarTypeKind getScalarType() const { return ScalarType; }
+ VScaleVal getScale() const { return Scale; }
private:
// Verify RVV vector type and set Valid.
@@ -263,18 +273,6 @@ public:
PrototypeDescriptor Proto);
};
-using RISCVPredefinedMacroT = uint8_t;
-
-enum RISCVPredefinedMacro : RISCVPredefinedMacroT {
- Basic = 0,
- V = 1 << 1,
- Zvfh = 1 << 2,
- RV64 = 1 << 3,
- VectorMaxELen64 = 1 << 4,
- VectorMaxELenFp32 = 1 << 5,
- VectorMaxELenFp64 = 1 << 6,
-};
-
enum PolicyScheme : uint8_t {
SchemeNone,
HasPassthruOperand,
@@ -302,7 +300,6 @@ private:
// The types we use to obtain the specific LLVM intrinsic. They are index of
// InputTypes. -1 means the return type.
std::vector<int64_t> IntrinsicTypes;
- RISCVPredefinedMacroT RISCVPredefinedMacros = 0;
unsigned NF = 1;
public:
@@ -333,9 +330,6 @@ public:
llvm::StringRef getIRName() const { return IRName; }
llvm::StringRef getManualCodegen() const { return ManualCodegen; }
PolicyScheme getPolicyScheme() const { return Scheme; }
- RISCVPredefinedMacroT getRISCVPredefinedMacros() const {
- return RISCVPredefinedMacros;
- }
unsigned getNF() const { return NF; }
const std::vector<int64_t> &getIntrinsicTypes() const {
return IntrinsicTypes;
@@ -347,8 +341,72 @@ public:
static std::string
getSuffixStr(BasicType Type, int Log2LMUL,
llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
+
+ static llvm::SmallVector<PrototypeDescriptor>
+ computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
+ bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
+ unsigned NF);
+};
+
+// RVVRequire should be sync'ed with target features, but only
+// required features used in riscv_vector.td.
+enum RVVRequire : uint8_t {
+ RVV_REQ_None = 0,
+ RVV_REQ_RV64 = 1 << 0,
+ RVV_REQ_FullMultiply = 1 << 1,
+
+ LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_FullMultiply)
+};
+
+// Raw RVV intrinsic info, used to expand later.
+// This struct is highly compact for minimized code size.
+struct RVVIntrinsicRecord {
+ // Intrinsic name, e.g. vadd_vv
+ const char *Name;
+
+ // Overloaded intrinsic name, could be empty if it can be computed from Name.
+ // e.g. vadd
+ const char *OverloadedName;
+
+ // Prototype for this intrinsic, index of RVVSignatureTable.
+ uint16_t PrototypeIndex;
+
+ // Suffix of intrinsic name, index of RVVSignatureTable.
+ uint16_t SuffixIndex;
+
+ // Suffix of overloaded intrinsic name, index of RVVSignatureTable.
+ uint16_t OverloadedSuffixIndex;
+
+ // Length of the prototype.
+ uint8_t PrototypeLength;
+
+ // Length of intrinsic name suffix.
+ uint8_t SuffixLength;
+
+ // Length of overloaded intrinsic suffix.
+ uint8_t OverloadedSuffixSize;
+
+ // Required target features for this intrinsic.
+ uint8_t RequiredExtensions;
+
+ // Supported type, mask of BasicType.
+ uint8_t TypeRangeMask;
+
+ // Supported LMUL.
+ uint8_t Log2LMULMask;
+
+ // Number of fields, greater than 1 if it's segment load/store.
+ uint8_t NF;
+
+ bool HasMasked : 1;
+ bool HasVL : 1;
+ bool HasMaskedOffOperand : 1;
};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const RVVIntrinsicRecord &RVVInstrRecord);
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
} // end namespace RISCV
} // end namespace clang
diff --git a/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h b/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
index 49e4a0c149f1..1a318da3acca 100644
--- a/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
+++ b/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
@@ -98,7 +98,7 @@ public:
OptionRequirement() : Opt(createRefactoringOption<OptionType>()) {}
ArrayRef<std::shared_ptr<RefactoringOption>>
- getRefactoringOptions() const final override {
+ getRefactoringOptions() const final {
return Opt;
}
diff --git a/clang/include/clang/Tooling/Refactoring/RefactoringActionRules.h b/clang/include/clang/Tooling/Refactoring/RefactoringActionRules.h
index 86fcc6ad0a79..5cb051d53433 100644
--- a/clang/include/clang/Tooling/Refactoring/RefactoringActionRules.h
+++ b/clang/include/clang/Tooling/Refactoring/RefactoringActionRules.h
@@ -52,7 +52,7 @@ using RefactoringActionRules =
class SourceChangeRefactoringRule : public RefactoringActionRuleBase {
public:
void invoke(RefactoringResultConsumer &Consumer,
- RefactoringRuleContext &Context) final override {
+ RefactoringRuleContext &Context) final {
Expected<AtomicChanges> Changes = createSourceReplacements(Context);
if (!Changes)
Consumer.handleError(Changes.takeError());
@@ -74,7 +74,7 @@ private:
class FindSymbolOccurrencesRefactoringRule : public RefactoringActionRuleBase {
public:
void invoke(RefactoringResultConsumer &Consumer,
- RefactoringRuleContext &Context) final override {
+ RefactoringRuleContext &Context) final {
Expected<SymbolOccurrences> Occurrences = findSymbolOccurrences(Context);
if (!Occurrences)
Consumer.handleError(Occurrences.takeError());
diff --git a/clang/include/clang/Tooling/Refactoring/RefactoringOptions.h b/clang/include/clang/Tooling/Refactoring/RefactoringOptions.h
index 1575a136b11c..75bd91d15016 100644
--- a/clang/include/clang/Tooling/Refactoring/RefactoringOptions.h
+++ b/clang/include/clang/Tooling/Refactoring/RefactoringOptions.h
@@ -24,7 +24,7 @@ template <typename T,
typename = std::enable_if_t<traits::IsValidOptionType<T>::value>>
class OptionalRefactoringOption : public RefactoringOption {
public:
- void passToVisitor(RefactoringOptionVisitor &Visitor) final override {
+ void passToVisitor(RefactoringOptionVisitor &Visitor) final {
Visitor.visit(*this, Value);
}
@@ -48,7 +48,7 @@ public:
const ValueType &getValue() const {
return *OptionalRefactoringOption<T>::Value;
}
- bool isRequired() const final override { return true; }
+ bool isRequired() const final { return true; }
};
} // end namespace tooling
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index f7e7b73d1218..0273e5068371 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTImporter.h"
-#include "clang/AST/ASTImporterSharedState.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTImporterSharedState.h"
#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
@@ -34,6 +34,7 @@
#include "clang/AST/LambdaCapture.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OperationKinds.h"
+#include "clang/AST/ParentMapContext.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -58,8 +59,8 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@@ -3219,9 +3220,12 @@ Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD,
}
// Returns true if the given D has a DeclContext up to the TranslationUnitDecl
-// which is equal to the given DC.
+// which is equal to the given DC, or D is equal to DC.
static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
- const DeclContext *DCi = D->getDeclContext();
+ const DeclContext *DCi = dyn_cast<DeclContext>(D);
+ if (!DCi)
+ DCi = D->getDeclContext();
+ assert(DCi && "Declaration should have a context");
while (DCi != D->getTranslationUnitDecl()) {
if (DCi == DC)
return true;
@@ -3230,9 +3234,36 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
return false;
}
+// Returns true if the statement S has a parent declaration that has a
+// DeclContext that is inside (or equal to) DC. In a specific use case if DC is
+// a FunctionDecl, check if statement S resides in the body of the function.
+static bool isAncestorDeclContextOf(const DeclContext *DC, const Stmt *S) {
+ ParentMapContext &ParentC = DC->getParentASTContext().getParentMapContext();
+ DynTypedNodeList Parents = ParentC.getParents(*S);
+ while (!Parents.empty()) {
+ if (const Decl *PD = Parents.begin()->get<Decl>())
+ return isAncestorDeclContextOf(DC, PD);
+ Parents = ParentC.getParents(*Parents.begin());
+ }
+ return false;
+}
+
static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
if (T.isNull())
return false;
+
+ auto CheckTemplateArgument = [FD](const TemplateArgument &Arg) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Type:
+ return hasTypeDeclaredInsideFunction(Arg.getAsType(), FD);
+ case TemplateArgument::Expression:
+ return isAncestorDeclContextOf(FD, Arg.getAsExpr());
+ default:
+ // FIXME: Handle other argument kinds.
+ return false;
+ }
+ };
+
if (const auto *RecordT = T->getAs<RecordType>()) {
const RecordDecl *RD = RecordT->getDecl();
assert(RD);
@@ -3241,12 +3272,15 @@ static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
return true;
}
if (const auto *RDTempl = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- return llvm::count_if(RDTempl->getTemplateArgs().asArray(),
- [FD](const TemplateArgument &Arg) {
- return hasTypeDeclaredInsideFunction(
- Arg.getAsType(), FD);
- });
+ if (llvm::count_if(RDTempl->getTemplateArgs().asArray(),
+ CheckTemplateArgument))
+ return true;
+ // Note: It is possible that T can be get as both a RecordType and a
+ // TemplateSpecializationType.
}
+ if (const auto *TST = T->getAs<TemplateSpecializationType>())
+ return llvm::count_if(TST->template_arguments(), CheckTemplateArgument);
+
return false;
}
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index f88a2e3fa268..aaba4345587b 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -394,7 +394,6 @@ void LinkageComputer::mergeTemplateLV(
shouldConsiderTemplateVisibility(fn, specInfo);
FunctionTemplateDecl *temp = specInfo->getTemplate();
-
// Merge information from the template declaration.
LinkageInfo tempLV = getLVForDecl(temp, computation);
// The linkage of the specialization should be consistent with the
@@ -468,11 +467,16 @@ void LinkageComputer::mergeTemplateLV(
// Merge information from the template parameters, but ignore
// visibility if we're only considering template arguments.
-
ClassTemplateDecl *temp = spec->getSpecializedTemplate();
- LinkageInfo tempLV =
+ // Merge information from the template declaration.
+ LinkageInfo tempLV = getLVForDecl(temp, computation);
+ // The linkage of the specialization should be consistent with the
+ // template declaration.
+ LV.setLinkage(tempLV.getLinkage());
+
+ LinkageInfo paramsLV =
getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
- LV.mergeMaybeWithVisibility(tempLV,
+ LV.mergeMaybeWithVisibility(paramsLV,
considerVisibility && !hasExplicitVisibilityAlready(computation));
// Merge information from the template arguments. We ignore
@@ -520,7 +524,6 @@ void LinkageComputer::mergeTemplateLV(LinkageInfo &LV,
// Merge information from the template parameters, but ignore
// visibility if we're only considering template arguments.
-
VarTemplateDecl *temp = spec->getSpecializedTemplate();
LinkageInfo tempLV =
getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
@@ -1077,7 +1080,6 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
// Finally, merge in information from the class.
LV.mergeMaybeWithVisibility(classLV, considerClassVisibility);
-
return LV;
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6ffb65d8e71d..9d92c848ccb8 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5266,10 +5266,14 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
}
}
bool Cond;
- if (IS->isConsteval())
+ if (IS->isConsteval()) {
Cond = IS->isNonNegatedConsteval();
- else if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(),
- Cond))
+ // If we are not in a constant context, if consteval should not evaluate
+ // to true.
+ if (!Info.InConstantContext)
+ Cond = !Cond;
+ } else if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(),
+ Cond))
return ESR_Failed;
if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) {
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 614d94ae31a6..84178ff488a5 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1659,9 +1659,13 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
appendInitializer(Block, I);
if (Init) {
+ // If the initializer is an ArrayInitLoopExpr, we want to extract the
+ // initializer, that's used for each element.
+ const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
+
findConstructionContexts(
ConstructionContextLayer::create(cfg->getBumpVectorContext(), I),
- Init);
+ AILE ? AILE->getSubExpr() : Init);
if (HasTemporaries) {
// For expression with temporaries go directly to subexpression to omit
@@ -2928,12 +2932,30 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
}
}
+ // If we bind to a tuple-like type, we iterate over the HoldingVars, and
+ // create a DeclStmt for each of them.
+ if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
+ for (auto BD : llvm::reverse(DD->bindings())) {
+ if (auto *VD = BD->getHoldingVar()) {
+ DeclGroupRef DG(VD);
+ DeclStmt *DSNew =
+ new (Context) DeclStmt(DG, VD->getLocation(), GetEndLoc(VD));
+ cfg->addSyntheticDeclStmt(DSNew, DS);
+ Block = VisitDeclSubExpr(DSNew);
+ }
+ }
+ }
+
autoCreateBlock();
appendStmt(Block, DS);
+ // If the initializer is an ArrayInitLoopExpr, we want to extract the
+ // initializer, that's used for each element.
+ const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
+
findConstructionContexts(
ConstructionContextLayer::create(cfg->getBumpVectorContext(), DS),
- Init);
+ AILE ? AILE->getSubExpr() : Init);
// Keep track of the last non-null block, as 'Block' can be nulled out
// if the initializer expression is something like a 'while' in a
@@ -3340,9 +3362,20 @@ CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
CFGBlock *LastBlock = VisitNoRecurse(E, asc);
+
+ unsigned Idx = 0;
for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(),
- et = E->capture_init_end(); it != et; ++it) {
+ et = E->capture_init_end();
+ it != et; ++it, ++Idx) {
if (Expr *Init = *it) {
+ // If the initializer is an ArrayInitLoopExpr, we want to extract the
+ // initializer, that's used for each element.
+ const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
+
+ findConstructionContexts(ConstructionContextLayer::create(
+ cfg->getBumpVectorContext(), {E, Idx}),
+ AILE ? AILE->getSubExpr() : Init);
+
CFGBlock *Tmp = Visit(Init);
if (Tmp)
LastBlock = Tmp;
@@ -5616,6 +5649,12 @@ static void print_construction_context(raw_ostream &OS,
Stmts.push_back(TOCC->getConstructorAfterElision());
break;
}
+ case ConstructionContext::LambdaCaptureKind: {
+ const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
+ Helper.handledStmt(const_cast<LambdaExpr *>(LCC->getLambdaExpr()), OS);
+ OS << "+" << LCC->getIndex();
+ return;
+ }
case ConstructionContext::ArgumentKind: {
const auto *ACC = cast<ArgumentConstructionContext>(CC);
if (const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
diff --git a/clang/lib/Analysis/ConstructionContext.cpp b/clang/lib/Analysis/ConstructionContext.cpp
index 6ba1e2173d2c..8a862c06f13a 100644
--- a/clang/lib/Analysis/ConstructionContext.cpp
+++ b/clang/lib/Analysis/ConstructionContext.cpp
@@ -156,6 +156,12 @@ const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers(
return create<CXX17ElidedCopyConstructorInitializerConstructionContext>(
C, I, BTE);
}
+ case ConstructionContextItem::LambdaCaptureKind: {
+ assert(ParentLayer->isLast());
+ const auto *E = cast<LambdaExpr>(ParentItem.getStmt());
+ return create<LambdaCaptureConstructionContext>(C, E,
+ ParentItem.getIndex());
+ }
} // switch (ParentItem.getKind())
llvm_unreachable("Unexpected construction context with destructor!");
@@ -200,6 +206,11 @@ const ConstructionContext *ConstructionContext::createFromLayers(
case ConstructionContextItem::ElidableConstructorKind: {
llvm_unreachable("The argument needs to be materialized first!");
}
+ case ConstructionContextItem::LambdaCaptureKind: {
+ assert(TopLayer->isLast());
+ const auto *E = cast<LambdaExpr>(TopItem.getStmt());
+ return create<LambdaCaptureConstructionContext>(C, E, TopItem.getIndex());
+ }
case ConstructionContextItem::InitializerKind: {
assert(TopLayer->isLast());
const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index e3bb902b1fe9..c876eaa6358a 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -455,14 +455,16 @@ const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) {
// array is considered modified if the loop-variable is a non-const reference.
const auto DeclStmtToNonRefToArray = declStmt(hasSingleDecl(varDecl(hasType(
hasUnqualifiedDesugaredType(referenceType(pointee(arrayType())))))));
- const auto RefToArrayRefToElements = match(
- findAll(stmt(cxxForRangeStmt(
- hasLoopVariable(varDecl(hasType(nonConstReferenceType()))
- .bind(NodeID<Decl>::value)),
- hasRangeStmt(DeclStmtToNonRefToArray),
- hasRangeInit(canResolveToExpr(equalsNode(Exp)))))
- .bind("stmt")),
- Stm, Context);
+ const auto RefToArrayRefToElements =
+ match(findAll(stmt(cxxForRangeStmt(
+ hasLoopVariable(
+ varDecl(anyOf(hasType(nonConstReferenceType()),
+ hasType(nonConstPointerType())))
+ .bind(NodeID<Decl>::value)),
+ hasRangeStmt(DeclStmtToNonRefToArray),
+ hasRangeInit(canResolveToExpr(equalsNode(Exp)))))
+ .bind("stmt")),
+ Stm, Context);
if (const auto *BadRangeInitFromArray =
selectFirst<Stmt>("stmt", RefToArrayRefToElements))
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index 5105999741e6..216f41bdee1c 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -113,16 +113,27 @@ BoolValue &DataflowAnalysisContext::getOrCreateNegation(BoolValue &Val) {
BoolValue &DataflowAnalysisContext::getOrCreateImplication(BoolValue &LHS,
BoolValue &RHS) {
- return &LHS == &RHS ? getBoolLiteralValue(true)
- : getOrCreateDisjunction(getOrCreateNegation(LHS), RHS);
+ if (&LHS == &RHS)
+ return getBoolLiteralValue(true);
+
+ auto Res = ImplicationVals.try_emplace(std::make_pair(&LHS, &RHS), nullptr);
+ if (Res.second)
+ Res.first->second =
+ &takeOwnership(std::make_unique<ImplicationValue>(LHS, RHS));
+ return *Res.first->second;
}
BoolValue &DataflowAnalysisContext::getOrCreateIff(BoolValue &LHS,
BoolValue &RHS) {
- return &LHS == &RHS
- ? getBoolLiteralValue(true)
- : getOrCreateConjunction(getOrCreateImplication(LHS, RHS),
- getOrCreateImplication(RHS, LHS));
+ if (&LHS == &RHS)
+ return getBoolLiteralValue(true);
+
+ auto Res = BiconditionalVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS),
+ nullptr);
+ if (Res.second)
+ Res.first->second =
+ &takeOwnership(std::make_unique<BiconditionalValue>(LHS, RHS));
+ return *Res.first->second;
}
AtomicBoolValue &DataflowAnalysisContext::makeFlowConditionToken() {
@@ -199,18 +210,18 @@ void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
if (!Res.second)
return;
- auto ConstraintsIT = FlowConditionConstraints.find(&Token);
- if (ConstraintsIT == FlowConditionConstraints.end()) {
+ auto ConstraintsIt = FlowConditionConstraints.find(&Token);
+ if (ConstraintsIt == FlowConditionConstraints.end()) {
Constraints.insert(&Token);
} else {
// Bind flow condition token via `iff` to its set of constraints:
// FC <=> (C1 ^ C2 ^ ...), where Ci are constraints
- Constraints.insert(&getOrCreateIff(Token, *ConstraintsIT->second));
+ Constraints.insert(&getOrCreateIff(Token, *ConstraintsIt->second));
}
- auto DepsIT = FlowConditionDeps.find(&Token);
- if (DepsIT != FlowConditionDeps.end()) {
- for (AtomicBoolValue *DepToken : DepsIT->second) {
+ auto DepsIt = FlowConditionDeps.find(&Token);
+ if (DepsIt != FlowConditionDeps.end()) {
+ for (AtomicBoolValue *DepToken : DepsIt->second) {
addTransitiveFlowConditionConstraints(*DepToken, Constraints,
VisitedTokens);
}
@@ -220,10 +231,10 @@ void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
BoolValue &DataflowAnalysisContext::substituteBoolValue(
BoolValue &Val,
llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) {
- auto IT = SubstitutionsCache.find(&Val);
- if (IT != SubstitutionsCache.end()) {
+ auto It = SubstitutionsCache.find(&Val);
+ if (It != SubstitutionsCache.end()) {
// Return memoized result of substituting this boolean value.
- return *IT->second;
+ return *It->second;
}
// Handle substitution on the boolean value (and its subvalues), saving the
@@ -258,6 +269,24 @@ BoolValue &DataflowAnalysisContext::substituteBoolValue(
Result = &getOrCreateConjunction(LeftSub, RightSub);
break;
}
+ case Value::Kind::Implication: {
+ auto &IV = *cast<ImplicationValue>(&Val);
+ auto &LeftSub =
+ substituteBoolValue(IV.getLeftSubValue(), SubstitutionsCache);
+ auto &RightSub =
+ substituteBoolValue(IV.getRightSubValue(), SubstitutionsCache);
+ Result = &getOrCreateImplication(LeftSub, RightSub);
+ break;
+ }
+ case Value::Kind::Biconditional: {
+ auto &BV = *cast<BiconditionalValue>(&Val);
+ auto &LeftSub =
+ substituteBoolValue(BV.getLeftSubValue(), SubstitutionsCache);
+ auto &RightSub =
+ substituteBoolValue(BV.getRightSubValue(), SubstitutionsCache);
+ Result = &getOrCreateIff(LeftSub, RightSub);
+ break;
+ }
default:
llvm_unreachable("Unhandled Value Kind");
}
@@ -280,19 +309,19 @@ BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowCondition(
BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowConditionWithCache(
AtomicBoolValue &Token,
llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) {
- auto ConstraintsIT = FlowConditionConstraints.find(&Token);
- if (ConstraintsIT == FlowConditionConstraints.end()) {
+ auto ConstraintsIt = FlowConditionConstraints.find(&Token);
+ if (ConstraintsIt == FlowConditionConstraints.end()) {
return getBoolLiteralValue(true);
}
- auto DepsIT = FlowConditionDeps.find(&Token);
- if (DepsIT != FlowConditionDeps.end()) {
- for (AtomicBoolValue *DepToken : DepsIT->second) {
+ auto DepsIt = FlowConditionDeps.find(&Token);
+ if (DepsIt != FlowConditionDeps.end()) {
+ for (AtomicBoolValue *DepToken : DepsIt->second) {
auto &NewDep = buildAndSubstituteFlowConditionWithCache(
*DepToken, SubstitutionsCache);
SubstitutionsCache[DepToken] = &NewDep;
}
}
- return substituteBoolValue(*ConstraintsIT->second, SubstitutionsCache);
+ return substituteBoolValue(*ConstraintsIt->second, SubstitutionsCache);
}
void DataflowAnalysisContext::dumpFlowCondition(AtomicBoolValue &Token) {
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 2b6cd0c4f857..f6f71e34b892 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -200,6 +200,42 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
}
}
+Environment Environment::pushCall(const CallExpr *Call) const {
+ Environment Env(*this);
+
+ // FIXME: Currently this only works if the callee is never a method and the
+ // same callee is never analyzed from multiple separate callsites. To
+ // generalize this, we'll need to store a "context" field (probably a stack of
+ // `const CallExpr *`s) in the `Environment`, and then change the
+ // `DataflowAnalysisContext` class to hold a map from contexts to "frames",
+ // where each frame stores its own version of what are currently the
+ // `DeclToLoc`, `ExprToLoc`, and `ThisPointeeLoc` fields.
+
+ const auto *FuncDecl = Call->getDirectCallee();
+ assert(FuncDecl != nullptr);
+ assert(FuncDecl->getBody() != nullptr);
+ // FIXME: In order to allow the callee to reference globals, we probably need
+ // to call `initGlobalVars` here in some way.
+
+ auto ParamIt = FuncDecl->param_begin();
+ auto ArgIt = Call->arg_begin();
+ auto ArgEnd = Call->arg_end();
+
+ // FIXME: Parameters don't always map to arguments 1:1; examples include
+ // overloaded operators implemented as member functions, and parameter packs.
+ for (; ArgIt != ArgEnd; ++ParamIt, ++ArgIt) {
+ assert(ParamIt != FuncDecl->param_end());
+
+ const VarDecl *Param = *ParamIt;
+ const Expr *Arg = *ArgIt;
+ auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
+ assert(ArgLoc != nullptr);
+ Env.setStorageLocation(*Param, *ArgLoc);
+ }
+
+ return Env;
+}
+
bool Environment::equivalentTo(const Environment &Other,
Environment::ValueModel &Model) const {
assert(DACtx == Other.DACtx);
@@ -352,16 +388,16 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) {
}
}
- auto IT = MemberLocToStruct.find(&Loc);
- if (IT != MemberLocToStruct.end()) {
+ auto It = MemberLocToStruct.find(&Loc);
+ if (It != MemberLocToStruct.end()) {
// `Loc` is the location of a struct member so we need to also update the
// value of the member in the corresponding `StructValue`.
- assert(IT->second.first != nullptr);
- StructValue &StructVal = *IT->second.first;
+ assert(It->second.first != nullptr);
+ StructValue &StructVal = *It->second.first;
- assert(IT->second.second != nullptr);
- const ValueDecl &Member = *IT->second.second;
+ assert(It->second.second != nullptr);
+ const ValueDecl &Member = *It->second.second;
StructVal.setChild(Member, Val);
}
diff --git a/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp b/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
index 309ff0682f50..714ad08643ed 100644
--- a/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
@@ -96,6 +96,20 @@ public:
S = formatv("(not\n{0})", debugString(N.getSubVal(), Depth + 1));
break;
}
+ case Value::Kind::Implication: {
+ auto &IV = cast<ImplicationValue>(B);
+ auto L = debugString(IV.getLeftSubValue(), Depth + 1);
+ auto R = debugString(IV.getRightSubValue(), Depth + 1);
+ S = formatv("(=>\n{0}\n{1})", L, R);
+ break;
+ }
+ case Value::Kind::Biconditional: {
+ auto &BV = cast<BiconditionalValue>(B);
+ auto L = debugString(BV.getLeftSubValue(), Depth + 1);
+ auto R = debugString(BV.getRightSubValue(), Depth + 1);
+ S = formatv("(=\n{0}\n{1})", L, R);
+ break;
+ }
default:
llvm_unreachable("Unhandled value kind");
}
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 500e1a7a9390..bbf7526adce9 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -20,7 +20,9 @@
#include "clang/AST/OperationKinds.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/OperatorKinds.h"
@@ -46,8 +48,9 @@ static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
public:
- TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
- : StmtToEnv(StmtToEnv), Env(Env) {}
+ TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
+ TransferOptions Options)
+ : StmtToEnv(StmtToEnv), Env(Env), Options(Options) {}
void VisitBinaryOperator(const BinaryOperator *S) {
const Expr *LHS = S->getLHS();
@@ -503,6 +506,35 @@ public:
if (ArgLoc == nullptr)
return;
Env.setStorageLocation(*S, *ArgLoc);
+ } else if (const FunctionDecl *F = S->getDirectCallee()) {
+ // This case is for context-sensitive analysis, which we only do if we
+ // have the callee body available in the translation unit.
+ if (!Options.ContextSensitive || F->getBody() == nullptr)
+ return;
+
+ auto &ASTCtx = F->getASTContext();
+
+ // FIXME: Cache these CFGs.
+ auto CFCtx = ControlFlowContext::build(F, F->getBody(), &ASTCtx);
+ // FIXME: Handle errors here and below.
+ assert(CFCtx);
+ auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
+
+ auto CalleeEnv = Env.pushCall(S);
+
+ // FIXME: Use the same analysis as the caller for the callee.
+ DataflowAnalysisOptions Options;
+ auto Analysis = NoopAnalysis(ASTCtx, Options);
+
+ auto BlockToOutputState =
+ dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
+ assert(BlockToOutputState);
+ assert(ExitBlock < BlockToOutputState->size());
+
+ auto ExitState = (*BlockToOutputState)[ExitBlock];
+ assert(ExitState);
+
+ Env = ExitState->Env;
}
}
@@ -564,11 +596,11 @@ public:
Env.setValue(Loc, *Val);
if (Type->isStructureOrClassType()) {
- for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
- const FieldDecl *Field = std::get<0>(IT);
+ for (auto It : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
+ const FieldDecl *Field = std::get<0>(It);
assert(Field != nullptr);
- const Expr *Init = std::get<1>(IT);
+ const Expr *Init = std::get<1>(It);
assert(Init != nullptr);
if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
@@ -633,10 +665,12 @@ private:
const StmtToEnvMap &StmtToEnv;
Environment &Env;
+ TransferOptions Options;
};
-void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
- TransferVisitor(StmtToEnv, Env).Visit(&S);
+void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
+ TransferOptions Options) {
+ TransferVisitor(StmtToEnv, Env, Options).Visit(&S);
}
} // namespace dataflow
diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 6ce9dd55914d..fbb521763ee6 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -47,9 +47,9 @@ public:
: CFCtx(CFCtx), BlockToState(BlockToState) {}
const Environment *getEnvironment(const Stmt &S) const override {
- auto BlockIT = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
- assert(BlockIT != CFCtx.getStmtToBlock().end());
- const auto &State = BlockToState[BlockIT->getSecond()->getBlockID()];
+ auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
+ assert(BlockIt != CFCtx.getStmtToBlock().end());
+ const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];
assert(State);
return &State.value().Env;
}
@@ -74,8 +74,9 @@ static int blockIndexInPredecessor(const CFGBlock &Pred,
class TerminatorVisitor : public ConstStmtVisitor<TerminatorVisitor> {
public:
TerminatorVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
- int BlockSuccIdx)
- : StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx) {}
+ int BlockSuccIdx, TransferOptions TransferOpts)
+ : StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx),
+ TransferOpts(TransferOpts) {}
void VisitIfStmt(const IfStmt *S) {
auto *Cond = S->getCond();
@@ -118,7 +119,7 @@ private:
void extendFlowCondition(const Expr &Cond) {
// The terminator sub-expression might not be evaluated.
if (Env.getStorageLocation(Cond, SkipPast::None) == nullptr)
- transfer(StmtToEnv, Cond, Env);
+ transfer(StmtToEnv, Cond, Env, TransferOpts);
// FIXME: The flow condition must be an r-value, so `SkipPast::None` should
// suffice.
@@ -150,6 +151,7 @@ private:
const StmtToEnvMap &StmtToEnv;
Environment &Env;
int BlockSuccIdx;
+ TransferOptions TransferOpts;
};
/// Computes the input state for a given basic block by joining the output
@@ -217,7 +219,8 @@ static TypeErasedDataflowAnalysisState computeBlockInputState(
if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) {
const StmtToEnvMapImpl StmtToEnv(CFCtx, BlockStates);
TerminatorVisitor(StmtToEnv, PredState.Env,
- blockIndexInPredecessor(*Pred, Block))
+ blockIndexInPredecessor(*Pred, Block),
+ Analysis.builtinTransferOptions())
.Visit(PredTerminatorStmt);
}
}
@@ -253,7 +256,8 @@ static void transferCFGStmt(
assert(S != nullptr);
if (Analysis.applyBuiltinTransfer())
- transfer(StmtToEnvMapImpl(CFCtx, BlockStates), *S, State.Env);
+ transfer(StmtToEnvMapImpl(CFCtx, BlockStates), *S, State.Env,
+ Analysis.builtinTransferOptions());
Analysis.transferTypeErased(S, State.Lattice, State.Env);
if (HandleTransferredStmt != nullptr)
diff --git a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
index 6a3948bd1fea..cd1fd708a43a 100644
--- a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
+++ b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
@@ -221,6 +221,18 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
UnprocessedSubVals.push(&N->getSubVal());
break;
}
+ case Value::Kind::Implication: {
+ auto *I = cast<ImplicationValue>(Val);
+ UnprocessedSubVals.push(&I->getLeftSubValue());
+ UnprocessedSubVals.push(&I->getRightSubValue());
+ break;
+ }
+ case Value::Kind::Biconditional: {
+ auto *B = cast<BiconditionalValue>(Val);
+ UnprocessedSubVals.push(&B->getLeftSubValue());
+ UnprocessedSubVals.push(&B->getRightSubValue());
+ break;
+ }
case Value::Kind::AtomicBool: {
Atomics[Var] = cast<AtomicBoolValue>(Val);
break;
@@ -263,30 +275,52 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
const Variable LeftSubVar = GetVar(&C->getLeftSubValue());
const Variable RightSubVar = GetVar(&C->getRightSubValue());
- // `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)`
- // which is already in conjunctive normal form. Below we add each of the
- // conjuncts of the latter expression to the result.
- Formula.addClause(negLit(Var), posLit(LeftSubVar));
- Formula.addClause(negLit(Var), posLit(RightSubVar));
- Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
+ if (LeftSubVar == RightSubVar) {
+ // `X <=> (A ^ A)` is equivalent to `(!X v A) ^ (X v !A)` which is
+ // already in conjunctive normal form. Below we add each of the
+ // conjuncts of the latter expression to the result.
+ Formula.addClause(negLit(Var), posLit(LeftSubVar));
+ Formula.addClause(posLit(Var), negLit(LeftSubVar));
- // Visit the sub-values of `Val`.
- UnprocessedSubVals.push(&C->getLeftSubValue());
- UnprocessedSubVals.push(&C->getRightSubValue());
+ // Visit a sub-value of `Val` (pick any, they are identical).
+ UnprocessedSubVals.push(&C->getLeftSubValue());
+ } else {
+ // `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)`
+ // which is already in conjunctive normal form. Below we add each of the
+ // conjuncts of the latter expression to the result.
+ Formula.addClause(negLit(Var), posLit(LeftSubVar));
+ Formula.addClause(negLit(Var), posLit(RightSubVar));
+ Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
+
+ // Visit the sub-values of `Val`.
+ UnprocessedSubVals.push(&C->getLeftSubValue());
+ UnprocessedSubVals.push(&C->getRightSubValue());
+ }
} else if (auto *D = dyn_cast<DisjunctionValue>(Val)) {
const Variable LeftSubVar = GetVar(&D->getLeftSubValue());
const Variable RightSubVar = GetVar(&D->getRightSubValue());
- // `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)`
- // which is already in conjunctive normal form. Below we add each of the
- // conjuncts of the latter expression to the result.
- Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
- Formula.addClause(posLit(Var), negLit(LeftSubVar));
- Formula.addClause(posLit(Var), negLit(RightSubVar));
+ if (LeftSubVar == RightSubVar) {
+ // `X <=> (A v A)` is equivalent to `(!X v A) ^ (X v !A)` which is
+ // already in conjunctive normal form. Below we add each of the
+ // conjuncts of the latter expression to the result.
+ Formula.addClause(negLit(Var), posLit(LeftSubVar));
+ Formula.addClause(posLit(Var), negLit(LeftSubVar));
- // Visit the sub-values of `Val`.
- UnprocessedSubVals.push(&D->getLeftSubValue());
- UnprocessedSubVals.push(&D->getRightSubValue());
+ // Visit a sub-value of `Val` (pick any, they are identical).
+ UnprocessedSubVals.push(&D->getLeftSubValue());
+ } else {
+ // `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)`
+ // which is already in conjunctive normal form. Below we add each of the
+ // conjuncts of the latter expression to the result.
+ Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
+ Formula.addClause(posLit(Var), negLit(LeftSubVar));
+ Formula.addClause(posLit(Var), negLit(RightSubVar));
+
+ // Visit the sub-values of `Val`.
+ UnprocessedSubVals.push(&D->getLeftSubValue());
+ UnprocessedSubVals.push(&D->getRightSubValue());
+ }
} else if (auto *N = dyn_cast<NegationValue>(Val)) {
const Variable SubVar = GetVar(&N->getSubVal());
@@ -298,6 +332,46 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
// Visit the sub-values of `Val`.
UnprocessedSubVals.push(&N->getSubVal());
+ } else if (auto *I = dyn_cast<ImplicationValue>(Val)) {
+ const Variable LeftSubVar = GetVar(&I->getLeftSubValue());
+ const Variable RightSubVar = GetVar(&I->getRightSubValue());
+
+ // `X <=> (A => B)` is equivalent to
+ // `(X v A) ^ (X v !B) ^ (!X v !A v B)` which is already in
+ // conjunctive normal form. Below we add each of the conjuncts of the
+ // latter expression to the result.
+ Formula.addClause(posLit(Var), posLit(LeftSubVar));
+ Formula.addClause(posLit(Var), negLit(RightSubVar));
+ Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
+
+ // Visit the sub-values of `Val`.
+ UnprocessedSubVals.push(&I->getLeftSubValue());
+ UnprocessedSubVals.push(&I->getRightSubValue());
+ } else if (auto *B = dyn_cast<BiconditionalValue>(Val)) {
+ const Variable LeftSubVar = GetVar(&B->getLeftSubValue());
+ const Variable RightSubVar = GetVar(&B->getRightSubValue());
+
+ if (LeftSubVar == RightSubVar) {
+ // `X <=> (A <=> A)` is equvalent to `X` which is already in
+ // conjunctive normal form. Below we add each of the conjuncts of the
+ // latter expression to the result.
+ Formula.addClause(posLit(Var));
+
+ // No need to visit the sub-values of `Val`.
+ } else {
+ // `X <=> (A <=> B)` is equivalent to
+ // `(X v A v B) ^ (X v !A v !B) ^ (!X v A v !B) ^ (!X v !A v B)` which is
+ // already in conjunctive normal form. Below we add each of the conjuncts
+ // of the latter expression to the result.
+ Formula.addClause(posLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
+ Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
+ Formula.addClause(negLit(Var), posLit(LeftSubVar), negLit(RightSubVar));
+ Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
+
+ // Visit the sub-values of `Val`.
+ UnprocessedSubVals.push(&B->getLeftSubValue());
+ UnprocessedSubVals.push(&B->getRightSubValue());
+ }
}
}
diff --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp
index 6c601c290c92..ff7f3ebe28f8 100644
--- a/clang/lib/Analysis/LiveVariables.cpp
+++ b/clang/lib/Analysis/LiveVariables.cpp
@@ -72,6 +72,11 @@ bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const {
bool alive = false;
for (const BindingDecl *BD : DD->bindings())
alive |= liveBindings.contains(BD);
+
+ // Note: the only known case this condition is necessary, is when a bindig
+ // to a tuple-like structure is created. The HoldingVar initializers have a
+ // DeclRefExpr to the DecompositionDecl.
+ alive |= liveDecls.contains(DD);
return alive;
}
return liveDecls.contains(D);
@@ -343,8 +348,12 @@ void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
if (const BindingDecl* BD = dyn_cast<BindingDecl>(D)) {
Killed = !BD->getType()->isReferenceType();
- if (Killed)
+ if (Killed) {
+ if (const auto *HV = BD->getHoldingVar())
+ val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
+
val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
+ }
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
Killed = writeShouldKill(VD);
if (Killed)
@@ -371,8 +380,12 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
const Decl* D = DR->getDecl();
bool InAssignment = LV.inAssignment[DR];
if (const auto *BD = dyn_cast<BindingDecl>(D)) {
- if (!InAssignment)
+ if (!InAssignment) {
+ if (const auto *HV = BD->getHoldingVar())
+ val.liveDecls = LV.DSetFact.add(val.liveDecls, HV);
+
val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
+ }
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!InAssignment && !isAlwaysAlive(VD))
val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
@@ -382,8 +395,16 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
for (const auto *DI : DS->decls()) {
if (const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
- for (const auto *BD : DD->bindings())
+ for (const auto *BD : DD->bindings()) {
+ if (const auto *HV = BD->getHoldingVar())
+ val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
+
val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
+ }
+
+ // When a bindig to a tuple-like structure is created, the HoldingVar
+ // initializers have a DeclRefExpr to the DecompositionDecl.
+ val.liveDecls = LV.DSetFact.remove(val.liveDecls, DD);
} else if (const auto *VD = dyn_cast<VarDecl>(DI)) {
if (!isAlwaysAlive(VD))
val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
diff --git a/clang/lib/Basic/Targets/CSKY.h b/clang/lib/Basic/Targets/CSKY.h
index 7e932e7c86b1..6edd035d9eb8 100644
--- a/clang/lib/Basic/Targets/CSKY.h
+++ b/clang/lib/Basic/Targets/CSKY.h
@@ -71,7 +71,7 @@ public:
bool isValidCPUName(StringRef Name) const override;
- virtual unsigned getMinGlobalAlign(uint64_t) const override;
+ unsigned getMinGlobalAlign(uint64_t) const override;
ArrayRef<Builtin::Info> getTargetBuiltins() const override;
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index 9120808e298d..ca01b44ae3a5 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -849,6 +849,9 @@ void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
? &llvm::APFloat::IEEEquad()
: &llvm::APFloat::PPCDoubleDouble();
Opts.IEEE128 = 1;
+ if (getTriple().isOSAIX() && Opts.EnableAIXQuadwordAtomicsABI &&
+ HasQuadwordAtomics)
+ MaxAtomicInlineWidth = 128;
}
ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index ea98dcf42de6..0affa58b2f4c 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -229,12 +229,12 @@ public:
bool validateInputSize(const llvm::StringMap<bool> &FeatureMap,
StringRef Constraint, unsigned Size) const override;
- virtual bool
+ bool
checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override {
return true;
};
- virtual bool
+ bool
checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const override {
return true;
};
diff --git a/clang/lib/CodeGen/ABIInfo.h b/clang/lib/CodeGen/ABIInfo.h
index fe6cc7a2b1c7..c1eb8a975796 100644
--- a/clang/lib/CodeGen/ABIInfo.h
+++ b/clang/lib/CodeGen/ABIInfo.h
@@ -127,7 +127,7 @@ namespace CodeGen {
public:
SwiftABIInfo(CodeGen::CodeGenTypes &cgt) : ABIInfo(cgt) {}
- bool supportsSwift() const final override { return true; }
+ bool supportsSwift() const final { return true; }
virtual bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> types,
bool asReturnValue) const = 0;
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index a46f7f37141f..0768e6581acb 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -41,6 +41,8 @@ struct CatchTypeInfo;
/// Implements C++ ABI-specific code generation functions.
class CGCXXABI {
+ friend class CodeGenModule;
+
protected:
CodeGenModule &CGM;
std::unique_ptr<MangleContext> MangleCtx;
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 104a30dd6b25..dfa78bf59c65 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -4473,17 +4473,22 @@ llvm::CallInst *CodeGenFunction::EmitRuntimeCall(llvm::FunctionCallee callee,
// they are nested within.
SmallVector<llvm::OperandBundleDef, 1>
CodeGenFunction::getBundlesForFunclet(llvm::Value *Callee) {
- SmallVector<llvm::OperandBundleDef, 1> BundleList;
// There is no need for a funclet operand bundle if we aren't inside a
// funclet.
if (!CurrentFuncletPad)
- return BundleList;
-
- // Skip intrinsics which cannot throw.
- auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts());
- if (CalleeFn && CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow())
- return BundleList;
+ return (SmallVector<llvm::OperandBundleDef, 1>());
+
+ // Skip intrinsics which cannot throw (as long as they don't lower into
+ // regular function calls in the course of IR transformations).
+ if (auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts())) {
+ if (CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow()) {
+ auto IID = CalleeFn->getIntrinsicID();
+ if (!llvm::IntrinsicInst::mayLowerToFunctionCall(IID))
+ return (SmallVector<llvm::OperandBundleDef, 1>());
+ }
+ }
+ SmallVector<llvm::OperandBundleDef, 1> BundleList;
BundleList.emplace_back("funclet", CurrentFuncletPad);
return BundleList;
}
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index cde31711a7db..c6696c4df775 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2698,15 +2698,21 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
// Don't insert type test assumes if we are forcing public
// visibility.
!CGM.AlwaysHasLTOVisibilityPublic(RD)) {
- llvm::Metadata *MD =
- CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
+ QualType Ty = QualType(RD->getTypeForDecl(), 0);
+ llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(Ty);
llvm::Value *TypeId =
llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD);
llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
+ // If we already know that the call has hidden LTO visibility, emit
+ // @llvm.type.test(). Otherwise emit @llvm.public.type.test(), which WPD
+ // will convert to @llvm.type.test() if we assert at link time that we have
+ // whole program visibility.
+ llvm::Intrinsic::ID IID = CGM.HasHiddenLTOVisibility(RD)
+ ? llvm::Intrinsic::type_test
+ : llvm::Intrinsic::public_type_test;
llvm::Value *TypeTest =
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
- {CastedVTable, TypeId});
+ Builder.CreateCall(CGM.getIntrinsic(IID), {CastedVTable, TypeId});
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest);
}
}
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 7e9e86763af9..94c48316add7 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -491,9 +491,11 @@ StringRef CGDebugInfo::getCurrentDirname() {
if (!CWDName.empty())
return CWDName;
- SmallString<256> CWD;
- llvm::sys::fs::current_path(CWD);
- return CWDName = internString(CWD);
+ llvm::ErrorOr<std::string> CWD =
+ CGM.getFileSystem()->getCurrentWorkingDirectory();
+ if (!CWD)
+ return StringRef();
+ return CWDName = internString(*CWD);
}
void CGDebugInfo::CreateCompileUnit() {
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index ec459f07f307..7bbe9af7ed59 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -2837,11 +2837,13 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
// Enter the continuation block and emit a phi if required.
CGF.EmitBlock(continueBB);
if (msgRet.isScalar()) {
- llvm::Value *v = msgRet.getScalarVal();
- llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
- phi->addIncoming(v, nonNilPathBB);
- phi->addIncoming(CGM.EmitNullConstant(ResultType), nilPathBB);
- msgRet = RValue::get(phi);
+ // If the return type is void, do nothing
+ if (llvm::Value *v = msgRet.getScalarVal()) {
+ llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
+ phi->addIncoming(v, nonNilPathBB);
+ phi->addIncoming(CGM.EmitNullConstant(ResultType), nilPathBB);
+ msgRet = RValue::get(phi);
+ }
} else if (msgRet.isAggregate()) {
// Aggregate zeroing is handled in nilCleanupBB when it's required.
} else /* isComplex() */ {
diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h
index 1d30c5061743..ff585efa3fce 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h
@@ -186,17 +186,16 @@ public:
/// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
/// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
- virtual void emitProcBindClause(CodeGenFunction &CGF,
- llvm::omp::ProcBindKind ProcBind,
- SourceLocation Loc) override;
+ void emitProcBindClause(CodeGenFunction &CGF,
+ llvm::omp::ProcBindKind ProcBind,
+ SourceLocation Loc) override;
/// Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
/// global_tid, kmp_int32 num_threads) to generate code for 'num_threads'
/// clause.
/// \param NumThreads An integer value of threads.
- virtual void emitNumThreadsClause(CodeGenFunction &CGF,
- llvm::Value *NumThreads,
- SourceLocation Loc) override;
+ void emitNumThreadsClause(CodeGenFunction &CGF, llvm::Value *NumThreads,
+ SourceLocation Loc) override;
/// This function ought to emit, in the general case, a call to
// the openmp runtime kmpc_push_num_teams. In NVPTX backend it is not needed
@@ -300,12 +299,12 @@ public:
/// SimpleReduction Emit reduction operation only. Used for omp simd
/// directive on the host.
/// ReductionKind The kind of reduction to perform.
- virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
- ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs,
- ArrayRef<const Expr *> ReductionOps,
- ReductionOptionsTy Options) override;
+ void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
+ ArrayRef<const Expr *> Privates,
+ ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs,
+ ArrayRef<const Expr *> ReductionOps,
+ ReductionOptionsTy Options) override;
/// Returns specified OpenMP runtime function for the current OpenMP
/// implementation. Specialized for the NVPTX device.
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index 4ffbecdf2741..12c6b3f49c43 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -146,6 +146,7 @@ namespace clang {
public:
BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
@@ -159,8 +160,8 @@ namespace clang {
AsmOutStream(std::move(OS)), Context(nullptr),
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
LLVMIRGenerationRefCount(0),
- Gen(CreateLLVMCodeGen(Diags, InFile, HeaderSearchOpts, PPOpts,
- CodeGenOpts, C, CoverageInfo)),
+ Gen(CreateLLVMCodeGen(Diags, InFile, std::move(FS), HeaderSearchOpts,
+ PPOpts, CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
@@ -171,6 +172,7 @@ namespace clang {
// to use the clang diagnostic handler for IR input files. It avoids
// initializing the OS field.
BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
@@ -183,8 +185,8 @@ namespace clang {
Context(nullptr),
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
LLVMIRGenerationRefCount(0),
- Gen(CreateLLVMCodeGen(Diags, "", HeaderSearchOpts, PPOpts,
- CodeGenOpts, C, CoverageInfo)),
+ Gen(CreateLLVMCodeGen(Diags, "", std::move(FS), HeaderSearchOpts,
+ PPOpts, CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)), CurLinkModule(Module) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
@@ -1052,10 +1054,10 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
CI.getPreprocessor());
std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
- BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
- CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
- CI.getLangOpts(), std::string(InFile), std::move(LinkModules),
- std::move(OS), *VMContext, CoverageInfo));
+ BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
+ CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
+ CI.getTargetOpts(), CI.getLangOpts(), std::string(InFile),
+ std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo));
BEConsumer = Result.get();
// Enable generating macro debug info only when debug info is not disabled and
@@ -1185,9 +1187,10 @@ void CodeGenAction::ExecuteAction() {
// Set clang diagnostic handler. To do this we need to create a fake
// BackendConsumer.
- BackendConsumer Result(BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
- CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
- CI.getTargetOpts(), CI.getLangOpts(), TheModule.get(),
+ BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
+ CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
+ CI.getCodeGenOpts(), CI.getTargetOpts(),
+ CI.getLangOpts(), TheModule.get(),
std::move(LinkModules), *VMContext, nullptr);
// PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be
// true here because the valued names are needed for reading textual IR.
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 101080b6fe13..4e8e120d89df 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -96,16 +96,18 @@ static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
llvm_unreachable("invalid C++ ABI kind");
}
-CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
+CodeGenModule::CodeGenModule(ASTContext &C,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
+ const HeaderSearchOptions &HSO,
const PreprocessorOptions &PPO,
const CodeGenOptions &CGO, llvm::Module &M,
DiagnosticsEngine &diags,
CoverageSourceInfo *CoverageInfo)
- : Context(C), LangOpts(C.getLangOpts()), HeaderSearchOpts(HSO),
- PreprocessorOpts(PPO), CodeGenOpts(CGO), TheModule(M), Diags(diags),
- Target(C.getTargetInfo()), ABI(createCXXABI(*this)),
- VMContext(M.getContext()), Types(*this), VTables(*this),
- SanitizerMD(new SanitizerMetadata(*this)) {
+ : Context(C), LangOpts(C.getLangOpts()), FS(std::move(FS)),
+ HeaderSearchOpts(HSO), PreprocessorOpts(PPO), CodeGenOpts(CGO),
+ TheModule(M), Diags(diags), Target(C.getTargetInfo()),
+ ABI(createCXXABI(*this)), VMContext(M.getContext()), Types(*this),
+ VTables(*this), SanitizerMD(new SanitizerMetadata(*this)) {
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
@@ -795,18 +797,17 @@ void CodeGenModule::Release() {
Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb ||
Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 ||
Arch == llvm::Triple::aarch64_be) {
- getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
- LangOpts.BranchTargetEnforcement);
-
- getModule().addModuleFlag(llvm::Module::Min, "sign-return-address",
- LangOpts.hasSignReturnAddress());
-
- getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-all",
- LangOpts.isSignReturnAddressScopeAll());
-
- getModule().addModuleFlag(llvm::Module::Min,
- "sign-return-address-with-bkey",
- !LangOpts.isSignReturnAddressWithAKey());
+ if (LangOpts.BranchTargetEnforcement)
+ getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
+ 1);
+ if (LangOpts.hasSignReturnAddress())
+ getModule().addModuleFlag(llvm::Module::Min, "sign-return-address", 1);
+ if (LangOpts.isSignReturnAddressScopeAll())
+ getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-all",
+ 1);
+ if (!LangOpts.isSignReturnAddressWithAKey())
+ getModule().addModuleFlag(llvm::Module::Min,
+ "sign-return-address-with-bkey", 1);
}
if (!CodeGenOpts.MemoryProfileOutput.empty()) {
@@ -7000,4 +7001,6 @@ void CodeGenModule::moveLazyEmissionStates(CodeGenModule *NewBuilder) {
"Still have (unmerged) EmittedDeferredDecls deferred decls");
NewBuilder->EmittedDeferredDecls = std::move(EmittedDeferredDecls);
+
+ NewBuilder->ABI->MangleCtx = std::move(ABI->MangleCtx);
}
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index c939e7a309f5..5fbcc5ad1f5f 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -47,6 +47,10 @@ class DataLayout;
class FunctionType;
class LLVMContext;
class IndexedInstrProfReader;
+
+namespace vfs {
+class FileSystem;
+}
}
namespace clang {
@@ -293,6 +297,7 @@ public:
private:
ASTContext &Context;
const LangOptions &LangOpts;
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
const CodeGenOptions &CodeGenOpts;
@@ -584,7 +589,8 @@ private:
llvm::DenseMap<const llvm::Constant *, llvm::GlobalVariable *> RTTIProxyMap;
public:
- CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
+ CodeGenModule(ASTContext &C, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
+ const HeaderSearchOptions &headersearchopts,
const PreprocessorOptions &ppopts,
const CodeGenOptions &CodeGenOpts, llvm::Module &M,
DiagnosticsEngine &Diags,
@@ -712,6 +718,9 @@ public:
ASTContext &getContext() const { return Context; }
const LangOptions &getLangOpts() const { return LangOpts; }
+ const IntrusiveRefCntPtr<llvm::vfs::FileSystem> &getFileSystem() const {
+ return FS;
+ }
const HeaderSearchOptions &getHeaderSearchOpts()
const { return HeaderSearchOpts; }
const PreprocessorOptions &getPreprocessorOpts()
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index f0003c4aab78..fc2ff15a6acd 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -707,8 +707,12 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
if (ShouldEmitCFICheck || ShouldEmitWPDInfo) {
llvm::Value *VFPAddr =
Builder.CreateGEP(CGF.Int8Ty, VTable, VTableOffset);
+ llvm::Intrinsic::ID IID = CGM.HasHiddenLTOVisibility(RD)
+ ? llvm::Intrinsic::type_test
+ : llvm::Intrinsic::public_type_test;
+
CheckResult = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::type_test),
+ CGM.getIntrinsic(IID),
{Builder.CreateBitCast(VFPAddr, CGF.Int8PtrTy), TypeId});
}
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 2bc1e8e8c5b9..f0c45654f8d9 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -782,7 +782,7 @@ public:
LoadVTablePtr(CodeGenFunction &CGF, Address This,
const CXXRecordDecl *RD) override;
- virtual bool
+ bool
isPermittedToBeHomogeneousAggregate(const CXXRecordDecl *RD) const override;
private:
diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp
index 8e97a298ce7f..c9a5e56c72c7 100644
--- a/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -23,6 +23,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/VirtualFileSystem.h"
#include <memory>
using namespace clang;
@@ -32,6 +33,7 @@ namespace {
class CodeGeneratorImpl : public CodeGenerator {
DiagnosticsEngine &Diags;
ASTContext *Ctx;
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
@@ -74,11 +76,12 @@ namespace {
public:
CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HSO,
const PreprocessorOptions &PPO, const CodeGenOptions &CGO,
llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr)
- : Diags(diags), Ctx(nullptr), HeaderSearchOpts(HSO),
+ : Diags(diags), Ctx(nullptr), FS(std::move(FS)), HeaderSearchOpts(HSO),
PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
CoverageInfo(CoverageInfo),
M(new llvm::Module(ExpandModuleName(ModuleName, CGO), C)) {
@@ -158,7 +161,7 @@ namespace {
if (auto TVSDKVersion =
Ctx->getTargetInfo().getDarwinTargetVariantSDKVersion())
M->setDarwinTargetVariantSDKVersion(*TVSDKVersion);
- Builder.reset(new CodeGen::CodeGenModule(Context, HeaderSearchOpts,
+ Builder.reset(new CodeGen::CodeGenModule(Context, FS, HeaderSearchOpts,
PreprocessorOpts, CodeGenOpts,
*M, Diags, CoverageInfo));
@@ -356,11 +359,14 @@ llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName,
return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C);
}
-CodeGenerator *clang::CreateLLVMCodeGen(
- DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
- const HeaderSearchOptions &HeaderSearchOpts,
- const PreprocessorOptions &PreprocessorOpts, const CodeGenOptions &CGO,
- llvm::LLVMContext &C, CoverageSourceInfo *CoverageInfo) {
- return new CodeGeneratorImpl(Diags, ModuleName, HeaderSearchOpts,
- PreprocessorOpts, CGO, C, CoverageInfo);
+CodeGenerator *
+clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
+ const HeaderSearchOptions &HeaderSearchOpts,
+ const PreprocessorOptions &PreprocessorOpts,
+ const CodeGenOptions &CGO, llvm::LLVMContext &C,
+ CoverageSourceInfo *CoverageInfo) {
+ return new CodeGeneratorImpl(Diags, ModuleName, std::move(FS),
+ HeaderSearchOpts, PreprocessorOpts, CGO, C,
+ CoverageInfo);
}
diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index d03e5bd50873..f6eaa35b4873 100644
--- a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -45,6 +45,7 @@ class PCHContainerGenerator : public ASTConsumer {
const std::string OutputFileName;
ASTContext *Ctx;
ModuleMap &MMap;
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
const HeaderSearchOptions &HeaderSearchOpts;
const PreprocessorOptions &PreprocessorOpts;
CodeGenOptions CodeGenOpts;
@@ -144,6 +145,7 @@ public:
: Diags(CI.getDiagnostics()), MainFileName(MainFileName),
OutputFileName(OutputFileName), Ctx(nullptr),
MMap(CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()),
+ FS(&CI.getVirtualFileSystem()),
HeaderSearchOpts(CI.getHeaderSearchOpts()),
PreprocessorOpts(CI.getPreprocessorOpts()),
TargetOpts(CI.getTargetOpts()), LangOpts(CI.getLangOpts()),
@@ -173,7 +175,7 @@ public:
M.reset(new llvm::Module(MainFileName, *VMContext));
M->setDataLayout(Ctx->getTargetInfo().getDataLayoutString());
Builder.reset(new CodeGen::CodeGenModule(
- *Ctx, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
+ *Ctx, FS, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
// Prepare CGDebugInfo to emit debug info for a clang module.
auto *DI = Builder->getModuleDebugInfo();
diff --git a/clang/lib/CodeGen/SanitizerMetadata.h b/clang/lib/CodeGen/SanitizerMetadata.h
index bcad32ce31df..f5dd0e503cc0 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.h
+++ b/clang/lib/CodeGen/SanitizerMetadata.h
@@ -20,7 +20,6 @@
namespace llvm {
class GlobalVariable;
class Instruction;
-class MDNode;
} // namespace llvm
namespace clang {
diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
index 5c49db2f0837..a64909d9a6e7 100644
--- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -548,6 +548,11 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
if (CPUArg)
checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures,
Triple, CPUArgFPUID);
+
+ // TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a
+ // longstanding behavior.
+ (void)Args.getLastArg(options::OPT_mtune_EQ);
+
// Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
unsigned FPUID = llvm::ARM::FK_INVALID;
const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/clang/lib/Driver/ToolChains/Arch/PPC.cpp
index bcaecf4b2d98..7817ec595ceb 100644
--- a/clang/lib/Driver/ToolChains/Arch/PPC.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/PPC.cpp
@@ -107,6 +107,10 @@ const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
+ // TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a
+ // longstanding behavior.
+ (void)Args.getLastArg(options::OPT_mtune_EQ);
+
if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe)
Features.push_back("+spe");
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 3044c2d92d21..b62a025c5072 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5112,6 +5112,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-mabi=vec-default");
}
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_quadword_atomics)) {
+ if (!Triple.isOSAIX() || Triple.isPPC32())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << RawTriple.str();
+ CmdArgs.push_back("-mabi=quadword-atomics");
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_mlong_double_128)) {
// Emit the unsupported option error until the Clang's library integration
// support for 128-bit long double is available for AIX.
diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp
index e5451c20a00c..e49e8b0bf7d1 100644
--- a/clang/lib/Driver/ToolChains/FreeBSD.cpp
+++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp
@@ -489,12 +489,14 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Vptr;
- if (IsX86_64 || IsMIPS64) {
+ if (IsAArch64 || IsX86_64 || IsMIPS64) {
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Thread;
}
if (IsX86 || IsX86_64) {
Res |= SanitizerKind::Function;
+ }
+ if (IsAArch64 || IsX86 || IsX86_64) {
Res |= SanitizerKind::SafeStack;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
@@ -502,8 +504,6 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
if (IsAArch64 || IsX86_64) {
Res |= SanitizerKind::KernelAddress;
Res |= SanitizerKind::KernelMemory;
- }
- if (IsX86_64) {
Res |= SanitizerKind::Memory;
}
return Res;
diff --git a/clang/lib/Edit/EditedSource.cpp b/clang/lib/Edit/EditedSource.cpp
index ee57660b8c72..a3386b2489b0 100644
--- a/clang/lib/Edit/EditedSource.cpp
+++ b/clang/lib/Edit/EditedSource.cpp
@@ -84,11 +84,11 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
auto I = ExpansionToArgMap.find(ExpLoc);
if (I != ExpansionToArgMap.end() &&
- find_if(I->second, [&](const MacroArgUse &U) {
+ llvm::any_of(I->second, [&](const MacroArgUse &U) {
return ArgUse.Identifier == U.Identifier &&
std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
std::tie(U.ImmediateExpansionLoc, U.UseLoc);
- }) != I->second.end()) {
+ })) {
// Trying to write in a macro argument input that has already been
// written by a previous commit for another expansion of the same macro
// argument name. For example:
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index 66f03dcb53a1..3f9b68ccbb39 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -239,55 +239,6 @@ bool FormatTokenLexer::tryMergeCSharpStringLiteral() {
if (Tokens.size() < 2)
return false;
- // Interpolated strings could contain { } with " characters inside.
- // $"{x ?? "null"}"
- // should not be split into $"{x ?? ", null, "}" but should treated as a
- // single string-literal.
- //
- // We opt not to try and format expressions inside {} within a C#
- // interpolated string. Formatting expressions within an interpolated string
- // would require similar work as that done for JavaScript template strings
- // in `handleTemplateStrings()`.
- auto &CSharpInterpolatedString = *(Tokens.end() - 2);
- if (CSharpInterpolatedString->getType() == TT_CSharpStringLiteral &&
- (CSharpInterpolatedString->TokenText.startswith(R"($")") ||
- CSharpInterpolatedString->TokenText.startswith(R"($@")"))) {
- int UnmatchedOpeningBraceCount = 0;
-
- auto TokenTextSize = CSharpInterpolatedString->TokenText.size();
- for (size_t Index = 0; Index < TokenTextSize; ++Index) {
- char C = CSharpInterpolatedString->TokenText[Index];
- if (C == '{') {
- // "{{" inside an interpolated string is an escaped '{' so skip it.
- if (Index + 1 < TokenTextSize &&
- CSharpInterpolatedString->TokenText[Index + 1] == '{') {
- ++Index;
- continue;
- }
- ++UnmatchedOpeningBraceCount;
- } else if (C == '}') {
- // "}}" inside an interpolated string is an escaped '}' so skip it.
- if (Index + 1 < TokenTextSize &&
- CSharpInterpolatedString->TokenText[Index + 1] == '}') {
- ++Index;
- continue;
- }
- --UnmatchedOpeningBraceCount;
- }
- }
-
- if (UnmatchedOpeningBraceCount > 0) {
- auto &NextToken = *(Tokens.end() - 1);
- CSharpInterpolatedString->TokenText =
- StringRef(CSharpInterpolatedString->TokenText.begin(),
- NextToken->TokenText.end() -
- CSharpInterpolatedString->TokenText.begin());
- CSharpInterpolatedString->ColumnWidth += NextToken->ColumnWidth;
- Tokens.erase(Tokens.end() - 1);
- return true;
- }
- }
-
// Look for @"aaaaaa" or $"aaaaaa".
auto &String = *(Tokens.end() - 1);
if (!String->is(tok::string_literal))
@@ -571,45 +522,105 @@ void FormatTokenLexer::tryParseJSRegexLiteral() {
resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));
}
+static auto lexCSharpString(const char *Begin, const char *End, bool Verbatim,
+ bool Interpolated) {
+ auto Repeated = [&Begin, End]() {
+ return Begin + 1 < End && Begin[1] == Begin[0];
+ };
+
+ // Look for a terminating '"' in the current file buffer.
+ // Make no effort to format code within an interpolated or verbatim string.
+ //
+ // Interpolated strings could contain { } with " characters inside.
+ // $"{x ?? "null"}"
+ // should not be split into $"{x ?? ", null, "}" but should be treated as a
+ // single string-literal.
+ //
+ // We opt not to try and format expressions inside {} within a C#
+ // interpolated string. Formatting expressions within an interpolated string
+ // would require similar work as that done for JavaScript template strings
+ // in `handleTemplateStrings()`.
+ for (int UnmatchedOpeningBraceCount = 0; Begin < End; ++Begin) {
+ switch (*Begin) {
+ case '\\':
+ if (!Verbatim)
+ ++Begin;
+ break;
+ case '{':
+ if (Interpolated) {
+ // {{ inside an interpolated string is escaped, so skip it.
+ if (Repeated())
+ ++Begin;
+ else
+ ++UnmatchedOpeningBraceCount;
+ }
+ break;
+ case '}':
+ if (Interpolated) {
+ // }} inside an interpolated string is escaped, so skip it.
+ if (Repeated())
+ ++Begin;
+ else if (UnmatchedOpeningBraceCount > 0)
+ --UnmatchedOpeningBraceCount;
+ else
+ return End;
+ }
+ break;
+ case '"':
+ if (UnmatchedOpeningBraceCount > 0)
+ break;
+ // "" within a verbatim string is an escaped double quote: skip it.
+ if (Verbatim && Repeated()) {
+ ++Begin;
+ break;
+ }
+ return Begin;
+ }
+ }
+
+ return End;
+}
+
void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
FormatToken *CSharpStringLiteral = Tokens.back();
- if (CSharpStringLiteral->getType() != TT_CSharpStringLiteral)
+ if (CSharpStringLiteral->isNot(TT_CSharpStringLiteral))
return;
+ auto &TokenText = CSharpStringLiteral->TokenText;
+
+ bool Verbatim = false;
+ bool Interpolated = false;
+ if (TokenText.startswith(R"($@")")) {
+ Verbatim = true;
+ Interpolated = true;
+ } else if (TokenText.startswith(R"(@")")) {
+ Verbatim = true;
+ } else if (TokenText.startswith(R"($")")) {
+ Interpolated = true;
+ }
+
// Deal with multiline strings.
- if (!(CSharpStringLiteral->TokenText.startswith(R"(@")") ||
- CSharpStringLiteral->TokenText.startswith(R"($@")"))) {
+ if (!Verbatim && !Interpolated)
return;
- }
- const char *StrBegin =
- Lex->getBufferLocation() - CSharpStringLiteral->TokenText.size();
+ const char *StrBegin = Lex->getBufferLocation() - TokenText.size();
const char *Offset = StrBegin;
- if (CSharpStringLiteral->TokenText.startswith(R"(@")"))
- Offset += 2;
- else // CSharpStringLiteral->TokenText.startswith(R"($@")")
+ if (Verbatim && Interpolated)
Offset += 3;
+ else
+ Offset += 2;
- // Look for a terminating '"' in the current file buffer.
- // Make no effort to format code within an interpolated or verbatim string.
- for (; Offset != Lex->getBuffer().end(); ++Offset) {
- if (Offset[0] == '"') {
- // "" within a verbatim string is an escaped double quote: skip it.
- if (Offset + 1 < Lex->getBuffer().end() && Offset[1] == '"')
- ++Offset;
- else
- break;
- }
- }
+ const auto End = Lex->getBuffer().end();
+ Offset = lexCSharpString(Offset, End, Verbatim, Interpolated);
// Make no attempt to format code properly if a verbatim string is
// unterminated.
- if (Offset == Lex->getBuffer().end())
+ if (Offset >= End)
return;
StringRef LiteralText(StrBegin, Offset - StrBegin + 1);
- CSharpStringLiteral->TokenText = LiteralText;
+ TokenText = LiteralText;
// Adjust width for potentially multiline string literals.
size_t FirstBreak = LiteralText.find('\n');
@@ -628,10 +639,8 @@ void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
StartColumn, Style.TabWidth, Encoding);
}
- SourceLocation loc = Offset < Lex->getBuffer().end()
- ? Lex->getSourceLocation(Offset + 1)
- : SourceMgr.getLocForEndOfFile(ID);
- resetLexer(SourceMgr.getFileOffset(loc));
+ assert(Offset < End);
+ resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset + 1)));
}
void FormatTokenLexer::handleTemplateStrings() {
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 48cd6a394107..2dd96e68bb92 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1926,6 +1926,12 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.EnableAIXExtendedAltivecABI = O.matches(OPT_mabi_EQ_vec_extabi);
}
+ if (Arg *A = Args.getLastArg(OPT_mabi_EQ_quadword_atomics)) {
+ if (!T.isOSAIX() || T.isPPC32())
+ Diags.Report(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << T.str();
+ }
+
bool NeedLocTracking = false;
if (!Opts.OptRecordFile.empty())
diff --git a/clang/lib/Headers/stdatomic.h b/clang/lib/Headers/stdatomic.h
index 3a0b9cc056be..318c7ca56e41 100644
--- a/clang/lib/Headers/stdatomic.h
+++ b/clang/lib/Headers/stdatomic.h
@@ -17,7 +17,8 @@
* explicitly disallows `stdatomic.h` in the C mode via an `#error`. Fallback
* to the clang resource header until that is fully supported.
*/
-#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>) && !defined(_MSC_VER)
+#if __STDC_HOSTED__ && \
+ __has_include_next(<stdatomic.h>) && !(defined(_MSC_VER) && !defined(__cplusplus))
# include_next <stdatomic.h>
#else
diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h
index f11ec0aa9e75..5b0f982b62dd 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.h
+++ b/clang/lib/Interpreter/IncrementalExecutor.h
@@ -21,7 +21,6 @@
namespace llvm {
class Error;
-class Module;
namespace orc {
class LLJIT;
class ThreadSafeContext;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 2f21b7b2fef0..aef9909a7c97 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -6344,23 +6344,27 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
diag::err_expected_member_name_or_semi)
<< (D.getDeclSpec().isEmpty() ? SourceRange()
: D.getDeclSpec().getSourceRange());
- } else if (getLangOpts().CPlusPlus) {
- if (Tok.isOneOf(tok::period, tok::arrow))
- Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow);
- else {
- SourceLocation Loc = D.getCXXScopeSpec().getEndLoc();
- if (Tok.isAtStartOfLine() && Loc.isValid())
- Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id)
- << getLangOpts().CPlusPlus;
- else
- Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
- diag::err_expected_unqualified_id)
- << getLangOpts().CPlusPlus;
- }
} else {
- Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
- diag::err_expected_either)
- << tok::identifier << tok::l_paren;
+ if (Tok.getKind() == tok::TokenKind::kw_while) {
+ Diag(Tok, diag::err_while_loop_outside_of_a_function);
+ } else if (getLangOpts().CPlusPlus) {
+ if (Tok.isOneOf(tok::period, tok::arrow))
+ Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow);
+ else {
+ SourceLocation Loc = D.getCXXScopeSpec().getEndLoc();
+ if (Tok.isAtStartOfLine() && Loc.isValid())
+ Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id)
+ << getLangOpts().CPlusPlus;
+ else
+ Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
+ diag::err_expected_unqualified_id)
+ << getLangOpts().CPlusPlus;
+ }
+ } else {
+ Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
+ diag::err_expected_either)
+ << tok::identifier << tok::l_paren;
+ }
}
D.SetIdentifier(nullptr, Tok.getLocation());
D.setInvalidType(true);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 143b373e9ea5..bf73ddfd1031 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -60,7 +60,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
SourceLocation &DeclEnd,
SourceLocation InlineLoc) {
assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
- SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
+ SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
ObjCDeclContextSwitch ObjCDC(*this);
if (Tok.is(tok::code_completion)) {
@@ -99,7 +99,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
if (Tok.is(tok::identifier)) {
Ident = Tok.getIdentifierInfo();
- IdentLoc = ConsumeToken(); // eat the identifier.
+ IdentLoc = ConsumeToken(); // eat the identifier.
while (Tok.is(tok::coloncolon) &&
(NextToken().is(tok::identifier) ||
(NextToken().is(tok::kw_inline) &&
@@ -199,7 +199,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
std::string RBraces;
for (unsigned i = 0, e = ExtraNSs.size(); i != e; ++i)
- RBraces += "} ";
+ RBraces += "} ";
Diag(ExtraNSs[0].NamespaceLoc, diag::ext_nested_namespace_definition)
<< FixItHint::CreateReplacement(
@@ -216,8 +216,9 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
// If we're still good, complain about inline namespaces in non-C++0x now.
if (InlineLoc.isValid())
- Diag(InlineLoc, getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace);
+ Diag(InlineLoc, getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_inline_namespace
+ : diag::ext_inline_namespace);
// Enter a scope for the namespace.
ParseScope NamespaceScope(this, Scope::DeclScope);
@@ -496,7 +497,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDirectiveOrDeclaration(
if (TemplateInfo.Kind) {
SourceRange R = TemplateInfo.getSourceRange();
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
- << 0 /* directive */ << R << FixItHint::CreateRemoval(R);
+ << 0 /* directive */ << R << FixItHint::CreateRemoval(R);
}
Decl *UsingDir = ParseUsingDirective(Context, UsingLoc, DeclEnd, Attrs);
@@ -651,9 +652,9 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
}
if (TryConsumeToken(tok::ellipsis, D.EllipsisLoc))
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ?
- diag::warn_cxx17_compat_using_declaration_pack :
- diag::ext_using_declaration_pack);
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
+ ? diag::warn_cxx17_compat_using_declaration_pack
+ : diag::ext_using_declaration_pack);
return false;
}
@@ -766,7 +767,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
if (TemplateInfo.Kind) {
SourceRange R = TemplateInfo.getSourceRange();
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
- << 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
+ << 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
// Unfortunately, we have to bail out instead of recovering by
// ignoring the parameters, just in case the nested name specifier
@@ -811,9 +812,10 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
}
if (DeclsInGroup.size() > 1)
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ?
- diag::warn_cxx17_compat_multi_using_declaration :
- diag::ext_multi_using_declaration);
+ Diag(Tok.getLocation(),
+ getLangOpts().CPlusPlus17
+ ? diag::warn_cxx17_compat_multi_using_declaration
+ : diag::ext_multi_using_declaration);
// Eat ';'.
DeclEnd = Tok.getLocation();
@@ -835,9 +837,9 @@ Decl *Parser::ParseAliasDeclarationAfterDeclarator(
return nullptr;
}
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_alias_declaration :
- diag::ext_alias_declaration);
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_alias_declaration
+ : diag::ext_alias_declaration);
// Type alias templates cannot be specialized.
int SpecKind = -1;
@@ -856,7 +858,7 @@ Decl *Parser::ParseAliasDeclarationAfterDeclarator(
else
Range = TemplateInfo.getSourceRange();
Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
- << SpecKind << Range;
+ << SpecKind << Range;
SkipUntil(tok::semi);
return nullptr;
}
@@ -869,15 +871,15 @@ Decl *Parser::ParseAliasDeclarationAfterDeclarator(
return nullptr;
} else if (D.TypenameLoc.isValid())
Diag(D.TypenameLoc, diag::err_alias_declaration_not_identifier)
- << FixItHint::CreateRemoval(SourceRange(
- D.TypenameLoc,
- D.SS.isNotEmpty() ? D.SS.getEndLoc() : D.TypenameLoc));
+ << FixItHint::CreateRemoval(
+ SourceRange(D.TypenameLoc, D.SS.isNotEmpty() ? D.SS.getEndLoc()
+ : D.TypenameLoc));
else if (D.SS.isNotEmpty())
Diag(D.SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
- << FixItHint::CreateRemoval(D.SS.getRange());
+ << FixItHint::CreateRemoval(D.SS.getRange());
if (D.EllipsisLoc.isValid())
Diag(D.EllipsisLoc, diag::err_alias_declaration_pack_expansion)
- << FixItHint::CreateRemoval(SourceRange(D.EllipsisLoc));
+ << FixItHint::CreateRemoval(SourceRange(D.EllipsisLoc));
Decl *DeclFromDeclSpec = nullptr;
TypeResult TypeAlias =
@@ -897,8 +899,8 @@ Decl *Parser::ParseAliasDeclarationAfterDeclarator(
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
MultiTemplateParamsArg TemplateParamsArg(
- TemplateParams ? TemplateParams->data() : nullptr,
- TemplateParams ? TemplateParams->size() : 0);
+ TemplateParams ? TemplateParams->data() : nullptr,
+ TemplateParams ? TemplateParams->size() : 0);
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
UsingLoc, D.Name, Attrs, TypeAlias,
DeclFromDeclSpec);
@@ -922,10 +924,13 @@ static FixItHint getStaticAssertNoMessageFixIt(const Expr *AssertExpr,
/// [C11] static_assert-declaration:
/// _Static_assert ( constant-expression , string-literal ) ;
///
-Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
+Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) {
assert(Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert) &&
"Not a static_assert declaration");
+ // Save the token used for static assertion.
+ Token SavedTok = Tok;
+
if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11)
Diag(Tok, diag::ext_c11_feature) << Tok.getName();
if (Tok.is(tok::kw_static_assert)) {
@@ -974,7 +979,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
if (!isTokenStringLiteral()) {
Diag(Tok, diag::err_expected_string_literal)
- << /*Source='static_assert'*/1;
+ << /*Source='static_assert'*/ 1;
SkipMalformedDecl();
return nullptr;
}
@@ -989,10 +994,11 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
T.consumeClose();
DeclEnd = Tok.getLocation();
- ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert);
+ // Passing the token used to the error message.
+ ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert,
+ SavedTok.getName());
- return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc,
- AssertExpr.get(),
+ return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, AssertExpr.get(),
AssertMessage.get(),
T.getCloseLocation());
}
@@ -1003,8 +1009,8 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
/// 'decltype' ( 'auto' ) [C++1y]
///
SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
- assert(Tok.isOneOf(tok::kw_decltype, tok::annot_decltype)
- && "Not a decltype specifier");
+ assert(Tok.isOneOf(tok::kw_decltype, tok::annot_decltype) &&
+ "Not a decltype specifier");
ExprResult Result;
SourceLocation StartLoc = Tok.getLocation();
@@ -1028,11 +1034,11 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- "decltype", tok::r_paren)) {
+ if (T.expectAndConsume(diag::err_expected_lparen_after, "decltype",
+ tok::r_paren)) {
DS.SetTypeSpecError();
- return T.getOpenLocation() == Tok.getLocation() ?
- StartLoc : T.getOpenLocation();
+ return T.getOpenLocation() == Tok.getLocation() ? StartLoc
+ : T.getOpenLocation();
}
// Check for C++1y 'decltype(auto)'.
@@ -1041,8 +1047,8 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
// be 'auto' since C++2b.
Diag(Tok.getLocation(),
getLangOpts().CPlusPlus14
- ? diag::warn_cxx11_compat_decltype_auto_type_specifier
- : diag::ext_decltype_auto_type_specifier);
+ ? diag::warn_cxx11_compat_decltype_auto_type_specifier
+ : diag::ext_decltype_auto_type_specifier);
ConsumeToken();
} else {
// Parse the expression
@@ -1100,18 +1106,17 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
unsigned DiagID;
const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
// Check for duplicate type specifiers (e.g. "int decltype(a)").
- if (Result.get()
- ? DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
- DiagID, Result.get(), Policy)
- : DS.SetTypeSpecType(DeclSpec::TST_decltype_auto, StartLoc, PrevSpec,
- DiagID, Policy)) {
+ if (Result.get() ? DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc,
+ PrevSpec, DiagID, Result.get(), Policy)
+ : DS.SetTypeSpecType(DeclSpec::TST_decltype_auto, StartLoc,
+ PrevSpec, DiagID, Policy)) {
Diag(StartLoc, DiagID) << PrevSpec;
DS.SetTypeSpecError();
}
return EndLoc;
}
-void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS,
+void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
SourceLocation StartLoc,
SourceLocation EndLoc) {
// make sure we have a token we can turn into an annotation token
@@ -1124,15 +1129,14 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS,
// semi-colon.
EndLoc = PP.getLastCachedTokenLocation();
}
- }
- else
- PP.EnterToken(Tok, /*IsReinject*/true);
+ } else
+ PP.EnterToken(Tok, /*IsReinject*/ true);
Tok.setKind(tok::annot_decltype);
setExprAnnotation(Tok,
- DS.getTypeSpecType() == TST_decltype ? DS.getRepAsExpr() :
- DS.getTypeSpecType() == TST_decltype_auto ? ExprResult() :
- ExprError());
+ DS.getTypeSpecType() == TST_decltype ? DS.getRepAsExpr()
+ : DS.getTypeSpecType() == TST_decltype_auto ? ExprResult()
+ : ExprError());
Tok.setAnnotationEndLoc(EndLoc);
Tok.setLocation(StartLoc);
PP.AnnotateCachedTokens(Tok);
@@ -1144,8 +1148,8 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
SourceLocation StartLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- "__underlying_type", tok::r_paren)) {
+ if (T.expectAndConsume(diag::err_expected_lparen_after, "__underlying_type",
+ tok::r_paren)) {
return;
}
@@ -1192,7 +1196,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// Ignore attempts to use typename
if (Tok.is(tok::kw_typename)) {
Diag(Tok, diag::err_expected_class_name_not_template)
- << FixItHint::CreateRemoval(Tok.getLocation());
+ << FixItHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
}
@@ -1211,7 +1215,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
if (Tok.isOneOf(tok::kw_decltype, tok::annot_decltype)) {
if (SS.isNotEmpty())
Diag(SS.getBeginLoc(), diag::err_unexpected_scope_on_base_decltype)
- << FixItHint::CreateRemoval(SS.getRange());
+ << FixItHint::CreateRemoval(SS.getRange());
// Fake up a Declarator to use with ActOnTypeName.
DeclSpec DS(AttrFactory);
@@ -1226,7 +1230,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->mightBeType()) {
- AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);
+ AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/ true);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TypeResult Type = getTypeAnnotation(Tok);
@@ -1253,10 +1257,9 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// required nor permitted" mode, and do this there.
TemplateNameKind TNK = TNK_Non_template;
TemplateTy Template;
- if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, getCurScope(),
- &SS, Template, TNK)) {
- Diag(IdLoc, diag::err_unknown_template_name)
- << Id;
+ if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, getCurScope(), &SS,
+ Template, TNK)) {
+ Diag(IdLoc, diag::err_unknown_template_name) << Id;
}
// Form the template name
@@ -1269,7 +1272,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
return true;
if (Tok.is(tok::annot_template_id) &&
takeTemplateIdAnnotation(Tok)->mightBeType())
- AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);
+ AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/ true);
// If we didn't end up with a typename token, there's nothing more we
// can do.
@@ -1332,28 +1335,29 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) {
bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
// This switch enumerates the valid "follow" set for type-specifiers.
switch (Tok.getKind()) {
- default: break;
- case tok::semi: // struct foo {...} ;
- case tok::star: // struct foo {...} * P;
- case tok::amp: // struct foo {...} & R = ...
- case tok::ampamp: // struct foo {...} && R = ...
- case tok::identifier: // struct foo {...} V ;
- case tok::r_paren: //(struct foo {...} ) {4}
- case tok::coloncolon: // struct foo {...} :: a::b;
- case tok::annot_cxxscope: // struct foo {...} a:: b;
- case tok::annot_typename: // struct foo {...} a ::b;
- case tok::annot_template_id: // struct foo {...} a<int> ::b;
- case tok::kw_decltype: // struct foo {...} decltype (a)::b;
- case tok::l_paren: // struct foo {...} ( x);
- case tok::comma: // __builtin_offsetof(struct foo{...} ,
- case tok::kw_operator: // struct foo operator ++() {...}
- case tok::kw___declspec: // struct foo {...} __declspec(...)
- case tok::l_square: // void f(struct f [ 3])
- case tok::ellipsis: // void f(struct f ... [Ns])
+ default:
+ break;
+ case tok::semi: // struct foo {...} ;
+ case tok::star: // struct foo {...} * P;
+ case tok::amp: // struct foo {...} & R = ...
+ case tok::ampamp: // struct foo {...} && R = ...
+ case tok::identifier: // struct foo {...} V ;
+ case tok::r_paren: //(struct foo {...} ) {4}
+ case tok::coloncolon: // struct foo {...} :: a::b;
+ case tok::annot_cxxscope: // struct foo {...} a:: b;
+ case tok::annot_typename: // struct foo {...} a ::b;
+ case tok::annot_template_id: // struct foo {...} a<int> ::b;
+ case tok::kw_decltype: // struct foo {...} decltype (a)::b;
+ case tok::l_paren: // struct foo {...} ( x);
+ case tok::comma: // __builtin_offsetof(struct foo{...} ,
+ case tok::kw_operator: // struct foo operator ++() {...}
+ case tok::kw___declspec: // struct foo {...} __declspec(...)
+ case tok::l_square: // void f(struct f [ 3])
+ case tok::ellipsis: // void f(struct f ... [Ns])
// FIXME: we should emit semantic diagnostic when declaration
// attribute is in type attribute position.
- case tok::kw___attribute: // struct foo __attribute__((used)) x;
- case tok::annot_pragma_pack: // struct foo {...} _Pragma(pack(pop));
+ case tok::kw___attribute: // struct foo __attribute__((used)) x;
+ case tok::annot_pragma_pack: // struct foo {...} _Pragma(pack(pop));
// struct foo {...} _Pragma(section(...));
case tok::annot_pragma_ms_pragma:
// struct foo {...} _Pragma(vtordisp(pop));
@@ -1362,40 +1366,40 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::annot_pragma_ms_pointers_to_members:
return true;
case tok::colon:
- return CouldBeBitfield || // enum E { ... } : 2;
- ColonIsSacred; // _Generic(..., enum E : 2);
+ return CouldBeBitfield || // enum E { ... } : 2;
+ ColonIsSacred; // _Generic(..., enum E : 2);
// Microsoft compatibility
- case tok::kw___cdecl: // struct foo {...} __cdecl x;
- case tok::kw___fastcall: // struct foo {...} __fastcall x;
- case tok::kw___stdcall: // struct foo {...} __stdcall x;
- case tok::kw___thiscall: // struct foo {...} __thiscall x;
- case tok::kw___vectorcall: // struct foo {...} __vectorcall x;
+ case tok::kw___cdecl: // struct foo {...} __cdecl x;
+ case tok::kw___fastcall: // struct foo {...} __fastcall x;
+ case tok::kw___stdcall: // struct foo {...} __stdcall x;
+ case tok::kw___thiscall: // struct foo {...} __thiscall x;
+ case tok::kw___vectorcall: // struct foo {...} __vectorcall x;
// We will diagnose these calling-convention specifiers on non-function
// declarations later, so claim they are valid after a type specifier.
return getLangOpts().MicrosoftExt;
// Type qualifiers
- case tok::kw_const: // struct foo {...} const x;
- case tok::kw_volatile: // struct foo {...} volatile x;
- case tok::kw_restrict: // struct foo {...} restrict x;
- case tok::kw__Atomic: // struct foo {...} _Atomic x;
- case tok::kw___unaligned: // struct foo {...} __unaligned *x;
+ case tok::kw_const: // struct foo {...} const x;
+ case tok::kw_volatile: // struct foo {...} volatile x;
+ case tok::kw_restrict: // struct foo {...} restrict x;
+ case tok::kw__Atomic: // struct foo {...} _Atomic x;
+ case tok::kw___unaligned: // struct foo {...} __unaligned *x;
// Function specifiers
// Note, no 'explicit'. An explicit function must be either a conversion
// operator or a constructor. Either way, it can't have a return type.
- case tok::kw_inline: // struct foo inline f();
- case tok::kw_virtual: // struct foo virtual f();
- case tok::kw_friend: // struct foo friend f();
+ case tok::kw_inline: // struct foo inline f();
+ case tok::kw_virtual: // struct foo virtual f();
+ case tok::kw_friend: // struct foo friend f();
// Storage-class specifiers
- case tok::kw_static: // struct foo {...} static x;
- case tok::kw_extern: // struct foo {...} extern x;
- case tok::kw_typedef: // struct foo {...} typedef x;
- case tok::kw_register: // struct foo {...} register x;
- case tok::kw_auto: // struct foo {...} auto x;
- case tok::kw_mutable: // struct foo {...} mutable x;
- case tok::kw_thread_local: // struct foo {...} thread_local x;
- case tok::kw_constexpr: // struct foo {...} constexpr x;
- case tok::kw_consteval: // struct foo {...} consteval x;
- case tok::kw_constinit: // struct foo {...} constinit x;
+ case tok::kw_static: // struct foo {...} static x;
+ case tok::kw_extern: // struct foo {...} extern x;
+ case tok::kw_typedef: // struct foo {...} typedef x;
+ case tok::kw_register: // struct foo {...} register x;
+ case tok::kw_auto: // struct foo {...} auto x;
+ case tok::kw_mutable: // struct foo {...} mutable x;
+ case tok::kw_thread_local: // struct foo {...} thread_local x;
+ case tok::kw_constexpr: // struct foo {...} constexpr x;
+ case tok::kw_consteval: // struct foo {...} consteval x;
+ case tok::kw_constinit: // struct foo {...} constinit x;
// As shown above, type qualifiers and storage class specifiers absolutely
// can occur after class specifiers according to the grammar. However,
// almost no one actually writes code like this. If we see one of these,
@@ -1414,7 +1418,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
if (!isKnownToBeTypeSpecifier(NextToken()))
return true;
break;
- case tok::r_brace: // struct bar { struct foo {...} }
+ case tok::r_brace: // struct bar { struct foo {...} }
// Missing ';' at end of struct is accepted as an extension in C mode.
if (!getLangOpts().CPlusPlus)
return true;
@@ -1507,8 +1511,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);
// Parse inheritance specifiers.
- if (Tok.isOneOf(tok::kw___single_inheritance,
- tok::kw___multiple_inheritance,
+ if (Tok.isOneOf(tok::kw___single_inheritance, tok::kw___multiple_inheritance,
tok::kw___virtual_inheritance))
ParseMicrosoftInheritanceClassAttributes(attrs);
@@ -1519,61 +1522,32 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// C++11 attributes
SourceLocation AttrFixitLoc = Tok.getLocation();
- if (TagType == DeclSpec::TST_struct &&
- Tok.isNot(tok::identifier) &&
- !Tok.isAnnotation() &&
- Tok.getIdentifierInfo() &&
- Tok.isOneOf(tok::kw___is_abstract,
- tok::kw___is_aggregate,
- tok::kw___is_arithmetic,
- tok::kw___is_array,
- tok::kw___is_assignable,
- tok::kw___is_base_of,
- tok::kw___is_class,
- tok::kw___is_complete_type,
- tok::kw___is_compound,
- tok::kw___is_const,
- tok::kw___is_constructible,
- tok::kw___is_convertible,
- tok::kw___is_convertible_to,
- tok::kw___is_destructible,
- tok::kw___is_empty,
- tok::kw___is_enum,
- tok::kw___is_floating_point,
- tok::kw___is_final,
- tok::kw___is_function,
- tok::kw___is_fundamental,
- tok::kw___is_integral,
- tok::kw___is_interface_class,
- tok::kw___is_literal,
- tok::kw___is_lvalue_expr,
- tok::kw___is_lvalue_reference,
- tok::kw___is_member_function_pointer,
- tok::kw___is_member_object_pointer,
- tok::kw___is_member_pointer,
- tok::kw___is_nothrow_assignable,
- tok::kw___is_nothrow_constructible,
- tok::kw___is_nothrow_destructible,
- tok::kw___is_object,
- tok::kw___is_pod,
- tok::kw___is_pointer,
- tok::kw___is_polymorphic,
- tok::kw___is_reference,
- tok::kw___is_rvalue_expr,
- tok::kw___is_rvalue_reference,
- tok::kw___is_same,
- tok::kw___is_scalar,
- tok::kw___is_sealed,
- tok::kw___is_signed,
- tok::kw___is_standard_layout,
- tok::kw___is_trivial,
- tok::kw___is_trivially_assignable,
- tok::kw___is_trivially_constructible,
- tok::kw___is_trivially_copyable,
- tok::kw___is_union,
- tok::kw___is_unsigned,
- tok::kw___is_void,
- tok::kw___is_volatile))
+ if (TagType == DeclSpec::TST_struct && Tok.isNot(tok::identifier) &&
+ !Tok.isAnnotation() && Tok.getIdentifierInfo() &&
+ Tok.isOneOf(
+ tok::kw___is_abstract, tok::kw___is_aggregate,
+ tok::kw___is_arithmetic, tok::kw___is_array, tok::kw___is_assignable,
+ tok::kw___is_base_of, tok::kw___is_class, tok::kw___is_complete_type,
+ tok::kw___is_compound, tok::kw___is_const, tok::kw___is_constructible,
+ tok::kw___is_convertible, tok::kw___is_convertible_to,
+ tok::kw___is_destructible, tok::kw___is_empty, tok::kw___is_enum,
+ tok::kw___is_floating_point, tok::kw___is_final,
+ tok::kw___is_function, tok::kw___is_fundamental,
+ tok::kw___is_integral, tok::kw___is_interface_class,
+ tok::kw___is_literal, tok::kw___is_lvalue_expr,
+ tok::kw___is_lvalue_reference, tok::kw___is_member_function_pointer,
+ tok::kw___is_member_object_pointer, tok::kw___is_member_pointer,
+ tok::kw___is_nothrow_assignable, tok::kw___is_nothrow_constructible,
+ tok::kw___is_nothrow_destructible, tok::kw___is_object,
+ tok::kw___is_pod, tok::kw___is_pointer, tok::kw___is_polymorphic,
+ tok::kw___is_reference, tok::kw___is_rvalue_expr,
+ tok::kw___is_rvalue_reference, tok::kw___is_same, tok::kw___is_scalar,
+ tok::kw___is_sealed, tok::kw___is_signed,
+ tok::kw___is_standard_layout, tok::kw___is_trivial,
+ tok::kw___is_trivially_assignable,
+ tok::kw___is_trivially_constructible, tok::kw___is_trivially_copyable,
+ tok::kw___is_union, tok::kw___is_unsigned, tok::kw___is_void,
+ tok::kw___is_volatile))
// GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
// name of struct templates, but some are keywords in GCC >= 4.3
// and Clang. Therefore, when we see the token sequence "struct
@@ -1767,7 +1741,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// C++ [class.friend]p2:
// A class shall not be defined in a friend declaration.
Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
- << SourceRange(DS.getFriendSpecLoc());
+ << SourceRange(DS.getFriendSpecLoc());
// Skip everything up to the semicolon, so that this looks like a proper
// friend class (or template thereof) declaration.
@@ -1821,7 +1795,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// A semicolon was missing after this declaration. Diagnose and recover.
ExpectAndConsume(tok::semi, diag::err_expected_after,
DeclSpec::getSpecifierName(TagType, PPol));
- PP.EnterToken(Tok, /*IsReinject*/true);
+ PP.EnterToken(Tok, /*IsReinject*/ true);
Tok.setKind(tok::semi);
}
} else
@@ -1838,10 +1812,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceRange AttrRange = Attributes.Range;
if (AttrRange.isValid()) {
Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed)
- << AttrRange
- << FixItHint::CreateInsertionFromRange(AttrFixitLoc,
- CharSourceRange(AttrRange, true))
- << FixItHint::CreateRemoval(AttrRange);
+ << AttrRange
+ << FixItHint::CreateInsertionFromRange(
+ AttrFixitLoc, CharSourceRange(AttrRange, true))
+ << FixItHint::CreateRemoval(AttrRange);
// Recover by adding misplaced attributes to the attribute list
// of the class so they can be applied on the class later.
@@ -1849,12 +1823,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
}
- if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error ||
- TUK != Sema::TUK_Definition)) {
+ if (!Name && !TemplateId &&
+ (DS.getTypeSpecType() == DeclSpec::TST_error ||
+ TUK != Sema::TUK_Definition)) {
if (DS.getTypeSpecType() != DeclSpec::TST_error) {
// We have a declaration or reference to an anonymous class.
Diag(StartLoc, diag::err_anon_type_definition)
- << DeclSpec::getSpecifierName(TagType, Policy);
+ << DeclSpec::getSpecifierName(TagType, Policy);
}
// If we are parsing a definition and stop at a base-clause, continue on
@@ -1869,7 +1844,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Create the tag portion of the class or class template.
DeclResult TagOrTempResult = true; // invalid
- TypeResult TypeResult = true; // invalid
+ TypeResult TypeResult = true; // invalid
bool Owned = false;
Sema::SkipBodyInfo SkipBody;
@@ -1881,7 +1856,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TemplateId->isInvalid()) {
// Can't build the declaration.
} else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
- TUK == Sema::TUK_Declaration) {
+ TUK == Sema::TUK_Declaration) {
// This is an explicit instantiation of a class template.
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
/*DiagnoseEmptyAttrs=*/true);
@@ -1901,14 +1876,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
/*DiagnoseEmptyAttrs=*/true);
- TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc,
- SS,
- TemplateId->TemplateKWLoc,
- TemplateId->Template,
- TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
- TemplateArgsPtr,
- TemplateId->RAngleLoc);
+ TypeResult = Actions.ActOnTagTemplateIdType(
+ TUK, TagType, StartLoc, SS, TemplateId->TemplateKWLoc,
+ TemplateId->Template, TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc);
} else {
// This is an explicit specialization or a class template
// partial specialization.
@@ -1990,7 +1961,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// If the declarator-id is not a template-id, issue a diagnostic and
// recover by ignoring the 'template' keyword.
Diag(Tok, diag::err_template_defn_explicit_instantiation)
- << 1 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc);
+ << 1 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc);
TemplateParams = nullptr;
}
@@ -2002,7 +1973,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
MultiTemplateParamsArg TParams;
if (TUK != Sema::TUK_Reference && TemplateParams)
TParams =
- MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size());
+ MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size());
stripTypeAttributesOffDeclSpec(attrs, DS, TUK);
@@ -2020,8 +1991,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// less common call.
if (IsDependent) {
assert(TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend);
- TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK,
- SS, Name, StartLoc, NameLoc);
+ TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK, SS,
+ Name, StartLoc, NameLoc);
}
}
@@ -2071,10 +2042,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
NameLoc.isValid() ? NameLoc : StartLoc,
PrevSpec, DiagID, TypeResult.get(), Policy);
} else if (!TagOrTempResult.isInvalid()) {
- Result = DS.SetTypeSpecType(TagType, StartLoc,
- NameLoc.isValid() ? NameLoc : StartLoc,
- PrevSpec, DiagID, TagOrTempResult.get(), Owned,
- Policy);
+ Result = DS.SetTypeSpecType(
+ TagType, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
+ DiagID, TagOrTempResult.get(), Owned, Policy);
} else {
DS.SetTypeSpecError();
return;
@@ -2183,12 +2153,12 @@ BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
// Parse the 'virtual' keyword (again!), in case it came after the
// access specifier.
- if (Tok.is(tok::kw_virtual)) {
+ if (Tok.is(tok::kw_virtual)) {
SourceLocation VirtualLoc = ConsumeToken();
if (IsVirtual) {
// Complain about duplicate 'virtual'
Diag(VirtualLoc, diag::err_dup_virtual)
- << FixItHint::CreateRemoval(VirtualLoc);
+ << FixItHint::CreateRemoval(VirtualLoc);
}
IsVirtual = true;
@@ -2237,10 +2207,14 @@ BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
/// 'public'
AccessSpecifier Parser::getAccessSpecifierIfPresent() const {
switch (Tok.getKind()) {
- default: return AS_none;
- case tok::kw_private: return AS_private;
- case tok::kw_protected: return AS_protected;
- case tok::kw_public: return AS_public;
+ default:
+ return AS_none;
+ case tok::kw_private:
+ return AS_private;
+ case tok::kw_protected:
+ return AS_protected;
+ case tok::kw_public:
+ return AS_public;
}
}
@@ -2248,10 +2222,9 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const {
/// delayed, e.g., default arguments or an exception-specification, create a
/// late-parsed method declaration record to handle the parsing at the end of
/// the class definition.
-void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
+void Parser::HandleMemberFunctionDeclDelays(Declarator &DeclaratorInfo,
Decl *ThisDecl) {
- DeclaratorChunk::FunctionTypeInfo &FTI
- = DeclaratorInfo.getFunctionTypeInfo();
+ DeclaratorChunk::FunctionTypeInfo &FTI = DeclaratorInfo.getFunctionTypeInfo();
// If there was a late-parsed exception-specification, we'll need a
// late parse
bool NeedLateParse = FTI.getExceptionSpecType() == EST_Unparsed;
@@ -2348,9 +2321,9 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
if (FriendLoc.isValid()) {
Diag(Tok.getLocation(), diag::err_friend_decl_spec)
- << VirtSpecifiers::getSpecifierName(Specifier)
- << FixItHint::CreateRemoval(Tok.getLocation())
- << SourceRange(FriendLoc, FriendLoc);
+ << VirtSpecifiers::getSpecifierName(Specifier)
+ << FixItHint::CreateRemoval(Tok.getLocation())
+ << SourceRange(FriendLoc, FriendLoc);
ConsumeToken();
continue;
}
@@ -2360,13 +2333,12 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
const char *PrevSpec = nullptr;
if (VS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec))
Diag(Tok.getLocation(), diag::err_duplicate_virt_specifier)
- << PrevSpec
- << FixItHint::CreateRemoval(Tok.getLocation());
+ << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation());
if (IsInterface && (Specifier == VirtSpecifiers::VS_Final ||
Specifier == VirtSpecifiers::VS_Sealed)) {
Diag(Tok.getLocation(), diag::err_override_control_interface)
- << VirtSpecifiers::getSpecifierName(Specifier);
+ << VirtSpecifiers::getSpecifierName(Specifier);
} else if (Specifier == VirtSpecifiers::VS_Sealed) {
Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword);
} else if (Specifier == VirtSpecifiers::VS_Abstract) {
@@ -2436,7 +2408,8 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
VS, getCurrentClass().IsInterface,
DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
if (!VS.isUnset())
- MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS);
+ MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo,
+ VS);
}
// If a simple-asm-expr is present, parse it.
@@ -2470,7 +2443,8 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
if (AL.isKnownToGCC() && !AL.isCXX11Attribute())
Diag(AL.getLoc(), diag::warn_gcc_attribute_location);
- MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS);
+ MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo,
+ VS);
}
}
@@ -2487,8 +2461,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
/// Look for declaration specifiers possibly occurring after C++11
/// virt-specifier-seq and diagnose them.
void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
- Declarator &D,
- VirtSpecifiers &VS) {
+ Declarator &D, VirtSpecifiers &VS) {
DeclSpec DS(AttrFactory);
// GNU-style and C++11 attributes are not allowed here, but they will be
@@ -2526,15 +2499,15 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
SourceLocation RefQualifierLoc;
if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) {
const char *Name = (RefQualifierIsLValueRef ? "& " : "&& ");
- FixItHint Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name);
+ FixItHint Insertion =
+ FixItHint::CreateInsertion(VS.getFirstLocation(), Name);
Function.RefQualifierIsLValueRef = RefQualifierIsLValueRef;
Function.RefQualifierLoc = RefQualifierLoc;
Diag(RefQualifierLoc, diag::err_declspec_after_virtspec)
- << (RefQualifierIsLValueRef ? "&" : "&&")
- << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier())
- << FixItHint::CreateRemoval(RefQualifierLoc)
- << Insertion;
+ << (RefQualifierIsLValueRef ? "&" : "&&")
+ << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier())
+ << FixItHint::CreateRemoval(RefQualifierLoc) << Insertion;
D.SetRangeEnd(RefQualifierLoc);
}
}
@@ -2676,10 +2649,10 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Handle: member-declaration ::= '__extension__' member-declaration
if (Tok.is(tok::kw___extension__)) {
// __extension__ silences extension warnings in the subexpression.
- ExtensionRAIIObject O(Diags); // Use RAII to do this.
+ ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseCXXClassMemberDeclaration(AS, AccessAttrs,
- TemplateInfo, TemplateDiags);
+ return ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
+ TemplateDiags);
}
ParsedAttributes DeclAttrs(AttrFactory);
@@ -2756,9 +2729,9 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return nullptr;
MultiTemplateParamsArg TemplateParams(
- TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data()
- : nullptr,
- TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
+ TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data()
+ : nullptr,
+ TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
if (TryConsumeToken(tok::semi)) {
if (DS.isFriendSpecified())
@@ -2769,7 +2742,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
getCurScope(), AS, DS, DeclAttrs, TemplateParams, false, AnonRecord);
DS.complete(TheDecl);
if (AnonRecord) {
- Decl* decls[] = {AnonRecord, TheDecl};
+ Decl *decls[] = {AnonRecord, TheDecl};
return Actions.BuildDeclaratorGroup(decls);
}
return Actions.ConvertDeclToDeclGroup(TheDecl);
@@ -2787,7 +2760,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SourceLocation EqualLoc;
SourceLocation PureSpecLoc;
- auto TryConsumePureSpecifier = [&] (bool AllowDefinition) {
+ auto TryConsumePureSpecifier = [&](bool AllowDefinition) {
if (Tok.isNot(tok::equal))
return false;
@@ -2891,9 +2864,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DS.ClearStorageClassSpecs();
}
- Decl *FunDecl =
- ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
- VS, PureSpecLoc);
+ Decl *FunDecl = ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo,
+ TemplateInfo, VS, PureSpecLoc);
if (FunDecl) {
for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
@@ -2961,17 +2933,16 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SmallVector<SourceRange, 4> Ranges;
DeclaratorInfo.getCXX11AttributeRanges(Ranges);
for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end(); I != E; ++I)
+ E = Ranges.end();
+ I != E; ++I)
Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I;
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
TemplateParams);
} else {
- ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS,
- DeclaratorInfo,
- TemplateParams,
- BitfieldSize.get(),
- VS, HasInClassInit);
+ ThisDecl = Actions.ActOnCXXMemberDeclarator(
+ getCurScope(), AS, DeclaratorInfo, TemplateParams, BitfieldSize.get(),
+ VS, HasInClassInit);
if (VarTemplateDecl *VT =
ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : nullptr)
@@ -3031,7 +3002,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
Actions.ActOnUninitializedDecl(ThisDecl);
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
} else if (ThisDecl)
- Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid());
+ Actions.AddInitializerToDecl(ThisDecl, Init.get(),
+ EqualLoc.isInvalid());
} else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static)
// No initializer.
Actions.ActOnUninitializedDecl(ThisDecl);
@@ -3069,7 +3041,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// the start of a declarator. The comma was probably a typo for a
// semicolon.
Diag(CommaLoc, diag::err_expected_semi_declaration)
- << FixItHint::CreateReplacement(CommaLoc, ";");
+ << FixItHint::CreateReplacement(CommaLoc, ";");
ExpectSemi = false;
break;
}
@@ -3127,23 +3099,23 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
/// be a constant-expression.
ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
SourceLocation &EqualLoc) {
- assert(Tok.isOneOf(tok::equal, tok::l_brace)
- && "Data member initializer not starting with '=' or '{'");
+ assert(Tok.isOneOf(tok::equal, tok::l_brace) &&
+ "Data member initializer not starting with '=' or '{'");
EnterExpressionEvaluationContext Context(
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, D);
if (TryConsumeToken(tok::equal, EqualLoc)) {
if (Tok.is(tok::kw_delete)) {
// In principle, an initializer of '= delete p;' is legal, but it will
- // never type-check. It's better to diagnose it as an ill-formed expression
- // than as an ill-formed deleted non-function member.
- // An initializer of '= delete p, foo' will never be parsed, because
- // a top-level comma always ends the initializer expression.
+ // never type-check. It's better to diagnose it as an ill-formed
+ // expression than as an ill-formed deleted non-function member. An
+ // initializer of '= delete p, foo' will never be parsed, because a
+ // top-level comma always ends the initializer expression.
const Token &Next = NextToken();
if (IsFunction || Next.isOneOf(tok::semi, tok::comma, tok::eof)) {
if (IsFunction)
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
- << 1 /* delete */;
+ << 1 /* delete */;
else
Diag(ConsumeToken(), diag::err_deleted_non_function);
return ExprError();
@@ -3151,7 +3123,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
} else if (Tok.is(tok::kw_default)) {
if (IsFunction)
Diag(Tok, diag::err_default_delete_in_multiple_declaration)
- << 0 /* default */;
+ << 0 /* default */;
else
Diag(ConsumeToken(), diag::err_default_special_members)
<< getLangOpts().CPlusPlus20;
@@ -3190,7 +3162,7 @@ void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc,
// within a template argument).
if (Tok.is(tok::colon)) {
// Enter the scope of the class so that we can correctly parse its bases.
- ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
+ ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope);
ParsingClassDefinition ParsingDef(*this, TagDecl, /*NonNestedClass*/ true,
TagType == DeclSpec::TST_interface);
auto OldContext =
@@ -3318,8 +3290,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
default:
if (tok::isPragmaAnnotation(Tok.getKind())) {
Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
- << DeclSpec::getSpecifierName(TagType,
- Actions.getASTContext().getPrintingPolicy());
+ << DeclSpec::getSpecifierName(
+ TagType, Actions.getASTContext().getPrintingPolicy());
ConsumeAnnotationToken();
return nullptr;
}
@@ -3338,9 +3310,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
ParsedAttributes &Attrs,
unsigned TagType, Decl *TagDecl) {
assert((TagType == DeclSpec::TST_struct ||
- TagType == DeclSpec::TST_interface ||
- TagType == DeclSpec::TST_union ||
- TagType == DeclSpec::TST_class) && "Invalid TagType!");
+ TagType == DeclSpec::TST_interface ||
+ TagType == DeclSpec::TST_union || TagType == DeclSpec::TST_class) &&
+ "Invalid TagType!");
llvm::TimeTraceScope TimeScope("ParseClass", [&]() {
if (auto *TD = dyn_cast_or_null<NamedDecl>(TagDecl))
@@ -3363,10 +3335,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// The Microsoft extension __interface does not permit nested classes.
if (getCurrentClass().IsInterface) {
Diag(RecordLoc, diag::err_invalid_member_in_interface)
- << /*ErrorType=*/6
- << (isa<NamedDecl>(TagDecl)
- ? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString()
- : "(anonymous)");
+ << /*ErrorType=*/6
+ << (isa<NamedDecl>(TagDecl)
+ ? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString()
+ : "(anonymous)");
}
break;
}
@@ -3379,7 +3351,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
}
// Enter a scope for the class.
- ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
+ ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope);
// Note that we are parsing a new (potentially-nested) class definition.
ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass,
@@ -3492,7 +3464,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (SuggestFixIt) {
LBraceDiag << FixItHint::CreateInsertion(BraceLoc, " {");
// Try recovering from missing { after base-clause.
- PP.EnterToken(Tok, /*IsReinject*/true);
+ PP.EnterToken(Tok, /*IsReinject*/ true);
Tok.setKind(tok::l_brace);
} else {
if (TagDecl)
@@ -3586,10 +3558,8 @@ void Parser::DiagnoseUnexpectedNamespace(NamedDecl *D) {
// FIXME: Suggest where the close brace should have gone by looking
// at indentation changes within the definition body.
- Diag(D->getLocation(),
- diag::err_missing_end_of_definition) << D;
- Diag(Tok.getLocation(),
- diag::note_missing_end_of_definition_before) << D;
+ Diag(D->getLocation(), diag::err_missing_end_of_definition) << D;
+ Diag(Tok.getLocation(), diag::note_missing_end_of_definition_before) << D;
// Push '};' onto the token stream to recover.
PP.EnterToken(Tok, /*IsReinject*/ true);
@@ -3632,7 +3602,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
SourceLocation ColonLoc = ConsumeToken();
- SmallVector<CXXCtorInitializer*, 4> MemInitializers;
+ SmallVector<CXXCtorInitializer *, 4> MemInitializers;
bool AnyErrors = false;
do {
@@ -3659,12 +3629,12 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
Tok.isOneOf(tok::identifier, tok::coloncolon)) {
SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation);
Diag(Loc, diag::err_ctor_init_missing_comma)
- << FixItHint::CreateInsertion(Loc, ", ");
+ << FixItHint::CreateInsertion(Loc, ", ");
} else {
// Skip over garbage, until we get to '{'. Don't eat the '{'.
if (!MemInit.isInvalid())
- Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_brace
- << tok::comma;
+ Diag(Tok.getLocation(), diag::err_expected_either)
+ << tok::l_brace << tok::comma;
SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
break;
}
@@ -3718,7 +3688,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
? takeTemplateIdAnnotation(Tok)
: nullptr;
if (TemplateId && TemplateId->mightBeType()) {
- AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);
+ AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/ true);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TemplateTypeTy = getTypeAnnotation(Tok);
ConsumeAnnotationToken();
@@ -3745,7 +3715,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
TemplateTypeTy.get(), DS, IdLoc,
InitList.get(), EllipsisLoc);
- } else if(Tok.is(tok::l_paren)) {
+ } else if (Tok.is(tok::l_paren)) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
@@ -3779,10 +3749,9 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
if (TemplateTypeTy.isInvalid())
return true;
- return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
- TemplateTypeTy.get(), DS, IdLoc,
- T.getOpenLocation(), ArgExprs,
- T.getCloseLocation(), EllipsisLoc);
+ return Actions.ActOnMemInitializer(
+ ConstructorDecl, getCurScope(), SS, II, TemplateTypeTy.get(), DS, IdLoc,
+ T.getOpenLocation(), ArgExprs, T.getCloseLocation(), EllipsisLoc);
}
if (TemplateTypeTy.isInvalid())
@@ -3803,13 +3772,11 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
/// noexcept-specification:
/// 'noexcept'
/// 'noexcept' '(' constant-expression ')'
-ExceptionSpecificationType
-Parser::tryParseExceptionSpecification(bool Delayed,
- SourceRange &SpecificationRange,
- SmallVectorImpl<ParsedType> &DynamicExceptions,
- SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
- ExprResult &NoexceptExpr,
- CachedTokens *&ExceptionSpecTokens) {
+ExceptionSpecificationType Parser::tryParseExceptionSpecification(
+ bool Delayed, SourceRange &SpecificationRange,
+ SmallVectorImpl<ParsedType> &DynamicExceptions,
+ SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
+ ExprResult &NoexceptExpr, CachedTokens *&ExceptionSpecTokens) {
ExceptionSpecificationType Result = EST_None;
ExceptionSpecTokens = nullptr;
@@ -3838,8 +3805,8 @@ Parser::tryParseExceptionSpecification(bool Delayed,
// Cache the tokens for the exception-specification.
ExceptionSpecTokens = new CachedTokens;
- ExceptionSpecTokens->push_back(StartTok); // 'throw' or 'noexcept'
- ExceptionSpecTokens->push_back(Tok); // '('
+ ExceptionSpecTokens->push_back(StartTok); // 'throw' or 'noexcept'
+ ExceptionSpecTokens->push_back(Tok); // '('
SpecificationRange.setEnd(ConsumeParen()); // '('
ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens,
@@ -3852,9 +3819,8 @@ Parser::tryParseExceptionSpecification(bool Delayed,
// See if there's a dynamic specification.
if (Tok.is(tok::kw_throw)) {
- Result = ParseDynamicExceptionSpecification(SpecificationRange,
- DynamicExceptions,
- DynamicExceptionRanges);
+ Result = ParseDynamicExceptionSpecification(
+ SpecificationRange, DynamicExceptions, DynamicExceptionRanges);
assert(DynamicExceptions.size() == DynamicExceptionRanges.size() &&
"Produced different number of exception types and ranges.");
}
@@ -3878,8 +3844,8 @@ Parser::tryParseExceptionSpecification(bool Delayed,
NoexceptExpr = ParseConstantExpression();
T.consumeClose();
if (!NoexceptExpr.isInvalid()) {
- NoexceptExpr = Actions.ActOnNoexceptSpec(NoexceptExpr.get(),
- NoexceptType);
+ NoexceptExpr =
+ Actions.ActOnNoexceptSpec(NoexceptExpr.get(), NoexceptType);
NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
} else {
NoexceptType = EST_BasicNoexcept;
@@ -3908,17 +3874,16 @@ Parser::tryParseExceptionSpecification(bool Delayed,
return Result;
}
-static void diagnoseDynamicExceptionSpecification(
- Parser &P, SourceRange Range, bool IsNoexcept) {
+static void diagnoseDynamicExceptionSpecification(Parser &P, SourceRange Range,
+ bool IsNoexcept) {
if (P.getLangOpts().CPlusPlus11) {
const char *Replacement = IsNoexcept ? "noexcept" : "noexcept(false)";
- P.Diag(Range.getBegin(),
- P.getLangOpts().CPlusPlus17 && !IsNoexcept
- ? diag::ext_dynamic_exception_spec
- : diag::warn_exception_spec_deprecated)
+ P.Diag(Range.getBegin(), P.getLangOpts().CPlusPlus17 && !IsNoexcept
+ ? diag::ext_dynamic_exception_spec
+ : diag::warn_exception_spec_deprecated)
<< Range;
P.Diag(Range.getBegin(), diag::note_exception_spec_deprecated)
- << Replacement << FixItHint::CreateReplacement(Range, Replacement);
+ << Replacement << FixItHint::CreateReplacement(Range, Replacement);
}
}
@@ -3934,9 +3899,8 @@ static void diagnoseDynamicExceptionSpecification(
/// type-id-list ',' type-id ... [opt]
///
ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
- SourceRange &SpecificationRange,
- SmallVectorImpl<ParsedType> &Exceptions,
- SmallVectorImpl<SourceRange> &Ranges) {
+ SourceRange &SpecificationRange, SmallVectorImpl<ParsedType> &Exceptions,
+ SmallVectorImpl<SourceRange> &Ranges) {
assert(Tok.is(tok::kw_throw) && "expected throw");
SpecificationRange.setBegin(ConsumeToken());
@@ -4010,10 +3974,9 @@ void Parser::ParseTrailingRequiresClause(Declarator &D) {
SourceLocation RequiresKWLoc = ConsumeToken();
ExprResult TrailingRequiresClause;
- ParseScope ParamScope(this,
- Scope::DeclScope |
- Scope::FunctionDeclarationScope |
- Scope::FunctionPrototypeScope);
+ ParseScope ParamScope(this, Scope::DeclScope |
+ Scope::FunctionDeclarationScope |
+ Scope::FunctionPrototypeScope);
Actions.ActOnStartTrailingRequiresClause(getCurScope(), D);
@@ -4063,9 +4026,9 @@ void Parser::ParseTrailingRequiresClause(Declarator &D) {
/// We have just started parsing the definition of a new class,
/// so push that class onto our stack of classes that is currently
/// being parsed.
-Sema::ParsingClassState
-Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass,
- bool IsInterface) {
+Sema::ParsingClassState Parser::PushParsingClass(Decl *ClassDecl,
+ bool NonNestedClass,
+ bool IsInterface) {
assert((NonNestedClass || !ClassStack.empty()) &&
"Nested class without outer class");
ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass, IsInterface));
@@ -4113,7 +4076,8 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) {
// This nested class has some members that will need to be processed
// after the top-level class is completely defined. Therefore, add
// it to the list of nested classes within its parent.
- assert(getCurScope()->isClassScope() && "Nested class outside of class scope?");
+ assert(getCurScope()->isClassScope() &&
+ "Nested class outside of class scope?");
ClassStack.top()->LateParsedDeclarations.push_back(
new LateParsedClass(this, Victim));
}
@@ -4295,13 +4259,10 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
/// '[' balanced-token-seq ']'
/// '{' balanced-token-seq '}'
/// any token but '(', ')', '[', ']', '{', or '}'
-bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
- SourceLocation AttrNameLoc,
- ParsedAttributes &Attrs,
- SourceLocation *EndLoc,
- IdentifierInfo *ScopeName,
- SourceLocation ScopeLoc,
- CachedTokens &OpenMPTokens) {
+bool Parser::ParseCXX11AttributeArgs(
+ IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc, CachedTokens &OpenMPTokens) {
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
SourceLocation LParenLoc = Tok.getLocation();
const LangOptions &LO = getLangOpts();
@@ -4321,7 +4282,8 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
!hasAttribute(LO.CPlusPlus ? AttributeCommonInfo::Syntax::AS_CXX11
: AttributeCommonInfo::Syntax::AS_C2x,
ScopeName, AttrName, getTargetInfo(), getLangOpts())) {
- if (getLangOpts().MicrosoftExt || getLangOpts().HLSL) {}
+ if (getLangOpts().MicrosoftExt || getLangOpts().HLSL) {
+ }
// Eat the left paren, then skip to the ending right paren.
ConsumeParen();
SkipUntil(tok::r_paren);
@@ -4339,7 +4301,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
if (ScopeName && ScopeName->isStr("omp")) {
Diag(AttrNameLoc, getLangOpts().OpenMP >= 51
? diag::warn_omp51_compat_attributes
- : diag::ext_omp_attributes);
+ : diag::ext_omp_attributes);
ParseOpenMPAttributeArgs(AttrName, OpenMPTokens);
@@ -4354,9 +4316,8 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
NumArgs = ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, Syntax);
else
- NumArgs =
- ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
- ScopeName, ScopeLoc, Syntax);
+ NumArgs = ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, Syntax);
if (!Attrs.empty() &&
IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) {
@@ -4444,7 +4405,7 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
Diag(Tok.getLocation(), diag::err_expected) << tok::colon;
}
- llvm::SmallDenseMap<IdentifierInfo*, SourceLocation, 4> SeenAttrs;
+ llvm::SmallDenseMap<IdentifierInfo *, SourceLocation, 4> SeenAttrs;
bool AttrParsed = false;
while (!Tok.isOneOf(tok::r_square, tok::semi, tok::eof)) {
@@ -4510,8 +4471,7 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
}
if (TryConsumeToken(tok::ellipsis))
- Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
- << AttrName;
+ Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) << AttrName;
}
// If we hit an error and recovered by parsing up to a semicolon, eat the
@@ -4556,8 +4516,7 @@ void Parser::DiagnoseAndSkipCXX11Attributes() {
if (EndLoc.isValid()) {
SourceRange Range(StartLoc, EndLoc);
- Diag(StartLoc, diag::err_attributes_not_allowed)
- << Range;
+ Diag(StartLoc, diag::err_attributes_not_allowed) << Range;
}
}
@@ -4756,7 +4715,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(
case IEB_Dependent:
Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
- << Result.IsIfExists;
+ << Result.IsIfExists;
// Fall through to skip.
LLVM_FALLTHROUGH;
@@ -4768,8 +4727,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
// __if_exists, __if_not_exists can nest.
if (Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
- ParseMicrosoftIfExistsClassDeclaration(TagType,
- AccessAttrs, CurAS);
+ ParseMicrosoftIfExistsClassDeclaration(TagType, AccessAttrs, CurAS);
continue;
}
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 6ca98876b8fc..74fa70379858 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -350,6 +350,16 @@ struct PragmaMaxTokensTotalHandler : public PragmaHandler {
Token &FirstToken) override;
};
+struct PragmaRISCVHandler : public PragmaHandler {
+ PragmaRISCVHandler(Sema &Actions)
+ : PragmaHandler("riscv"), Actions(Actions) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+ Token &FirstToken) override;
+
+private:
+ Sema &Actions;
+};
+
void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
for (auto &T : Toks)
T.setFlag(clang::Token::IsReinjected);
@@ -493,6 +503,11 @@ void Parser::initializePragmaHandlers() {
MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>();
PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
+
+ if (getTargetInfo().getTriple().isRISCV()) {
+ RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions);
+ PP.AddPragmaHandler("clang", RISCVPragmaHandler.get());
+ }
}
void Parser::resetPragmaHandlers() {
@@ -617,6 +632,11 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
MaxTokensTotalPragmaHandler.reset();
+
+ if (getTargetInfo().getTriple().isRISCV()) {
+ PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get());
+ RISCVPragmaHandler.reset();
+ }
}
/// Handle the annotation token produced for #pragma unused(...)
@@ -3929,3 +3949,35 @@ void PragmaMaxTokensTotalHandler::HandlePragma(Preprocessor &PP,
PP.overrideMaxTokens(MaxTokens, Loc);
}
+
+// Handle '#pragma clang riscv intrinsic vector'.
+void PragmaRISCVHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducer Introducer,
+ Token &FirstToken) {
+ Token Tok;
+ PP.Lex(Tok);
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ if (!II || !II->isStr("intrinsic")) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
+ << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'intrinsic'";
+ return;
+ }
+
+ PP.Lex(Tok);
+ II = Tok.getIdentifierInfo();
+ if (!II || !II->isStr("vector")) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
+ << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'vector'";
+ return;
+ }
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "clang riscv intrinsic";
+ return;
+ }
+
+ Actions.DeclareRISCVVBuiltins = true;
+}
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index ab8748c2c63d..fd044660845b 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -153,7 +153,7 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
return true;
}
-bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
+bool Parser::ExpectAndConsumeSemi(unsigned DiagID, StringRef TokenUsed) {
if (TryConsumeToken(tok::semi))
return false;
@@ -172,7 +172,7 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
return false;
}
- return ExpectAndConsume(tok::semi, DiagID);
+ return ExpectAndConsume(tok::semi, DiagID , TokenUsed);
}
void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index 499279a2659d..98260226dfd3 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -91,7 +91,7 @@ void Scope::Init(Scope *parent, unsigned flags) {
UsingDirectives.clear();
Entity = nullptr;
ErrorTrap.reset();
- NRVO.setPointerAndInt(nullptr, false);
+ NRVO = None;
}
bool Scope::containedInPrototypeScope() const {
@@ -118,19 +118,71 @@ void Scope::AddFlags(unsigned FlagsToSet) {
Flags |= FlagsToSet;
}
-void Scope::mergeNRVOIntoParent() {
- if (VarDecl *Candidate = NRVO.getPointer()) {
- if (isDeclScope(Candidate))
- Candidate->setNRVOVariable(true);
+// The algorithm for updating NRVO candidate is as follows:
+// 1. All previous candidates become invalid because a new NRVO candidate is
+// obtained. Therefore, we need to clear return slots for other
+// variables defined before the current return statement in the current
+// scope and in outer scopes.
+// 2. Store the new candidate if its return slot is available. Otherwise,
+// there is no NRVO candidate so far.
+void Scope::updateNRVOCandidate(VarDecl *VD) {
+ auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
+ bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
+
+ // We found a candidate variable that can be put into a return slot.
+ // Clear the set, because other variables cannot occupy a return
+ // slot in the same scope.
+ S->ReturnSlots.clear();
+
+ if (IsReturnSlotFound)
+ S->ReturnSlots.insert(VD);
+
+ return IsReturnSlotFound;
+ };
+
+ bool CanBePutInReturnSlot = false;
+
+ for (auto *S = this; S; S = S->getParent()) {
+ CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
+
+ if (S->getEntity())
+ break;
}
- if (getEntity())
+ // Consider the variable as NRVO candidate if the return slot is available
+ // for it in the current scope, or if it can be available in outer scopes.
+ NRVO = CanBePutInReturnSlot ? VD : nullptr;
+}
+
+void Scope::applyNRVO() {
+ // There is no NRVO candidate in the current scope.
+ if (!NRVO.hasValue())
return;
- if (NRVO.getInt())
- getParent()->setNoNRVO();
- else if (NRVO.getPointer())
- getParent()->addNRVOCandidate(NRVO.getPointer());
+ if (*NRVO && isDeclScope(*NRVO))
+ NRVO.getValue()->setNRVOVariable(true);
+
+ // It's necessary to propagate NRVO candidate to the parent scope for cases
+ // when the parent scope doesn't contain a return statement.
+ // For example:
+ // X foo(bool b) {
+ // X x;
+ // if (b)
+ // return x;
+ // exit(0);
+ // }
+ // Also, we need to propagate nullptr value that means NRVO is not
+ // allowed in this scope.
+ // For example:
+ // X foo(bool b) {
+ // X x;
+ // if (b)
+ // return x;
+ // else
+ // return X(); // NRVO is not allowed
+ // }
+ if (!getEntity())
+ getParent()->NRVO = *NRVO;
}
LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
@@ -193,8 +245,10 @@ void Scope::dumpImpl(raw_ostream &OS) const {
if (const DeclContext *DC = getEntity())
OS << "Entity : (clang::DeclContext*)" << DC << '\n';
- if (NRVO.getInt())
- OS << "NRVO not allowed\n";
- else if (NRVO.getPointer())
- OS << "NRVO candidate : (clang::VarDecl*)" << NRVO.getPointer() << '\n';
+ if (!NRVO)
+ OS << "there is no NRVO candidate\n";
+ else if (*NRVO)
+ OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
+ else
+ OS << "NRVO is not allowed\n";
}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 326010d4d93f..08957ce9fada 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -37,6 +37,7 @@
#include "clang/Sema/Initialization.h"
#include "clang/Sema/MultiplexExternalSemaSource.h"
#include "clang/Sema/ObjCMethodList.h"
+#include "clang/Sema/RISCVIntrinsicManager.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaConsumer.h"
@@ -137,9 +138,9 @@ public:
void reset() { S = nullptr; }
- virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType,
- FileID PrevFID) override {
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override {
if (!S)
return;
switch (Reason) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 8d2fc5331a0d..985005d0b79b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2092,7 +2092,7 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
- S->mergeNRVOIntoParent();
+ S->applyNRVO();
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
@@ -18899,14 +18899,24 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
const llvm::APSInt &InitVal = ECD->getInitVal();
// Keep track of the size of positive and negative values.
- if (InitVal.isUnsigned() || InitVal.isNonNegative())
- NumPositiveBits = std::max(NumPositiveBits,
- (unsigned)InitVal.getActiveBits());
- else
+ if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
+ // If the enumerator is zero that should still be counted as a positive
+ // bit since we need a bit to store the value zero.
+ unsigned ActiveBits = InitVal.getActiveBits();
+ NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
+ } else {
NumNegativeBits = std::max(NumNegativeBits,
(unsigned)InitVal.getMinSignedBits());
+ }
}
+ // If we have have an empty set of enumerators we still need one bit.
+ // From [dcl.enum]p8
+ // If the enumerator-list is empty, the values of the enumeration are as if
+ // the enumeration had a single enumerator with value 0
+ if (!NumPositiveBits && !NumNegativeBits)
+ NumPositiveBits = 1;
+
// Figure out the type that should be used for this enum.
QualType BestType;
unsigned BestWidth;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index cd5cdbde7f3f..0f79978b0911 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13824,7 +13824,8 @@ static void CheckIdentityFieldAssignment(Expr *LHSExpr, Expr *RHSExpr,
// C99 6.5.16.1
QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
SourceLocation Loc,
- QualType CompoundType) {
+ QualType CompoundType,
+ BinaryOperatorKind Opc) {
assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject));
// Verify that LHS is a modifiable lvalue, and emit error if not.
@@ -13937,10 +13938,18 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// expression or an unevaluated operand
ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr);
} else {
- // C++2a [expr.ass]p6:
+ // C++20 [expr.ass]p6:
// [Compound-assignment] expressions are deprecated if E1 has
- // volatile-qualified type
- Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
+ // volatile-qualified type and op is not one of the bitwise
+ // operators |, &, ˆ.
+ switch (Opc) {
+ case BO_OrAssign:
+ case BO_AndAssign:
+ case BO_XorAssign:
+ break;
+ default:
+ Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
+ }
}
}
@@ -14879,7 +14888,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
switch (Opc) {
case BO_Assign:
- ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
+ ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType(), Opc);
if (getLangOpts().CPlusPlus &&
LHS.get()->getObjectKind() != OK_ObjCProperty) {
VK = LHS.get()->getValueKind();
@@ -14976,32 +14985,37 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
Opc == BO_DivAssign);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
- ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
+ ResultTy =
+ CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_RemAssign:
CompResultTy = CheckRemainderOperands(LHS, RHS, OpLoc, true);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
- ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
+ ResultTy =
+ CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_AddAssign:
ConvertHalfVec = true;
CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
- ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
+ ResultTy =
+ CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_SubAssign:
ConvertHalfVec = true;
CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
- ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
+ ResultTy =
+ CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_ShlAssign:
case BO_ShrAssign:
CompResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc, true);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
- ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
+ ResultTy =
+ CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_AndAssign:
case BO_OrAssign: // fallthrough
@@ -15011,7 +15025,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
- ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
+ ResultTy =
+ CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_Comma:
ResultTy = CheckCommaOperands(*this, LHS, RHS, OpLoc);
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 242e1f81d75c..68158ec977cf 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -29,6 +29,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
+#include "clang/Sema/RISCVIntrinsicManager.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
@@ -928,6 +929,14 @@ bool Sema::LookupBuiltin(LookupResult &R) {
}
}
+ if (DeclareRISCVVBuiltins) {
+ if (!RVIntrinsicManager)
+ RVIntrinsicManager = CreateRISCVIntrinsicManager(*this);
+
+ if (RVIntrinsicManager->CreateIntrinsicIfFound(R, II, PP))
+ return true;
+ }
+
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID()) {
// In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any
@@ -3838,6 +3847,12 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
+ //
+ // C++20 [basic.lookup.argdep] p4.3
+ // -- are exported, are attached to a named module M, do not appear
+ // in the translation unit containing the point of the lookup, and
+ // have the same innermost enclosing non-inline namespace scope as
+ // a declaration of an associated entity attached to M.
DeclContext::lookup_result R = NS->lookup(Name);
for (auto *D : R) {
auto *Underlying = D;
@@ -3858,6 +3873,36 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
if (isVisible(D)) {
Visible = true;
break;
+ } else if (getLangOpts().CPlusPlusModules &&
+ D->isInExportDeclContext()) {
+ // C++20 [basic.lookup.argdep] p4.3 .. are exported ...
+ Module *FM = D->getOwningModule();
+ // exports are only valid in module purview and outside of any
+ // PMF (although a PMF should not even be present in a module
+ // with an import).
+ assert(FM && FM->isModulePurview() && !FM->isPrivateModule() &&
+ "bad export context");
+ // .. are attached to a named module M, do not appear in the
+ // translation unit containing the point of the lookup..
+ if (!isModuleUnitOfCurrentTU(FM) &&
+ llvm::any_of(AssociatedClasses, [&](auto *E) {
+ // ... and have the same innermost enclosing non-inline
+ // namespace scope as a declaration of an associated entity
+ // attached to M
+ if (!E->hasOwningModule() ||
+ E->getOwningModule()->getTopLevelModuleName() !=
+ FM->getTopLevelModuleName())
+ return false;
+ // TODO: maybe this could be cached when generating the
+ // associated namespaces / entities.
+ DeclContext *Ctx = E->getDeclContext();
+ while (!Ctx->isFileContext() || Ctx->isInlineNamespace())
+ Ctx = Ctx->getParent();
+ return Ctx == NS;
+ })) {
+ Visible = true;
+ break;
+ }
}
} else if (D->getFriendObjectKind()) {
auto *RD = cast<CXXRecordDecl>(D->getLexicalDeclContext());
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index c226ed625479..d72cc33ed0f5 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -63,8 +63,9 @@ static ExprResult CreateFunctionRefExpr(
// being used.
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return ExprError();
- DeclRefExpr *DRE = new (S.Context)
- DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
+ DeclRefExpr *DRE =
+ DeclRefExpr::Create(S.Context, Fn->getQualifierLoc(), SourceLocation(),
+ Fn, false, Loc, Fn->getType(), VK_LValue, FoundDecl);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
@@ -6400,6 +6401,27 @@ void Sema::AddOverloadCandidate(
return;
}
+ // Functions with internal linkage are only viable in the same module unit.
+ if (auto *MF = Function->getOwningModule()) {
+ if (getLangOpts().CPlusPlusModules && !MF->isModuleMapModule() &&
+ !isModuleUnitOfCurrentTU(MF)) {
+ /// FIXME: Currently, the semantics of linkage in clang is slightly
+ /// different from the semantics in C++ spec. In C++ spec, only names
+ /// have linkage. So that all entities of the same should share one
+ /// linkage. But in clang, different entities of the same could have
+ /// different linkage.
+ NamedDecl *ND = Function;
+ if (auto *SpecInfo = Function->getTemplateSpecializationInfo())
+ ND = SpecInfo->getTemplate();
+
+ if (ND->getFormalLinkage() == Linkage::InternalLinkage) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_module_mismatched;
+ return;
+ }
+ }
+ }
+
if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() &&
!Function->getAttr<TargetAttr>()->isDefaultVersion()) {
Candidate.Viable = false;
diff --git a/clang/lib/Sema/SemaRISCVVectorLookup.cpp b/clang/lib/Sema/SemaRISCVVectorLookup.cpp
new file mode 100644
index 000000000000..50fd841c231b
--- /dev/null
+++ b/clang/lib/Sema/SemaRISCVVectorLookup.cpp
@@ -0,0 +1,395 @@
+//==- SemaRISCVVectorLookup.cpp - Name Lookup for RISC-V Vector Intrinsic -==//
+//
+// 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 implements name lookup for RISC-V vector intrinsic.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/RISCVIntrinsicManager.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Support/RISCVVIntrinsicUtils.h"
+#include "llvm/ADT/SmallVector.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace clang;
+using namespace clang::RISCV;
+
+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;
+
+ /// Function signature, first element is return type.
+ RVVTypes Signature;
+};
+
+struct RVVOverloadIntrinsicDef {
+ // Indexes of RISCVIntrinsicManagerImpl::IntrinsicList.
+ SmallVector<size_t, 8> Indexes;
+};
+
+} // namespace
+
+static const PrototypeDescriptor RVVSignatureTable[] = {
+#define DECL_SIGNATURE_TABLE
+#include "clang/Basic/riscv_vector_builtin_sema.inc"
+#undef DECL_SIGNATURE_TABLE
+};
+
+static const RVVIntrinsicRecord RVVIntrinsicRecords[] = {
+#define DECL_INTRINSIC_RECORDS
+#include "clang/Basic/riscv_vector_builtin_sema.inc"
+#undef DECL_INTRINSIC_RECORDS
+};
+
+// Get subsequence of signature table.
+static ArrayRef<PrototypeDescriptor> ProtoSeq2ArrayRef(uint16_t Index,
+ uint8_t Length) {
+ return makeArrayRef(&RVVSignatureTable[Index], Length);
+}
+
+static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) {
+ QualType QT;
+ switch (Type->getScalarType()) {
+ case ScalarTypeKind::Void:
+ QT = Context.VoidTy;
+ break;
+ case ScalarTypeKind::Size_t:
+ QT = Context.getSizeType();
+ break;
+ case ScalarTypeKind::Ptrdiff_t:
+ QT = Context.getPointerDiffType();
+ break;
+ case ScalarTypeKind::UnsignedLong:
+ QT = Context.UnsignedLongTy;
+ break;
+ case ScalarTypeKind::SignedLong:
+ QT = Context.LongTy;
+ break;
+ case ScalarTypeKind::Boolean:
+ QT = Context.BoolTy;
+ break;
+ case ScalarTypeKind::SignedInteger:
+ QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), true);
+ break;
+ case ScalarTypeKind::UnsignedInteger:
+ QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), false);
+ break;
+ case ScalarTypeKind::Float:
+ switch (Type->getElementBitwidth()) {
+ case 64:
+ QT = Context.DoubleTy;
+ break;
+ case 32:
+ QT = Context.FloatTy;
+ break;
+ case 16:
+ QT = Context.Float16Ty;
+ break;
+ default:
+ llvm_unreachable("Unsupported floating point width.");
+ }
+ break;
+ case Invalid:
+ llvm_unreachable("Unhandled type.");
+ }
+ if (Type->isVector())
+ QT = Context.getScalableVectorType(QT, Type->getScale().getValue());
+
+ if (Type->isConstant())
+ QT = Context.getConstType(QT);
+
+ // Transform the type to a pointer as the last step, if necessary.
+ if (Type->isPointer())
+ QT = Context.getPointerType(QT);
+
+ return QT;
+}
+
+namespace {
+class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager {
+private:
+ Sema &S;
+ ASTContext &Context;
+
+ // List of all RVV intrinsic.
+ std::vector<RVVIntrinsicDef> IntrinsicList;
+ // Mapping function name to index of IntrinsicList.
+ StringMap<size_t> Intrinsics;
+ // Mapping function name to RVVOverloadIntrinsicDef.
+ StringMap<RVVOverloadIntrinsicDef> OverloadIntrinsics;
+
+ // Create IntrinsicList
+ void InitIntrinsicList();
+
+ // Create RVVIntrinsicDef.
+ void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr,
+ StringRef OverloadedSuffixStr, bool IsMask,
+ RVVTypes &Types);
+
+ // Create FunctionDecl for a vector intrinsic.
+ void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II,
+ Preprocessor &PP, unsigned Index,
+ bool IsOverload);
+
+public:
+ RISCVIntrinsicManagerImpl(clang::Sema &S) : S(S), Context(S.Context) {
+ InitIntrinsicList();
+ }
+
+ // Create RISC-V vector intrinsic and insert into symbol table if found, and
+ // return true, otherwise return false.
+ bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II,
+ Preprocessor &PP) override;
+};
+} // namespace
+
+void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
+ const TargetInfo &TI = Context.getTargetInfo();
+ bool HasVectorFloat32 = TI.hasFeature("zve32f");
+ bool HasVectorFloat64 = TI.hasFeature("zve64d");
+ bool HasZvfh = TI.hasFeature("experimental-zvfh");
+ bool HasRV64 = TI.hasFeature("64bit");
+ bool HasFullMultiply = TI.hasFeature("v");
+
+ // Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics
+ // in RISCVVEmitter.cpp.
+ for (auto &Record : RVVIntrinsicRecords) {
+ // Create Intrinsics for each type and LMUL.
+ BasicType BaseType = BasicType::Unknown;
+ ArrayRef<PrototypeDescriptor> BasicProtoSeq =
+ ProtoSeq2ArrayRef(Record.PrototypeIndex, Record.PrototypeLength);
+ ArrayRef<PrototypeDescriptor> SuffixProto =
+ ProtoSeq2ArrayRef(Record.SuffixIndex, Record.SuffixLength);
+ ArrayRef<PrototypeDescriptor> OverloadedSuffixProto = ProtoSeq2ArrayRef(
+ Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize);
+
+ llvm::SmallVector<PrototypeDescriptor> ProtoSeq =
+ RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/false,
+ /*HasMaskedOffOperand=*/false,
+ Record.HasVL, Record.NF);
+
+ llvm::SmallVector<PrototypeDescriptor> ProtoMaskSeq =
+ RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/true,
+ Record.HasMaskedOffOperand,
+ Record.HasVL, Record.NF);
+
+ for (unsigned int TypeRangeMaskShift = 0;
+ TypeRangeMaskShift <= static_cast<unsigned int>(BasicType::MaxOffset);
+ ++TypeRangeMaskShift) {
+ unsigned int BaseTypeI = 1 << TypeRangeMaskShift;
+ BaseType = static_cast<BasicType>(BaseTypeI);
+
+ if ((BaseTypeI & Record.TypeRangeMask) != BaseTypeI)
+ continue;
+
+ // Check requirement.
+ if (BaseType == BasicType::Float16 && !HasZvfh)
+ continue;
+
+ if (BaseType == BasicType::Float32 && !HasVectorFloat32)
+ continue;
+
+ if (BaseType == BasicType::Float64 && !HasVectorFloat64)
+ continue;
+
+ if (((Record.RequiredExtensions & RVV_REQ_RV64) == RVV_REQ_RV64) &&
+ !HasRV64)
+ continue;
+
+ if ((BaseType == BasicType::Int64) &&
+ ((Record.RequiredExtensions & RVV_REQ_FullMultiply) ==
+ RVV_REQ_FullMultiply) &&
+ !HasFullMultiply)
+ continue;
+
+ // Expanded with different LMUL.
+ for (int Log2LMUL = -3; Log2LMUL <= 3; Log2LMUL++) {
+ if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3))))
+ continue;
+
+ Optional<RVVTypes> Types =
+ RVVType::computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq);
+
+ // Ignored to create new intrinsic if there are any illegal types.
+ if (!Types.hasValue())
+ continue;
+
+ std::string SuffixStr =
+ RVVIntrinsic::getSuffixStr(BaseType, Log2LMUL, SuffixProto);
+ std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
+ BaseType, Log2LMUL, OverloadedSuffixProto);
+
+ // Create non-masked intrinsic.
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types);
+
+ if (Record.HasMasked) {
+ // Create masked intrinsic.
+ Optional<RVVTypes> MaskTypes = RVVType::computeTypes(
+ BaseType, Log2LMUL, Record.NF, ProtoMaskSeq);
+
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true,
+ *MaskTypes);
+ }
+ }
+ }
+ }
+}
+
+// Compute name and signatures for intrinsic with practical types.
+void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
+ const RVVIntrinsicRecord &Record, StringRef SuffixStr,
+ StringRef OverloadedSuffixStr, bool IsMask, RVVTypes &Signature) {
+ // Function name, e.g. vadd_vv_i32m1.
+ std::string Name = Record.Name;
+ if (!SuffixStr.empty())
+ Name += "_" + SuffixStr.str();
+
+ if (IsMask)
+ Name += "_m";
+
+ // Overloaded function name, e.g. vadd.
+ std::string OverloadedName;
+ if (!Record.OverloadedName)
+ OverloadedName = StringRef(Record.Name).split("_").first.str();
+ else
+ OverloadedName = Record.OverloadedName;
+ if (!OverloadedSuffixStr.empty())
+ OverloadedName += "_" + OverloadedSuffixStr.str();
+
+ // clang built-in function name, e.g. __builtin_rvv_vadd.
+ std::string BuiltinName = "__builtin_rvv_" + std::string(Record.Name);
+ if (IsMask)
+ BuiltinName += "_m";
+
+ // Put into IntrinsicList.
+ size_t Index = IntrinsicList.size();
+ IntrinsicList.push_back({Name, OverloadedName, BuiltinName, Signature});
+
+ // Creating mapping to Intrinsics.
+ Intrinsics.insert({Name, Index});
+
+ // Get the RVVOverloadIntrinsicDef.
+ RVVOverloadIntrinsicDef &OverloadIntrinsicDef =
+ OverloadIntrinsics[OverloadedName];
+
+ // And added the index.
+ OverloadIntrinsicDef.Indexes.push_back(Index);
+}
+
+void RISCVIntrinsicManagerImpl::CreateRVVIntrinsicDecl(LookupResult &LR,
+ IdentifierInfo *II,
+ Preprocessor &PP,
+ unsigned Index,
+ bool IsOverload) {
+ ASTContext &Context = S.Context;
+ RVVIntrinsicDef &IDef = IntrinsicList[Index];
+ RVVTypes Sigs = IDef.Signature;
+ size_t SigLength = Sigs.size();
+ RVVType *ReturnType = Sigs[0];
+ QualType RetType = RVVType2Qual(Context, ReturnType);
+ SmallVector<QualType, 8> ArgTypes;
+ QualType BuiltinFuncType;
+
+ // Skip return type, and convert RVVType to QualType for arguments.
+ for (size_t i = 1; i < SigLength; ++i)
+ ArgTypes.push_back(RVVType2Qual(Context, Sigs[i]));
+
+ FunctionProtoType::ExtProtoInfo PI(
+ Context.getDefaultCallingConvention(false, false, true));
+
+ PI.Variadic = false;
+
+ SourceLocation Loc = LR.getNameLoc();
+ BuiltinFuncType = Context.getFunctionType(RetType, ArgTypes, PI);
+ DeclContext *Parent = Context.getTranslationUnitDecl();
+
+ FunctionDecl *RVVIntrinsicDecl = FunctionDecl::Create(
+ Context, Parent, Loc, Loc, II, BuiltinFuncType, /*TInfo=*/nullptr,
+ SC_Extern, S.getCurFPFeatures().isFPConstrained(),
+ /*isInlineSpecified*/ false,
+ /*hasWrittenPrototype*/ true);
+
+ // Create Decl objects for each parameter, adding them to the
+ // FunctionDecl.
+ const auto *FP = cast<FunctionProtoType>(BuiltinFuncType);
+ SmallVector<ParmVarDecl *, 8> ParmList;
+ for (unsigned IParm = 0, E = FP->getNumParams(); IParm != E; ++IParm) {
+ ParmVarDecl *Parm =
+ ParmVarDecl::Create(Context, RVVIntrinsicDecl, Loc, Loc, nullptr,
+ FP->getParamType(IParm), nullptr, SC_None, nullptr);
+ Parm->setScopeInfo(0, IParm);
+ ParmList.push_back(Parm);
+ }
+ RVVIntrinsicDecl->setParams(ParmList);
+
+ // Add function attributes.
+ if (IsOverload)
+ RVVIntrinsicDecl->addAttr(OverloadableAttr::CreateImplicit(Context));
+
+ // Setup alias to __builtin_rvv_*
+ IdentifierInfo &IntrinsicII = PP.getIdentifierTable().get(IDef.BuiltinName);
+ RVVIntrinsicDecl->addAttr(
+ BuiltinAliasAttr::CreateImplicit(S.Context, &IntrinsicII));
+
+ // Add to symbol table.
+ LR.addDecl(RVVIntrinsicDecl);
+}
+
+bool RISCVIntrinsicManagerImpl::CreateIntrinsicIfFound(LookupResult &LR,
+ IdentifierInfo *II,
+ Preprocessor &PP) {
+ StringRef Name = II->getName();
+
+ // Lookup the function name from the overload intrinsics first.
+ auto OvIItr = OverloadIntrinsics.find(Name);
+ if (OvIItr != OverloadIntrinsics.end()) {
+ const RVVOverloadIntrinsicDef &OvIntrinsicDef = OvIItr->second;
+ for (auto Index : OvIntrinsicDef.Indexes)
+ CreateRVVIntrinsicDecl(LR, II, PP, Index,
+ /*IsOverload*/ true);
+
+ // If we added overloads, need to resolve the lookup result.
+ LR.resolveKind();
+ return true;
+ }
+
+ // Lookup the function name from the intrinsics.
+ auto Itr = Intrinsics.find(Name);
+ if (Itr != Intrinsics.end()) {
+ CreateRVVIntrinsicDecl(LR, II, PP, Itr->second,
+ /*IsOverload*/ false);
+ return true;
+ }
+
+ // It's not an RVV intrinsics.
+ return false;
+}
+
+namespace clang {
+std::unique_ptr<clang::sema::RISCVIntrinsicManager>
+CreateRISCVIntrinsicManager(Sema &S) {
+ return std::make_unique<RISCVIntrinsicManagerImpl>(S);
+}
+} // namespace clang
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index f25694ce48c9..c6ca10c0342c 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -3898,12 +3898,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext())
return R;
- if (VarDecl *VD =
- const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) {
- CurScope->addNRVOCandidate(VD);
- } else {
- CurScope->setNoNRVO();
- }
+ VarDecl *VD =
+ const_cast<VarDecl *>(cast<ReturnStmt>(R.get())->getNRVOCandidate());
+
+ CurScope->updateNRVOCandidate(VD);
CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 95c83ebfaeab..1542a07713fb 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/TemplateName.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/Stack.h"
@@ -8707,23 +8708,59 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
// Check for conflicting previous declaration.
DeclarationNameInfo NameInfo(NewDecl->getDeclName(), NameLoc);
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
- ForVisibleRedeclaration);
+ forRedeclarationInCurContext());
LookupName(Previous, S);
-
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage=*/false,
/*AllowInlineNamespace*/false);
- if (!Previous.empty()) {
- auto *Old = Previous.getRepresentativeDecl();
- Diag(NameLoc, isa<ConceptDecl>(Old) ? diag::err_redefinition :
- diag::err_redefinition_different_kind) << NewDecl->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
- }
+ bool AddToScope = true;
+ CheckConceptRedefinition(NewDecl, Previous, AddToScope);
ActOnDocumentableDecl(NewDecl);
- PushOnScopeChains(NewDecl, S);
+ if (AddToScope)
+ PushOnScopeChains(NewDecl, S);
return NewDecl;
}
+void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
+ LookupResult &Previous, bool &AddToScope) {
+ AddToScope = true;
+
+ if (Previous.empty())
+ return;
+
+ auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl());
+ if (!OldConcept) {
+ auto *Old = Previous.getRepresentativeDecl();
+ Diag(NewDecl->getLocation(), diag::err_redefinition_different_kind)
+ << NewDecl->getDeclName();
+ notePreviousDefinition(Old, NewDecl->getLocation());
+ AddToScope = false;
+ return;
+ }
+ // Check if we can merge with a concept declaration.
+ bool IsSame = Context.isSameEntity(NewDecl, OldConcept);
+ if (!IsSame) {
+ Diag(NewDecl->getLocation(), diag::err_redefinition_different_concept)
+ << NewDecl->getDeclName();
+ notePreviousDefinition(OldConcept, NewDecl->getLocation());
+ AddToScope = false;
+ return;
+ }
+ if (hasReachableDefinition(OldConcept)) {
+ Diag(NewDecl->getLocation(), diag::err_redefinition)
+ << NewDecl->getDeclName();
+ notePreviousDefinition(OldConcept, NewDecl->getLocation());
+ AddToScope = false;
+ return;
+ }
+ if (!Previous.isSingleResult()) {
+ // FIXME: we should produce an error in case of ambig and failed lookups.
+ // Other decls (e.g. namespaces) also have this shortcoming.
+ return;
+ }
+ Context.setPrimaryMergedDecl(NewDecl, OldConcept);
+}
+
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index d70e824224df..73800191dfc1 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2926,7 +2926,8 @@ Attr *ASTRecordReader::readAttr() {
/// Reads attributes from the current stream position.
void ASTRecordReader::readAttributes(AttrVec &Attrs) {
for (unsigned I = 0, E = readInt(); I != E; ++I)
- Attrs.push_back(readAttr());
+ if (auto *A = readAttr())
+ Attrs.push_back(A);
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index fac8fc141d2c..0739dcc1ce60 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -4347,8 +4347,12 @@ void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
void ASTRecordWriter::AddAttr(const Attr *A) {
auto &Record = *this;
- if (!A)
+ // FIXME: Clang can't handle the serialization/deserialization of
+ // preferred_name properly now. See
+ // https://github.com/llvm/llvm-project/issues/56490 for example.
+ if (!A || (isa<PreferredNameAttr>(A) && Writer->isWritingNamedModules()))
return Record.push_back(0);
+
Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs
Record.AddIdentifierRef(A->getAttrName());
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 987cf65d6fec..9a6c013bcf66 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -26,9 +26,11 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <functional>
using namespace clang;
using namespace ento;
+using namespace std::placeholders;
namespace {
struct AnyArgExpr {
@@ -118,10 +120,14 @@ public:
const LocationContext *LCtx,
const CallEvent *Call) const;
- typedef void (CStringChecker::*FnCheck)(CheckerContext &,
- const CallExpr *) const;
+ using FnCheck = std::function<void(const CStringChecker *, CheckerContext &,
+ const CallExpr *)>;
+
CallDescriptionMap<FnCheck> Callbacks = {
- {{CDF_MaybeBuiltin, "memcpy", 3}, &CStringChecker::evalMemcpy},
+ {{CDF_MaybeBuiltin, "memcpy", 3},
+ std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, false)},
+ {{CDF_MaybeBuiltin, "wmemcpy", 3},
+ std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, true)},
{{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy},
{{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp},
{{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove},
@@ -135,7 +141,9 @@ public:
{{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat},
{{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat},
{{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength},
+ {{CDF_MaybeBuiltin, "wcslen", 1}, &CStringChecker::evalstrLength},
{{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength},
+ {{CDF_MaybeBuiltin, "wcsnlen", 2}, &CStringChecker::evalstrnLength},
{{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp},
{{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp},
{{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp},
@@ -152,14 +160,14 @@ public:
StdCopyBackward{{"std", "copy_backward"}, 3};
FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const;
- void evalMemcpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemcpy(CheckerContext &C, const CallExpr *CE, bool IsWide) const;
void evalMempcpy(CheckerContext &C, const CallExpr *CE) const;
void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest, SourceArgExpr Source,
- bool Restricted, bool IsMempcpy) const;
+ bool Restricted, bool IsMempcpy, bool IsWide) const;
void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
@@ -240,13 +248,14 @@ public:
AnyArgExpr Arg, SVal l) const;
ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
- AccessKind Access) const;
+ AccessKind Access, bool IsWide = false) const;
ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
AnyArgExpr Buffer, SizeArgExpr Size,
- AccessKind Access) const;
+ AccessKind Access,
+ bool IsWide = false) const;
ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state,
SizeArgExpr Size, AnyArgExpr First,
- AnyArgExpr Second) const;
+ AnyArgExpr Second, bool IsWide = false) const;
void emitOverlapBug(CheckerContext &C,
ProgramStateRef state,
const Stmt *First,
@@ -329,7 +338,8 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
- AccessKind Access) const {
+ AccessKind Access,
+ bool IsWide) const {
// If a previous check has failed, propagate the failure.
if (!state)
@@ -344,17 +354,36 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
if (!ER)
return state;
- if (ER->getValueType() != C.getASTContext().CharTy)
- return state;
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ ASTContext &Ctx = svalBuilder.getContext();
+
+ // Get the index of the accessed element.
+ NonLoc Idx = ER->getIndex();
+
+ if (!IsWide) {
+ if (ER->getValueType() != Ctx.CharTy)
+ return state;
+ } else {
+ if (ER->getValueType() != Ctx.WideCharTy)
+ return state;
+
+ QualType SizeTy = Ctx.getSizeType();
+ NonLoc WideSize =
+ svalBuilder
+ .makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(),
+ SizeTy)
+ .castAs<NonLoc>();
+ SVal Offset = svalBuilder.evalBinOpNN(state, BO_Mul, Idx, WideSize, SizeTy);
+ if (Offset.isUnknown())
+ return state;
+ Idx = Offset.castAs<NonLoc>();
+ }
// Get the size of the array.
const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
DefinedOrUnknownSVal Size =
getDynamicExtent(state, superReg, C.getSValBuilder());
- // Get the index of the accessed element.
- DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
-
ProgramStateRef StInBound, StOutBound;
std::tie(StInBound, StOutBound) = state->assumeInBoundDual(Idx, Size);
if (StOutBound && !StInBound) {
@@ -385,11 +414,10 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
return StInBound;
}
-ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
- ProgramStateRef State,
- AnyArgExpr Buffer,
- SizeArgExpr Size,
- AccessKind Access) const {
+ProgramStateRef
+CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
+ AnyArgExpr Buffer, SizeArgExpr Size,
+ AccessKind Access, bool IsWide) const {
// If a previous check has failed, propagate the failure.
if (!State)
return nullptr;
@@ -398,7 +426,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
ASTContext &Ctx = svalBuilder.getContext();
QualType SizeTy = Size.Expression->getType();
- QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
+ QualType PtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
// Check that the first buffer is non-null.
SVal BufVal = C.getSVal(Buffer.Expression);
@@ -432,7 +460,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
SVal BufEnd =
svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
- State = CheckLocation(C, State, Buffer, BufEnd, Access);
+ State = CheckLocation(C, State, Buffer, BufEnd, Access, IsWide);
// If the buffer isn't large enough, abort.
if (!State)
@@ -446,7 +474,8 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
ProgramStateRef state,
SizeArgExpr Size, AnyArgExpr First,
- AnyArgExpr Second) const {
+ AnyArgExpr Second,
+ bool IsWide) const {
if (!Filter.CheckCStringBufferOverlap)
return state;
@@ -525,7 +554,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
// Convert the first buffer's start address to char*.
// Bail out if the cast fails.
ASTContext &Ctx = svalBuilder.getContext();
- QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
+ QualType CharPtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
SVal FirstStart =
svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType());
Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
@@ -1161,7 +1190,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest,
SourceArgExpr Source, bool Restricted,
- bool IsMempcpy) const {
+ bool IsMempcpy, bool IsWide) const {
CurrentFunctionDescription = "memory copy function";
// See if the size argument is zero.
@@ -1204,11 +1233,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
return;
// Ensure the accesses are valid and that the buffers do not overlap.
- state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write);
- state = CheckBufferAccess(C, state, Source, Size, AccessKind::read);
+ state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, IsWide);
+ state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, IsWide);
if (Restricted)
- state = CheckOverlap(C, state, Size, Dest, Source);
+ state = CheckOverlap(C, state, Size, Dest, Source, IsWide);
if (!state)
return;
@@ -1258,7 +1287,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
}
}
-void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
+void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE,
+ bool IsWide) const {
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is the address of the destination buffer.
DestinationArgExpr Dest = {CE->getArg(0), 0};
@@ -1269,7 +1299,8 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = false;
- evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy);
+ evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy,
+ IsWide);
}
void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
@@ -1281,7 +1312,8 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = true;
- evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
+ evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
+ false);
}
void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
@@ -1293,7 +1325,8 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
- evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
+ evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
+ false);
}
void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
@@ -1304,7 +1337,8 @@ void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
- evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
+ evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
+ false);
}
void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
@@ -2336,7 +2370,7 @@ bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
// Check and evaluate the call.
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
- (this->*Callback)(C, CE);
+ Callback(this, C, CE);
// If the evaluate call resulted in no change, chain to the next eval call
// handler.
diff --git a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
index 895212d134b8..b673b51c4623 100644
--- a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
@@ -55,9 +55,9 @@ public:
ID.AddPointer(getTag());
}
- virtual PathDiagnosticPieceRef
- VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
- PathSensitiveBugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
// FIXME: Scan the map once in the visitor's constructor and do a direct
// lookup by region.
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 36464707d06a..adedc9c30fad 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -852,9 +852,8 @@ protected:
return false;
}
- virtual bool
- wasModifiedInFunction(const ExplodedNode *CallEnterN,
- const ExplodedNode *CallExitEndN) override {
+ bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
+ const ExplodedNode *CallExitEndN) override {
if (!doesFnIntendToHandleOwnership(
CallExitEndN->getFirstPred()->getLocationContext()->getDecl(),
CallExitEndN->getState()->getAnalysisManager().getASTContext()))
@@ -885,7 +884,7 @@ protected:
"later deallocation");
}
- virtual PathDiagnosticPieceRef
+ PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
const ObjCMethodCall &Call,
const ExplodedNode *N) override {
@@ -893,7 +892,7 @@ protected:
return nullptr;
}
- virtual PathDiagnosticPieceRef
+ PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
const CXXConstructorCall &Call,
const ExplodedNode *N) override {
@@ -901,7 +900,7 @@ protected:
return nullptr;
}
- virtual PathDiagnosticPieceRef
+ PathDiagnosticPieceRef
maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
const ExplodedNode *N) override {
// TODO: Factor the logic of "what constitutes as an entity being passed
diff --git a/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
index cddf206728b1..27fd40a441fa 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
@@ -182,7 +182,7 @@ public:
return false;
};
- if (std::any_of(RD->field_begin(), RD->field_end(), IsTrickyField))
+ if (llvm::any_of(RD->fields(), IsTrickyField))
return true;
return false;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index ef673ae41a3d..5897e5096461 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -240,7 +240,7 @@ class StdLibraryFunctionsChecker
ArgNo OtherArgN;
public:
- virtual StringRef getName() const override { return "Comparison"; };
+ StringRef getName() const override { return "Comparison"; };
ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
ArgNo OtherArgN)
: ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
index 38e69e81d800..cd91fa9b090c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -57,19 +57,17 @@ class RegularField final : public FieldNode {
public:
RegularField(const FieldRegion *FR) : FieldNode(FR) {}
- virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+ void printNoteMsg(llvm::raw_ostream &Out) const override {
Out << "uninitialized field ";
}
- virtual void printPrefix(llvm::raw_ostream &Out) const override {}
+ void printPrefix(llvm::raw_ostream &Out) const override {}
- virtual void printNode(llvm::raw_ostream &Out) const override {
+ void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl());
}
- virtual void printSeparator(llvm::raw_ostream &Out) const override {
- Out << '.';
- }
+ void printSeparator(llvm::raw_ostream &Out) const override { Out << '.'; }
};
/// Represents that the FieldNode that comes after this is declared in a base
@@ -85,20 +83,20 @@ public:
assert(T->getAsCXXRecordDecl());
}
- virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+ void printNoteMsg(llvm::raw_ostream &Out) const override {
llvm_unreachable("This node can never be the final node in the "
"fieldchain!");
}
- virtual void printPrefix(llvm::raw_ostream &Out) const override {}
+ void printPrefix(llvm::raw_ostream &Out) const override {}
- virtual void printNode(llvm::raw_ostream &Out) const override {
+ void printNode(llvm::raw_ostream &Out) const override {
Out << BaseClassT->getAsCXXRecordDecl()->getName() << "::";
}
- virtual void printSeparator(llvm::raw_ostream &Out) const override {}
+ void printSeparator(llvm::raw_ostream &Out) const override {}
- virtual bool isBase() const override { return true; }
+ bool isBase() const override { return true; }
};
} // end of anonymous namespace
diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
index a6e81b3657a2..f5bd765ff679 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -34,20 +34,20 @@ public:
LocField(const FieldRegion *FR, const bool IsDereferenced = true)
: FieldNode(FR), IsDereferenced(IsDereferenced) {}
- virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+ void printNoteMsg(llvm::raw_ostream &Out) const override {
if (IsDereferenced)
Out << "uninitialized pointee ";
else
Out << "uninitialized pointer ";
}
- virtual void printPrefix(llvm::raw_ostream &Out) const override {}
+ void printPrefix(llvm::raw_ostream &Out) const override {}
- virtual void printNode(llvm::raw_ostream &Out) const override {
+ void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl());
}
- virtual void printSeparator(llvm::raw_ostream &Out) const override {
+ void printSeparator(llvm::raw_ostream &Out) const override {
if (getDecl()->getType()->isPointerType())
Out << "->";
else
@@ -64,11 +64,11 @@ public:
NeedsCastLocField(const FieldRegion *FR, const QualType &T)
: FieldNode(FR), CastBackType(T) {}
- virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+ void printNoteMsg(llvm::raw_ostream &Out) const override {
Out << "uninitialized pointee ";
}
- virtual void printPrefix(llvm::raw_ostream &Out) const override {
+ void printPrefix(llvm::raw_ostream &Out) const override {
// If this object is a nonloc::LocAsInteger.
if (getDecl()->getType()->isIntegerType())
Out << "reinterpret_cast";
@@ -78,13 +78,11 @@ public:
Out << '<' << CastBackType.getAsString() << ">(";
}
- virtual void printNode(llvm::raw_ostream &Out) const override {
+ void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl()) << ')';
}
- virtual void printSeparator(llvm::raw_ostream &Out) const override {
- Out << "->";
- }
+ void printSeparator(llvm::raw_ostream &Out) const override { Out << "->"; }
};
/// Represents a Loc field that points to itself.
@@ -93,17 +91,17 @@ class CyclicLocField final : public FieldNode {
public:
CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
- virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+ void printNoteMsg(llvm::raw_ostream &Out) const override {
Out << "object references itself ";
}
- virtual void printPrefix(llvm::raw_ostream &Out) const override {}
+ void printPrefix(llvm::raw_ostream &Out) const override {}
- virtual void printNode(llvm::raw_ostream &Out) const override {
+ void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl());
}
- virtual void printSeparator(llvm::raw_ostream &Out) const override {
+ void printSeparator(llvm::raw_ostream &Out) const override {
llvm_unreachable("CyclicLocField objects must be the last node of the "
"fieldchain!");
}
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 2caa5bbc16df..3a90c37a36da 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -530,9 +530,8 @@ public:
private:
/// \return Whether \c RegionOfInterest was modified at \p CurrN compared to
/// the value it holds in \p CallExitBeginN.
- virtual bool
- wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
- const ExplodedNode *CallExitBeginN) override;
+ bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
+ const ExplodedNode *CallExitBeginN) override;
/// Attempts to find the region of interest in a given record decl,
/// by either following the base classes or fields.
@@ -547,19 +546,17 @@ private:
// Region of interest corresponds to an IVar, exiting a method
// which could have written into that IVar, but did not.
- virtual PathDiagnosticPieceRef
- maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
- const ObjCMethodCall &Call,
- const ExplodedNode *N) override final;
+ PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
+ const ObjCMethodCall &Call,
+ const ExplodedNode *N) final;
- virtual PathDiagnosticPieceRef
- maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
- const CXXConstructorCall &Call,
- const ExplodedNode *N) override final;
+ PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
+ const CXXConstructorCall &Call,
+ const ExplodedNode *N) final;
- virtual PathDiagnosticPieceRef
+ PathDiagnosticPieceRef
maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
- const ExplodedNode *N) override final;
+ const ExplodedNode *N) final;
/// Consume the information on the no-store stack frame in order to
/// either emit a note or suppress the report enirely.
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index d8f56f2f8cff..19149d079822 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -196,6 +196,14 @@ typedef llvm::ImmutableMap<
IndexOfElementToConstructMap;
REGISTER_TRAIT_WITH_PROGRAMSTATE(IndexOfElementToConstruct,
IndexOfElementToConstructMap)
+
+// This trait is responsible for holding our pending ArrayInitLoopExprs.
+// It pairs the LocationContext and the initializer CXXConstructExpr with
+// the size of the array that's being copy initialized.
+typedef llvm::ImmutableMap<
+ std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned>
+ PendingInitLoopMap;
+REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingInitLoop, PendingInitLoopMap)
//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
@@ -462,6 +470,34 @@ ProgramStateRef ExprEngine::setIndexOfElementToConstruct(
return State->set<IndexOfElementToConstruct>(Key, Idx);
}
+Optional<unsigned> ExprEngine::getPendingInitLoop(ProgramStateRef State,
+ const CXXConstructExpr *E,
+ const LocationContext *LCtx) {
+
+ return Optional<unsigned>::create(
+ State->get<PendingInitLoop>({E, LCtx->getStackFrame()}));
+}
+
+ProgramStateRef ExprEngine::removePendingInitLoop(ProgramStateRef State,
+ const CXXConstructExpr *E,
+ const LocationContext *LCtx) {
+ auto Key = std::make_pair(E, LCtx->getStackFrame());
+
+ assert(E && State->contains<PendingInitLoop>(Key));
+ return State->remove<PendingInitLoop>(Key);
+}
+
+ProgramStateRef ExprEngine::setPendingInitLoop(ProgramStateRef State,
+ const CXXConstructExpr *E,
+ const LocationContext *LCtx,
+ unsigned Size) {
+ auto Key = std::make_pair(E, LCtx->getStackFrame());
+
+ assert(!State->contains<PendingInitLoop>(Key) && Size > 0);
+
+ return State->set<PendingInitLoop>(Key, Size);
+}
+
Optional<unsigned>
ExprEngine::getIndexOfElementToConstruct(ProgramStateRef State,
const CXXConstructExpr *E,
@@ -487,17 +523,23 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
const LocationContext *LC, SVal V) {
ConstructedObjectKey Key(Item, LC->getStackFrame());
- const CXXConstructExpr *E = nullptr;
+ const Expr *Init = nullptr;
if (auto DS = dyn_cast_or_null<DeclStmt>(Item.getStmtOrNull())) {
if (auto VD = dyn_cast_or_null<VarDecl>(DS->getSingleDecl()))
- E = dyn_cast<CXXConstructExpr>(VD->getInit());
+ Init = VD->getInit();
}
- if (!E && !Item.getStmtOrNull()) {
- auto CtorInit = Item.getCXXCtorInitializer();
- E = dyn_cast<CXXConstructExpr>(CtorInit->getInit());
- }
+ if (auto LE = dyn_cast_or_null<LambdaExpr>(Item.getStmtOrNull()))
+ Init = *(LE->capture_init_begin() + Item.getIndex());
+
+ if (!Init && !Item.getStmtOrNull())
+ Init = Item.getCXXCtorInitializer()->getInit();
+
+ // In an ArrayInitLoopExpr the real initializer is returned by
+ // getSubExpr().
+ if (const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init))
+ Init = AILE->getSubExpr();
// FIXME: Currently the state might already contain the marker due to
// incorrect handling of temporaries bound to default parameters.
@@ -508,7 +550,8 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
assert((!State->get<ObjectsUnderConstruction>(Key) ||
Key.getItem().getKind() ==
ConstructionContextItem::TemporaryDestructorKind ||
- State->contains<IndexOfElementToConstruct>({E, LC})) &&
+ State->contains<IndexOfElementToConstruct>(
+ {dyn_cast_or_null<CXXConstructExpr>(Init), LC})) &&
"The object is already marked as `UnderConstruction`, when it's not "
"supposed to!");
return State->set<ObjectsUnderConstruction>(Key, V);
@@ -2744,7 +2787,10 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
SVal Base = state->getLValue(DD, LCtx);
if (DD->getType()->isReferenceType()) {
- Base = state->getSVal(Base.getAsRegion());
+ if (const MemRegion *R = Base.getAsRegion())
+ Base = state->getSVal(R);
+ else
+ Base = UnknownVal();
}
SVal V = UnknownVal();
@@ -2765,15 +2811,27 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
V = state->getLValue(BD->getType(), Idx, Base);
}
- // Handle binding to tuple-like strcutures
- else if (BD->getHoldingVar()) {
- // FIXME: handle tuples
- return;
+ // Handle binding to tuple-like structures
+ else if (const auto *HV = BD->getHoldingVar()) {
+ V = state->getLValue(HV, LCtx);
+
+ if (HV->getType()->isReferenceType()) {
+ if (const MemRegion *R = V.getAsRegion())
+ V = state->getSVal(R);
+ else
+ V = UnknownVal();
+ }
} else
llvm_unreachable("An unknown case of structured binding encountered!");
- if (BD->getType()->isReferenceType())
- V = state->getSVal(V.getAsRegion());
+ // In case of tuple-like types the references are already handled, so we
+ // don't want to handle them again.
+ if (BD->getType()->isReferenceType() && !BD->getHoldingVar()) {
+ if (const MemRegion *R = V.getAsRegion())
+ V = state->getSVal(R);
+ else
+ V = UnknownVal();
+ }
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
ProgramPoint::PostLValueKind);
@@ -2797,6 +2855,11 @@ void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex,
const Expr *Arr = Ex->getCommonExpr()->getSourceExpr();
for (auto *Node : CheckerPreStmt) {
+
+ // The constructor visitior has already taken care of everything.
+ if (auto *CE = dyn_cast<CXXConstructExpr>(Ex->getSubExpr()))
+ break;
+
const LocationContext *LCtx = Node->getLocationContext();
ProgramStateRef state = Node->getState();
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 08fac9fb2e69..04e00274b2a7 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -290,6 +290,23 @@ SVal ExprEngine::computeObjectUnderConstruction(
return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
}
+ case ConstructionContext::LambdaCaptureKind: {
+ CallOpts.IsTemporaryCtorOrDtor = true;
+
+ const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
+
+ SVal Base = loc::MemRegionVal(
+ MRMgr.getCXXTempObjectRegion(LCC->getInitializer(), LCtx));
+
+ const auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
+ if (getIndexOfElementToConstruct(State, CE, LCtx)) {
+ CallOpts.IsArrayCtorOrDtor = true;
+ Base = State->getLValue(E->getType(), svalBuilder.makeArrayIndex(Idx),
+ Base);
+ }
+
+ return Base;
+ }
case ConstructionContext::ArgumentKind: {
// Arguments are technically temporaries.
CallOpts.IsTemporaryCtorOrDtor = true;
@@ -450,6 +467,17 @@ ProgramStateRef ExprEngine::updateObjectsUnderConstruction(
return State;
}
+ case ConstructionContext::LambdaCaptureKind: {
+ const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
+
+ // If we capture and array, we want to store the super region, not a
+ // sub-region.
+ if (const auto *EL = dyn_cast_or_null<ElementRegion>(V.getAsRegion()))
+ V = loc::MemRegionVal(EL->getSuperRegion());
+
+ return addObjectUnderConstruction(
+ State, {LCC->getLambdaExpr(), LCC->getIndex()}, LCtx, V);
+ }
case ConstructionContext::ArgumentKind: {
const auto *ACC = cast<ArgumentConstructionContext>(CC);
if (const auto *BTE = ACC->getCXXBindTemporaryExpr())
@@ -462,6 +490,59 @@ ProgramStateRef ExprEngine::updateObjectsUnderConstruction(
llvm_unreachable("Unhandled construction context!");
}
+static ProgramStateRef
+bindRequiredArrayElementToEnvironment(ProgramStateRef State,
+ const ArrayInitLoopExpr *AILE,
+ const LocationContext *LCtx, SVal Idx) {
+ // The ctor in this case is guaranteed to be a copy ctor, otherwise we hit a
+ // compile time error.
+ //
+ // -ArrayInitLoopExpr <-- we're here
+ // |-OpaqueValueExpr
+ // | `-DeclRefExpr <-- match this
+ // `-CXXConstructExpr
+ // `-ImplicitCastExpr
+ // `-ArraySubscriptExpr
+ // |-ImplicitCastExpr
+ // | `-OpaqueValueExpr
+ // | `-DeclRefExpr
+ // `-ArrayInitIndexExpr
+ //
+ // The resulting expression might look like the one below in an implicit
+ // copy/move ctor.
+ //
+ // ArrayInitLoopExpr <-- we're here
+ // |-OpaqueValueExpr
+ // | `-MemberExpr <-- match this
+ // | (`-CXXStaticCastExpr) <-- move ctor only
+ // | `-DeclRefExpr
+ // `-CXXConstructExpr
+ // `-ArraySubscriptExpr
+ // |-ImplicitCastExpr
+ // | `-OpaqueValueExpr
+ // | `-MemberExpr
+ // | `-DeclRefExpr
+ // `-ArrayInitIndexExpr
+ //
+ // HACK: There is no way we can put the index of the array element into the
+ // CFG unless we unroll the loop, so we manually select and bind the required
+ // parameter to the environment.
+ const auto *CE = cast<CXXConstructExpr>(AILE->getSubExpr());
+ const auto *OVESrc = AILE->getCommonExpr()->getSourceExpr();
+
+ SVal Base = UnknownVal();
+ if (const auto *ME = dyn_cast<MemberExpr>(OVESrc))
+ Base = State->getSVal(ME, LCtx);
+ else if (const auto *DRE = cast<DeclRefExpr>(OVESrc))
+ Base = State->getLValue(cast<VarDecl>(DRE->getDecl()), LCtx);
+ else
+ llvm_unreachable("ArrayInitLoopExpr contains unexpected source expression");
+
+ SVal NthElem = State->getLValue(CE->getType(), Idx, Base);
+
+ return State->BindExpr(CE->getArg(0), LCtx, NthElem);
+}
+
void ExprEngine::handleConstructor(const Expr *E,
ExplodedNode *Pred,
ExplodedNodeSet &destNodes) {
@@ -502,12 +583,26 @@ void ExprEngine::handleConstructor(const Expr *E,
// Inherited constructors are always base class constructors.
assert(CE && !CIE && "A complete constructor is inherited?!");
+ // If the ctor is part of an ArrayInitLoopExpr, we want to handle it
+ // differently.
+ auto *AILE = CC ? CC->getArrayInitLoop() : nullptr;
+
unsigned Idx = 0;
- if (CE->getType()->isArrayType()) {
+ if (CE->getType()->isArrayType() || AILE) {
Idx = getIndexOfElementToConstruct(State, CE, LCtx).value_or(0u);
State = setIndexOfElementToConstruct(State, CE, LCtx, Idx + 1);
}
+ if (AILE) {
+ // Only set this once even though we loop through it multiple times.
+ if (!getPendingInitLoop(State, CE, LCtx))
+ State = setPendingInitLoop(State, CE, LCtx,
+ AILE->getArraySize().getLimitedValue());
+
+ State = bindRequiredArrayElementToEnvironment(
+ State, AILE, LCtx, svalBuilder.makeArrayIndex(Idx));
+ }
+
// The target region is found from construction context.
std::tie(State, Target) =
handleConstructionContext(CE, State, LCtx, CC, CallOpts, Idx);
@@ -908,7 +1003,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// values are properly placed inside the required region, however if an
// initializer list is used, this doesn't happen automatically.
auto *Init = CNE->getInitializer();
- bool isInitList = dyn_cast_or_null<InitListExpr>(Init);
+ bool isInitList = isa_and_nonnull<InitListExpr>(Init);
QualType ObjTy =
isInitList ? Init->getType() : CNE->getType()->getPointeeType();
@@ -1038,19 +1133,40 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
// If we created a new MemRegion for the lambda, we should explicitly bind
// the captures.
+ unsigned Idx = 0;
CXXRecordDecl::field_iterator CurField = LE->getLambdaClass()->field_begin();
for (LambdaExpr::const_capture_init_iterator i = LE->capture_init_begin(),
e = LE->capture_init_end();
- i != e; ++i, ++CurField) {
+ i != e; ++i, ++CurField, ++Idx) {
FieldDecl *FieldForCapture = *CurField;
SVal FieldLoc = State->getLValue(FieldForCapture, V);
SVal InitVal;
if (!FieldForCapture->hasCapturedVLAType()) {
Expr *InitExpr = *i;
+
+ if (const auto AILE = dyn_cast<ArrayInitLoopExpr>(InitExpr)) {
+ // If the AILE initializes a POD array, we need to keep it as the
+ // InitExpr.
+ if (dyn_cast<CXXConstructExpr>(AILE->getSubExpr()))
+ InitExpr = AILE->getSubExpr();
+ }
+
assert(InitExpr && "Capture missing initialization expression");
- InitVal = State->getSVal(InitExpr, LocCtxt);
+
+ if (dyn_cast<CXXConstructExpr>(InitExpr)) {
+ InitVal = *getObjectUnderConstruction(State, {LE, Idx}, LocCtxt);
+ InitVal = State->getSVal(InitVal.getAsRegion());
+
+ State = finishObjectConstruction(State, {LE, Idx}, LocCtxt);
+ } else
+ InitVal = State->getSVal(InitExpr, LocCtxt);
+
} else {
+
+ assert(!getObjectUnderConstruction(State, {LE, Idx}, LocCtxt) &&
+ "VLA capture by value is a compile time error!");
+
// The field stores the length of a captured variable-length array.
// These captures don't have initialization expressions; instead we
// get the length from the VLAType size expression.
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index ebcca92a3e4e..8fb2ce9cd18f 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -265,9 +265,13 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
ShouldRepeatCall = shouldRepeatCtorCall(state, CCE, callerCtx);
- if (!ShouldRepeatCall &&
- getIndexOfElementToConstruct(state, CCE, callerCtx))
- state = removeIndexOfElementToConstruct(state, CCE, callerCtx);
+ if (!ShouldRepeatCall) {
+ if (getIndexOfElementToConstruct(state, CCE, callerCtx))
+ state = removeIndexOfElementToConstruct(state, CCE, callerCtx);
+
+ if (getPendingInitLoop(state, CCE, callerCtx))
+ state = removePendingInitLoop(state, CCE, callerCtx);
+ }
}
if (const auto *CNE = dyn_cast<CXXNewExpr>(CE)) {
@@ -815,8 +819,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
// We still allow construction into ElementRegion targets when they don't
// represent array elements.
if (CallOpts.IsArrayCtorOrDtor) {
- if (!shouldInlineArrayConstruction(
- dyn_cast<ArrayType>(CtorExpr->getType())))
+ if (!shouldInlineArrayConstruction(Pred->getState(), CtorExpr, CurLC))
return CIP_DisallowedOnce;
}
@@ -1082,10 +1085,14 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
return true;
}
-bool ExprEngine::shouldInlineArrayConstruction(const ArrayType *Type) {
- if (!Type)
+bool ExprEngine::shouldInlineArrayConstruction(const ProgramStateRef State,
+ const CXXConstructExpr *CE,
+ const LocationContext *LCtx) {
+ if (!CE)
return false;
+ auto Type = CE->getType();
+
// FIXME: Handle other arrays types.
if (const auto *CAT = dyn_cast<ConstantArrayType>(Type)) {
unsigned Size = getContext().getConstantArrayElementCount(CAT);
@@ -1093,6 +1100,10 @@ bool ExprEngine::shouldInlineArrayConstruction(const ArrayType *Type) {
return Size <= AMgr.options.maxBlockVisitOnPath;
}
+ // Check if we're inside an ArrayInitLoopExpr, and it's sufficiently small.
+ if (auto Size = getPendingInitLoop(State, CE, LCtx))
+ return *Size <= AMgr.options.maxBlockVisitOnPath;
+
return false;
}
@@ -1111,6 +1122,9 @@ bool ExprEngine::shouldRepeatCtorCall(ProgramStateRef State,
return Size > getIndexOfElementToConstruct(State, E, LCtx);
}
+ if (auto Size = getPendingInitLoop(State, E, LCtx))
+ return Size > getIndexOfElementToConstruct(State, E, LCtx);
+
return false;
}
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 5e946483a93d..d8ece9f39a25 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1888,6 +1888,30 @@ SVal RegionStoreManager::getSValFromStringLiteral(const StringLiteral *SL,
return svalBuilder.makeIntVal(Code, ElemT);
}
+static Optional<SVal> getDerivedSymbolForBinding(
+ RegionBindingsConstRef B, const TypedValueRegion *BaseRegion,
+ const TypedValueRegion *SubReg, const ASTContext &Ctx, SValBuilder &SVB) {
+ assert(BaseRegion);
+ QualType BaseTy = BaseRegion->getValueType();
+ QualType Ty = SubReg->getValueType();
+ if (BaseTy->isScalarType() && Ty->isScalarType()) {
+ if (Ctx.getTypeSizeInChars(BaseTy) >= Ctx.getTypeSizeInChars(Ty)) {
+ if (const Optional<SVal> &ParentValue = B.getDirectBinding(BaseRegion)) {
+ if (SymbolRef ParentValueAsSym = ParentValue->getAsSymbol())
+ return SVB.getDerivedRegionValueSymbolVal(ParentValueAsSym, SubReg);
+
+ if (ParentValue->isUndef())
+ return UndefinedVal();
+
+ // Other cases: give up. We are indexing into a larger object
+ // that has some value, but we don't know how to handle that yet.
+ return UnknownVal();
+ }
+ }
+ }
+ return None;
+}
+
SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
const ElementRegion* R) {
// Check if the region has a binding.
@@ -1932,27 +1956,10 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
if (!O.getRegion())
return UnknownVal();
- if (const TypedValueRegion *baseR =
- dyn_cast_or_null<TypedValueRegion>(O.getRegion())) {
- QualType baseT = baseR->getValueType();
- if (baseT->isScalarType()) {
- QualType elemT = R->getElementType();
- if (elemT->isScalarType()) {
- if (Ctx.getTypeSizeInChars(baseT) >= Ctx.getTypeSizeInChars(elemT)) {
- if (const Optional<SVal> &V = B.getDirectBinding(superR)) {
- if (SymbolRef parentSym = V->getAsSymbol())
- return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
-
- if (V->isUnknownOrUndef())
- return *V;
- // Other cases: give up. We are indexing into a larger object
- // that has some value, but we don't know how to handle that yet.
- return UnknownVal();
- }
- }
- }
- }
- }
+ if (const TypedValueRegion *baseR = dyn_cast<TypedValueRegion>(O.getRegion()))
+ if (auto V = getDerivedSymbolForBinding(B, baseR, R, Ctx, svalBuilder))
+ return *V;
+
return getBindingForFieldOrElementCommon(B, R, R->getElementType());
}
@@ -1988,6 +1995,26 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
}
}
+ // Handle the case where we are accessing into a larger scalar object.
+ // For example, this handles:
+ // struct header {
+ // unsigned a : 1;
+ // unsigned b : 1;
+ // };
+ // struct parse_t {
+ // unsigned bits0 : 1;
+ // unsigned bits2 : 2; // <-- header
+ // unsigned bits4 : 4;
+ // };
+ // int parse(parse_t *p) {
+ // unsigned copy = p->bits2;
+ // header *bits = (header *)&copy;
+ // return bits->b; <-- here
+ // }
+ if (const auto *Base = dyn_cast<TypedValueRegion>(R->getBaseRegion()))
+ if (auto V = getDerivedSymbolForBinding(B, Base, R, Ctx, svalBuilder))
+ return *V;
+
return getBindingForFieldOrElementCommon(B, R, Ty);
}
diff --git a/clang/lib/Support/RISCVVIntrinsicUtils.cpp b/clang/lib/Support/RISCVVIntrinsicUtils.cpp
index 19eb65b39b0a..513e6376f5ae 100644
--- a/clang/lib/Support/RISCVVIntrinsicUtils.cpp
+++ b/clang/lib/Support/RISCVVIntrinsicUtils.cpp
@@ -873,27 +873,6 @@ RVVIntrinsic::RVVIntrinsic(
Name += "_m";
}
- // Init RISC-V extensions
- for (const auto &T : OutInTypes) {
- if (T->isFloatVector(16) || T->isFloat(16))
- RISCVPredefinedMacros |= RISCVPredefinedMacro::Zvfh;
- if (T->isFloatVector(32))
- RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELenFp32;
- if (T->isFloatVector(64))
- RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELenFp64;
- if (T->isVector(64))
- RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELen64;
- }
- for (auto Feature : RequiredFeatures) {
- if (Feature == "RV64")
- RISCVPredefinedMacros |= RISCVPredefinedMacro::RV64;
- // Note: Full multiply instruction (mulh, mulhu, mulhsu, smul) for EEW=64
- // require V.
- if (Feature == "FullMultiply" &&
- (RISCVPredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64))
- RISCVPredefinedMacros |= RISCVPredefinedMacro::V;
- }
-
// Init OutputType and InputTypes
OutputType = OutInTypes[0];
InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
@@ -930,6 +909,48 @@ std::string RVVIntrinsic::getSuffixStr(
return join(SuffixStrs, "_");
}
+llvm::SmallVector<PrototypeDescriptor>
+RVVIntrinsic::computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
+ bool IsMasked, bool HasMaskedOffOperand,
+ bool HasVL, unsigned NF) {
+ SmallVector<PrototypeDescriptor> NewPrototype(Prototype.begin(),
+ Prototype.end());
+ if (IsMasked) {
+ // If HasMaskedOffOperand, insert result type as first input operand.
+ if (HasMaskedOffOperand) {
+ if (NF == 1) {
+ NewPrototype.insert(NewPrototype.begin() + 1, NewPrototype[0]);
+ } else {
+ // Convert
+ // (void, op0 address, op1 address, ...)
+ // to
+ // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
+ PrototypeDescriptor MaskoffType = NewPrototype[1];
+ MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
+ for (unsigned I = 0; I < NF; ++I)
+ NewPrototype.insert(NewPrototype.begin() + NF + 1, MaskoffType);
+ }
+ }
+ if (HasMaskedOffOperand && NF > 1) {
+ // Convert
+ // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
+ // to
+ // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
+ // ...)
+ NewPrototype.insert(NewPrototype.begin() + NF + 1,
+ PrototypeDescriptor::Mask);
+ } else {
+ // If IsMasked, insert PrototypeDescriptor:Mask as first input operand.
+ NewPrototype.insert(NewPrototype.begin() + 1, PrototypeDescriptor::Mask);
+ }
+ }
+
+ // If HasVL, append PrototypeDescriptor:VL to last operand
+ if (HasVL)
+ NewPrototype.push_back(PrototypeDescriptor::VL);
+ return NewPrototype;
+}
+
SmallVector<PrototypeDescriptor> parsePrototypes(StringRef Prototypes) {
SmallVector<PrototypeDescriptor> PrototypeDescriptors;
const StringRef Primaries("evwqom0ztul");
@@ -951,5 +972,30 @@ SmallVector<PrototypeDescriptor> parsePrototypes(StringRef Prototypes) {
return PrototypeDescriptors;
}
+raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {
+ OS << "{";
+ OS << "\"" << Record.Name << "\",";
+ if (Record.OverloadedName == nullptr ||
+ StringRef(Record.OverloadedName).empty())
+ OS << "nullptr,";
+ else
+ OS << "\"" << Record.OverloadedName << "\",";
+ OS << Record.PrototypeIndex << ",";
+ OS << Record.SuffixIndex << ",";
+ OS << Record.OverloadedSuffixIndex << ",";
+ OS << (int)Record.PrototypeLength << ",";
+ OS << (int)Record.SuffixLength << ",";
+ OS << (int)Record.OverloadedSuffixSize << ",";
+ OS << (int)Record.RequiredExtensions << ",";
+ OS << (int)Record.TypeRangeMask << ",";
+ OS << (int)Record.Log2LMULMask << ",";
+ OS << (int)Record.NF << ",";
+ OS << (int)Record.HasMasked << ",";
+ OS << (int)Record.HasVL << ",";
+ OS << (int)Record.HasMaskedOffOperand << ",";
+ OS << "},\n";
+ return OS;
+}
+
} // end namespace RISCV
} // end namespace clang
diff --git a/clang/utils/TableGen/RISCVVEmitter.cpp b/clang/utils/TableGen/RISCVVEmitter.cpp
index db4cd77d8c53..fc5f705b7fd4 100644
--- a/clang/utils/TableGen/RISCVVEmitter.cpp
+++ b/clang/utils/TableGen/RISCVVEmitter.cpp
@@ -20,6 +20,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
@@ -29,6 +30,60 @@ using namespace llvm;
using namespace clang::RISCV;
namespace {
+struct SemaRecord {
+ // Intrinsic name, e.g. vadd_vv
+ std::string Name;
+
+ // Overloaded intrinsic name, could be empty if can be computed from Name
+ // e.g. vadd
+ std::string OverloadedName;
+
+ // Supported type, mask of BasicType.
+ unsigned TypeRangeMask;
+
+ // Supported LMUL.
+ unsigned Log2LMULMask;
+
+ // Required extensions for this intrinsic.
+ unsigned RequiredExtensions;
+
+ // Prototype for this intrinsic.
+ SmallVector<PrototypeDescriptor> Prototype;
+
+ // Suffix of intrinsic name.
+ SmallVector<PrototypeDescriptor> Suffix;
+
+ // Suffix of overloaded intrinsic name.
+ SmallVector<PrototypeDescriptor> OverloadedSuffix;
+
+ // Number of field, large than 1 if it's segment load/store.
+ unsigned NF;
+
+ bool HasMasked :1;
+ bool HasVL :1;
+ bool HasMaskedOffOperand :1;
+};
+
+// Compressed function signature table.
+class SemaSignatureTable {
+private:
+ std::vector<PrototypeDescriptor> SignatureTable;
+
+ void insert(ArrayRef<PrototypeDescriptor> Signature);
+
+public:
+ static constexpr unsigned INVALID_INDEX = ~0U;
+
+ // Create compressed signature table from SemaRecords.
+ void init(ArrayRef<SemaRecord> SemaRecords);
+
+ // Query the Signature, return INVALID_INDEX if not found.
+ unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature);
+
+ /// Print signature table in RVVHeader Record to \p OS
+ void print(raw_ostream &OS);
+};
+
class RVVEmitter {
private:
RecordKeeper &Records;
@@ -45,22 +100,22 @@ public:
/// Emit all the information needed to map builtin -> LLVM IR intrinsic.
void createCodeGen(raw_ostream &o);
+ /// Emit all the information needed by SemaRISCVVectorLookup.cpp.
+ /// We've large number of intrinsic function for RVV, creating a customized
+ /// could speed up the compilation time.
+ void createSema(raw_ostream &o);
+
private:
- /// Create all intrinsics and add them to \p Out
- void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out);
+ /// Create all intrinsics and add them to \p Out and SemaRecords.
+ void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
+ std::vector<SemaRecord> *SemaRecords = nullptr);
+ /// Create all intrinsic records and SemaSignatureTable from SemaRecords.
+ void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
+ SemaSignatureTable &SST,
+ ArrayRef<SemaRecord> SemaRecords);
+
/// Print HeaderCode in RVVHeader Record to \p Out
void printHeaderCode(raw_ostream &OS);
-
- /// Emit Acrh predecessor definitions and body, assume the element of Defs are
- /// sorted by extension.
- void emitArchMacroAndBody(
- std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o,
- std::function<void(raw_ostream &, const RVVIntrinsic &)>);
-
- // Emit the architecture preprocessor definitions. Return true when emits
- // non-empty string.
- bool emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros,
- raw_ostream &o);
};
} // namespace
@@ -151,33 +206,82 @@ void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) {
OS << " break;\n";
}
-void emitIntrinsicFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) {
- OS << "__attribute__((__clang_builtin_alias__(";
- OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n";
- OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getName() << "(";
- // Emit function arguments
- const RVVTypes &InputTypes = RVVI.getInputTypes();
- if (!InputTypes.empty()) {
- ListSeparator LS;
- for (unsigned i = 0; i < InputTypes.size(); ++i)
- OS << LS << InputTypes[i]->getTypeStr();
- }
- OS << ");\n";
+//===----------------------------------------------------------------------===//
+// SemaSignatureTable implementation
+//===----------------------------------------------------------------------===//
+void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) {
+ // Sort signature entries by length, let longer signature insert first, to
+ // make it more possible to reuse table entries, that can reduce ~10% table
+ // size.
+ struct Compare {
+ bool operator()(const SmallVector<PrototypeDescriptor> &A,
+ const SmallVector<PrototypeDescriptor> &B) const {
+ if (A.size() != B.size())
+ return A.size() > B.size();
+
+ size_t Len = A.size();
+ for (size_t i = 0; i < Len; ++i) {
+ if (A[i] != B[i])
+ return A[i] < B[i];
+ }
+
+ return false;
+ }
+ };
+
+ std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures;
+ auto InsertToSignatureSet =
+ [&](const SmallVector<PrototypeDescriptor> &Signature) {
+ if (Signature.empty())
+ return;
+
+ Signatures.insert(Signature);
+ };
+
+ assert(!SemaRecords.empty());
+
+ llvm::for_each(SemaRecords, [&](const SemaRecord &SR) {
+ InsertToSignatureSet(SR.Prototype);
+ InsertToSignatureSet(SR.Suffix);
+ InsertToSignatureSet(SR.OverloadedSuffix);
+ });
+
+ llvm::for_each(Signatures, [this](auto &Sig) { insert(Sig); });
+}
+
+void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) {
+ if (getIndex(Signature) != INVALID_INDEX)
+ return;
+
+ // Insert Signature into SignatureTable if not found in the table.
+ SignatureTable.insert(SignatureTable.begin(), Signature.begin(),
+ Signature.end());
}
-void emitOverloadedFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) {
- OS << "__attribute__((__clang_builtin_alias__(";
- OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n";
- OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getOverloadedName()
- << "(";
- // Emit function arguments
- const RVVTypes &InputTypes = RVVI.getInputTypes();
- if (!InputTypes.empty()) {
- ListSeparator LS;
- for (unsigned i = 0; i < InputTypes.size(); ++i)
- OS << LS << InputTypes[i]->getTypeStr();
+unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) {
+ // Empty signature could be point into any index since there is length
+ // field when we use, so just always point it to 0.
+ if (Signature.empty())
+ return 0;
+
+ // Checking Signature already in table or not.
+ if (Signature.size() < SignatureTable.size()) {
+ size_t Bound = SignatureTable.size() - Signature.size() + 1;
+ for (size_t Index = 0; Index < Bound; ++Index) {
+ if (equal(Signature.begin(), Signature.end(),
+ SignatureTable.begin() + Index))
+ return Index;
+ }
}
- OS << ");\n";
+
+ return INVALID_INDEX;
+}
+
+void SemaSignatureTable::print(raw_ostream &OS) {
+ for (const auto &Sig : SignatureTable)
+ OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", "
+ << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM)
+ << "),\n";
}
//===----------------------------------------------------------------------===//
@@ -212,10 +316,9 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
OS << "extern \"C\" {\n";
OS << "#endif\n\n";
- printHeaderCode(OS);
+ OS << "#pragma clang riscv intrinsic vector\n\n";
- std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
- createRVVIntrinsics(Defs);
+ printHeaderCode(OS);
auto printType = [&](auto T) {
OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
@@ -255,7 +358,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
}
OS << "#endif\n";
- OS << "#if defined(__riscv_f)\n";
+ OS << "#if (__riscv_v_elen_fp >= 32)\n";
for (int Log2LMUL : Log2LMULs) {
auto T = RVVType::computeType(BasicType::Float32, Log2LMUL,
PrototypeDescriptor::Vector);
@@ -264,7 +367,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
}
OS << "#endif\n";
- OS << "#if defined(__riscv_d)\n";
+ OS << "#if (__riscv_v_elen_fp >= 64)\n";
for (int Log2LMUL : Log2LMULs) {
auto T = RVVType::computeType(BasicType::Float64, Log2LMUL,
PrototypeDescriptor::Vector);
@@ -273,37 +376,8 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
}
OS << "#endif\n\n";
- // The same extension include in the same arch guard marco.
- llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
- const std::unique_ptr<RVVIntrinsic> &B) {
- return A->getRISCVPredefinedMacros() < B->getRISCVPredefinedMacros();
- });
-
- OS << "#define __rvv_ai static __inline__\n";
-
- // Print intrinsic functions with macro
- emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
- OS << "__rvv_ai ";
- emitIntrinsicFuncDef(Inst, OS);
- });
-
- OS << "#undef __rvv_ai\n\n";
-
OS << "#define __riscv_v_intrinsic_overloading 1\n";
- // Print Overloaded APIs
- OS << "#define __rvv_aio static __inline__ "
- "__attribute__((__overloadable__))\n";
-
- emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
- if (!Inst.isMasked() && !Inst.hasUnMaskedOverloaded())
- return;
- OS << "__rvv_aio ";
- emitOverloadedFuncDef(Inst, OS);
- });
-
- OS << "#undef __rvv_aio\n";
-
OS << "\n#ifdef __cplusplus\n";
OS << "}\n";
OS << "#endif // __cplusplus\n";
@@ -392,7 +466,8 @@ void RVVEmitter::createCodeGen(raw_ostream &OS) {
}
void RVVEmitter::createRVVIntrinsics(
- std::vector<std::unique_ptr<RVVIntrinsic>> &Out) {
+ std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
+ std::vector<SemaRecord> *SemaRecords) {
std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin");
for (auto *R : RV) {
StringRef Name = R->getValueAsString("Name");
@@ -404,12 +479,12 @@ void RVVEmitter::createRVVIntrinsics(
bool HasMasked = R->getValueAsBit("HasMasked");
bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");
bool HasVL = R->getValueAsBit("HasVL");
- Record *MaskedPolicyRecord = R->getValueAsDef("MaskedPolicy");
- PolicyScheme MaskedPolicy =
- static_cast<PolicyScheme>(MaskedPolicyRecord->getValueAsInt("Value"));
- Record *UnMaskedPolicyRecord = R->getValueAsDef("UnMaskedPolicy");
- PolicyScheme UnMaskedPolicy =
- static_cast<PolicyScheme>(UnMaskedPolicyRecord->getValueAsInt("Value"));
+ Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme");
+ auto MaskedPolicyScheme =
+ static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value"));
+ Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme");
+ auto UnMaskedPolicyScheme =
+ static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value"));
bool HasUnMaskedOverloaded = R->getValueAsBit("HasUnMaskedOverloaded");
std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");
bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias");
@@ -425,50 +500,19 @@ void RVVEmitter::createRVVIntrinsics(
// Parse prototype and create a list of primitive type with transformers
// (operand) in Prototype. Prototype[0] is output operand.
- SmallVector<PrototypeDescriptor> Prototype = parsePrototypes(Prototypes);
+ SmallVector<PrototypeDescriptor> BasicPrototype =
+ parsePrototypes(Prototypes);
SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto);
SmallVector<PrototypeDescriptor> OverloadedSuffixDesc =
parsePrototypes(OverloadedSuffixProto);
// Compute Builtin types
- SmallVector<PrototypeDescriptor> MaskedPrototype = Prototype;
- if (HasMasked) {
- // If HasMaskedOffOperand, insert result type as first input operand.
- if (HasMaskedOffOperand) {
- if (NF == 1) {
- MaskedPrototype.insert(MaskedPrototype.begin() + 1, Prototype[0]);
- } else {
- // Convert
- // (void, op0 address, op1 address, ...)
- // to
- // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
- PrototypeDescriptor MaskoffType = Prototype[1];
- MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
- for (unsigned I = 0; I < NF; ++I)
- MaskedPrototype.insert(MaskedPrototype.begin() + NF + 1,
- MaskoffType);
- }
- }
- if (HasMaskedOffOperand && NF > 1) {
- // Convert
- // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
- // to
- // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
- // ...)
- MaskedPrototype.insert(MaskedPrototype.begin() + NF + 1,
- PrototypeDescriptor::Mask);
- } else {
- // If HasMasked, insert PrototypeDescriptor:Mask as first input operand.
- MaskedPrototype.insert(MaskedPrototype.begin() + 1,
- PrototypeDescriptor::Mask);
- }
- }
- // If HasVL, append PrototypeDescriptor:VL to last operand
- if (HasVL) {
- Prototype.push_back(PrototypeDescriptor::VL);
- MaskedPrototype.push_back(PrototypeDescriptor::VL);
- }
+ auto Prototype = RVVIntrinsic::computeBuiltinTypes(
+ BasicPrototype, /*IsMasked=*/false, /*HasMaskedOffOperand=*/false,
+ HasVL, NF);
+ auto MaskedPrototype = RVVIntrinsic::computeBuiltinTypes(
+ BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF);
// Create Intrinsics for each type and LMUL.
for (char I : TypeRange) {
@@ -487,7 +531,7 @@ void RVVEmitter::createRVVIntrinsics(
Out.push_back(std::make_unique<RVVIntrinsic>(
Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
/*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL,
- UnMaskedPolicy, HasUnMaskedOverloaded, HasBuiltinAlias,
+ UnMaskedPolicyScheme, HasUnMaskedOverloaded, HasBuiltinAlias,
ManualCodegen, *Types, IntrinsicTypes, RequiredFeatures, NF));
if (HasMasked) {
// Create a masked intrinsic
@@ -496,12 +540,57 @@ void RVVEmitter::createRVVIntrinsics(
Out.push_back(std::make_unique<RVVIntrinsic>(
Name, SuffixStr, OverloadedName, OverloadedSuffixStr,
MaskedIRName,
- /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicy,
+ /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme,
HasUnMaskedOverloaded, HasBuiltinAlias, MaskedManualCodegen,
*MaskTypes, IntrinsicTypes, RequiredFeatures, NF));
}
} // end for Log2LMULList
} // end for TypeRange
+
+ // We don't emit vsetvli and vsetvlimax for SemaRecord.
+ // They are written in riscv_vector.td and will emit those marco define in
+ // riscv_vector.h
+ if (Name == "vsetvli" || Name == "vsetvlimax")
+ continue;
+
+ if (!SemaRecords)
+ continue;
+
+ // Create SemaRecord
+ SemaRecord SR;
+ SR.Name = Name.str();
+ SR.OverloadedName = OverloadedName.str();
+ BasicType TypeRangeMask = BasicType::Unknown;
+ for (char I : TypeRange)
+ TypeRangeMask |= ParseBasicType(I);
+
+ SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask);
+
+ unsigned Log2LMULMask = 0;
+ for (int Log2LMUL : Log2LMULList)
+ Log2LMULMask |= 1 << (Log2LMUL + 3);
+
+ SR.Log2LMULMask = Log2LMULMask;
+
+ SR.RequiredExtensions = 0;
+ for (auto RequiredFeature : RequiredFeatures) {
+ RVVRequire RequireExt = StringSwitch<RVVRequire>(RequiredFeature)
+ .Case("RV64", RVV_REQ_RV64)
+ .Case("FullMultiply", RVV_REQ_FullMultiply)
+ .Default(RVV_REQ_None);
+ assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?");
+ SR.RequiredExtensions |= RequireExt;
+ }
+
+ SR.NF = NF;
+ SR.HasMasked = HasMasked;
+ SR.HasVL = HasVL;
+ SR.HasMaskedOffOperand = HasMaskedOffOperand;
+ SR.Prototype = std::move(BasicPrototype);
+ SR.Suffix = parsePrototypes(SuffixProto);
+ SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto);
+
+ SemaRecords->push_back(SR);
}
}
@@ -514,47 +603,59 @@ void RVVEmitter::printHeaderCode(raw_ostream &OS) {
}
}
-void RVVEmitter::emitArchMacroAndBody(
- std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS,
- std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) {
- RISCVPredefinedMacroT PrevMacros =
- (*Defs.begin())->getRISCVPredefinedMacros();
- bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS);
- for (auto &Def : Defs) {
- RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros();
- if (CurMacros != PrevMacros) {
- if (NeedEndif)
- OS << "#endif\n\n";
- NeedEndif = emitMacroRestrictionStr(CurMacros, OS);
- PrevMacros = CurMacros;
- }
- if (Def->hasBuiltinAlias())
- PrintBody(OS, *Def);
+void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
+ SemaSignatureTable &SST,
+ ArrayRef<SemaRecord> SemaRecords) {
+ SST.init(SemaRecords);
+
+ for (const auto &SR : SemaRecords) {
+ Out.emplace_back(RVVIntrinsicRecord());
+ RVVIntrinsicRecord &R = Out.back();
+ R.Name = SR.Name.c_str();
+ R.OverloadedName = SR.OverloadedName.c_str();
+ R.PrototypeIndex = SST.getIndex(SR.Prototype);
+ R.SuffixIndex = SST.getIndex(SR.Suffix);
+ R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix);
+ R.PrototypeLength = SR.Prototype.size();
+ R.SuffixLength = SR.Suffix.size();
+ R.OverloadedSuffixSize = SR.OverloadedSuffix.size();
+ R.RequiredExtensions = SR.RequiredExtensions;
+ R.TypeRangeMask = SR.TypeRangeMask;
+ R.Log2LMULMask = SR.Log2LMULMask;
+ R.NF = SR.NF;
+ R.HasMasked = SR.HasMasked;
+ R.HasVL = SR.HasVL;
+ R.HasMaskedOffOperand = SR.HasMaskedOffOperand;
+
+ assert(R.PrototypeIndex !=
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
+ assert(R.SuffixIndex !=
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
+ assert(R.OverloadedSuffixIndex !=
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
}
- if (NeedEndif)
- OS << "#endif\n\n";
}
-bool RVVEmitter::emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros,
- raw_ostream &OS) {
- if (PredefinedMacros == RISCVPredefinedMacro::Basic)
- return false;
- OS << "#if ";
- ListSeparator LS(" && ");
- if (PredefinedMacros & RISCVPredefinedMacro::V)
- OS << LS << "defined(__riscv_v)";
- if (PredefinedMacros & RISCVPredefinedMacro::Zvfh)
- OS << LS << "defined(__riscv_zvfh)";
- if (PredefinedMacros & RISCVPredefinedMacro::RV64)
- OS << LS << "(__riscv_xlen == 64)";
- if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64)
- OS << LS << "(__riscv_v_elen >= 64)";
- if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32)
- OS << LS << "(__riscv_v_elen_fp >= 32)";
- if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64)
- OS << LS << "(__riscv_v_elen_fp >= 64)";
- OS << "\n";
- return true;
+void RVVEmitter::createSema(raw_ostream &OS) {
+ std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
+ std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords;
+ SemaSignatureTable SST;
+ std::vector<SemaRecord> SemaRecords;
+
+ createRVVIntrinsics(Defs, &SemaRecords);
+
+ createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords);
+
+ // Emit signature table for SemaRISCVVectorLookup.cpp.
+ OS << "#ifdef DECL_SIGNATURE_TABLE\n";
+ SST.print(OS);
+ OS << "#endif\n";
+
+ // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
+ OS << "#ifdef DECL_INTRINSIC_RECORDS\n";
+ for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords)
+ OS << Record;
+ OS << "#endif\n";
}
namespace clang {
@@ -570,4 +671,8 @@ void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
RVVEmitter(Records).createCodeGen(OS);
}
+void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) {
+ RVVEmitter(Records).createSema(OS);
+}
+
} // End namespace clang
diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index bb9366e2b7fc..d18a31226e80 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -88,6 +88,7 @@ enum ActionType {
GenRISCVVectorHeader,
GenRISCVVectorBuiltins,
GenRISCVVectorBuiltinCG,
+ GenRISCVVectorBuiltinSema,
GenAttrDocs,
GenDiagDocs,
GenOptDocs,
@@ -243,6 +244,8 @@ cl::opt<ActionType> Action(
"Generate riscv_vector_builtins.inc for clang"),
clEnumValN(GenRISCVVectorBuiltinCG, "gen-riscv-vector-builtin-codegen",
"Generate riscv_vector_builtin_cg.inc for clang"),
+ clEnumValN(GenRISCVVectorBuiltinSema, "gen-riscv-vector-builtin-sema",
+ "Generate riscv_vector_builtin_sema.inc for clang"),
clEnumValN(GenAttrDocs, "gen-attr-docs",
"Generate attribute documentation"),
clEnumValN(GenDiagDocs, "gen-diag-docs",
@@ -458,6 +461,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenRISCVVectorBuiltinCG:
EmitRVVBuiltinCG(Records, OS);
break;
+ case GenRISCVVectorBuiltinSema:
+ EmitRVVBuiltinSema(Records, OS);
+ break;
case GenAttrDocs:
EmitClangAttrDocs(Records, OS);
break;
diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h
index fd8b9fcda20f..2ba857f66f50 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -110,6 +110,7 @@ void EmitMveBuiltinAliases(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitRVVHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitRVVBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitRVVBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitRVVBuiltinSema(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitCdeHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitCdeBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
diff --git a/compiler-rt/lib/builtins/int_types.h b/compiler-rt/lib/builtins/int_types.h
index 7a72de480676..9ee5a327b28a 100644
--- a/compiler-rt/lib/builtins/int_types.h
+++ b/compiler-rt/lib/builtins/int_types.h
@@ -64,7 +64,7 @@ typedef union {
} udwords;
#if defined(__LP64__) || defined(__wasm__) || defined(__mips64) || \
- defined(__riscv) || defined(_WIN64)
+ defined(__riscv) || defined(_WIN64) || defined(__powerpc__)
#define CRT_HAS_128BIT
#endif
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
index 517f776baf6e..08c6062ba067 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -120,6 +120,11 @@ bool MprotectReadOnly(uptr addr, uptr size);
void MprotectMallocZones(void *addr, int prot);
+#if SANITIZER_WINDOWS
+// Zero previously mmap'd memory. Currently used only on Windows.
+bool ZeroMmapFixedRegion(uptr fixed_addr, uptr size) WARN_UNUSED_RESULT;
+#endif
+
#if SANITIZER_LINUX
// Unmap memory. Currently only used on Linux.
void UnmapFromTo(uptr from, uptr to);
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
index b4506e52efaa..e0568c9b62d5 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
@@ -234,6 +234,17 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
return (void *)mapped_addr;
}
+// ZeroMmapFixedRegion zero's out a region of memory previously returned from a
+// call to one of the MmapFixed* helpers. On non-windows systems this would be
+// done with another mmap, but on windows remapping is not an option.
+// VirtualFree(DECOMMIT)+VirtualAlloc(RECOMMIT) would also be a way to zero the
+// memory, but we can't do this atomically, so instead we fall back to using
+// internal_memset.
+bool ZeroMmapFixedRegion(uptr fixed_addr, uptr size) {
+ internal_memset((void*) fixed_addr, 0, size);
+ return true;
+}
+
bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
// FIXME: is this really "NoReserve"? On Win32 this does not matter much,
// but on Win64 it does.
diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.inc b/compiler-rt/lib/tsan/rtl/tsan_flags.inc
index c6a5fb8bc984..731d776cc893 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_flags.inc
+++ b/compiler-rt/lib/tsan/rtl/tsan_flags.inc
@@ -23,10 +23,6 @@ TSAN_FLAG(bool, enable_annotations, true,
TSAN_FLAG(bool, suppress_equal_stacks, true,
"Suppress a race report if we've already output another race report "
"with the same stack.")
-TSAN_FLAG(bool, suppress_equal_addresses, true,
- "Suppress a race report if we've already output another race report "
- "on the same address.")
-
TSAN_FLAG(bool, report_bugs, true,
"Turns off bug reporting entirely (useful for benchmarking).")
TSAN_FLAG(bool, report_thread_leaks, true, "Report thread leaks at exit?")
diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform.h b/compiler-rt/lib/tsan/rtl/tsan_platform.h
index 12643f7f512c..7c13c7335136 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h
@@ -394,6 +394,7 @@ struct MappingGo48 {
0300 0000 0000 - 0700 0000 0000: -
0700 0000 0000 - 0770 0000 0000: metainfo (memory blocks and sync objects)
07d0 0000 0000 - 8000 0000 0000: -
+PIE binaries currently not supported, but it should be theoretically possible.
*/
struct MappingGoWindows {
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
index 825a9d791ecc..ff3bb33eb134 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -197,13 +197,30 @@ static void DoResetImpl(uptr epoch) {
}
DPrintf("Resetting shadow...\n");
- if (!MmapFixedSuperNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(),
- "shadow")) {
+ auto shadow_begin = ShadowBeg();
+ auto shadow_end = ShadowEnd();
+#if SANITIZER_GO
+ CHECK_NE(0, ctx->mapped_shadow_begin);
+ shadow_begin = ctx->mapped_shadow_begin;
+ shadow_end = ctx->mapped_shadow_end;
+ VPrintf(2, "shadow_begin-shadow_end: (0x%zx-0x%zx)\n",
+ shadow_begin, shadow_end);
+#endif
+
+#if SANITIZER_WINDOWS
+ auto resetFailed =
+ !ZeroMmapFixedRegion(shadow_begin, shadow_end - shadow_begin);
+#else
+ auto resetFailed =
+ !MmapFixedSuperNoReserve(shadow_begin, shadow_end-shadow_begin, "shadow");
+#endif
+ if (resetFailed) {
Printf("failed to reset shadow memory\n");
Die();
}
DPrintf("Resetting meta shadow...\n");
ctx->metamap.ResetClocks();
+ StoreShadow(&ctx->last_spurious_race, Shadow::kEmpty);
ctx->resetting = false;
}
@@ -368,7 +385,6 @@ Context::Context()
}),
racy_mtx(MutexTypeRacy),
racy_stacks(),
- racy_addresses(),
fired_suppressions_mtx(MutexTypeFired),
slot_mtx(MutexTypeSlots),
resetting() {
@@ -557,18 +573,50 @@ void UnmapShadow(ThreadState *thr, uptr addr, uptr size) {
#endif
void MapShadow(uptr addr, uptr size) {
+ // Ensure thead registry lock held, so as to synchronize
+ // with DoReset, which also access the mapped_shadow_* ctxt fields.
+ ThreadRegistryLock lock0(&ctx->thread_registry);
+ static bool data_mapped = false;
+
+#if !SANITIZER_GO
// Global data is not 64K aligned, but there are no adjacent mappings,
// so we can get away with unaligned mapping.
// CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment
const uptr kPageSize = GetPageSizeCached();
uptr shadow_begin = RoundDownTo((uptr)MemToShadow(addr), kPageSize);
uptr shadow_end = RoundUpTo((uptr)MemToShadow(addr + size), kPageSize);
- if (!MmapFixedSuperNoReserve(shadow_begin, shadow_end - shadow_begin,
- "shadow"))
+ if (!MmapFixedNoReserve(shadow_begin, shadow_end - shadow_begin, "shadow"))
Die();
+#else
+ uptr shadow_begin = RoundDownTo((uptr)MemToShadow(addr), (64 << 10));
+ uptr shadow_end = RoundUpTo((uptr)MemToShadow(addr + size), (64 << 10));
+ VPrintf(2, "MapShadow for (0x%zx-0x%zx), begin/end: (0x%zx-0x%zx)\n",
+ addr, addr + size, shadow_begin, shadow_end);
+
+ if (!data_mapped) {
+ // First call maps data+bss.
+ if (!MmapFixedSuperNoReserve(shadow_begin, shadow_end - shadow_begin, "shadow"))
+ Die();
+ } else {
+ VPrintf(2, "ctx->mapped_shadow_{begin,end} = (0x%zx-0x%zx)\n",
+ ctx->mapped_shadow_begin, ctx->mapped_shadow_end);
+ // Second and subsequent calls map heap.
+ if (shadow_end <= ctx->mapped_shadow_end)
+ return;
+ if (ctx->mapped_shadow_begin < shadow_begin)
+ ctx->mapped_shadow_begin = shadow_begin;
+ if (shadow_begin < ctx->mapped_shadow_end)
+ shadow_begin = ctx->mapped_shadow_end;
+ VPrintf(2, "MapShadow begin/end = (0x%zx-0x%zx)\n",
+ shadow_begin, shadow_end);
+ if (!MmapFixedSuperNoReserve(shadow_begin, shadow_end - shadow_begin,
+ "shadow"))
+ Die();
+ ctx->mapped_shadow_end = shadow_end;
+ }
+#endif
// Meta shadow is 2:1, so tread carefully.
- static bool data_mapped = false;
static uptr mapped_meta_end = 0;
uptr meta_begin = (uptr)MemToMeta(addr);
uptr meta_end = (uptr)MemToMeta(addr + size);
@@ -585,8 +633,7 @@ void MapShadow(uptr addr, uptr size) {
// Windows wants 64K alignment.
meta_begin = RoundDownTo(meta_begin, 64 << 10);
meta_end = RoundUpTo(meta_end, 64 << 10);
- if (meta_end <= mapped_meta_end)
- return;
+ CHECK_GT(meta_end, mapped_meta_end);
if (meta_begin < mapped_meta_end)
meta_begin = mapped_meta_end;
if (!MmapFixedSuperNoReserve(meta_begin, meta_end - meta_begin,
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index c8d3c48a0c0c..e1e121e2ee07 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -314,9 +314,43 @@ struct Context {
ThreadRegistry thread_registry;
+ // This is used to prevent a very unlikely but very pathological behavior.
+ // Since memory access handling is not synchronized with DoReset,
+ // a thread running concurrently with DoReset can leave a bogus shadow value
+ // that will be later falsely detected as a race. For such false races
+ // RestoreStack will return false and we will not report it.
+ // However, consider that a thread leaves a whole lot of such bogus values
+ // and these values are later read by a whole lot of threads.
+ // This will cause massive amounts of ReportRace calls and lots of
+ // serialization. In very pathological cases the resulting slowdown
+ // can be >100x. This is very unlikely, but it was presumably observed
+ // in practice: https://github.com/google/sanitizers/issues/1552
+ // If this happens, previous access sid+epoch will be the same for all of
+ // these false races b/c if the thread will try to increment epoch, it will
+ // notice that DoReset has happened and will stop producing bogus shadow
+ // values. So, last_spurious_race is used to remember the last sid+epoch
+ // for which RestoreStack returned false. Then it is used to filter out
+ // races with the same sid+epoch very early and quickly.
+ // It is of course possible that multiple threads left multiple bogus shadow
+ // values and all of them are read by lots of threads at the same time.
+ // In such case last_spurious_race will only be able to deduplicate a few
+ // races from one thread, then few from another and so on. An alternative
+ // would be to hold an array of such sid+epoch, but we consider such scenario
+ // as even less likely.
+ // Note: this can lead to some rare false negatives as well:
+ // 1. When a legit access with the same sid+epoch participates in a race
+ // as the "previous" memory access, it will be wrongly filtered out.
+ // 2. When RestoreStack returns false for a legit memory access because it
+ // was already evicted from the thread trace, we will still remember it in
+ // last_spurious_race. Then if there is another racing memory access from
+ // the same thread that happened in the same epoch, but was stored in the
+ // next thread trace part (which is still preserved in the thread trace),
+ // we will also wrongly filter it out while RestoreStack would actually
+ // succeed for that second memory access.
+ RawShadow last_spurious_race;
+
Mutex racy_mtx;
Vector<RacyStacks> racy_stacks;
- Vector<RacyAddress> racy_addresses;
// Number of fired suppressions may be large enough.
Mutex fired_suppressions_mtx;
InternalMmapVector<FiredSuppression> fired_suppressions;
@@ -338,6 +372,10 @@ struct Context {
uptr trace_part_total_allocated SANITIZER_GUARDED_BY(slot_mtx);
uptr trace_part_recycle_finished SANITIZER_GUARDED_BY(slot_mtx);
uptr trace_part_finished_excess SANITIZER_GUARDED_BY(slot_mtx);
+#if SANITIZER_GO
+ uptr mapped_shadow_begin;
+ uptr mapped_shadow_end;
+#endif
};
extern Context *ctx; // The one and the only global runtime context.
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_access.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_access.cpp
index 7d771bfaad7f..8b20984a0100 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_access.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_access.cpp
@@ -145,15 +145,6 @@ void TraceTime(ThreadState* thr) {
TraceEvent(thr, ev);
}
-ALWAYS_INLINE RawShadow LoadShadow(RawShadow* p) {
- return static_cast<RawShadow>(
- atomic_load((atomic_uint32_t*)p, memory_order_relaxed));
-}
-
-ALWAYS_INLINE void StoreShadow(RawShadow* sp, RawShadow s) {
- atomic_store((atomic_uint32_t*)sp, static_cast<u32>(s), memory_order_relaxed);
-}
-
NOINLINE void DoReportRace(ThreadState* thr, RawShadow* shadow_mem, Shadow cur,
Shadow old,
AccessType typ) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
index 4cf8816489df..444f210390cc 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
@@ -629,35 +629,6 @@ static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2]) {
return false;
}
-static bool FindRacyAddress(const RacyAddress &ra0) {
- for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) {
- RacyAddress ra2 = ctx->racy_addresses[i];
- uptr maxbeg = max(ra0.addr_min, ra2.addr_min);
- uptr minend = min(ra0.addr_max, ra2.addr_max);
- if (maxbeg < minend) {
- VPrintf(2, "ThreadSanitizer: suppressing report as doubled (addr)\n");
- return true;
- }
- }
- return false;
-}
-
-static bool HandleRacyAddress(ThreadState *thr, uptr addr_min, uptr addr_max) {
- if (!flags()->suppress_equal_addresses)
- return false;
- RacyAddress ra0 = {addr_min, addr_max};
- {
- ReadLock lock(&ctx->racy_mtx);
- if (FindRacyAddress(ra0))
- return true;
- }
- Lock lock(&ctx->racy_mtx);
- if (FindRacyAddress(ra0))
- return true;
- ctx->racy_addresses.PushBack(ra0);
- return false;
-}
-
bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
// These should have been checked in ShouldReport.
// It's too late to check them here, we have already taken locks.
@@ -730,6 +701,11 @@ static bool IsFiredSuppression(Context *ctx, ReportType type, uptr addr) {
return false;
}
+static bool SpuriousRace(Shadow old) {
+ Shadow last(LoadShadow(&ctx->last_spurious_race));
+ return last.sid() == old.sid() && last.epoch() == old.epoch();
+}
+
void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old,
AccessType typ0) {
CheckedMutex::CheckNoLocks();
@@ -750,6 +726,8 @@ void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old,
((typ0 & kAccessAtomic) || (typ1 & kAccessAtomic)) &&
!(typ0 & kAccessFree) && !(typ1 & kAccessFree))
return;
+ if (SpuriousRace(old))
+ return;
const uptr kMop = 2;
Shadow s[kMop] = {cur, old};
@@ -761,8 +739,6 @@ void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old,
uptr addr_max = max(end0, end1);
if (IsExpectedReport(addr_min, addr_max - addr_min))
return;
- if (HandleRacyAddress(thr, addr_min, addr_max))
- return;
ReportType rep_typ = ReportTypeRace;
if ((typ0 & kAccessVptr) && (typ1 & kAccessFree))
@@ -791,9 +767,13 @@ void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old,
Lock slot_lock(&ctx->slots[static_cast<uptr>(s[1].sid())].mtx);
ThreadRegistryLock l0(&ctx->thread_registry);
Lock slots_lock(&ctx->slot_mtx);
+ if (SpuriousRace(old))
+ return;
if (!RestoreStack(EventType::kAccessExt, s[1].sid(), s[1].epoch(), addr1,
- size1, typ1, &tids[1], &traces[1], mset[1], &tags[1]))
+ size1, typ1, &tids[1], &traces[1], mset[1], &tags[1])) {
+ StoreShadow(&ctx->last_spurious_race, old.raw());
return;
+ }
if (IsFiredSuppression(ctx, rep_typ, traces[1]))
return;
diff --git a/compiler-rt/lib/tsan/rtl/tsan_shadow.h b/compiler-rt/lib/tsan/rtl/tsan_shadow.h
index b222acf9e6c5..6b8114ef5132 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_shadow.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_shadow.h
@@ -178,6 +178,16 @@ class Shadow {
static_assert(sizeof(Shadow) == kShadowSize, "bad Shadow size");
+ALWAYS_INLINE RawShadow LoadShadow(RawShadow *p) {
+ return static_cast<RawShadow>(
+ atomic_load((atomic_uint32_t *)p, memory_order_relaxed));
+}
+
+ALWAYS_INLINE void StoreShadow(RawShadow *sp, RawShadow s) {
+ atomic_store((atomic_uint32_t *)sp, static_cast<u32>(s),
+ memory_order_relaxed);
+}
+
} // namespace __tsan
#endif
diff --git a/libcxx/include/__algorithm/copy.h b/libcxx/include/__algorithm/copy.h
index 886a1ac6ce3e..5428baa68859 100644
--- a/libcxx/include/__algorithm/copy.h
+++ b/libcxx/include/__algorithm/copy.h
@@ -58,20 +58,20 @@ pair<_InValueT*, _OutValueT*> __copy_impl(_InValueT* __first, _InValueT* __last,
template <class _InIter, class _OutIter,
__enable_if_t<is_same<typename remove_const<__iter_value_type<_InIter> >::type, __iter_value_type<_OutIter> >::value
- && __is_cpp17_contiguous_iterator<_InIter>::value
- && __is_cpp17_contiguous_iterator<_OutIter>::value
- && is_trivially_copy_assignable<__iter_value_type<_OutIter> >::value, int> = 0>
+ && __is_cpp17_contiguous_iterator<typename _InIter::iterator_type>::value
+ && __is_cpp17_contiguous_iterator<typename _OutIter::iterator_type>::value
+ && is_trivially_copy_assignable<__iter_value_type<_OutIter> >::value
+ && __is_reverse_iterator<_InIter>::value
+ && __is_reverse_iterator<_OutIter>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
-pair<reverse_iterator<_InIter>, reverse_iterator<_OutIter> >
-__copy_impl(reverse_iterator<_InIter> __first,
- reverse_iterator<_InIter> __last,
- reverse_iterator<_OutIter> __result) {
+pair<_InIter, _OutIter>
+__copy_impl(_InIter __first, _InIter __last, _OutIter __result) {
auto __first_base = std::__unwrap_iter(__first.base());
auto __last_base = std::__unwrap_iter(__last.base());
auto __result_base = std::__unwrap_iter(__result.base());
auto __result_first = __result_base - (__first_base - __last_base);
std::__copy_impl(__last_base, __first_base, __result_first);
- return std::make_pair(__last, reverse_iterator<_OutIter>(std::__rewrap_iter(__result.base(), __result_first)));
+ return std::make_pair(__last, _OutIter(std::__rewrap_iter(__result.base(), __result_first)));
}
template <class _InIter, class _Sent, class _OutIter,
diff --git a/libcxx/include/__algorithm/copy_backward.h b/libcxx/include/__algorithm/copy_backward.h
index dd43a91ffa87..26b8c4d791fd 100644
--- a/libcxx/include/__algorithm/copy_backward.h
+++ b/libcxx/include/__algorithm/copy_backward.h
@@ -10,10 +10,16 @@
#define _LIBCPP___ALGORITHM_COPY_BACKWARD_H
#include <__algorithm/copy.h>
+#include <__algorithm/iterator_operations.h>
+#include <__algorithm/ranges_copy.h>
#include <__algorithm/unwrap_iter.h>
+#include <__concepts/same_as.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__iterator/reverse_iterator.h>
+#include <__ranges/subrange.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
#include <cstring>
#include <type_traits>
@@ -23,29 +29,31 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Iter1, class _Sent1, class _Iter2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
-pair<_Iter1, _Iter2> __copy_backward_impl(_Iter1 __first, _Sent1 __last, _Iter2 __result) {
- auto __ret = std::__copy(reverse_iterator<_Iter1>(__last),
- reverse_iterator<_Sent1>(__first),
- reverse_iterator<_Iter2>(__result));
- return pair<_Iter1, _Iter2>(__ret.first.base(), __ret.second.base());
+template <class _AlgPolicy, class _InputIterator, class _OutputIterator,
+ __enable_if_t<is_same<_AlgPolicy, _ClassicAlgPolicy>::value, int> = 0>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 pair<_InputIterator, _OutputIterator>
+__copy_backward(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
+ auto __ret = std::__copy(
+ __unconstrained_reverse_iterator<_InputIterator>(__last),
+ __unconstrained_reverse_iterator<_InputIterator>(__first),
+ __unconstrained_reverse_iterator<_OutputIterator>(__result));
+ return pair<_InputIterator, _OutputIterator>(__ret.first.base(), __ret.second.base());
}
-template <class _Iter1, class _Sent1, class _Iter2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
-pair<_Iter1, _Iter2> __copy_backward(_Iter1 __first, _Sent1 __last, _Iter2 __result) {
- auto __ret = std::__copy_backward_impl(std::__unwrap_iter(__first),
- std::__unwrap_iter(__last),
- std::__unwrap_iter(__result));
- return pair<_Iter1, _Iter2>(std::__rewrap_iter(__first, __ret.first), std::__rewrap_iter(__result, __ret.second));
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+template <class _AlgPolicy, class _Iter1, class _Sent1, class _Iter2,
+ __enable_if_t<is_same<_AlgPolicy, _RangeAlgPolicy>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter1, _Iter2> __copy_backward(_Iter1 __first, _Sent1 __last, _Iter2 __result) {
+ auto __reverse_range = std::__reverse_range(std::ranges::subrange(std::move(__first), std::move(__last)));
+ auto __ret = ranges::copy(std::move(__reverse_range), std::make_reverse_iterator(__result));
+ return std::make_pair(__ret.in.base(), __ret.out.base());
}
+#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
template <class _BidirectionalIterator1, class _BidirectionalIterator2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
-_BidirectionalIterator2
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _BidirectionalIterator2
copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) {
- return std::__copy_backward(__first, __last, __result).second;
+ return std::__copy_backward<_ClassicAlgPolicy>(__first, __last, __result).second;
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/equal_range.h b/libcxx/include/__algorithm/equal_range.h
index 42d009ebbc0f..b11165baf384 100644
--- a/libcxx/include/__algorithm/equal_range.h
+++ b/libcxx/include/__algorithm/equal_range.h
@@ -21,6 +21,7 @@
#include <__iterator/advance.h>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
#include <__type_traits/is_callable.h>
#include <__type_traits/is_copy_constructible.h>
#include <__utility/move.h>
diff --git a/libcxx/include/__algorithm/includes.h b/libcxx/include/__algorithm/includes.h
index 102d3db39a2d..c64194a2c826 100644
--- a/libcxx/include/__algorithm/includes.h
+++ b/libcxx/include/__algorithm/includes.h
@@ -12,7 +12,10 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
#include <__iterator/iterator_traits.h>
+#include <__type_traits/is_callable.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -21,13 +24,15 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Comp>
+template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Comp, class _Proj1, class _Proj2>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
-__includes(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Comp&& __comp) {
+__includes(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
+ _Comp&& __comp, _Proj1&& __proj1, _Proj2&& __proj2) {
for (; __first2 != __last2; ++__first1) {
- if (__first1 == __last1 || __comp(*__first2, *__first1))
+ if (__first1 == __last1 || std::__invoke(
+ __comp, std::__invoke(__proj2, *__first2), std::__invoke(__proj1, *__first1)))
return false;
- if (!__comp(*__first1, *__first2))
+ if (!std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
++__first2;
}
return true;
@@ -40,9 +45,13 @@ _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
_InputIterator2 __first2,
_InputIterator2 __last2,
_Compare __comp) {
+ static_assert(__is_callable<_Compare, decltype(*__first1), decltype(*__first2)>::value,
+ "Comparator has to be callable");
+
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
return std::__includes(
- std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), static_cast<_Comp_ref>(__comp));
+ std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
+ static_cast<_Comp_ref>(__comp), __identity(), __identity());
}
template <class _InputIterator1, class _InputIterator2>
diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index f4364969b8f9..cb662e791872 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.h
@@ -105,8 +105,8 @@ __buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator
value_type* __p = __buff;
for (_BidirectionalIterator __i = __middle; __i != __last; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
- typedef reverse_iterator<_BidirectionalIterator> _RBi;
- typedef reverse_iterator<value_type*> _Rv;
+ typedef __unconstrained_reverse_iterator<_BidirectionalIterator> _RBi;
+ typedef __unconstrained_reverse_iterator<value_type*> _Rv;
typedef __invert<_Compare> _Inverted;
std::__half_inplace_merge<_AlgPolicy, _Inverted>(_Rv(__p), _Rv(__buff),
_RBi(__middle), _RBi(__first),
diff --git a/libcxx/include/__algorithm/is_heap.h b/libcxx/include/__algorithm/is_heap.h
index fe44e634f6dd..0d399a09b857 100644
--- a/libcxx/include/__algorithm/is_heap.h
+++ b/libcxx/include/__algorithm/is_heap.h
@@ -28,7 +28,7 @@ bool
is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
{
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__is_heap_until<_Comp_ref>(__first, __last, __comp) == __last;
+ return std::__is_heap_until(__first, __last, static_cast<_Comp_ref>(__comp)) == __last;
}
template<class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/is_heap_until.h b/libcxx/include/__algorithm/is_heap_until.h
index 39f313eb0d3f..adb35af887fb 100644
--- a/libcxx/include/__algorithm/is_heap_until.h
+++ b/libcxx/include/__algorithm/is_heap_until.h
@@ -22,7 +22,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Compare, class _RandomAccessIterator>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _RandomAccessIterator
-__is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
+__is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare&& __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
difference_type __len = __last - __first;
@@ -52,7 +52,7 @@ _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
{
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__is_heap_until<_Comp_ref>(__first, __last, __comp);
+ return std::__is_heap_until(__first, __last, static_cast<_Comp_ref>(__comp));
}
template<class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/ranges_copy_backward.h b/libcxx/include/__algorithm/ranges_copy_backward.h
index 49c1b26add6d..673df8025fab 100644
--- a/libcxx/include/__algorithm/ranges_copy_backward.h
+++ b/libcxx/include/__algorithm/ranges_copy_backward.h
@@ -11,6 +11,7 @@
#include <__algorithm/copy_backward.h>
#include <__algorithm/in_out_result.h>
+#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/reverse_iterator.h>
@@ -39,7 +40,7 @@ struct __fn {
requires indirectly_copyable<_InIter1, _InIter2>
_LIBCPP_HIDE_FROM_ABI constexpr
copy_backward_result<_InIter1, _InIter2> operator()(_InIter1 __first, _Sent1 __last, _InIter2 __result) const {
- auto __ret = std::__copy_backward(std::move(__first), std::move(__last), std::move(__result));
+ auto __ret = std::__copy_backward<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
return {std::move(__ret.first), std::move(__ret.second)};
}
@@ -47,9 +48,7 @@ struct __fn {
requires indirectly_copyable<iterator_t<_Range>, _Iter>
_LIBCPP_HIDE_FROM_ABI constexpr
copy_backward_result<borrowed_iterator_t<_Range>, _Iter> operator()(_Range&& __r, _Iter __result) const {
- auto __ret = std::__copy_backward(ranges::begin(__r),
- ranges::end(__r),
- std::move(__result));
+ auto __ret = std::__copy_backward<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), std::move(__result));
return {std::move(__ret.first), std::move(__ret.second)};
}
};
diff --git a/libcxx/include/__algorithm/ranges_generate.h b/libcxx/include/__algorithm/ranges_generate.h
index c23645e6d906..149296574d80 100644
--- a/libcxx/include/__algorithm/ranges_generate.h
+++ b/libcxx/include/__algorithm/ranges_generate.h
@@ -9,21 +9,15 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_GENERATE_H
#define _LIBCPP___ALGORITHM_RANGES_GENERATE_H
-#include <__algorithm/generate.h>
-#include <__algorithm/make_projected.h>
#include <__concepts/constructible.h>
#include <__concepts/invocable.h>
#include <__config>
-#include <__functional/identity.h>
#include <__functional/invoke.h>
-#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
-#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
-#include <__utility/forward.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -39,22 +33,28 @@ namespace __generate {
struct __fn {
+ template <class _OutIter, class _Sent, class _Func>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ static _OutIter __generate_fn_impl(_OutIter __first, _Sent __last, _Func& __gen) {
+ for (; __first != __last; ++__first) {
+ *__first = __gen();
+ }
+
+ return __first;
+ }
+
template <input_or_output_iterator _OutIter, sentinel_for<_OutIter> _Sent, copy_constructible _Func>
requires invocable<_Func&> && indirectly_writable<_OutIter, invoke_result_t<_Func&>>
_LIBCPP_HIDE_FROM_ABI constexpr
_OutIter operator()(_OutIter __first, _Sent __last, _Func __gen) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__gen;
- return {};
+ return __generate_fn_impl(std::move(__first), std::move(__last), __gen);
}
template <class _Range, copy_constructible _Func>
requires invocable<_Func&> && output_range<_Range, invoke_result_t<_Func&>>
_LIBCPP_HIDE_FROM_ABI constexpr
borrowed_iterator_t<_Range> operator()(_Range&& __range, _Func __gen) const {
- // TODO: implement
- (void)__range; (void)__gen;
- return {};
+ return __generate_fn_impl(ranges::begin(__range), ranges::end(__range), __gen);
}
};
diff --git a/libcxx/include/__algorithm/ranges_generate_n.h b/libcxx/include/__algorithm/ranges_generate_n.h
index 7bde5fb4e579..63f466cecdd7 100644
--- a/libcxx/include/__algorithm/ranges_generate_n.h
+++ b/libcxx/include/__algorithm/ranges_generate_n.h
@@ -9,21 +9,16 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_GENERATE_N_H
#define _LIBCPP___ALGORITHM_RANGES_GENERATE_N_H
-#include <__algorithm/generate_n.h>
-#include <__algorithm/make_projected.h>
#include <__concepts/constructible.h>
#include <__concepts/invocable.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
-#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/incrementable_traits.h>
#include <__iterator/iterator_traits.h>
-#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
-#include <__utility/forward.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -43,9 +38,12 @@ struct __fn {
requires invocable<_Func&> && indirectly_writable<_OutIter, invoke_result_t<_Func&>>
_LIBCPP_HIDE_FROM_ABI constexpr
_OutIter operator()(_OutIter __first, iter_difference_t<_OutIter> __n, _Func __gen) const {
- // TODO: implement
- (void)__first; (void)__n; (void)__gen;
- return {};
+ for (; __n > 0; --__n) {
+ *__first = __gen();
+ ++__first;
+ }
+
+ return __first;
}
};
diff --git a/libcxx/include/__algorithm/ranges_includes.h b/libcxx/include/__algorithm/ranges_includes.h
index ba054e6fd89d..2c7581af68af 100644
--- a/libcxx/include/__algorithm/ranges_includes.h
+++ b/libcxx/include/__algorithm/ranges_includes.h
@@ -56,7 +56,9 @@ struct __fn {
std::move(__last1),
std::move(__first2),
std::move(__last2),
- ranges::__make_projected_comp(__comp, __proj1, __proj2));
+ std::move(__comp),
+ std::move(__proj1),
+ std::move(__proj2));
}
template <
@@ -73,7 +75,9 @@ struct __fn {
ranges::end(__range1),
ranges::begin(__range2),
ranges::end(__range2),
- ranges::__make_projected_comp(__comp, __proj1, __proj2));
+ std::move(__comp),
+ std::move(__proj1),
+ std::move(__proj2));
}
};
diff --git a/libcxx/include/__algorithm/ranges_is_heap.h b/libcxx/include/__algorithm/ranges_is_heap.h
index 00105189fed7..a3e86d1a8d72 100644
--- a/libcxx/include/__algorithm/ranges_is_heap.h
+++ b/libcxx/include/__algorithm/ranges_is_heap.h
@@ -9,18 +9,17 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_IS_HEAP_H
#define _LIBCPP___ALGORITHM_RANGES_IS_HEAP_H
-#include <__algorithm/is_heap.h>
+#include <__algorithm/is_heap_until.h>
#include <__algorithm/make_projected.h>
#include <__config>
#include <__functional/identity.h>
-#include <__functional/invoke.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
-#include <__utility/forward.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -36,22 +35,28 @@ namespace __is_heap {
struct __fn {
+ template <class _Iter, class _Sent, class _Proj, class _Comp>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ static bool __is_heap_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) {
+ auto __last_iter = ranges::next(__first, __last);
+ auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
+
+ auto __result = std::__is_heap_until(std::move(__first), std::move(__last_iter), __projected_comp);
+ return __result == __last;
+ }
+
template <random_access_iterator _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less>
_LIBCPP_HIDE_FROM_ABI constexpr
bool operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__comp; (void)__proj;
- return {};
+ return __is_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
}
template <random_access_range _Range, class _Proj = identity,
indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less>
_LIBCPP_HIDE_FROM_ABI constexpr
bool operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
- // TODO: implement
- (void)__range; (void)__comp; (void)__proj;
- return {};
+ return __is_heap_fn_impl(ranges::begin(__range), ranges::end(__range), __comp, __proj);
}
};
diff --git a/libcxx/include/__algorithm/ranges_is_heap_until.h b/libcxx/include/__algorithm/ranges_is_heap_until.h
index ad021d6f2525..bcd33ad404e8 100644
--- a/libcxx/include/__algorithm/ranges_is_heap_until.h
+++ b/libcxx/include/__algorithm/ranges_is_heap_until.h
@@ -13,15 +13,14 @@
#include <__algorithm/make_projected.h>
#include <__config>
#include <__functional/identity.h>
-#include <__functional/invoke.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
-#include <__utility/forward.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -37,22 +36,27 @@ namespace __is_heap_until {
struct __fn {
+ template <class _Iter, class _Sent, class _Proj, class _Comp>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ static _Iter __is_heap_until_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) {
+ auto __last_iter = ranges::next(__first, __last);
+ auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
+
+ return std::__is_heap_until(std::move(__first), std::move(__last_iter), __projected_comp);
+ }
+
template <random_access_iterator _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less>
_LIBCPP_HIDE_FROM_ABI constexpr
_Iter operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__comp; (void)__proj;
- return {};
+ return __is_heap_until_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
}
template <random_access_range _Range, class _Proj = identity,
indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less>
_LIBCPP_HIDE_FROM_ABI constexpr
borrowed_iterator_t<_Range> operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
- // TODO: implement
- (void)__range; (void)__comp; (void)__proj;
- return {};
+ return __is_heap_until_fn_impl(ranges::begin(__range), ranges::end(__range), __comp, __proj);
}
};
diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index 84ddcd25b0b5..82db2cf052b5 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -45,7 +45,7 @@
# define _LIBCPP_ASSERT(expression, message) \
(__builtin_expect(static_cast<bool>(expression), 1) ? \
(void)0 : \
- ::std::__libcpp_assertion_handler(__FILE__, __LINE__, #expression, message))
+ ::std::__libcpp_assertion_handler("%s:%d: assertion %s failed: %s", __FILE__, __LINE__, #expression, message))
#elif !defined(_LIBCPP_ASSERTIONS_DISABLE_ASSUME) && __has_builtin(__builtin_assume)
# define _LIBCPP_ASSERT(expression, message) \
(_LIBCPP_DIAGNOSTIC_PUSH \
@@ -58,8 +58,8 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ASSERTION_HANDLER
-void __libcpp_assertion_handler(char const* __file, int __line, char const* __expression, char const* __message);
+_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ASSERTION_HANDLER _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2)
+void __libcpp_assertion_handler(const char *__format, ...);
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__concepts/arithmetic.h b/libcxx/include/__concepts/arithmetic.h
index 023f031e7e07..d91570f02b8b 100644
--- a/libcxx/include/__concepts/arithmetic.h
+++ b/libcxx/include/__concepts/arithmetic.h
@@ -10,6 +10,8 @@
#define _LIBCPP___CONCEPTS_ARITHMETIC_H
#include <__config>
+#include <__type_traits/is_signed_integer.h>
+#include <__type_traits/is_unsigned_integer.h>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__format/formatter_integer.h b/libcxx/include/__format/formatter_integer.h
index 0281b4f2fa67..3139c9efdf80 100644
--- a/libcxx/include/__format/formatter_integer.h
+++ b/libcxx/include/__format/formatter_integer.h
@@ -19,6 +19,7 @@
#include <__format/formatter_integral.h>
#include <__format/formatter_output.h>
#include <__format/parser_std_format_spec.h>
+#include <__type_traits/make_32_64_or_128_bit.h>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__functional/invoke.h b/libcxx/include/__functional/invoke.h
index 7381462ffca5..d56a0accdbce 100644
--- a/libcxx/include/__functional/invoke.h
+++ b/libcxx/include/__functional/invoke.h
@@ -24,6 +24,7 @@
#include <__type_traits/is_reference_wrapper.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_void.h>
+#include <__type_traits/nat.h>
#include <__type_traits/remove_cv.h>
#include <__utility/declval.h>
#include <__utility/forward.h>
@@ -41,16 +42,6 @@ struct __any
__any(...);
};
-struct __nat
-{
-#ifndef _LIBCPP_CXX03_LANG
- __nat() = delete;
- __nat(const __nat&) = delete;
- __nat& operator=(const __nat&) = delete;
- ~__nat() = delete;
-#endif
-};
-
template <class _MP, bool _IsMemberFunctionPtr, bool _IsMemberObjectPtr>
struct __member_pointer_traits_imp
{
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index 6123a310ad63..959ef7fe7d83 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -18,6 +18,7 @@
#include <__debug>
#include <__functional/hash.h>
#include <__iterator/iterator_traits.h>
+#include <__memory/swap_allocator.h>
#include <__utility/swap.h>
#include <cmath>
#include <initializer_list>
diff --git a/libcxx/include/__iterator/incrementable_traits.h b/libcxx/include/__iterator/incrementable_traits.h
index ef5f5110a30e..4109b58d46a9 100644
--- a/libcxx/include/__iterator/incrementable_traits.h
+++ b/libcxx/include/__iterator/incrementable_traits.h
@@ -11,6 +11,7 @@
#define _LIBCPP___ITERATOR_INCREMENTABLE_TRAITS_H
#include <__config>
+#include <__type_traits/is_primary_template.h>
#include <concepts>
#include <type_traits>
diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h
index 63525e230add..254f8c2339e4 100644
--- a/libcxx/include/__iterator/iterator_traits.h
+++ b/libcxx/include/__iterator/iterator_traits.h
@@ -501,6 +501,12 @@ using __iter_to_alloc_type = pair<
typename add_const<typename iterator_traits<_InputIterator>::value_type::first_type>::type,
typename iterator_traits<_InputIterator>::value_type::second_type>;
+template <class _Iter>
+using __iterator_category_type = typename iterator_traits<_Iter>::iterator_category;
+
+template <class _Iter>
+using __iterator_pointer_type = typename iterator_traits<_Iter>::pointer;
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___ITERATOR_ITERATOR_TRAITS_H
diff --git a/libcxx/include/__iterator/reverse_iterator.h b/libcxx/include/__iterator/reverse_iterator.h
index 7f4ef3c3d503..5c344c2ee310 100644
--- a/libcxx/include/__iterator/reverse_iterator.h
+++ b/libcxx/include/__iterator/reverse_iterator.h
@@ -197,6 +197,12 @@ public:
#endif // _LIBCPP_STD_VER > 17
};
+template <class _Iter>
+struct __is_reverse_iterator : false_type {};
+
+template <class _Iter>
+struct __is_reverse_iterator<reverse_iterator<_Iter> > : true_type {};
+
template <class _Iter1, class _Iter2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
bool
@@ -327,20 +333,162 @@ reverse_iterator<_Iter> make_reverse_iterator(_Iter __i)
}
#endif
+#if _LIBCPP_STD_VER <= 17
template <class _Iter>
-using _ReverseWrapper = reverse_iterator<reverse_iterator<_Iter> >;
+using __unconstrained_reverse_iterator = reverse_iterator<_Iter>;
+#else
-template <class _Iter, bool __b>
-struct __unwrap_iter_impl<_ReverseWrapper<_Iter>, __b> {
+// __unconstrained_reverse_iterator allows us to use reverse iterators in the implementation of algorithms by working
+// around a language issue in C++20.
+// In C++20, when a reverse iterator wraps certain C++20-hostile iterators, calling comparison operators on it will
+// result in a compilation error. However, calling comparison operators on the pristine hostile iterator is not
+// an error. Thus, we cannot use reverse_iterators in the implementation of an algorithm that accepts a
+// C++20-hostile iterator. This class is an internal workaround -- it is a copy of reverse_iterator with
+// tweaks to make it support hostile iterators.
+//
+// A C++20-hostile iterator is one that defines a comparison operator where one of the arguments is an exact match
+// and the other requires an implicit conversion, for example:
+// friend bool operator==(const BaseIter&, const DerivedIter&);
+//
+// C++20 rules for rewriting equality operators create another overload of this function with parameters reversed:
+// friend bool operator==(const DerivedIter&, const BaseIter&);
+//
+// This creates an ambiguity in overload resolution.
+//
+// Clang treats this ambiguity differently in different contexts. When operator== is actually called in the function
+// body, the code is accepted with a warning. When a concept requires operator== to be a valid expression, however,
+// it evaluates to false. Thus, the implementation of reverse_iterator::operator== can actually call operator== on its
+// base iterators, but the constraints on reverse_iterator::operator== prevent it from being considered during overload
+// resolution. This class simply removes the problematic constraints from comparison functions.
+template <class _Iter>
+class __unconstrained_reverse_iterator {
+ _Iter __iter_;
+
+public:
+ static_assert(__is_cpp17_bidirectional_iterator<_Iter>::value);
+
+ using iterator_type = _Iter;
+ using iterator_category =
+ _If<__is_cpp17_random_access_iterator<_Iter>::value, random_access_iterator_tag, __iterator_category_type<_Iter>>;
+ using pointer = __iterator_pointer_type<_Iter>;
+ using value_type = iter_value_t<_Iter>;
+ using difference_type = iter_difference_t<_Iter>;
+ using reference = iter_reference_t<_Iter>;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator() = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator(const __unconstrained_reverse_iterator&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __unconstrained_reverse_iterator(_Iter __iter) : __iter_(__iter) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() const { return __iter_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr reference operator*() const {
+ auto __tmp = __iter_;
+ return *--__tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr pointer operator->() const {
+ if constexpr (is_pointer_v<_Iter>) {
+ return std::prev(__iter_);
+ } else {
+ return std::prev(__iter_).operator->();
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator& operator++() {
+ --__iter_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator operator++(int) {
+ auto __tmp = *this;
+ --__iter_;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator& operator--() {
+ ++__iter_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator operator--(int) {
+ auto __tmp = *this;
+ ++__iter_;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator& operator+=(difference_type __n) {
+ __iter_ -= __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator& operator-=(difference_type __n) {
+ __iter_ += __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator operator+(difference_type __n) const {
+ return __unconstrained_reverse_iterator(__iter_ - __n);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator operator-(difference_type __n) const {
+ return __unconstrained_reverse_iterator(__iter_ + __n);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr difference_type operator-(const __unconstrained_reverse_iterator& __other) const {
+ return __other.__iter_ - __iter_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const { return *(*this + __n); }
+
+ // Deliberately unconstrained unlike the comparison functions in `reverse_iterator` -- see the class comment for the
+ // rationale.
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator==(const __unconstrained_reverse_iterator& __lhs, const __unconstrained_reverse_iterator& __rhs) {
+ return __lhs.base() == __rhs.base();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator!=(const __unconstrained_reverse_iterator& __lhs, const __unconstrained_reverse_iterator& __rhs) {
+ return __lhs.base() != __rhs.base();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator<(const __unconstrained_reverse_iterator& __lhs, const __unconstrained_reverse_iterator& __rhs) {
+ return __lhs.base() > __rhs.base();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator>(const __unconstrained_reverse_iterator& __lhs, const __unconstrained_reverse_iterator& __rhs) {
+ return __lhs.base() < __rhs.base();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator<=(const __unconstrained_reverse_iterator& __lhs, const __unconstrained_reverse_iterator& __rhs) {
+ return __lhs.base() >= __rhs.base();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator>=(const __unconstrained_reverse_iterator& __lhs, const __unconstrained_reverse_iterator& __rhs) {
+ return __lhs.base() <= __rhs.base();
+ }
+};
+
+template <class _Iter>
+struct __is_reverse_iterator<__unconstrained_reverse_iterator<_Iter>> : true_type {};
+
+#endif // _LIBCPP_STD_VER <= 17
+
+template <template <class> class _RevIter1, template <class> class _RevIter2, class _Iter>
+struct __unwrap_reverse_iter_impl {
using _UnwrappedIter = decltype(__unwrap_iter_impl<_Iter>::__unwrap(std::declval<_Iter>()));
+ using _ReverseWrapper = _RevIter1<_RevIter2<_Iter> >;
- static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ReverseWrapper<_Iter>
- __rewrap(_ReverseWrapper<_Iter> __orig_iter, _UnwrappedIter __unwrapped_iter) {
- return _ReverseWrapper<_Iter>(
- reverse_iterator<_Iter>(__unwrap_iter_impl<_Iter>::__rewrap(__orig_iter.base().base(), __unwrapped_iter)));
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ReverseWrapper
+ __rewrap(_ReverseWrapper __orig_iter, _UnwrappedIter __unwrapped_iter) {
+ return _ReverseWrapper(
+ _RevIter2<_Iter>(__unwrap_iter_impl<_Iter>::__rewrap(__orig_iter.base().base(), __unwrapped_iter)));
}
- static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _UnwrappedIter __unwrap(_ReverseWrapper<_Iter> __i) _NOEXCEPT {
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _UnwrappedIter __unwrap(_ReverseWrapper __i) _NOEXCEPT {
return __unwrap_iter_impl<_Iter>::__unwrap(__i.base().base());
}
};
@@ -355,6 +503,26 @@ _LIBCPP_HIDE_FROM_ABI constexpr ranges::
}
#endif
+template <class _Iter, bool __b>
+struct __unwrap_iter_impl<reverse_iterator<reverse_iterator<_Iter> >, __b>
+ : __unwrap_reverse_iter_impl<reverse_iterator, reverse_iterator, _Iter> {};
+
+#if _LIBCPP_STD_VER > 17
+
+template <class _Iter, bool __b>
+struct __unwrap_iter_impl<reverse_iterator<__unconstrained_reverse_iterator<_Iter>>, __b>
+ : __unwrap_reverse_iter_impl<reverse_iterator, __unconstrained_reverse_iterator, _Iter> {};
+
+template <class _Iter, bool __b>
+struct __unwrap_iter_impl<__unconstrained_reverse_iterator<reverse_iterator<_Iter>>, __b>
+ : __unwrap_reverse_iter_impl<__unconstrained_reverse_iterator, reverse_iterator, _Iter> {};
+
+template <class _Iter, bool __b>
+struct __unwrap_iter_impl<__unconstrained_reverse_iterator<__unconstrained_reverse_iterator<_Iter>>, __b>
+ : __unwrap_reverse_iter_impl<__unconstrained_reverse_iterator, __unconstrained_reverse_iterator, _Iter> {};
+
+#endif // _LIBCPP_STD_VER > 17
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___ITERATOR_REVERSE_ITERATOR_H
diff --git a/libcxx/include/__memory/swap_allocator.h b/libcxx/include/__memory/swap_allocator.h
new file mode 100644
index 000000000000..64970fa9e2f4
--- /dev/null
+++ b/libcxx/include/__memory/swap_allocator.h
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___MEMORY_SWAP_ALLOCATOR_H
+#define _LIBCPP___MEMORY_SWAP_ALLOCATOR_H
+
+#include <__config>
+#include <__memory/allocator_traits.h>
+#include <__type_traits/integral_constant.h>
+#include <__utility/swap.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <typename _Alloc>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void __swap_allocator(_Alloc& __a1, _Alloc& __a2, true_type)
+#if _LIBCPP_STD_VER > 11
+ _NOEXCEPT
+#else
+ _NOEXCEPT_(__is_nothrow_swappable<_Alloc>::value)
+#endif
+{
+ using _VSTD::swap;
+ swap(__a1, __a2);
+}
+
+template <typename _Alloc>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void
+__swap_allocator(_Alloc&, _Alloc&, false_type) _NOEXCEPT {}
+
+template <typename _Alloc>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void __swap_allocator(_Alloc& __a1, _Alloc& __a2)
+#if _LIBCPP_STD_VER > 11
+ _NOEXCEPT
+#else
+ _NOEXCEPT_(__is_nothrow_swappable<_Alloc>::value)
+#endif
+{
+ _VSTD::__swap_allocator(
+ __a1, __a2, integral_constant<bool, allocator_traits<_Alloc>::propagate_on_container_swap::value>());
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___MEMORY_SWAP_ALLOCATOR_H
diff --git a/libcxx/include/__memory/temporary_buffer.h b/libcxx/include/__memory/temporary_buffer.h
index 9822bd30c826..b1f7a126299f 100644
--- a/libcxx/include/__memory/temporary_buffer.h
+++ b/libcxx/include/__memory/temporary_buffer.h
@@ -11,6 +11,7 @@
#define _LIBCPP___MEMORY_TEMPORARY_BUFFER_H
#include <__config>
+#include <__type_traits/alignment_of.h>
#include <__utility/pair.h>
#include <cstddef>
#include <new>
diff --git a/libcxx/include/__memory/uninitialized_algorithms.h b/libcxx/include/__memory/uninitialized_algorithms.h
index 3a8560f080c6..72b6890c2225 100644
--- a/libcxx/include/__memory/uninitialized_algorithms.h
+++ b/libcxx/include/__memory/uninitialized_algorithms.h
@@ -10,12 +10,17 @@
#ifndef _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H
#define _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H
+#include <__algorithm/copy.h>
+#include <__algorithm/move.h>
#include <__config>
#include <__iterator/iterator_traits.h>
+#include <__iterator/reverse_iterator.h>
#include <__memory/addressof.h>
#include <__memory/allocator_traits.h>
#include <__memory/construct_at.h>
+#include <__memory/pointer_traits.h>
#include <__memory/voidify.h>
+#include <__type_traits/is_constant_evaluated.h>
#include <__utility/move.h>
#include <__utility/pair.h>
#include <__utility/transaction.h>
@@ -347,6 +352,7 @@ uninitialized_move_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofir
__unreachable_sentinel(), __iter_move);
}
+// TODO: Rewrite this to iterate left to right and use reverse_iterators when calling
// Destroys every element in the range [first, last) FROM RIGHT TO LEFT using allocator
// destruction. If elements are themselves C-style arrays, they are recursively destroyed
// in the same manner.
@@ -492,6 +498,144 @@ constexpr void __uninitialized_allocator_value_construct_n(_Alloc& __alloc, _Bid
#endif // _LIBCPP_STD_VER > 14
+// Destroy all elements in [__first, __last) from left to right using allocator destruction.
+template <class _Alloc, class _Iter, class _Sent>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 void
+__allocator_destroy(_Alloc& __alloc, _Iter __first, _Sent __last) {
+ for (; __first != __last; ++__first)
+ allocator_traits<_Alloc>::destroy(__alloc, std::__to_address(__first));
+}
+
+template <class _Alloc, class _Iter>
+class _AllocatorDestroyRangeReverse {
+public:
+ _LIBCPP_HIDE_FROM_ABI _AllocatorDestroyRangeReverse(_Alloc& __alloc, _Iter& __first, _Iter& __last)
+ : __alloc_(__alloc), __first_(__first), __last_(__last) {}
+
+ _LIBCPP_CONSTEXPR_AFTER_CXX11 void operator()() const {
+ std::__allocator_destroy(__alloc_, std::reverse_iterator<_Iter>(__last_), std::reverse_iterator<_Iter>(__first_));
+ }
+
+private:
+ _Alloc& __alloc_;
+ _Iter& __first_;
+ _Iter& __last_;
+};
+
+// Copy-construct [__first1, __last1) in [__first2, __first2 + N), where N is distance(__first1, __last1).
+//
+// The caller has to ensure that __first2 can hold at least N uninitialized elements. If an exception is thrown the
+// already copied elements are destroyed in reverse order of their construction.
+template <class _Alloc, class _Iter1, class _Sent1, class _Iter2>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _Iter2
+__uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) {
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ auto __destruct_first = __first2;
+ try {
+#endif
+ while (__first1 != __last1) {
+ allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), *__first1);
+ ++__first1;
+ ++__first2;
+ }
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ } catch (...) {
+ _AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2)();
+ throw;
+ }
+#endif
+ return __first2;
+}
+
+template <class _Alloc, class _Type>
+struct __allocator_has_trivial_copy_construct : _Not<__has_construct<_Alloc, _Type*, const _Type&> > {};
+
+template <class _Type>
+struct __allocator_has_trivial_copy_construct<allocator<_Type>, _Type> : true_type {};
+
+template <class _Alloc,
+ class _Type,
+ class _RawType = typename remove_const<_Type>::type,
+ __enable_if_t<
+ // using _RawType because of the allocator<T const> extension
+ is_trivially_copy_constructible<_RawType>::value && is_trivially_copy_assignable<_RawType>::value &&
+ __allocator_has_trivial_copy_construct<_Alloc, _RawType>::value>* = nullptr>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _Type*
+__uninitialized_allocator_copy(_Alloc&, const _Type* __first1, const _Type* __last1, _Type* __first2) {
+ // TODO: Remove the const_cast once we drop support for std::allocator<T const>
+ if (__libcpp_is_constant_evaluated()) {
+ while (__first1 != __last1) {
+ std::__construct_at(std::__to_address(__first2), *__first1);
+ ++__first1;
+ ++__first2;
+ }
+ return __first2;
+ } else {
+ return std::copy(__first1, __last1, const_cast<_RawType*>(__first2));
+ }
+}
+
+// Move-construct the elements [__first1, __last1) into [__first2, __first2 + N)
+// if the move constructor is noexcept, where N is distance(__first1, __last1).
+//
+// Otherwise try to copy all elements. If an exception is thrown the already copied
+// elements are destroyed in reverse order of their construction.
+template <class _Alloc, class _Iter1, class _Sent1, class _Iter2>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _Iter2 __uninitialized_allocator_move_if_noexcept(
+ _Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) {
+ static_assert(__is_cpp17_move_insertable<_Alloc>::value,
+ "The specified type does not meet the requirements of Cpp17MoveInsertable");
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ auto __destruct_first = __first2;
+ try {
+#endif
+ while (__first1 != __last1) {
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), std::move_if_noexcept(*__first1));
+#else
+ allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), std::move(*__first1));
+#endif
+ ++__first1;
+ ++__first2;
+ }
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ } catch (...) {
+ _AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2)();
+ throw;
+ }
+#endif
+ return __first2;
+}
+
+template <class _Alloc, class _Type>
+struct __allocator_has_trivial_move_construct : _Not<__has_construct<_Alloc, _Type*, _Type&&> > {};
+
+template <class _Type>
+struct __allocator_has_trivial_move_construct<allocator<_Type>, _Type> : true_type {};
+
+#ifndef _LIBCPP_COMPILER_GCC
+template <
+ class _Alloc,
+ class _Iter1,
+ class _Iter2,
+ class _Type = typename iterator_traits<_Iter1>::value_type,
+ class = __enable_if_t<is_trivially_move_constructible<_Type>::value && is_trivially_move_assignable<_Type>::value &&
+ __allocator_has_trivial_move_construct<_Alloc, _Type>::value> >
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _Iter1
+__uninitialized_allocator_move_if_noexcept(_Alloc&, _Iter1 __first1, _Iter1 __last1, _Iter2 __first2) {
+ if (__libcpp_is_constant_evaluated()) {
+ while (__first1 != __last1) {
+ std::__construct_at(std::__to_address(__first2), std::move(*__first1));
+ ++__first1;
+ ++__first2;
+ }
+ return __first2;
+ } else {
+ return std::move(__first1, __last1, __first2);
+ }
+}
+#endif // _LIBCPP_COMPILER_GCC
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index 7409b51b1f96..f78167466217 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -19,6 +19,7 @@
#include <__iterator/move_iterator.h>
#include <__memory/allocator.h>
#include <__memory/compressed_pair.h>
+#include <__memory/swap_allocator.h>
#include <__utility/forward.h>
#include <memory>
#include <type_traits>
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index 8d8449706871..59525a03047a 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -17,6 +17,7 @@
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/next.h>
+#include <__memory/swap_allocator.h>
#include <__utility/forward.h>
#include <__utility/swap.h>
#include <limits>
diff --git a/libcxx/include/__type_traits/aligned_storage.h b/libcxx/include/__type_traits/aligned_storage.h
new file mode 100644
index 000000000000..9659a90ae50c
--- /dev/null
+++ b/libcxx/include/__type_traits/aligned_storage.h
@@ -0,0 +1,142 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_ALIGNED_STORAGE_H
+#define _LIBCPP___TYPE_TRAITS_ALIGNED_STORAGE_H
+
+#include <__config>
+#include <__type_traits/conditional.h>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/nat.h>
+#include <__type_traits/type_list.h>
+#include <cstddef>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp>
+struct __align_type
+{
+ static const size_t value = _LIBCPP_PREFERRED_ALIGNOF(_Tp);
+ typedef _Tp type;
+};
+
+struct __struct_double {long double __lx;};
+struct __struct_double4 {double __lx[4];};
+
+typedef
+ __type_list<__align_type<unsigned char>,
+ __type_list<__align_type<unsigned short>,
+ __type_list<__align_type<unsigned int>,
+ __type_list<__align_type<unsigned long>,
+ __type_list<__align_type<unsigned long long>,
+ __type_list<__align_type<double>,
+ __type_list<__align_type<long double>,
+ __type_list<__align_type<__struct_double>,
+ __type_list<__align_type<__struct_double4>,
+ __type_list<__align_type<int*>,
+ __nat
+ > > > > > > > > > > __all_types;
+
+template <size_t _Align>
+struct _ALIGNAS(_Align) __fallback_overaligned {};
+
+template <class _TL, size_t _Align> struct __find_pod;
+
+template <class _Hp, size_t _Align>
+struct __find_pod<__type_list<_Hp, __nat>, _Align>
+{
+ typedef typename conditional<
+ _Align == _Hp::value,
+ typename _Hp::type,
+ __fallback_overaligned<_Align>
+ >::type type;
+};
+
+template <class _Hp, class _Tp, size_t _Align>
+struct __find_pod<__type_list<_Hp, _Tp>, _Align>
+{
+ typedef typename conditional<
+ _Align == _Hp::value,
+ typename _Hp::type,
+ typename __find_pod<_Tp, _Align>::type
+ >::type type;
+};
+
+template <class _TL, size_t _Len> struct __find_max_align;
+
+template <class _Hp, size_t _Len>
+struct __find_max_align<__type_list<_Hp, __nat>, _Len> : public integral_constant<size_t, _Hp::value> {};
+
+template <size_t _Len, size_t _A1, size_t _A2>
+struct __select_align
+{
+private:
+ static const size_t __min = _A2 < _A1 ? _A2 : _A1;
+ static const size_t __max = _A1 < _A2 ? _A2 : _A1;
+public:
+ static const size_t value = _Len < __max ? __min : __max;
+};
+
+template <class _Hp, class _Tp, size_t _Len>
+struct __find_max_align<__type_list<_Hp, _Tp>, _Len>
+ : public integral_constant<size_t, __select_align<_Len, _Hp::value, __find_max_align<_Tp, _Len>::value>::value> {};
+
+template <size_t _Len, size_t _Align = __find_max_align<__all_types, _Len>::value>
+struct _LIBCPP_TEMPLATE_VIS aligned_storage
+{
+ typedef typename __find_pod<__all_types, _Align>::type _Aligner;
+ union type
+ {
+ _Aligner __align;
+ unsigned char __data[(_Len + _Align - 1)/_Align * _Align];
+ };
+};
+
+#if _LIBCPP_STD_VER > 11
+template <size_t _Len, size_t _Align = __find_max_align<__all_types, _Len>::value>
+ using aligned_storage_t = typename aligned_storage<_Len, _Align>::type;
+#endif
+
+#define _CREATE_ALIGNED_STORAGE_SPECIALIZATION(n) \
+template <size_t _Len>\
+struct _LIBCPP_TEMPLATE_VIS aligned_storage<_Len, n>\
+{\
+ struct _ALIGNAS(n) type\
+ {\
+ unsigned char __lx[(_Len + n - 1)/n * n];\
+ };\
+}
+
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x8);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x10);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x20);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x40);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x80);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x100);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x200);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x400);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x800);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1000);
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2000);
+// PE/COFF does not support alignment beyond 8192 (=0x2000)
+#if !defined(_LIBCPP_OBJECT_FORMAT_COFF)
+_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4000);
+#endif // !defined(_LIBCPP_OBJECT_FORMAT_COFF)
+
+#undef _CREATE_ALIGNED_STORAGE_SPECIALIZATION
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_ALIGNED_STORAGE_H
diff --git a/libcxx/include/__type_traits/aligned_union.h b/libcxx/include/__type_traits/aligned_union.h
new file mode 100644
index 000000000000..31eb9353a9e2
--- /dev/null
+++ b/libcxx/include/__type_traits/aligned_union.h
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_ALIGNED_UNION_H
+#define _LIBCPP___TYPE_TRAITS_ALIGNED_UNION_H
+
+#include <__config>
+#include <__type_traits/aligned_storage.h>
+#include <__type_traits/integral_constant.h>
+#include <cstddef>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <size_t _I0, size_t ..._In>
+struct __static_max;
+
+template <size_t _I0>
+struct __static_max<_I0>
+{
+ static const size_t value = _I0;
+};
+
+template <size_t _I0, size_t _I1, size_t ..._In>
+struct __static_max<_I0, _I1, _In...>
+{
+ static const size_t value = _I0 >= _I1 ? __static_max<_I0, _In...>::value :
+ __static_max<_I1, _In...>::value;
+};
+
+template <size_t _Len, class _Type0, class ..._Types>
+struct aligned_union
+{
+ static const size_t alignment_value = __static_max<_LIBCPP_PREFERRED_ALIGNOF(_Type0),
+ _LIBCPP_PREFERRED_ALIGNOF(_Types)...>::value;
+ static const size_t __len = __static_max<_Len, sizeof(_Type0),
+ sizeof(_Types)...>::value;
+ typedef typename aligned_storage<__len, alignment_value>::type type;
+};
+
+#if _LIBCPP_STD_VER > 11
+template <size_t _Len, class ..._Types> using aligned_union_t = typename aligned_union<_Len, _Types...>::type;
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_ALIGNED_UNION_H
diff --git a/libcxx/include/__type_traits/common_reference.h b/libcxx/include/__type_traits/common_reference.h
new file mode 100644
index 000000000000..559d39858ec8
--- /dev/null
+++ b/libcxx/include/__type_traits/common_reference.h
@@ -0,0 +1,188 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_COMMON_REFERENCE_H
+#define _LIBCPP___TYPE_TRAITS_COMMON_REFERENCE_H
+
+#include <__config>
+#include <__type_traits/common_type.h>
+#include <__type_traits/copy_cv.h>
+#include <__type_traits/copy_cvref.h>
+#include <__type_traits/is_convertible.h>
+#include <__type_traits/is_reference.h>
+#include <__type_traits/remove_cv.h>
+#include <__type_traits/remove_cvref.h>
+#include <__type_traits/remove_reference.h>
+#include <__utility/declval.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// common_reference
+#if _LIBCPP_STD_VER > 17
+// Let COND_RES(X, Y) be:
+template <class _Xp, class _Yp>
+using __cond_res =
+ decltype(false ? declval<_Xp(&)()>()() : declval<_Yp(&)()>()());
+
+// Let `XREF(A)` denote a unary alias template `T` such that `T<U>` denotes the same type as `U`
+// with the addition of `A`'s cv and reference qualifiers, for a non-reference cv-unqualified type
+// `U`.
+// [Note: `XREF(A)` is `__xref<A>::template __apply`]
+template <class _Tp>
+struct __xref {
+ template<class _Up>
+ using __apply = __copy_cvref_t<_Tp, _Up>;
+};
+
+// Given types A and B, let X be remove_reference_t<A>, let Y be remove_reference_t<B>,
+// and let COMMON-REF(A, B) be:
+template<class _Ap, class _Bp, class _Xp = remove_reference_t<_Ap>, class _Yp = remove_reference_t<_Bp>>
+struct __common_ref;
+
+template<class _Xp, class _Yp>
+using __common_ref_t = typename __common_ref<_Xp, _Yp>::__type;
+
+template<class _Xp, class _Yp>
+using __cv_cond_res = __cond_res<__copy_cv_t<_Xp, _Yp>&, __copy_cv_t<_Yp, _Xp>&>;
+
+
+// If A and B are both lvalue reference types, COMMON-REF(A, B) is
+// COND-RES(COPYCV(X, Y)&, COPYCV(Y, X)&) if that type exists and is a reference type.
+template<class _Ap, class _Bp, class _Xp, class _Yp>
+requires requires { typename __cv_cond_res<_Xp, _Yp>; } && is_reference_v<__cv_cond_res<_Xp, _Yp>>
+struct __common_ref<_Ap&, _Bp&, _Xp, _Yp>
+{
+ using __type = __cv_cond_res<_Xp, _Yp>;
+};
+
+// Otherwise, let C be remove_reference_t<COMMON-REF(X&, Y&)>&&. ...
+template <class _Xp, class _Yp>
+using __common_ref_C = remove_reference_t<__common_ref_t<_Xp&, _Yp&>>&&;
+
+
+// .... If A and B are both rvalue reference types, C is well-formed, and
+// is_convertible_v<A, C> && is_convertible_v<B, C> is true, then COMMON-REF(A, B) is C.
+template<class _Ap, class _Bp, class _Xp, class _Yp>
+requires
+ requires { typename __common_ref_C<_Xp, _Yp>; } &&
+ is_convertible_v<_Ap&&, __common_ref_C<_Xp, _Yp>> &&
+ is_convertible_v<_Bp&&, __common_ref_C<_Xp, _Yp>>
+struct __common_ref<_Ap&&, _Bp&&, _Xp, _Yp>
+{
+ using __type = __common_ref_C<_Xp, _Yp>;
+};
+
+// Otherwise, let D be COMMON-REF(const X&, Y&). ...
+template <class _Tp, class _Up>
+using __common_ref_D = __common_ref_t<const _Tp&, _Up&>;
+
+// ... If A is an rvalue reference and B is an lvalue reference and D is well-formed and
+// is_convertible_v<A, D> is true, then COMMON-REF(A, B) is D.
+template<class _Ap, class _Bp, class _Xp, class _Yp>
+requires requires { typename __common_ref_D<_Xp, _Yp>; } &&
+ is_convertible_v<_Ap&&, __common_ref_D<_Xp, _Yp>>
+struct __common_ref<_Ap&&, _Bp&, _Xp, _Yp>
+{
+ using __type = __common_ref_D<_Xp, _Yp>;
+};
+
+// Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+// COMMON-REF(A, B) is COMMON-REF(B, A).
+template<class _Ap, class _Bp, class _Xp, class _Yp>
+struct __common_ref<_Ap&, _Bp&&, _Xp, _Yp> : __common_ref<_Bp&&, _Ap&> {};
+
+// Otherwise, COMMON-REF(A, B) is ill-formed.
+template<class _Ap, class _Bp, class _Xp, class _Yp>
+struct __common_ref {};
+
+// Note C: For the common_reference trait applied to a parameter pack [...]
+
+template <class...>
+struct common_reference;
+
+template <class... _Types>
+using common_reference_t = typename common_reference<_Types...>::type;
+
+// bullet 1 - sizeof...(T) == 0
+template<>
+struct common_reference<> {};
+
+// bullet 2 - sizeof...(T) == 1
+template <class _Tp>
+struct common_reference<_Tp>
+{
+ using type = _Tp;
+};
+
+// bullet 3 - sizeof...(T) == 2
+template <class _Tp, class _Up> struct __common_reference_sub_bullet3;
+template <class _Tp, class _Up> struct __common_reference_sub_bullet2 : __common_reference_sub_bullet3<_Tp, _Up> {};
+template <class _Tp, class _Up> struct __common_reference_sub_bullet1 : __common_reference_sub_bullet2<_Tp, _Up> {};
+
+// sub-bullet 1 - If T1 and T2 are reference types and COMMON-REF(T1, T2) is well-formed, then
+// the member typedef `type` denotes that type.
+template <class _Tp, class _Up> struct common_reference<_Tp, _Up> : __common_reference_sub_bullet1<_Tp, _Up> {};
+
+template <class _Tp, class _Up>
+requires is_reference_v<_Tp> && is_reference_v<_Up> && requires { typename __common_ref_t<_Tp, _Up>; }
+struct __common_reference_sub_bullet1<_Tp, _Up>
+{
+ using type = __common_ref_t<_Tp, _Up>;
+};
+
+// sub-bullet 2 - Otherwise, if basic_common_reference<remove_cvref_t<T1>, remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type
+// is well-formed, then the member typedef `type` denotes that type.
+template <class, class, template <class> class, template <class> class> struct basic_common_reference {};
+
+template <class _Tp, class _Up>
+using __basic_common_reference_t = typename basic_common_reference<
+ remove_cvref_t<_Tp>, remove_cvref_t<_Up>,
+ __xref<_Tp>::template __apply, __xref<_Up>::template __apply>::type;
+
+template <class _Tp, class _Up>
+requires requires { typename __basic_common_reference_t<_Tp, _Up>; }
+struct __common_reference_sub_bullet2<_Tp, _Up>
+{
+ using type = __basic_common_reference_t<_Tp, _Up>;
+};
+
+// sub-bullet 3 - Otherwise, if COND-RES(T1, T2) is well-formed,
+// then the member typedef `type` denotes that type.
+template <class _Tp, class _Up>
+requires requires { typename __cond_res<_Tp, _Up>; }
+struct __common_reference_sub_bullet3<_Tp, _Up>
+{
+ using type = __cond_res<_Tp, _Up>;
+};
+
+
+// sub-bullet 4 & 5 - Otherwise, if common_type_t<T1, T2> is well-formed,
+// then the member typedef `type` denotes that type.
+// - Otherwise, there shall be no member `type`.
+template <class _Tp, class _Up> struct __common_reference_sub_bullet3 : common_type<_Tp, _Up> {};
+
+// bullet 4 - If there is such a type `C`, the member typedef type shall denote the same type, if
+// any, as `common_reference_t<C, Rest...>`.
+template <class _Tp, class _Up, class _Vp, class... _Rest>
+requires requires { typename common_reference_t<_Tp, _Up>; }
+struct common_reference<_Tp, _Up, _Vp, _Rest...>
+ : common_reference<common_reference_t<_Tp, _Up>, _Vp, _Rest...>
+{};
+
+// bullet 5 - Otherwise, there shall be no member `type`.
+template <class...> struct common_reference {};
+
+#endif // _LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_COMMON_REFERENCE_H
diff --git a/libcxx/include/__type_traits/common_type.h b/libcxx/include/__type_traits/common_type.h
new file mode 100644
index 000000000000..55321e9936dd
--- /dev/null
+++ b/libcxx/include/__type_traits/common_type.h
@@ -0,0 +1,138 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_COMMON_TYPE_H
+#define _LIBCPP___TYPE_TRAITS_COMMON_TYPE_H
+
+#include <__config>
+#include <__type_traits/conditional.h>
+#include <__type_traits/decay.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/remove_cvref.h>
+#include <__type_traits/void_t.h>
+#include <__utility/declval.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER > 17
+// Let COND_RES(X, Y) be:
+template <class _Tp, class _Up>
+using __cond_type = decltype(false ? declval<_Tp>() : declval<_Up>());
+
+template <class _Tp, class _Up, class = void>
+struct __common_type3 {};
+
+// sub-bullet 4 - "if COND_RES(CREF(D1), CREF(D2)) denotes a type..."
+template <class _Tp, class _Up>
+struct __common_type3<_Tp, _Up, void_t<__cond_type<const _Tp&, const _Up&>>>
+{
+ using type = remove_cvref_t<__cond_type<const _Tp&, const _Up&>>;
+};
+
+template <class _Tp, class _Up, class = void>
+struct __common_type2_imp : __common_type3<_Tp, _Up> {};
+#else
+template <class _Tp, class _Up, class = void>
+struct __common_type2_imp {};
+#endif
+
+// sub-bullet 3 - "if decay_t<decltype(false ? declval<D1>() : declval<D2>())> ..."
+template <class _Tp, class _Up>
+struct __common_type2_imp<_Tp, _Up,
+ typename __void_t<decltype(
+ true ? declval<_Tp>() : declval<_Up>()
+ )>::type>
+{
+ typedef _LIBCPP_NODEBUG typename decay<decltype(
+ true ? declval<_Tp>() : declval<_Up>()
+ )>::type type;
+};
+
+template <class, class = void>
+struct __common_type_impl {};
+
+// Clang provides variadic templates in C++03 as an extension.
+#if !defined(_LIBCPP_CXX03_LANG) || defined(__clang__)
+# define _LIBCPP_OPTIONAL_PACK(...) , __VA_ARGS__
+template <class... _Tp>
+struct __common_types;
+template <class... _Tp>
+struct _LIBCPP_TEMPLATE_VIS common_type;
+#else
+# define _LIBCPP_OPTIONAL_PACK(...)
+struct __no_arg;
+template <class _Tp, class _Up, class = __no_arg>
+struct __common_types;
+template <class _Tp = __no_arg, class _Up = __no_arg, class _Vp = __no_arg,
+ class _Unused = __no_arg>
+struct common_type {
+ static_assert(sizeof(_Unused) == 0,
+ "common_type accepts at most 3 arguments in C++03");
+};
+#endif // _LIBCPP_CXX03_LANG
+
+template <class _Tp, class _Up>
+struct __common_type_impl<
+ __common_types<_Tp, _Up>,
+ typename __void_t<typename common_type<_Tp, _Up>::type>::type>
+{
+ typedef typename common_type<_Tp, _Up>::type type;
+};
+
+template <class _Tp, class _Up, class _Vp _LIBCPP_OPTIONAL_PACK(class... _Rest)>
+struct __common_type_impl<
+ __common_types<_Tp, _Up, _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)>,
+ typename __void_t<typename common_type<_Tp, _Up>::type>::type>
+ : __common_type_impl<__common_types<typename common_type<_Tp, _Up>::type,
+ _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)> > {
+};
+
+// bullet 1 - sizeof...(Tp) == 0
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS common_type<> {};
+
+// bullet 2 - sizeof...(Tp) == 1
+
+template <class _Tp>
+struct _LIBCPP_TEMPLATE_VIS common_type<_Tp>
+ : public common_type<_Tp, _Tp> {};
+
+// bullet 3 - sizeof...(Tp) == 2
+
+// sub-bullet 1 - "If is_same_v<T1, D1> is false or ..."
+template <class _Tp, class _Up>
+struct _LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up>
+ : conditional<
+ _IsSame<_Tp, typename decay<_Tp>::type>::value && _IsSame<_Up, typename decay<_Up>::type>::value,
+ __common_type2_imp<_Tp, _Up>,
+ common_type<typename decay<_Tp>::type, typename decay<_Up>::type>
+ >::type
+{};
+
+// bullet 4 - sizeof...(Tp) > 2
+
+template <class _Tp, class _Up, class _Vp _LIBCPP_OPTIONAL_PACK(class... _Rest)>
+struct _LIBCPP_TEMPLATE_VIS
+ common_type<_Tp, _Up, _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)>
+ : __common_type_impl<
+ __common_types<_Tp, _Up, _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)> > {};
+
+#undef _LIBCPP_OPTIONAL_PACK
+
+#if _LIBCPP_STD_VER > 11
+template <class ..._Tp> using common_type_t = typename common_type<_Tp...>::type;
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_COMMON_TYPE_H
diff --git a/libcxx/include/__type_traits/copy_cv.h b/libcxx/include/__type_traits/copy_cv.h
new file mode 100644
index 000000000000..8e9bfe0a522f
--- /dev/null
+++ b/libcxx/include/__type_traits/copy_cv.h
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_COPY_CV_H
+#define _LIBCPP___TYPE_TRAITS_COPY_CV_H
+
+#include <__config>
+#include <__type_traits/add_const.h>
+#include <__type_traits/add_cv.h>
+#include <__type_traits/add_volatile.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// Let COPYCV(FROM, TO) be an alias for type TO with the addition of FROM's
+// top-level cv-qualifiers.
+template <class _From, class _To>
+struct __copy_cv
+{
+ using type = _To;
+};
+
+template <class _From, class _To>
+struct __copy_cv<const _From, _To>
+{
+ using type = typename add_const<_To>::type;
+};
+
+template <class _From, class _To>
+struct __copy_cv<volatile _From, _To>
+{
+ using type = typename add_volatile<_To>::type;
+};
+
+template <class _From, class _To>
+struct __copy_cv<const volatile _From, _To>
+{
+ using type = typename add_cv<_To>::type;
+};
+
+template <class _From, class _To>
+using __copy_cv_t = typename __copy_cv<_From, _To>::type;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_COPY_CV_H
diff --git a/libcxx/include/__type_traits/copy_cvref.h b/libcxx/include/__type_traits/copy_cvref.h
new file mode 100644
index 000000000000..69b97ac1cb17
--- /dev/null
+++ b/libcxx/include/__type_traits/copy_cvref.h
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_COPY_CVREF_H
+#define _LIBCPP___TYPE_TRAITS_COPY_CVREF_H
+
+#include <__config>
+#include <__type_traits/add_lvalue_reference.h>
+#include <__type_traits/add_rvalue_reference.h>
+#include <__type_traits/copy_cv.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _From, class _To>
+struct __copy_cvref
+{
+ using type = __copy_cv_t<_From, _To>;
+};
+
+template <class _From, class _To>
+struct __copy_cvref<_From&, _To>
+{
+ using type = typename add_lvalue_reference<__copy_cv_t<_From, _To> >::type;
+};
+
+template <class _From, class _To>
+struct __copy_cvref<_From&&, _To>
+{
+ using type = typename add_rvalue_reference<__copy_cv_t<_From, _To> >::type;
+};
+
+template <class _From, class _To>
+using __copy_cvref_t = typename __copy_cvref<_From, _To>::type;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_COPY_CVREF_H
diff --git a/libcxx/include/__type_traits/is_nothrow_convertible.h b/libcxx/include/__type_traits/is_nothrow_convertible.h
new file mode 100644
index 000000000000..712b6f2cf4b8
--- /dev/null
+++ b/libcxx/include/__type_traits/is_nothrow_convertible.h
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_IS_NOTHROW_CONVERTIBLE_H
+#define _LIBCPP___TYPE_TRAITS_IS_NOTHROW_CONVERTIBLE_H
+
+#include <__config>
+#include <__type_traits/conjunction.h>
+#include <__type_traits/disjunction.h>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/is_convertible.h>
+#include <__type_traits/is_void.h>
+#include <__type_traits/lazy.h>
+#include <__utility/declval.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER > 17
+
+template <typename _Tp>
+static void __test_noexcept(_Tp) noexcept;
+
+template<typename _Fm, typename _To>
+static bool_constant<noexcept(_VSTD::__test_noexcept<_To>(declval<_Fm>()))>
+__is_nothrow_convertible_test();
+
+template <typename _Fm, typename _To>
+struct __is_nothrow_convertible_helper: decltype(__is_nothrow_convertible_test<_Fm, _To>())
+{ };
+
+template <typename _Fm, typename _To>
+struct is_nothrow_convertible : _Or<
+ _And<is_void<_To>, is_void<_Fm>>,
+ _Lazy<_And, is_convertible<_Fm, _To>, __is_nothrow_convertible_helper<_Fm, _To>>
+>::type { };
+
+template <typename _Fm, typename _To>
+inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<_Fm, _To>::value;
+
+#endif // _LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_NOTHROW_CONVERTIBLE_H
diff --git a/libcxx/include/__type_traits/is_primary_template.h b/libcxx/include/__type_traits/is_primary_template.h
new file mode 100644
index 000000000000..a9bebcf7e64c
--- /dev/null
+++ b/libcxx/include/__type_traits/is_primary_template.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_IS_PRIMARY_TEMPLATE_H
+#define _LIBCPP___TYPE_TRAITS_IS_PRIMARY_TEMPLATE_H
+
+#include <__config>
+#include <__type_traits/enable_if.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/is_valid_expansion.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp>
+using __test_for_primary_template = __enable_if_t<
+ _IsSame<_Tp, typename _Tp::__primary_template>::value
+ >;
+template <class _Tp>
+using __is_primary_template = _IsValidExpansion<
+ __test_for_primary_template, _Tp
+ >;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_PRIMARY_TEMPLATE_H
diff --git a/libcxx/include/__type_traits/is_signed_integer.h b/libcxx/include/__type_traits/is_signed_integer.h
new file mode 100644
index 000000000000..95aa11bfa1b5
--- /dev/null
+++ b/libcxx/include/__type_traits/is_signed_integer.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_IS_SIGNED_INTEGER_H
+#define _LIBCPP___TYPE_TRAITS_IS_SIGNED_INTEGER_H
+
+#include <__config>
+#include <__type_traits/integral_constant.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp> struct __libcpp_is_signed_integer : public false_type {};
+template <> struct __libcpp_is_signed_integer<signed char> : public true_type {};
+template <> struct __libcpp_is_signed_integer<signed short> : public true_type {};
+template <> struct __libcpp_is_signed_integer<signed int> : public true_type {};
+template <> struct __libcpp_is_signed_integer<signed long> : public true_type {};
+template <> struct __libcpp_is_signed_integer<signed long long> : public true_type {};
+#ifndef _LIBCPP_HAS_NO_INT128
+template <> struct __libcpp_is_signed_integer<__int128_t> : public true_type {};
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_SIGNED_INTEGER_H
diff --git a/libcxx/include/__type_traits/is_unsigned_integer.h b/libcxx/include/__type_traits/is_unsigned_integer.h
new file mode 100644
index 000000000000..54b29acd9ea3
--- /dev/null
+++ b/libcxx/include/__type_traits/is_unsigned_integer.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_IS_UNSIGNED_INTEGER_H
+#define _LIBCPP___TYPE_TRAITS_IS_UNSIGNED_INTEGER_H
+
+#include <__config>
+#include <__type_traits/integral_constant.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp> struct __libcpp_is_unsigned_integer : public false_type {};
+template <> struct __libcpp_is_unsigned_integer<unsigned char> : public true_type {};
+template <> struct __libcpp_is_unsigned_integer<unsigned short> : public true_type {};
+template <> struct __libcpp_is_unsigned_integer<unsigned int> : public true_type {};
+template <> struct __libcpp_is_unsigned_integer<unsigned long> : public true_type {};
+template <> struct __libcpp_is_unsigned_integer<unsigned long long> : public true_type {};
+#ifndef _LIBCPP_HAS_NO_INT128
+template <> struct __libcpp_is_unsigned_integer<__uint128_t> : public true_type {};
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_UNSIGNED_INTEGER_H
diff --git a/libcxx/include/__type_traits/is_valid_expansion.h b/libcxx/include/__type_traits/is_valid_expansion.h
new file mode 100644
index 000000000000..c45db7509e41
--- /dev/null
+++ b/libcxx/include/__type_traits/is_valid_expansion.h
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_IS_VALID_EXPANSION_H
+#define _LIBCPP___TYPE_TRAITS_IS_VALID_EXPANSION_H
+
+#include <__config>
+#include <__type_traits/integral_constant.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <template <class...> class _Templ, class ..._Args, class = _Templ<_Args...> >
+true_type __sfinae_test_impl(int);
+template <template <class...> class, class ...>
+false_type __sfinae_test_impl(...);
+
+template <template <class ...> class _Templ, class ..._Args>
+using _IsValidExpansion _LIBCPP_NODEBUG = decltype(__sfinae_test_impl<_Templ, _Args...>(0));
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_VALID_EXPANSION_H
diff --git a/libcxx/include/__type_traits/lazy.h b/libcxx/include/__type_traits/lazy.h
new file mode 100644
index 000000000000..6874b06f3c5a
--- /dev/null
+++ b/libcxx/include/__type_traits/lazy.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_LAZY_H
+#define _LIBCPP___TYPE_TRAITS_LAZY_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <template <class...> class _Func, class ..._Args>
+struct _Lazy : _Func<_Args...> {};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_LAZY_H
diff --git a/libcxx/include/__type_traits/make_32_64_or_128_bit.h b/libcxx/include/__type_traits/make_32_64_or_128_bit.h
new file mode 100644
index 000000000000..87340eac7fb1
--- /dev/null
+++ b/libcxx/include/__type_traits/make_32_64_or_128_bit.h
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_MAKE_32_64_OR_128_BIT_H
+#define _LIBCPP___TYPE_TRAITS_MAKE_32_64_OR_128_BIT_H
+
+#include <__config>
+#include <__type_traits/conditional.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/is_signed.h>
+#include <__type_traits/is_unsigned.h>
+#include <__type_traits/make_unsigned.h>
+#include <cstdint>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+/// Helper to promote an integral to smallest 32, 64, or 128 bit representation.
+///
+/// The restriction is the same as the integral version of to_char.
+template <class _Tp>
+#if _LIBCPP_STD_VER > 17
+ requires (is_signed_v<_Tp> || is_unsigned_v<_Tp> || is_same_v<_Tp, char>)
+#endif
+using __make_32_64_or_128_bit_t =
+ __copy_unsigned_t<_Tp,
+ __conditional_t<sizeof(_Tp) <= sizeof(int32_t), int32_t,
+ __conditional_t<sizeof(_Tp) <= sizeof(int64_t), int64_t,
+#ifndef _LIBCPP_HAS_NO_INT128
+ __conditional_t<sizeof(_Tp) <= sizeof(__int128_t), __int128_t,
+ /* else */ void>
+#else
+ /* else */ void
+#endif
+ > >
+ >;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_MAKE_32_64_OR_128_BIT_H
diff --git a/libcxx/include/__type_traits/make_signed.h b/libcxx/include/__type_traits/make_signed.h
new file mode 100644
index 000000000000..fbc31172a978
--- /dev/null
+++ b/libcxx/include/__type_traits/make_signed.h
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_MAKE_SIGNED_H
+#define _LIBCPP___TYPE_TRAITS_MAKE_SIGNED_H
+
+#include <__config>
+#include <__type_traits/apply_cv.h>
+#include <__type_traits/is_enum.h>
+#include <__type_traits/is_integral.h>
+#include <__type_traits/nat.h>
+#include <__type_traits/remove_cv.h>
+#include <__type_traits/type_list.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+typedef
+ __type_list<signed char,
+ __type_list<signed short,
+ __type_list<signed int,
+ __type_list<signed long,
+ __type_list<signed long long,
+#ifndef _LIBCPP_HAS_NO_INT128
+ __type_list<__int128_t,
+#endif
+ __nat
+#ifndef _LIBCPP_HAS_NO_INT128
+ >
+#endif
+ > > > > > __signed_types;
+
+template <class _Tp, bool = is_integral<_Tp>::value || is_enum<_Tp>::value>
+struct __make_signed {};
+
+template <class _Tp>
+struct __make_signed<_Tp, true>
+{
+ typedef typename __find_first<__signed_types, sizeof(_Tp)>::type type;
+};
+
+template <> struct __make_signed<bool, true> {};
+template <> struct __make_signed< signed short, true> {typedef short type;};
+template <> struct __make_signed<unsigned short, true> {typedef short type;};
+template <> struct __make_signed< signed int, true> {typedef int type;};
+template <> struct __make_signed<unsigned int, true> {typedef int type;};
+template <> struct __make_signed< signed long, true> {typedef long type;};
+template <> struct __make_signed<unsigned long, true> {typedef long type;};
+template <> struct __make_signed< signed long long, true> {typedef long long type;};
+template <> struct __make_signed<unsigned long long, true> {typedef long long type;};
+#ifndef _LIBCPP_HAS_NO_INT128
+template <> struct __make_signed<__int128_t, true> {typedef __int128_t type;};
+template <> struct __make_signed<__uint128_t, true> {typedef __int128_t type;};
+#endif
+
+template <class _Tp>
+struct _LIBCPP_TEMPLATE_VIS make_signed
+{
+ typedef typename __apply_cv<_Tp, typename __make_signed<typename remove_cv<_Tp>::type>::type>::type type;
+};
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using make_signed_t = typename make_signed<_Tp>::type;
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_MAKE_SIGNED_H
diff --git a/libcxx/include/__type_traits/make_unsigned.h b/libcxx/include/__type_traits/make_unsigned.h
new file mode 100644
index 000000000000..8110a5ca9609
--- /dev/null
+++ b/libcxx/include/__type_traits/make_unsigned.h
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_MAKE_UNSIGNED_H
+#define _LIBCPP___TYPE_TRAITS_MAKE_UNSIGNED_H
+
+#include <__config>
+#include <__type_traits/apply_cv.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/is_enum.h>
+#include <__type_traits/is_integral.h>
+#include <__type_traits/is_unsigned.h>
+#include <__type_traits/nat.h>
+#include <__type_traits/remove_cv.h>
+#include <__type_traits/type_list.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+typedef
+ __type_list<unsigned char,
+ __type_list<unsigned short,
+ __type_list<unsigned int,
+ __type_list<unsigned long,
+ __type_list<unsigned long long,
+#ifndef _LIBCPP_HAS_NO_INT128
+ __type_list<__uint128_t,
+#endif
+ __nat
+#ifndef _LIBCPP_HAS_NO_INT128
+ >
+#endif
+ > > > > > __unsigned_types;
+
+template <class _Tp, bool = is_integral<_Tp>::value || is_enum<_Tp>::value>
+struct __make_unsigned {};
+
+template <class _Tp>
+struct __make_unsigned<_Tp, true>
+{
+ typedef typename __find_first<__unsigned_types, sizeof(_Tp)>::type type;
+};
+
+template <> struct __make_unsigned<bool, true> {};
+template <> struct __make_unsigned< signed short, true> {typedef unsigned short type;};
+template <> struct __make_unsigned<unsigned short, true> {typedef unsigned short type;};
+template <> struct __make_unsigned< signed int, true> {typedef unsigned int type;};
+template <> struct __make_unsigned<unsigned int, true> {typedef unsigned int type;};
+template <> struct __make_unsigned< signed long, true> {typedef unsigned long type;};
+template <> struct __make_unsigned<unsigned long, true> {typedef unsigned long type;};
+template <> struct __make_unsigned< signed long long, true> {typedef unsigned long long type;};
+template <> struct __make_unsigned<unsigned long long, true> {typedef unsigned long long type;};
+#ifndef _LIBCPP_HAS_NO_INT128
+template <> struct __make_unsigned<__int128_t, true> {typedef __uint128_t type;};
+template <> struct __make_unsigned<__uint128_t, true> {typedef __uint128_t type;};
+#endif
+
+template <class _Tp>
+struct _LIBCPP_TEMPLATE_VIS make_unsigned
+{
+ typedef typename __apply_cv<_Tp, typename __make_unsigned<typename remove_cv<_Tp>::type>::type>::type type;
+};
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using make_unsigned_t = typename make_unsigned<_Tp>::type;
+#endif
+
+#ifndef _LIBCPP_CXX03_LANG
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr
+typename make_unsigned<_Tp>::type __to_unsigned_like(_Tp __x) noexcept {
+ return static_cast<typename make_unsigned<_Tp>::type>(__x);
+}
+#endif
+
+template <class _Tp, class _Up>
+using __copy_unsigned_t = __conditional_t<is_unsigned<_Tp>::value, typename make_unsigned<_Up>::type, _Up>;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_MAKE_UNSIGNED_H
diff --git a/libcxx/include/__type_traits/nat.h b/libcxx/include/__type_traits/nat.h
new file mode 100644
index 000000000000..5216ef520420
--- /dev/null
+++ b/libcxx/include/__type_traits/nat.h
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_NAT_H
+#define _LIBCPP___TYPE_TRAITS_NAT_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+struct __nat
+{
+#ifndef _LIBCPP_CXX03_LANG
+ __nat() = delete;
+ __nat(const __nat&) = delete;
+ __nat& operator=(const __nat&) = delete;
+ ~__nat() = delete;
+#endif
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_NAT_H
diff --git a/libcxx/include/__type_traits/promote.h b/libcxx/include/__type_traits/promote.h
new file mode 100644
index 000000000000..a9226a74b300
--- /dev/null
+++ b/libcxx/include/__type_traits/promote.h
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_PROMOTE_H
+#define _LIBCPP___TYPE_TRAITS_PROMOTE_H
+
+#include <__config>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/is_same.h>
+#include <__utility/declval.h>
+#include <cstddef>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp>
+struct __numeric_type
+{
+ static void __test(...);
+ static float __test(float);
+ static double __test(char);
+ static double __test(int);
+ static double __test(unsigned);
+ static double __test(long);
+ static double __test(unsigned long);
+ static double __test(long long);
+ static double __test(unsigned long long);
+ static double __test(double);
+ static long double __test(long double);
+
+ typedef decltype(__test(declval<_Tp>())) type;
+ static const bool value = _IsNotSame<type, void>::value;
+};
+
+template <>
+struct __numeric_type<void>
+{
+ static const bool value = true;
+};
+
+template <class _A1, class _A2 = void, class _A3 = void,
+ bool = __numeric_type<_A1>::value &&
+ __numeric_type<_A2>::value &&
+ __numeric_type<_A3>::value>
+class __promote_imp
+{
+public:
+ static const bool value = false;
+};
+
+template <class _A1, class _A2, class _A3>
+class __promote_imp<_A1, _A2, _A3, true>
+{
+private:
+ typedef typename __promote_imp<_A1>::type __type1;
+ typedef typename __promote_imp<_A2>::type __type2;
+ typedef typename __promote_imp<_A3>::type __type3;
+public:
+ typedef decltype(__type1() + __type2() + __type3()) type;
+ static const bool value = true;
+};
+
+template <class _A1, class _A2>
+class __promote_imp<_A1, _A2, void, true>
+{
+private:
+ typedef typename __promote_imp<_A1>::type __type1;
+ typedef typename __promote_imp<_A2>::type __type2;
+public:
+ typedef decltype(__type1() + __type2()) type;
+ static const bool value = true;
+};
+
+template <class _A1>
+class __promote_imp<_A1, void, void, true>
+{
+public:
+ typedef typename __numeric_type<_A1>::type type;
+ static const bool value = true;
+};
+
+template <class _A1, class _A2 = void, class _A3 = void>
+class __promote : public __promote_imp<_A1, _A2, _A3> {};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_PROMOTE_H
diff --git a/libcxx/include/__type_traits/remove_cvref.h b/libcxx/include/__type_traits/remove_cvref.h
new file mode 100644
index 000000000000..d937501fedce
--- /dev/null
+++ b/libcxx/include/__type_traits/remove_cvref.h
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_REMOVE_CVREF_H
+#define _LIBCPP___TYPE_TRAITS_REMOVE_CVREF_H
+
+#include <__config>
+#include <__type_traits/is_same.h>
+#include <__type_traits/remove_cv.h>
+#include <__type_traits/remove_reference.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp>
+using __uncvref_t _LIBCPP_NODEBUG = typename remove_cv<typename remove_reference<_Tp>::type>::type;
+
+template <class _Tp, class _Up>
+struct __is_same_uncvref : _IsSame<__uncvref_t<_Tp>, __uncvref_t<_Up> > {};
+
+#if _LIBCPP_STD_VER > 17
+// remove_cvref - same as __uncvref
+template <class _Tp>
+struct remove_cvref {
+ using type _LIBCPP_NODEBUG = __uncvref_t<_Tp>;
+};
+
+template <class _Tp> using remove_cvref_t = typename remove_cvref<_Tp>::type;
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_REMOVE_CVREF_H
diff --git a/libcxx/include/__type_traits/type_list.h b/libcxx/include/__type_traits/type_list.h
new file mode 100644
index 000000000000..5a9e3319a1d4
--- /dev/null
+++ b/libcxx/include/__type_traits/type_list.h
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TYPE_TRAITS_TYPE_LIST_H
+#define _LIBCPP___TYPE_TRAITS_TYPE_LIST_H
+
+#include <__config>
+#include <cstddef>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Hp, class _Tp>
+struct __type_list
+{
+ typedef _Hp _Head;
+ typedef _Tp _Tail;
+};
+
+template <class _TypeList, size_t _Size, bool = _Size <= sizeof(typename _TypeList::_Head)> struct __find_first;
+
+template <class _Hp, class _Tp, size_t _Size>
+struct __find_first<__type_list<_Hp, _Tp>, _Size, true>
+{
+ typedef _LIBCPP_NODEBUG _Hp type;
+};
+
+template <class _Hp, class _Tp, size_t _Size>
+struct __find_first<__type_list<_Hp, _Tp>, _Size, false>
+{
+ typedef _LIBCPP_NODEBUG typename __find_first<_Tp, _Size>::type type;
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_TYPE_LIST_H
diff --git a/libcxx/include/__utility/transaction.h b/libcxx/include/__utility/transaction.h
index 87e51c0b198e..e2cc43820845 100644
--- a/libcxx/include/__utility/transaction.h
+++ b/libcxx/include/__utility/transaction.h
@@ -86,6 +86,11 @@ private:
bool __completed_;
};
+template <class _Rollback>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __transaction<_Rollback> __make_transaction(_Rollback __rollback) {
+ return __transaction<_Rollback>(std::move(__rollback));
+}
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___UTILITY_TRANSACTION_H
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 5958ad1a95af..197b3b1043bb 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -331,6 +331,23 @@ namespace ranges {
constexpr borrowed_iterator_t<R>
ranges::sort_heap(R&& r, Comp comp = {}, Proj proj = {}); // since C++20
+ template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
+ indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
+ constexpr bool is_heap(I first, S last, Comp comp = {}, Proj proj = {}); // Since C++20
+
+ template<random_access_range R, class Proj = identity,
+ indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
+ constexpr bool is_heap(R&& r, Comp comp = {}, Proj proj = {}); // Since C++20
+
+ template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
+ indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
+ constexpr I is_heap_until(I first, S last, Comp comp = {}, Proj proj = {}); // Since C++20
+
+ template<random_access_range R, class Proj = identity,
+ indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
+ constexpr borrowed_iterator_t<R>
+ is_heap_until(R&& r, Comp comp = {}, Proj proj = {}); // Since C++20
+
template<bidirectional_iterator I, sentinel_for<I> S>
requires permutable<I>
constexpr I ranges::reverse(I first, S last); // since C++20
@@ -380,6 +397,18 @@ namespace ranges {
template<class T, output_iterator<const T&> O>
constexpr O ranges::fill_n(O first, iter_difference_t<O> n, const T& value); // since C++20
+ template<input_or_output_iterator O, sentinel_for<O> S, copy_constructible F>
+ requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
+ constexpr O generate(O first, S last, F gen); // Since C++20
+
+ template<class R, copy_constructible F>
+ requires invocable<F&> && output_range<R, invoke_result_t<F&>>
+ constexpr borrowed_iterator_t<R> generate(R&& r, F gen); // Since C++20
+
+ template<input_or_output_iterator O, copy_constructible F>
+ requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
+ constexpr O generate_n(O first, iter_difference_t<O> n, F gen); // Since C++20
+
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
@@ -1575,7 +1604,11 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_find_if_not.h>
#include <__algorithm/ranges_for_each.h>
#include <__algorithm/ranges_for_each_n.h>
+#include <__algorithm/ranges_generate.h>
+#include <__algorithm/ranges_generate_n.h>
#include <__algorithm/ranges_includes.h>
+#include <__algorithm/ranges_is_heap.h>
+#include <__algorithm/ranges_is_heap_until.h>
#include <__algorithm/ranges_is_partitioned.h>
#include <__algorithm/ranges_is_sorted.h>
#include <__algorithm/ranges_is_sorted_until.h>
diff --git a/libcxx/include/charconv b/libcxx/include/charconv
index 9f474ae711f3..4f00755a83bb 100644
--- a/libcxx/include/charconv
+++ b/libcxx/include/charconv
@@ -88,6 +88,7 @@ namespace std {
#include <__config>
#include <__debug>
#include <__errc>
+#include <__type_traits/make_32_64_or_128_bit.h>
#include <__utility/unreachable.h>
#include <cmath> // for log2f
#include <cstdint>
diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index aab3b8715d01..ee90aaa4771f 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -188,6 +188,7 @@ template <class T, class Allocator, class Predicate>
#include <__iterator/iterator_traits.h>
#include <__iterator/move_iterator.h>
#include <__iterator/next.h>
+#include <__memory/swap_allocator.h>
#include <__utility/forward.h>
#include <limits>
#include <memory>
diff --git a/libcxx/include/list b/libcxx/include/list
index 1db29d14b842..5fcbd67c6703 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -194,6 +194,7 @@ template <class T, class Allocator, class Predicate>
#include <__iterator/next.h>
#include <__iterator/prev.h>
#include <__iterator/reverse_iterator.h>
+#include <__memory/swap_allocator.h>
#include <__utility/forward.h>
#include <__utility/move.h>
#include <__utility/swap.h>
diff --git a/libcxx/include/math.h b/libcxx/include/math.h
index 7d553e728d0f..0ec584af9dbe 100644
--- a/libcxx/include/math.h
+++ b/libcxx/include/math.h
@@ -305,6 +305,7 @@ long double truncl(long double x);
// back to C++ linkage before including these C++ headers.
extern "C++" {
+#include <__type_traits/promote.h>
#include <limits>
#include <stdlib.h>
#include <type_traits>
diff --git a/libcxx/include/memory b/libcxx/include/memory
index ec9f5773929f..56f8159fbd44 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -885,93 +885,6 @@ template<size_t N, class T>
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Alloc, class _Ptr>
-_LIBCPP_INLINE_VISIBILITY
-void __construct_forward_with_exception_guarantees(_Alloc& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __begin2) {
- static_assert(__is_cpp17_move_insertable<_Alloc>::value,
- "The specified type does not meet the requirements of Cpp17MoveInsertable");
- typedef allocator_traits<_Alloc> _Traits;
- for (; __begin1 != __end1; ++__begin1, (void)++__begin2) {
- _Traits::construct(__a, _VSTD::__to_address(__begin2),
-#ifdef _LIBCPP_NO_EXCEPTIONS
- _VSTD::move(*__begin1)
-#else
- _VSTD::move_if_noexcept(*__begin1)
-#endif
- );
- }
-}
-
-template <class _Alloc, class _Tp, typename enable_if<
- (__is_default_allocator<_Alloc>::value || !__has_construct<_Alloc, _Tp*, _Tp>::value) &&
- is_trivially_move_constructible<_Tp>::value
->::type>
-_LIBCPP_INLINE_VISIBILITY
-void __construct_forward_with_exception_guarantees(_Alloc&, _Tp* __begin1, _Tp* __end1, _Tp*& __begin2) {
- ptrdiff_t _Np = __end1 - __begin1;
- if (_Np > 0) {
- _VSTD::memcpy(__begin2, __begin1, _Np * sizeof(_Tp));
- __begin2 += _Np;
- }
-}
-
-template <class _Alloc, class _Iter, class _Ptr>
-_LIBCPP_INLINE_VISIBILITY
-void __construct_range_forward(_Alloc& __a, _Iter __begin1, _Iter __end1, _Ptr& __begin2) {
- typedef allocator_traits<_Alloc> _Traits;
- for (; __begin1 != __end1; ++__begin1, (void) ++__begin2) {
- _Traits::construct(__a, _VSTD::__to_address(__begin2), *__begin1);
- }
-}
-
-template <class _Alloc, class _Source, class _Dest,
- class _RawSource = typename remove_const<_Source>::type,
- class _RawDest = typename remove_const<_Dest>::type,
- class =
- typename enable_if<
- is_trivially_copy_constructible<_Dest>::value &&
- is_same<_RawSource, _RawDest>::value &&
- (__is_default_allocator<_Alloc>::value || !__has_construct<_Alloc, _Dest*, _Source&>::value)
- >::type>
-_LIBCPP_INLINE_VISIBILITY
-void __construct_range_forward(_Alloc&, _Source* __begin1, _Source* __end1, _Dest*& __begin2) {
- ptrdiff_t _Np = __end1 - __begin1;
- if (_Np > 0) {
- _VSTD::memcpy(const_cast<_RawDest*>(__begin2), __begin1, _Np * sizeof(_Dest));
- __begin2 += _Np;
- }
-}
-
-template <class _Alloc, class _Ptr>
-_LIBCPP_INLINE_VISIBILITY
-void __construct_backward_with_exception_guarantees(_Alloc& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __end2) {
- static_assert(__is_cpp17_move_insertable<_Alloc>::value,
- "The specified type does not meet the requirements of Cpp17MoveInsertable");
- typedef allocator_traits<_Alloc> _Traits;
- while (__end1 != __begin1) {
- _Traits::construct(__a, _VSTD::__to_address(__end2 - 1),
-#ifdef _LIBCPP_NO_EXCEPTIONS
- _VSTD::move(*--__end1)
-#else
- _VSTD::move_if_noexcept(*--__end1)
-#endif
- );
- --__end2;
- }
-}
-
-template <class _Alloc, class _Tp, class = typename enable_if<
- (__is_default_allocator<_Alloc>::value || !__has_construct<_Alloc, _Tp*, _Tp>::value) &&
- is_trivially_move_constructible<_Tp>::value
->::type>
-_LIBCPP_INLINE_VISIBILITY
-void __construct_backward_with_exception_guarantees(_Alloc&, _Tp* __begin1, _Tp* __end1, _Tp*& __end2) {
- ptrdiff_t _Np = __end1 - __begin1;
- __end2 -= _Np;
- if (_Np > 0)
- _VSTD::memcpy(static_cast<void*>(__end2), static_cast<void const*>(__begin1), _Np * sizeof(_Tp));
-}
-
struct __destruct_n
{
private:
@@ -1013,37 +926,6 @@ public:
_LIBCPP_FUNC_VIS void* align(size_t __align, size_t __sz, void*& __ptr, size_t& __space);
-// --- Helper for container swap --
-template <typename _Alloc>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
-void __swap_allocator(_Alloc & __a1, _Alloc & __a2, true_type)
-#if _LIBCPP_STD_VER > 11
- _NOEXCEPT
-#else
- _NOEXCEPT_(__is_nothrow_swappable<_Alloc>::value)
-#endif
-{
- using _VSTD::swap;
- swap(__a1, __a2);
-}
-
-template <typename _Alloc>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
-void __swap_allocator(_Alloc &, _Alloc &, false_type) _NOEXCEPT {}
-
-template <typename _Alloc>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
-void __swap_allocator(_Alloc & __a1, _Alloc & __a2)
-#if _LIBCPP_STD_VER > 11
- _NOEXCEPT
-#else
- _NOEXCEPT_(__is_nothrow_swappable<_Alloc>::value)
-#endif
-{
- _VSTD::__swap_allocator(__a1, __a2,
- integral_constant<bool, allocator_traits<_Alloc>::propagate_on_container_swap::value>());
-}
-
template <typename _Alloc, typename _Traits=allocator_traits<_Alloc> >
struct __noexcept_move_assign_container : public integral_constant<bool,
_Traits::propagate_on_container_move_assignment::value
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index cbf0b4f7f16d..98485bcd93ab 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -832,6 +832,7 @@ module std [system] {
module ranges_uninitialized_algorithms { private header "__memory/ranges_uninitialized_algorithms.h" }
module raw_storage_iterator { private header "__memory/raw_storage_iterator.h" }
module shared_ptr { private header "__memory/shared_ptr.h" }
+ module swap_allocator { private header "__memory/swap_allocator.h" }
module temporary_buffer { private header "__memory/temporary_buffer.h" }
module uninitialized_algorithms { private header "__memory/uninitialized_algorithms.h" }
module unique_ptr { private header "__memory/unique_ptr.h" }
@@ -1090,10 +1091,16 @@ module std [system] {
module add_pointer { private header "__type_traits/add_pointer.h" }
module add_rvalue_reference { private header "__type_traits/add_rvalue_reference.h" }
module add_volatile { private header "__type_traits/add_volatile.h" }
+ module aligned_storage { private header "__type_traits/aligned_storage.h" }
+ module aligned_union { private header "__type_traits/aligned_union.h" }
module alignment_of { private header "__type_traits/alignment_of.h" }
module apply_cv { private header "__type_traits/apply_cv.h" }
+ module common_reference { private header "__type_traits/common_reference.h" }
+ module common_type { private header "__type_traits/common_type.h" }
module conditional { private header "__type_traits/conditional.h" }
module conjunction { private header "__type_traits/conjunction.h" }
+ module copy_cv { private header "__type_traits/copy_cv.h" }
+ module copy_cvref { private header "__type_traits/copy_cvref.h" }
module decay { private header "__type_traits/decay.h" }
module disjunction { private header "__type_traits/disjunction.h" }
module enable_if { private header "__type_traits/enable_if.h" }
@@ -1135,6 +1142,7 @@ module std [system] {
module is_move_constructible { private header "__type_traits/is_move_constructible.h" }
module is_nothrow_assignable { private header "__type_traits/is_nothrow_assignable.h" }
module is_nothrow_constructible { private header "__type_traits/is_nothrow_constructible.h" }
+ module is_nothrow_convertible { private header "__type_traits/is_nothrow_convertible.h" }
module is_nothrow_copy_assignable { private header "__type_traits/is_nothrow_copy_assignable.h" }
module is_nothrow_copy_constructible { private header "__type_traits/is_nothrow_copy_constructible.h" }
module is_nothrow_default_constructible { private header "__type_traits/is_nothrow_default_constructible.h" }
@@ -1146,6 +1154,7 @@ module std [system] {
module is_pod { private header "__type_traits/is_pod.h" }
module is_pointer { private header "__type_traits/is_pointer.h" }
module is_polymorphic { private header "__type_traits/is_polymorphic.h" }
+ module is_primary_template { private header "__type_traits/is_primary_template.h" }
module is_reference { private header "__type_traits/is_reference.h" }
module is_reference_wrapper { private header "__type_traits/is_reference_wrapper.h" }
module is_referenceable { private header "__type_traits/is_referenceable.h" }
@@ -1153,6 +1162,7 @@ module std [system] {
module is_scalar { private header "__type_traits/is_scalar.h" }
module is_scoped_enum { private header "__type_traits/is_scoped_enum.h" }
module is_signed { private header "__type_traits/is_signed.h" }
+ module is_signed_integer { private header "__type_traits/is_signed_integer.h" }
module is_standard_layout { private header "__type_traits/is_standard_layout.h" }
module is_trivial { private header "__type_traits/is_trivial.h" }
module is_trivially_assignable { private header "__type_traits/is_trivially_assignable.h" }
@@ -1167,18 +1177,28 @@ module std [system] {
module is_unbounded_array { private header "__type_traits/is_unbounded_array.h" }
module is_union { private header "__type_traits/is_union.h" }
module is_unsigned { private header "__type_traits/is_unsigned.h" }
+ module is_unsigned_integer { private header "__type_traits/is_unsigned_integer.h" }
+ module is_valid_expansion { private header "__type_traits/is_valid_expansion.h" }
module is_void { private header "__type_traits/is_void.h" }
module is_volatile { private header "__type_traits/is_volatile.h" }
+ module lazy { private header "__type_traits/lazy.h" }
+ module make_32_64_or_128_bit { private header "__type_traits/make_32_64_or_128_bit.h" }
+ module make_signed { private header "__type_traits/make_signed.h" }
+ module make_unsigned { private header "__type_traits/make_unsigned.h" }
+ module nat { private header "__type_traits/nat.h" }
module negation { private header "__type_traits/negation.h" }
+ module promote { private header "__type_traits/promote.h" }
module rank { private header "__type_traits/rank.h" }
module remove_all_extents { private header "__type_traits/remove_all_extents.h" }
module remove_const { private header "__type_traits/remove_const.h" }
module remove_cv { private header "__type_traits/remove_cv.h" }
+ module remove_cvref { private header "__type_traits/remove_cvref.h" }
module remove_extent { private header "__type_traits/remove_extent.h" }
module remove_pointer { private header "__type_traits/remove_pointer.h" }
module remove_reference { private header "__type_traits/remove_reference.h" }
module remove_volatile { private header "__type_traits/remove_volatile.h" }
module type_identity { private header "__type_traits/type_identity.h" }
+ module type_list { private header "__type_traits/type_list.h" }
module underlying_type { private header "__type_traits/underlying_type.h" }
module void_t { private header "__type_traits/void_t.h" }
}
diff --git a/libcxx/include/string b/libcxx/include/string
index bb169a82c9e7..3723dc8a3938 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -532,6 +532,7 @@ basic_string<char32_t> operator "" s( const char32_t *str, size_t len );
#include <__iterator/reverse_iterator.h>
#include <__iterator/wrap_iter.h>
#include <__memory/allocate_at_least.h>
+#include <__memory/swap_allocator.h>
#include <__string/char_traits.h>
#include <__string/extern_template_lists.h>
#include <__utility/auto_cast.h>
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index f7d81e65dd8e..3a086c595f92 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -425,8 +425,12 @@ namespace std
#include <__type_traits/add_pointer.h>
#include <__type_traits/add_rvalue_reference.h>
#include <__type_traits/add_volatile.h>
+#include <__type_traits/aligned_storage.h>
+#include <__type_traits/aligned_union.h>
#include <__type_traits/alignment_of.h>
#include <__type_traits/apply_cv.h>
+#include <__type_traits/common_reference.h>
+#include <__type_traits/common_type.h>
#include <__type_traits/conditional.h>
#include <__type_traits/conjunction.h>
#include <__type_traits/decay.h>
@@ -469,6 +473,7 @@ namespace std
#include <__type_traits/is_move_constructible.h>
#include <__type_traits/is_nothrow_assignable.h>
#include <__type_traits/is_nothrow_constructible.h>
+#include <__type_traits/is_nothrow_convertible.h>
#include <__type_traits/is_nothrow_copy_assignable.h>
#include <__type_traits/is_nothrow_copy_constructible.h>
#include <__type_traits/is_nothrow_default_constructible.h>
@@ -503,6 +508,8 @@ namespace std
#include <__type_traits/is_unsigned.h>
#include <__type_traits/is_void.h>
#include <__type_traits/is_volatile.h>
+#include <__type_traits/make_signed.h>
+#include <__type_traits/make_unsigned.h>
#include <__type_traits/negation.h>
#include <__type_traits/rank.h>
#include <__type_traits/remove_all_extents.h>
@@ -529,798 +536,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _T1, class _T2> struct _LIBCPP_TEMPLATE_VIS pair;
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS hash;
-template <template <class...> class _Func, class ..._Args>
-struct _Lazy : _Func<_Args...> {};
-
// Member detector base
-template <template <class...> class _Templ, class ..._Args, class = _Templ<_Args...> >
-true_type __sfinae_test_impl(int);
-template <template <class...> class, class ...>
-false_type __sfinae_test_impl(...);
-
-template <template <class ...> class _Templ, class ..._Args>
-using _IsValidExpansion _LIBCPP_NODEBUG = decltype(__sfinae_test_impl<_Templ, _Args...>(0));
-
template <class _Tp, bool>
struct _LIBCPP_TEMPLATE_VIS __dependent_type : public _Tp {};
-// is_same
-
-template <class _Tp>
-using __test_for_primary_template = __enable_if_t<
- _IsSame<_Tp, typename _Tp::__primary_template>::value
- >;
-template <class _Tp>
-using __is_primary_template = _IsValidExpansion<
- __test_for_primary_template, _Tp
- >;
-
// is_integral
-// [basic.fundamental] defines five standard signed integer types;
-// __int128_t is an extended signed integer type.
-// The signed and unsigned integer types, plus bool and the
-// five types with "char" in their name, compose the "integral" types.
-
-template <class _Tp> struct __libcpp_is_signed_integer : public false_type {};
-template <> struct __libcpp_is_signed_integer<signed char> : public true_type {};
-template <> struct __libcpp_is_signed_integer<signed short> : public true_type {};
-template <> struct __libcpp_is_signed_integer<signed int> : public true_type {};
-template <> struct __libcpp_is_signed_integer<signed long> : public true_type {};
-template <> struct __libcpp_is_signed_integer<signed long long> : public true_type {};
-#ifndef _LIBCPP_HAS_NO_INT128
-template <> struct __libcpp_is_signed_integer<__int128_t> : public true_type {};
-#endif
-
-template <class _Tp> struct __libcpp_is_unsigned_integer : public false_type {};
-template <> struct __libcpp_is_unsigned_integer<unsigned char> : public true_type {};
-template <> struct __libcpp_is_unsigned_integer<unsigned short> : public true_type {};
-template <> struct __libcpp_is_unsigned_integer<unsigned int> : public true_type {};
-template <> struct __libcpp_is_unsigned_integer<unsigned long> : public true_type {};
-template <> struct __libcpp_is_unsigned_integer<unsigned long long> : public true_type {};
-#ifndef _LIBCPP_HAS_NO_INT128
-template <> struct __libcpp_is_unsigned_integer<__uint128_t> : public true_type {};
-#endif
-
template <class _Tp>
struct __unconstref {
typedef _LIBCPP_NODEBUG typename remove_const<typename remove_reference<_Tp>::type>::type type;
};
-template <class _Tp>
-using __uncvref_t _LIBCPP_NODEBUG = typename remove_cv<typename remove_reference<_Tp>::type>::type;
-
-// __is_same_uncvref
-
-template <class _Tp, class _Up>
-struct __is_same_uncvref : _IsSame<__uncvref_t<_Tp>, __uncvref_t<_Up> > {};
-
-#if _LIBCPP_STD_VER > 17
-// remove_cvref - same as __uncvref
-template <class _Tp>
-struct remove_cvref {
- using type _LIBCPP_NODEBUG = __uncvref_t<_Tp>;
-};
-
-template <class _Tp> using remove_cvref_t = typename remove_cvref<_Tp>::type;
-#endif
-
-// is_nothrow_convertible
-
-#if _LIBCPP_STD_VER > 17
-
-template <typename _Tp>
-static void __test_noexcept(_Tp) noexcept;
-
-template<typename _Fm, typename _To>
-static bool_constant<noexcept(_VSTD::__test_noexcept<_To>(declval<_Fm>()))>
-__is_nothrow_convertible_test();
-
-template <typename _Fm, typename _To>
-struct __is_nothrow_convertible_helper: decltype(__is_nothrow_convertible_test<_Fm, _To>())
-{ };
-
-template <typename _Fm, typename _To>
-struct is_nothrow_convertible : _Or<
- _And<is_void<_To>, is_void<_Fm>>,
- _Lazy<_And, is_convertible<_Fm, _To>, __is_nothrow_convertible_helper<_Fm, _To>>
->::type { };
-
-template <typename _Fm, typename _To>
-inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<_Fm, _To>::value;
-
-#endif // _LIBCPP_STD_VER > 17
-
-// aligned_storage
-
-template <class _Hp, class _Tp>
-struct __type_list
-{
- typedef _Hp _Head;
- typedef _Tp _Tail;
-};
-
-template <class _Tp>
-struct __align_type
-{
- static const size_t value = _LIBCPP_PREFERRED_ALIGNOF(_Tp);
- typedef _Tp type;
-};
-
-struct __struct_double {long double __lx;};
-struct __struct_double4 {double __lx[4];};
-
-typedef
- __type_list<__align_type<unsigned char>,
- __type_list<__align_type<unsigned short>,
- __type_list<__align_type<unsigned int>,
- __type_list<__align_type<unsigned long>,
- __type_list<__align_type<unsigned long long>,
- __type_list<__align_type<double>,
- __type_list<__align_type<long double>,
- __type_list<__align_type<__struct_double>,
- __type_list<__align_type<__struct_double4>,
- __type_list<__align_type<int*>,
- __nat
- > > > > > > > > > > __all_types;
-
-template <size_t _Align>
-struct _ALIGNAS(_Align) __fallback_overaligned {};
-
-template <class _TL, size_t _Align> struct __find_pod;
-
-template <class _Hp, size_t _Align>
-struct __find_pod<__type_list<_Hp, __nat>, _Align>
-{
- typedef typename conditional<
- _Align == _Hp::value,
- typename _Hp::type,
- __fallback_overaligned<_Align>
- >::type type;
-};
-
-template <class _Hp, class _Tp, size_t _Align>
-struct __find_pod<__type_list<_Hp, _Tp>, _Align>
-{
- typedef typename conditional<
- _Align == _Hp::value,
- typename _Hp::type,
- typename __find_pod<_Tp, _Align>::type
- >::type type;
-};
-
-template <class _TL, size_t _Len> struct __find_max_align;
-
-template <class _Hp, size_t _Len>
-struct __find_max_align<__type_list<_Hp, __nat>, _Len> : public integral_constant<size_t, _Hp::value> {};
-
-template <size_t _Len, size_t _A1, size_t _A2>
-struct __select_align
-{
-private:
- static const size_t __min = _A2 < _A1 ? _A2 : _A1;
- static const size_t __max = _A1 < _A2 ? _A2 : _A1;
-public:
- static const size_t value = _Len < __max ? __min : __max;
-};
-
-template <class _Hp, class _Tp, size_t _Len>
-struct __find_max_align<__type_list<_Hp, _Tp>, _Len>
- : public integral_constant<size_t, __select_align<_Len, _Hp::value, __find_max_align<_Tp, _Len>::value>::value> {};
-
-template <size_t _Len, size_t _Align = __find_max_align<__all_types, _Len>::value>
-struct _LIBCPP_TEMPLATE_VIS aligned_storage
-{
- typedef typename __find_pod<__all_types, _Align>::type _Aligner;
- union type
- {
- _Aligner __align;
- unsigned char __data[(_Len + _Align - 1)/_Align * _Align];
- };
-};
-
-#if _LIBCPP_STD_VER > 11
-template <size_t _Len, size_t _Align = __find_max_align<__all_types, _Len>::value>
- using aligned_storage_t = typename aligned_storage<_Len, _Align>::type;
-#endif
-
-#define _CREATE_ALIGNED_STORAGE_SPECIALIZATION(n) \
-template <size_t _Len>\
-struct _LIBCPP_TEMPLATE_VIS aligned_storage<_Len, n>\
-{\
- struct _ALIGNAS(n) type\
- {\
- unsigned char __lx[(_Len + n - 1)/n * n];\
- };\
-}
-
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x8);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x10);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x20);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x40);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x80);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x100);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x200);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x400);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x800);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1000);
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2000);
-// PE/COFF does not support alignment beyond 8192 (=0x2000)
-#if !defined(_LIBCPP_OBJECT_FORMAT_COFF)
-_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4000);
-#endif // !defined(_LIBCPP_OBJECT_FORMAT_COFF)
-
-#undef _CREATE_ALIGNED_STORAGE_SPECIALIZATION
-
-
-// aligned_union
-
-template <size_t _I0, size_t ..._In>
-struct __static_max;
-
-template <size_t _I0>
-struct __static_max<_I0>
-{
- static const size_t value = _I0;
-};
-
-template <size_t _I0, size_t _I1, size_t ..._In>
-struct __static_max<_I0, _I1, _In...>
-{
- static const size_t value = _I0 >= _I1 ? __static_max<_I0, _In...>::value :
- __static_max<_I1, _In...>::value;
-};
-
-template <size_t _Len, class _Type0, class ..._Types>
-struct aligned_union
-{
- static const size_t alignment_value = __static_max<_LIBCPP_PREFERRED_ALIGNOF(_Type0),
- _LIBCPP_PREFERRED_ALIGNOF(_Types)...>::value;
- static const size_t __len = __static_max<_Len, sizeof(_Type0),
- sizeof(_Types)...>::value;
- typedef typename aligned_storage<__len, alignment_value>::type type;
-};
-
-#if _LIBCPP_STD_VER > 11
-template <size_t _Len, class ..._Types> using aligned_union_t = typename aligned_union<_Len, _Types...>::type;
-#endif
-
-template <class _Tp>
-struct __numeric_type
-{
- static void __test(...);
- static float __test(float);
- static double __test(char);
- static double __test(int);
- static double __test(unsigned);
- static double __test(long);
- static double __test(unsigned long);
- static double __test(long long);
- static double __test(unsigned long long);
- static double __test(double);
- static long double __test(long double);
-
- typedef decltype(__test(declval<_Tp>())) type;
- static const bool value = _IsNotSame<type, void>::value;
-};
-
-template <>
-struct __numeric_type<void>
-{
- static const bool value = true;
-};
-
-// __promote
-
-template <class _A1, class _A2 = void, class _A3 = void,
- bool = __numeric_type<_A1>::value &&
- __numeric_type<_A2>::value &&
- __numeric_type<_A3>::value>
-class __promote_imp
-{
-public:
- static const bool value = false;
-};
-
-template <class _A1, class _A2, class _A3>
-class __promote_imp<_A1, _A2, _A3, true>
-{
-private:
- typedef typename __promote_imp<_A1>::type __type1;
- typedef typename __promote_imp<_A2>::type __type2;
- typedef typename __promote_imp<_A3>::type __type3;
-public:
- typedef decltype(__type1() + __type2() + __type3()) type;
- static const bool value = true;
-};
-
-template <class _A1, class _A2>
-class __promote_imp<_A1, _A2, void, true>
-{
-private:
- typedef typename __promote_imp<_A1>::type __type1;
- typedef typename __promote_imp<_A2>::type __type2;
-public:
- typedef decltype(__type1() + __type2()) type;
- static const bool value = true;
-};
-
-template <class _A1>
-class __promote_imp<_A1, void, void, true>
-{
-public:
- typedef typename __numeric_type<_A1>::type type;
- static const bool value = true;
-};
-
-template <class _A1, class _A2 = void, class _A3 = void>
-class __promote : public __promote_imp<_A1, _A2, _A3> {};
-
-// make_signed / make_unsigned
-
-typedef
- __type_list<signed char,
- __type_list<signed short,
- __type_list<signed int,
- __type_list<signed long,
- __type_list<signed long long,
-#ifndef _LIBCPP_HAS_NO_INT128
- __type_list<__int128_t,
-#endif
- __nat
-#ifndef _LIBCPP_HAS_NO_INT128
- >
-#endif
- > > > > > __signed_types;
-
-typedef
- __type_list<unsigned char,
- __type_list<unsigned short,
- __type_list<unsigned int,
- __type_list<unsigned long,
- __type_list<unsigned long long,
-#ifndef _LIBCPP_HAS_NO_INT128
- __type_list<__uint128_t,
-#endif
- __nat
-#ifndef _LIBCPP_HAS_NO_INT128
- >
-#endif
- > > > > > __unsigned_types;
-
-template <class _TypeList, size_t _Size, bool = _Size <= sizeof(typename _TypeList::_Head)> struct __find_first;
-
-template <class _Hp, class _Tp, size_t _Size>
-struct __find_first<__type_list<_Hp, _Tp>, _Size, true>
-{
- typedef _LIBCPP_NODEBUG _Hp type;
-};
-
-template <class _Hp, class _Tp, size_t _Size>
-struct __find_first<__type_list<_Hp, _Tp>, _Size, false>
-{
- typedef _LIBCPP_NODEBUG typename __find_first<_Tp, _Size>::type type;
-};
-
-template <class _Tp, bool = is_integral<_Tp>::value || is_enum<_Tp>::value>
-struct __make_signed {};
-
-template <class _Tp>
-struct __make_signed<_Tp, true>
-{
- typedef typename __find_first<__signed_types, sizeof(_Tp)>::type type;
-};
-
-template <> struct __make_signed<bool, true> {};
-template <> struct __make_signed< signed short, true> {typedef short type;};
-template <> struct __make_signed<unsigned short, true> {typedef short type;};
-template <> struct __make_signed< signed int, true> {typedef int type;};
-template <> struct __make_signed<unsigned int, true> {typedef int type;};
-template <> struct __make_signed< signed long, true> {typedef long type;};
-template <> struct __make_signed<unsigned long, true> {typedef long type;};
-template <> struct __make_signed< signed long long, true> {typedef long long type;};
-template <> struct __make_signed<unsigned long long, true> {typedef long long type;};
-#ifndef _LIBCPP_HAS_NO_INT128
-template <> struct __make_signed<__int128_t, true> {typedef __int128_t type;};
-template <> struct __make_signed<__uint128_t, true> {typedef __int128_t type;};
-#endif
-
-template <class _Tp>
-struct _LIBCPP_TEMPLATE_VIS make_signed
-{
- typedef typename __apply_cv<_Tp, typename __make_signed<typename remove_cv<_Tp>::type>::type>::type type;
-};
-
-#if _LIBCPP_STD_VER > 11
-template <class _Tp> using make_signed_t = typename make_signed<_Tp>::type;
-#endif
-
-template <class _Tp, bool = is_integral<_Tp>::value || is_enum<_Tp>::value>
-struct __make_unsigned {};
-
-template <class _Tp>
-struct __make_unsigned<_Tp, true>
-{
- typedef typename __find_first<__unsigned_types, sizeof(_Tp)>::type type;
-};
-
-template <> struct __make_unsigned<bool, true> {};
-template <> struct __make_unsigned< signed short, true> {typedef unsigned short type;};
-template <> struct __make_unsigned<unsigned short, true> {typedef unsigned short type;};
-template <> struct __make_unsigned< signed int, true> {typedef unsigned int type;};
-template <> struct __make_unsigned<unsigned int, true> {typedef unsigned int type;};
-template <> struct __make_unsigned< signed long, true> {typedef unsigned long type;};
-template <> struct __make_unsigned<unsigned long, true> {typedef unsigned long type;};
-template <> struct __make_unsigned< signed long long, true> {typedef unsigned long long type;};
-template <> struct __make_unsigned<unsigned long long, true> {typedef unsigned long long type;};
-#ifndef _LIBCPP_HAS_NO_INT128
-template <> struct __make_unsigned<__int128_t, true> {typedef __uint128_t type;};
-template <> struct __make_unsigned<__uint128_t, true> {typedef __uint128_t type;};
-#endif
-
-template <class _Tp>
-struct _LIBCPP_TEMPLATE_VIS make_unsigned
-{
- typedef typename __apply_cv<_Tp, typename __make_unsigned<typename remove_cv<_Tp>::type>::type>::type type;
-};
-
-#if _LIBCPP_STD_VER > 11
-template <class _Tp> using make_unsigned_t = typename make_unsigned<_Tp>::type;
-#endif
-
-#ifndef _LIBCPP_CXX03_LANG
-template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI constexpr
-typename make_unsigned<_Tp>::type __to_unsigned_like(_Tp __x) noexcept {
- return static_cast<typename make_unsigned<_Tp>::type>(__x);
-}
-#endif
-
-template <class _Tp, class _Up>
-using __copy_unsigned_t = __conditional_t<is_unsigned<_Tp>::value, typename make_unsigned<_Up>::type, _Up>;
-
-/// Helper to promote an integral to smallest 32, 64, or 128 bit representation.
-///
-/// The restriction is the same as the integral version of to_char.
-template <class _Tp>
-#if _LIBCPP_STD_VER > 17
- requires (is_signed_v<_Tp> || is_unsigned_v<_Tp> || is_same_v<_Tp, char>)
-#endif
-using __make_32_64_or_128_bit_t =
- __copy_unsigned_t<_Tp,
- __conditional_t<sizeof(_Tp) <= sizeof(int32_t), int32_t,
- __conditional_t<sizeof(_Tp) <= sizeof(int64_t), int64_t,
-#ifndef _LIBCPP_HAS_NO_INT128
- __conditional_t<sizeof(_Tp) <= sizeof(__int128_t), __int128_t,
- /* else */ void>
-#else
- /* else */ void
-#endif
- > >
- >;
-
-#if _LIBCPP_STD_VER > 17
-// Let COND_RES(X, Y) be:
-template <class _Tp, class _Up>
-using __cond_type = decltype(false ? declval<_Tp>() : declval<_Up>());
-
-template <class _Tp, class _Up, class = void>
-struct __common_type3 {};
-
-// sub-bullet 4 - "if COND_RES(CREF(D1), CREF(D2)) denotes a type..."
-template <class _Tp, class _Up>
-struct __common_type3<_Tp, _Up, void_t<__cond_type<const _Tp&, const _Up&>>>
-{
- using type = remove_cvref_t<__cond_type<const _Tp&, const _Up&>>;
-};
-
-template <class _Tp, class _Up, class = void>
-struct __common_type2_imp : __common_type3<_Tp, _Up> {};
-#else
-template <class _Tp, class _Up, class = void>
-struct __common_type2_imp {};
-#endif
-
-// sub-bullet 3 - "if decay_t<decltype(false ? declval<D1>() : declval<D2>())> ..."
-template <class _Tp, class _Up>
-struct __common_type2_imp<_Tp, _Up,
- typename __void_t<decltype(
- true ? declval<_Tp>() : declval<_Up>()
- )>::type>
-{
- typedef _LIBCPP_NODEBUG typename decay<decltype(
- true ? declval<_Tp>() : declval<_Up>()
- )>::type type;
-};
-
-template <class, class = void>
-struct __common_type_impl {};
-
-// Clang provides variadic templates in C++03 as an extension.
-#if !defined(_LIBCPP_CXX03_LANG) || defined(__clang__)
-# define _LIBCPP_OPTIONAL_PACK(...) , __VA_ARGS__
-template <class... _Tp>
-struct __common_types;
-template <class... _Tp>
-struct _LIBCPP_TEMPLATE_VIS common_type;
-#else
-# define _LIBCPP_OPTIONAL_PACK(...)
-struct __no_arg;
-template <class _Tp, class _Up, class = __no_arg>
-struct __common_types;
-template <class _Tp = __no_arg, class _Up = __no_arg, class _Vp = __no_arg,
- class _Unused = __no_arg>
-struct common_type {
- static_assert(sizeof(_Unused) == 0,
- "common_type accepts at most 3 arguments in C++03");
-};
-#endif // _LIBCPP_CXX03_LANG
-
-template <class _Tp, class _Up>
-struct __common_type_impl<
- __common_types<_Tp, _Up>,
- typename __void_t<typename common_type<_Tp, _Up>::type>::type>
-{
- typedef typename common_type<_Tp, _Up>::type type;
-};
-
-template <class _Tp, class _Up, class _Vp _LIBCPP_OPTIONAL_PACK(class... _Rest)>
-struct __common_type_impl<
- __common_types<_Tp, _Up, _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)>,
- typename __void_t<typename common_type<_Tp, _Up>::type>::type>
- : __common_type_impl<__common_types<typename common_type<_Tp, _Up>::type,
- _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)> > {
-};
-
-// bullet 1 - sizeof...(Tp) == 0
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS common_type<> {};
-
-// bullet 2 - sizeof...(Tp) == 1
-
-template <class _Tp>
-struct _LIBCPP_TEMPLATE_VIS common_type<_Tp>
- : public common_type<_Tp, _Tp> {};
-
-// bullet 3 - sizeof...(Tp) == 2
-
-// sub-bullet 1 - "If is_same_v<T1, D1> is false or ..."
-template <class _Tp, class _Up>
-struct _LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up>
- : conditional<
- _IsSame<_Tp, typename decay<_Tp>::type>::value && _IsSame<_Up, typename decay<_Up>::type>::value,
- __common_type2_imp<_Tp, _Up>,
- common_type<typename decay<_Tp>::type, typename decay<_Up>::type>
- >::type
-{};
-
-// bullet 4 - sizeof...(Tp) > 2
-
-template <class _Tp, class _Up, class _Vp _LIBCPP_OPTIONAL_PACK(class... _Rest)>
-struct _LIBCPP_TEMPLATE_VIS
- common_type<_Tp, _Up, _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)>
- : __common_type_impl<
- __common_types<_Tp, _Up, _Vp _LIBCPP_OPTIONAL_PACK(_Rest...)> > {};
-
-#undef _LIBCPP_OPTIONAL_PACK
-
-#if _LIBCPP_STD_VER > 11
-template <class ..._Tp> using common_type_t = typename common_type<_Tp...>::type;
-#endif
-
-// Let COPYCV(FROM, TO) be an alias for type TO with the addition of FROM's
-// top-level cv-qualifiers.
-template <class _From, class _To>
-struct __copy_cv
-{
- using type = _To;
-};
-
-template <class _From, class _To>
-struct __copy_cv<const _From, _To>
-{
- using type = typename add_const<_To>::type;
-};
-
-template <class _From, class _To>
-struct __copy_cv<volatile _From, _To>
-{
- using type = typename add_volatile<_To>::type;
-};
-
-template <class _From, class _To>
-struct __copy_cv<const volatile _From, _To>
-{
- using type = typename add_cv<_To>::type;
-};
-
-template <class _From, class _To>
-using __copy_cv_t = typename __copy_cv<_From, _To>::type;
-
-template <class _From, class _To>
-struct __copy_cvref
-{
- using type = __copy_cv_t<_From, _To>;
-};
-
-template <class _From, class _To>
-struct __copy_cvref<_From&, _To>
-{
- using type = typename add_lvalue_reference<__copy_cv_t<_From, _To> >::type;
-};
-
-template <class _From, class _To>
-struct __copy_cvref<_From&&, _To>
-{
- using type = typename add_rvalue_reference<__copy_cv_t<_From, _To> >::type;
-};
-
-template <class _From, class _To>
-using __copy_cvref_t = typename __copy_cvref<_From, _To>::type;
-
-
-// common_reference
-#if _LIBCPP_STD_VER > 17
-// Let COND_RES(X, Y) be:
-template <class _Xp, class _Yp>
-using __cond_res =
- decltype(false ? declval<_Xp(&)()>()() : declval<_Yp(&)()>()());
-
-// Let `XREF(A)` denote a unary alias template `T` such that `T<U>` denotes the same type as `U`
-// with the addition of `A`'s cv and reference qualifiers, for a non-reference cv-unqualified type
-// `U`.
-// [Note: `XREF(A)` is `__xref<A>::template __apply`]
-template <class _Tp>
-struct __xref {
- template<class _Up>
- using __apply = __copy_cvref_t<_Tp, _Up>;
-};
-
-// Given types A and B, let X be remove_reference_t<A>, let Y be remove_reference_t<B>,
-// and let COMMON-REF(A, B) be:
-template<class _Ap, class _Bp, class _Xp = remove_reference_t<_Ap>, class _Yp = remove_reference_t<_Bp>>
-struct __common_ref;
-
-template<class _Xp, class _Yp>
-using __common_ref_t = typename __common_ref<_Xp, _Yp>::__type;
-
-template<class _Xp, class _Yp>
-using __cv_cond_res = __cond_res<__copy_cv_t<_Xp, _Yp>&, __copy_cv_t<_Yp, _Xp>&>;
-
-
-// If A and B are both lvalue reference types, COMMON-REF(A, B) is
-// COND-RES(COPYCV(X, Y)&, COPYCV(Y, X)&) if that type exists and is a reference type.
-template<class _Ap, class _Bp, class _Xp, class _Yp>
-requires requires { typename __cv_cond_res<_Xp, _Yp>; } && is_reference_v<__cv_cond_res<_Xp, _Yp>>
-struct __common_ref<_Ap&, _Bp&, _Xp, _Yp>
-{
- using __type = __cv_cond_res<_Xp, _Yp>;
-};
-
-// Otherwise, let C be remove_reference_t<COMMON-REF(X&, Y&)>&&. ...
-template <class _Xp, class _Yp>
-using __common_ref_C = remove_reference_t<__common_ref_t<_Xp&, _Yp&>>&&;
-
-
-// .... If A and B are both rvalue reference types, C is well-formed, and
-// is_convertible_v<A, C> && is_convertible_v<B, C> is true, then COMMON-REF(A, B) is C.
-template<class _Ap, class _Bp, class _Xp, class _Yp>
-requires
- requires { typename __common_ref_C<_Xp, _Yp>; } &&
- is_convertible_v<_Ap&&, __common_ref_C<_Xp, _Yp>> &&
- is_convertible_v<_Bp&&, __common_ref_C<_Xp, _Yp>>
-struct __common_ref<_Ap&&, _Bp&&, _Xp, _Yp>
-{
- using __type = __common_ref_C<_Xp, _Yp>;
-};
-
-// Otherwise, let D be COMMON-REF(const X&, Y&). ...
-template <class _Tp, class _Up>
-using __common_ref_D = __common_ref_t<const _Tp&, _Up&>;
-
-// ... If A is an rvalue reference and B is an lvalue reference and D is well-formed and
-// is_convertible_v<A, D> is true, then COMMON-REF(A, B) is D.
-template<class _Ap, class _Bp, class _Xp, class _Yp>
-requires requires { typename __common_ref_D<_Xp, _Yp>; } &&
- is_convertible_v<_Ap&&, __common_ref_D<_Xp, _Yp>>
-struct __common_ref<_Ap&&, _Bp&, _Xp, _Yp>
-{
- using __type = __common_ref_D<_Xp, _Yp>;
-};
-
-// Otherwise, if A is an lvalue reference and B is an rvalue reference, then
-// COMMON-REF(A, B) is COMMON-REF(B, A).
-template<class _Ap, class _Bp, class _Xp, class _Yp>
-struct __common_ref<_Ap&, _Bp&&, _Xp, _Yp> : __common_ref<_Bp&&, _Ap&> {};
-
-// Otherwise, COMMON-REF(A, B) is ill-formed.
-template<class _Ap, class _Bp, class _Xp, class _Yp>
-struct __common_ref {};
-
-// Note C: For the common_reference trait applied to a parameter pack [...]
-
-template <class...>
-struct common_reference;
-
-template <class... _Types>
-using common_reference_t = typename common_reference<_Types...>::type;
-
-// bullet 1 - sizeof...(T) == 0
-template<>
-struct common_reference<> {};
-
-// bullet 2 - sizeof...(T) == 1
-template <class _Tp>
-struct common_reference<_Tp>
-{
- using type = _Tp;
-};
-
-// bullet 3 - sizeof...(T) == 2
-template <class _Tp, class _Up> struct __common_reference_sub_bullet3;
-template <class _Tp, class _Up> struct __common_reference_sub_bullet2 : __common_reference_sub_bullet3<_Tp, _Up> {};
-template <class _Tp, class _Up> struct __common_reference_sub_bullet1 : __common_reference_sub_bullet2<_Tp, _Up> {};
-
-// sub-bullet 1 - If T1 and T2 are reference types and COMMON-REF(T1, T2) is well-formed, then
-// the member typedef `type` denotes that type.
-template <class _Tp, class _Up> struct common_reference<_Tp, _Up> : __common_reference_sub_bullet1<_Tp, _Up> {};
-
-template <class _Tp, class _Up>
-requires is_reference_v<_Tp> && is_reference_v<_Up> && requires { typename __common_ref_t<_Tp, _Up>; }
-struct __common_reference_sub_bullet1<_Tp, _Up>
-{
- using type = __common_ref_t<_Tp, _Up>;
-};
-
-// sub-bullet 2 - Otherwise, if basic_common_reference<remove_cvref_t<T1>, remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type
-// is well-formed, then the member typedef `type` denotes that type.
-template <class, class, template <class> class, template <class> class> struct basic_common_reference {};
-
-template <class _Tp, class _Up>
-using __basic_common_reference_t = typename basic_common_reference<
- remove_cvref_t<_Tp>, remove_cvref_t<_Up>,
- __xref<_Tp>::template __apply, __xref<_Up>::template __apply>::type;
-
-template <class _Tp, class _Up>
-requires requires { typename __basic_common_reference_t<_Tp, _Up>; }
-struct __common_reference_sub_bullet2<_Tp, _Up>
-{
- using type = __basic_common_reference_t<_Tp, _Up>;
-};
-
-// sub-bullet 3 - Otherwise, if COND-RES(T1, T2) is well-formed,
-// then the member typedef `type` denotes that type.
-template <class _Tp, class _Up>
-requires requires { typename __cond_res<_Tp, _Up>; }
-struct __common_reference_sub_bullet3<_Tp, _Up>
-{
- using type = __cond_res<_Tp, _Up>;
-};
-
-
-// sub-bullet 4 & 5 - Otherwise, if common_type_t<T1, T2> is well-formed,
-// then the member typedef `type` denotes that type.
-// - Otherwise, there shall be no member `type`.
-template <class _Tp, class _Up> struct __common_reference_sub_bullet3 : common_type<_Tp, _Up> {};
-
-// bullet 4 - If there is such a type `C`, the member typedef type shall denote the same type, if
-// any, as `common_reference_t<C, Rest...>`.
-template <class _Tp, class _Up, class _Vp, class... _Rest>
-requires requires { typename common_reference_t<_Tp, _Up>; }
-struct common_reference<_Tp, _Up, _Vp, _Rest...>
- : common_reference<common_reference_t<_Tp, _Up>, _Vp, _Rest...>
-{};
-
-// bullet 5 - Otherwise, there shall be no member `type`.
-template <class...> struct common_reference {};
-
-#endif // _LIBCPP_STD_VER > 17
-
#ifndef _LIBCPP_CXX03_LANG
// First of all, we can't implement this check in C++03 mode because the {}
// default initialization syntax isn't valid.
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 14f586c9bfd7..30030f85e43c 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -291,6 +291,8 @@ erase_if(vector<T, Allocator>& c, Predicate pred); // C++20
#include <__iterator/reverse_iterator.h>
#include <__iterator/wrap_iter.h>
#include <__memory/allocate_at_least.h>
+#include <__memory/pointer_traits.h>
+#include <__memory/swap_allocator.h>
#include <__split_buffer>
#include <__utility/forward.h>
#include <__utility/move.h>
@@ -895,9 +897,11 @@ template <class _Tp, class _Allocator>
void
vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v)
{
-
__annotate_delete();
- _VSTD::__construct_backward_with_exception_guarantees(this->__alloc(), this->__begin_, this->__end_, __v.__begin_);
+ using _RevIter = std::reverse_iterator<pointer>;
+ __v.__begin_ = std::__uninitialized_allocator_move_if_noexcept(
+ __alloc(), _RevIter(__end_), _RevIter(__begin_), _RevIter(__v.__begin_))
+ .base();
_VSTD::swap(this->__begin_, __v.__begin_);
_VSTD::swap(this->__end_, __v.__end_);
_VSTD::swap(this->__end_cap(), __v.__end_cap());
@@ -912,8 +916,11 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, a
{
__annotate_delete();
pointer __r = __v.__begin_;
- _VSTD::__construct_backward_with_exception_guarantees(this->__alloc(), this->__begin_, __p, __v.__begin_);
- _VSTD::__construct_forward_with_exception_guarantees(this->__alloc(), __p, this->__end_, __v.__end_);
+ using _RevIter = std::reverse_iterator<pointer>;
+ __v.__begin_ = std::__uninitialized_allocator_move_if_noexcept(
+ __alloc(), _RevIter(__p), _RevIter(__begin_), _RevIter(__v.__begin_))
+ .base();
+ __v.__end_ = std::__uninitialized_allocator_move_if_noexcept(__alloc(), __p, __end_, __v.__end_);
_VSTD::swap(this->__begin_, __v.__begin_);
_VSTD::swap(this->__end_, __v.__end_);
_VSTD::swap(this->__end_cap(), __v.__end_cap());
@@ -1001,8 +1008,8 @@ typename enable_if
>::type
vector<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last, size_type __n)
{
- _ConstructTransaction __tx(*this, __n);
- _VSTD::__construct_range_forward(this->__alloc(), __first, __last, __tx.__pos_);
+ _ConstructTransaction __tx(*this, __n);
+ __tx.__pos_ = std::__uninitialized_allocator_copy(__alloc(), __first, __last, __tx.__pos_);
}
// Default constructs __n objects starting at __end_
diff --git a/libcxx/src/assert.cpp b/libcxx/src/assert.cpp
index 54459800728b..c218645f1771 100644
--- a/libcxx/src/assert.cpp
+++ b/libcxx/src/assert.cpp
@@ -8,14 +8,57 @@
#include <__assert>
#include <__config>
+#include <cstdarg>
#include <cstdio>
#include <cstdlib>
+#ifdef __BIONIC__
+# include <android/api-level.h>
+# include <syslog.h>
+extern "C" void android_set_abort_message(const char* msg);
+#endif
+
+#if defined(__APPLE__) && __has_include(<CrashReporterClient.h>)
+# include <CrashReporterClient.h>
+#endif
+
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_WEAK
-void __libcpp_assertion_handler(char const* __file, int __line, char const* __expression, char const* __message) {
- std::fprintf(stderr, "%s:%d: libc++ assertion '%s' failed. %s\n", __file, __line, __expression, __message);
+void __libcpp_assertion_handler(char const* format, ...) {
+ // Write message to stderr. We do this before formatting into a
+ // buffer so that we still get some information out if that fails.
+ {
+ va_list list;
+ va_start(list, format);
+ std::vfprintf(stderr, format, list);
+ va_end(list);
+ }
+
+ // Format the arguments into an allocated buffer for CrashReport & friends.
+ // We leak the buffer on purpose, since we're about to abort() anyway.
+ char* buffer; (void)buffer;
+ va_list list;
+ va_start(list, format);
+
+#if defined(__APPLE__) && __has_include(<CrashReporterClient.h>)
+ // Note that we should technically synchronize accesses here (by e.g. taking a lock),
+ // however concretely we're only setting a pointer, so the likelihood of a race here
+ // is low.
+ vasprintf(&buffer, format, list);
+ CRSetCrashLogMessage(buffer);
+#elif defined(__BIONIC__)
+ // Show error in tombstone.
+ vasprintf(&buffer, format, list);
+ android_set_abort_message(buffer);
+
+ // Show error in logcat.
+ openlog("libc++", 0, 0);
+ syslog(LOG_CRIT, "%s", buffer);
+ closelog();
+#endif
+ va_end(list);
+
std::abort();
}
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index dd17adc4dbea..6c0fd3139e87 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -290,7 +290,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) {
// Add a given library by searching it from input search paths.
void LinkerDriver::addLibrary(StringRef name) {
if (Optional<std::string> path = searchLibrary(name))
- addFile(*path, /*withLOption=*/true);
+ addFile(saver().save(*path), /*withLOption=*/true);
else
error("unable to find library -l" + name, ErrorTag::LibNotFound, {name});
}
@@ -809,13 +809,10 @@ static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &args) {
// --build-id=sha1 are actually tree hashes for performance reasons.
static std::pair<BuildIdKind, std::vector<uint8_t>>
getBuildId(opt::InputArgList &args) {
- auto *arg = args.getLastArg(OPT_build_id, OPT_build_id_eq);
+ auto *arg = args.getLastArg(OPT_build_id);
if (!arg)
return {BuildIdKind::None, {}};
- if (arg->getOption().getID() == OPT_build_id)
- return {BuildIdKind::Fast, {}};
-
StringRef s = arg->getValue();
if (s == "fast")
return {BuildIdKind::Fast, {}};
@@ -1691,8 +1688,10 @@ void LinkerDriver::inferMachineType() {
static uint64_t getMaxPageSize(opt::InputArgList &args) {
uint64_t val = args::getZOptionValue(args, OPT_z, "max-page-size",
target->defaultMaxPageSize);
- if (!isPowerOf2_64(val))
+ if (!isPowerOf2_64(val)) {
error("max-page-size: value isn't a power of 2");
+ return target->defaultMaxPageSize;
+ }
if (config->nmagic || config->omagic) {
if (val != target->defaultMaxPageSize)
warn("-z max-page-size set, but paging disabled by omagic or nmagic");
@@ -1706,8 +1705,10 @@ static uint64_t getMaxPageSize(opt::InputArgList &args) {
static uint64_t getCommonPageSize(opt::InputArgList &args) {
uint64_t val = args::getZOptionValue(args, OPT_z, "common-page-size",
target->defaultCommonPageSize);
- if (!isPowerOf2_64(val))
+ if (!isPowerOf2_64(val)) {
error("common-page-size: value isn't a power of 2");
+ return target->defaultCommonPageSize;
+ }
if (config->nmagic || config->omagic) {
if (val != target->defaultCommonPageSize)
warn("-z common-page-size set, but paging disabled by omagic or nmagic");
diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp
index 54e4f9374e61..51f3dc3a056e 100644
--- a/lld/ELF/DriverUtils.cpp
+++ b/lld/ELF/DriverUtils.cpp
@@ -52,23 +52,16 @@ ELFOptTable::ELFOptTable() : OptTable(optInfo) {}
// Set color diagnostics according to --color-diagnostics={auto,always,never}
// or --no-color-diagnostics flags.
static void handleColorDiagnostics(opt::InputArgList &args) {
- auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
- OPT_no_color_diagnostics);
+ auto *arg = args.getLastArg(OPT_color_diagnostics);
if (!arg)
return;
- if (arg->getOption().getID() == OPT_color_diagnostics) {
+ StringRef s = arg->getValue();
+ if (s == "always")
lld::errs().enable_colors(true);
- } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
+ else if (s == "never")
lld::errs().enable_colors(false);
- } else {
- StringRef s = arg->getValue();
- if (s == "always")
- lld::errs().enable_colors(true);
- else if (s == "never")
- lld::errs().enable_colors(false);
- else if (s != "auto")
- error("unknown option: --color-diagnostics=" + s);
- }
+ else if (s != "auto")
+ error("unknown option: --color-diagnostics=" + s);
}
static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {
@@ -187,6 +180,7 @@ std::string elf::createResponseFile(const opt::InputArgList &args) {
break;
case OPT_call_graph_ordering_file:
case OPT_dynamic_list:
+ case OPT_export_dynamic_symbol_list:
case OPT_just_symbols:
case OPT_library_path:
case OPT_retain_symbols_file:
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index c0076a3722fe..927dc272b532 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -460,9 +460,9 @@ static void addDependentLibrary(StringRef specifier, const InputFile *f) {
if (!config->dependentLibraries)
return;
if (Optional<std::string> s = searchLibraryBaseName(specifier))
- driver->addFile(*s, /*withLOption=*/true);
+ driver->addFile(saver().save(*s), /*withLOption=*/true);
else if (Optional<std::string> s = findFromSearchPaths(specifier))
- driver->addFile(*s, /*withLOption=*/true);
+ driver->addFile(saver().save(*s), /*withLOption=*/true);
else if (fs::exists(specifier))
driver->addFile(specifier, /*withLOption=*/false);
else
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 3be42904b7fe..9f30117c0279 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -112,9 +112,9 @@ static StringRef getOutputSectionName(const InputSectionBase *s) {
uint64_t ExprValue::getValue() const {
if (sec)
- return alignTo(sec->getOutputSection()->addr + sec->getOffset(val),
- alignment);
- return alignTo(val, alignment);
+ return alignToPowerOf2(sec->getOutputSection()->addr + sec->getOffset(val),
+ alignment);
+ return alignToPowerOf2(val, alignment);
}
uint64_t ExprValue::getSecAddr() const {
@@ -989,7 +989,7 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
// sec->alignment is the max of ALIGN and the maximum of input
// section alignments.
const uint64_t pos = dot;
- dot = alignTo(dot, sec->alignment);
+ dot = alignToPowerOf2(dot, sec->alignment);
sec->addr = dot;
expandMemoryRegions(dot - pos);
}
@@ -1003,7 +1003,7 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
if (sec->lmaExpr) {
ctx->lmaOffset = sec->lmaExpr().getValue() - dot;
} else if (MemoryRegion *mr = sec->lmaRegion) {
- uint64_t lmaStart = alignTo(mr->curPos, sec->alignment);
+ uint64_t lmaStart = alignToPowerOf2(mr->curPos, sec->alignment);
if (mr->curPos < lmaStart)
expandMemoryRegion(mr, lmaStart - mr->curPos, sec->name);
ctx->lmaOffset = lmaStart - dot;
@@ -1046,7 +1046,7 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
for (InputSection *isec : cast<InputSectionDescription>(cmd)->sections) {
assert(isec->getParent() == sec);
const uint64_t pos = dot;
- dot = alignTo(dot, isec->alignment);
+ dot = alignToPowerOf2(dot, isec->alignment);
isec->outSecOff = dot - sec->addr;
dot += isec->getSize();
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index c98d21717de0..80c0ff9fe1b8 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -50,10 +50,9 @@ def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">
def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
-def build_id: F<"build-id">, HelpText<"Alias for --build-id=fast">;
-
-def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">,
+def build_id: J<"build-id=">, HelpText<"Generate build ID note">,
MetaVarName<"[fast,md5,sha1,uuid,0x<hexstring>]">;
+def : F<"build-id">, Alias<build_id>, AliasArgs<["fast"]>, HelpText<"Alias for --build-id=fast">;
defm check_sections: B<"check-sections",
"Check section addresses for overlaps (default)",
@@ -119,12 +118,13 @@ defm call_graph_profile_sort: BB<"call-graph-profile-sort",
// --chroot doesn't have a help text because it is an internal option.
def chroot: Separate<["--"], "chroot">;
-defm color_diagnostics: BB<"color-diagnostics",
- "Alias for --color-diagnostics=always",
- "Alias for --color-diagnostics=never">;
-def color_diagnostics_eq: JJ<"color-diagnostics=">,
+def color_diagnostics: JJ<"color-diagnostics=">,
HelpText<"Use colors in diagnostics (default: auto)">,
MetaVarName<"[auto,always,never]">;
+def : Flag<["--"], "color-diagnostics">, Alias<color_diagnostics>, AliasArgs<["always"]>,
+ HelpText<"Alias for --color-diagnostics=always">;
+def : Flag<["--"], "no-color-diagnostics">, Alias<color_diagnostics>, AliasArgs<["never"]>,
+ HelpText<"Alias for --color-diagnostics=never">;
def cref: FF<"cref">,
HelpText<"Output cross reference table. If -Map is specified, print to the map file">;
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 4d73541b3d42..7fc50b293b15 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -1392,7 +1392,7 @@ Expr ScriptParser::readPrimary() {
Expr e = readExpr();
if (consume(")")) {
e = checkAlignment(e, location);
- return [=] { return alignTo(script->getDot(), e().getValue()); };
+ return [=] { return alignToPowerOf2(script->getDot(), e().getValue()); };
}
expect(",");
Expr e2 = checkAlignment(readExpr(), location);
@@ -1423,7 +1423,8 @@ Expr ScriptParser::readPrimary() {
expect(")");
seenDataAlign = true;
return [=] {
- return alignTo(script->getDot(), std::max((uint64_t)1, e().getValue()));
+ uint64_t align = std::max(uint64_t(1), e().getValue());
+ return (script->getDot() + align - 1) & -align;
};
}
if (tok == "DATA_SEGMENT_END") {
@@ -1443,7 +1444,7 @@ Expr ScriptParser::readPrimary() {
expect(")");
seenRelroEnd = true;
Expr e = getPageSize();
- return [=] { return alignTo(script->getDot(), e().getValue()); };
+ return [=] { return alignToPowerOf2(script->getDot(), e().getValue()); };
}
if (tok == "DEFINED") {
StringRef name = unquote(readParenLiteral());
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index a0c5e6d04748..919afc7a6e0e 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -498,7 +498,7 @@ void EhFrameSection::iterateFDEWithLSDA(
static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) {
memcpy(buf, d.data(), d.size());
- size_t aligned = alignTo(d.size(), config->wordsize);
+ size_t aligned = alignToPowerOf2(d.size(), config->wordsize);
assert(std::all_of(buf + d.size(), buf + aligned,
[](uint8_t c) { return c == 0; }));
@@ -533,11 +533,11 @@ void EhFrameSection::finalizeContents() {
size_t off = 0;
for (CieRecord *rec : cieRecords) {
rec->cie->outputOff = off;
- off += alignTo(rec->cie->size, config->wordsize);
+ off += alignToPowerOf2(rec->cie->size, config->wordsize);
for (EhSectionPiece *fde : rec->fdes) {
fde->outputOff = off;
- off += alignTo(fde->size, config->wordsize);
+ off += alignToPowerOf2(fde->size, config->wordsize);
}
}
@@ -919,7 +919,7 @@ void MipsGotSection::build() {
for (SectionCommand *cmd : os->commands) {
if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
for (InputSection *isec : isd->sections) {
- uint64_t off = alignTo(secSize, isec->alignment);
+ uint64_t off = alignToPowerOf2(secSize, isec->alignment);
secSize = off + isec->getSize();
}
}
@@ -3330,7 +3330,7 @@ void MergeNoTailSection::finalizeContents() {
for (size_t i = 0; i < numShards; ++i) {
shards[i].finalizeInOrder();
if (shards[i].getSize() > 0)
- off = alignTo(off, alignment);
+ off = alignToPowerOf2(off, alignment);
shardOffsets[i] = off;
off += shards[i].getSize();
}
@@ -3612,7 +3612,7 @@ InputSection *ThunkSection::getTargetInputSection() const {
bool ThunkSection::assignOffsets() {
uint64_t off = 0;
for (Thunk *t : thunks) {
- off = alignTo(off, t->alignment);
+ off = alignToPowerOf2(off, t->alignment);
t->setOffset(off);
uint32_t size = t->size();
t->getThunkTargetSym()->size = size;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 2994e79cd1de..c9345d812270 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -2483,7 +2483,7 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
(prev->p_flags & PF_X) != (p->p_flags & PF_X)) ||
cmd->type == SHT_LLVM_PART_EHDR)
cmd->addrExpr = [] {
- return alignTo(script->getDot(), config->maxPageSize);
+ return alignToPowerOf2(script->getDot(), config->maxPageSize);
};
// PT_TLS is at the start of the first RW PT_LOAD. If `p` includes PT_TLS,
// it must be the RW. Align to p_align(PT_TLS) to make sure
@@ -2500,13 +2500,13 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
// blocks correctly. We need to keep the workaround for a while.
else if (Out::tlsPhdr && Out::tlsPhdr->firstSec == p->firstSec)
cmd->addrExpr = [] {
- return alignTo(script->getDot(), config->maxPageSize) +
- alignTo(script->getDot() % config->maxPageSize,
- Out::tlsPhdr->p_align);
+ return alignToPowerOf2(script->getDot(), config->maxPageSize) +
+ alignToPowerOf2(script->getDot() % config->maxPageSize,
+ Out::tlsPhdr->p_align);
};
else
cmd->addrExpr = [] {
- return alignTo(script->getDot(), config->maxPageSize) +
+ return alignToPowerOf2(script->getDot(), config->maxPageSize) +
script->getDot() % config->maxPageSize;
};
}
@@ -2540,7 +2540,7 @@ static uint64_t computeFileOffset(OutputSection *os, uint64_t off) {
// If the section is not in a PT_LOAD, we just have to align it.
if (!os->ptLoad)
- return alignTo(off, os->alignment);
+ return alignToPowerOf2(off, os->alignment);
// If two sections share the same PT_LOAD the file offset is calculated
// using this formula: Off2 = Off1 + (VA2 - VA1).
@@ -2599,15 +2599,15 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
// following section to avoid loading non-segments parts of the file.
if (config->zSeparate != SeparateSegmentKind::None && lastRX &&
lastRX->lastSec == sec)
- off = alignTo(off, config->maxPageSize);
+ off = alignToPowerOf2(off, config->maxPageSize);
}
for (OutputSection *osec : outputSections)
if (!(osec->flags & SHF_ALLOC)) {
- osec->offset = alignTo(off, osec->alignment);
+ osec->offset = alignToPowerOf2(off, osec->alignment);
off = osec->offset + osec->size;
}
- sectionHeaderOff = alignTo(off, config->wordsize);
+ sectionHeaderOff = alignToPowerOf2(off, config->wordsize);
fileSize = sectionHeaderOff + (outputSections.size() + 1) * sizeof(Elf_Shdr);
// Our logic assumes that sections have rising VA within the same segment.
@@ -2659,8 +2659,9 @@ template <class ELFT> void Writer<ELFT>::setPhdrs(Partition &part) {
// musl/glibc ld.so rounds the size down, so we need to round up
// to protect the last page. This is a no-op on FreeBSD which always
// rounds up.
- p->p_memsz = alignTo(p->p_offset + p->p_memsz, config->commonPageSize) -
- p->p_offset;
+ p->p_memsz =
+ alignToPowerOf2(p->p_offset + p->p_memsz, config->commonPageSize) -
+ p->p_offset;
}
}
}
@@ -2880,8 +2881,9 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
if (p->p_type == PT_LOAD && (p->p_flags & PF_X))
fillTrap(Out::bufferStart +
alignDown(p->firstSec->offset + p->p_filesz, 4),
- Out::bufferStart + alignTo(p->firstSec->offset + p->p_filesz,
- config->maxPageSize));
+ Out::bufferStart +
+ alignToPowerOf2(p->firstSec->offset + p->p_filesz,
+ config->maxPageSize));
// Round up the file size of the last segment to the page boundary iff it is
// an executable segment to ensure that other tools don't accidentally
@@ -2893,7 +2895,7 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
if (last && (last->p_flags & PF_X))
last->p_memsz = last->p_filesz =
- alignTo(last->p_filesz, config->maxPageSize);
+ alignToPowerOf2(last->p_filesz, config->maxPageSize);
}
}
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 454708fad4ef..ce2d55bef456 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -266,7 +266,8 @@ static DenseMap<StringRef, ArchiveFileInfo> loadedArchives;
static InputFile *addFile(StringRef path, LoadType loadType,
bool isLazy = false, bool isExplicit = true,
- bool isBundleLoader = false) {
+ bool isBundleLoader = false,
+ bool isForceHidden = false) {
Optional<MemoryBufferRef> buffer = readFile(path);
if (!buffer)
return nullptr;
@@ -293,7 +294,7 @@ static InputFile *addFile(StringRef path, LoadType loadType,
if (!archive->isEmpty() && !archive->hasSymbolTable())
error(path + ": archive has no index; run ranlib to add one");
- file = make<ArchiveFile>(std::move(archive));
+ file = make<ArchiveFile>(std::move(archive), isForceHidden);
} else {
file = entry->second.file;
// Command-line loads take precedence. If file is previously loaded via
@@ -406,10 +407,12 @@ static InputFile *addFile(StringRef path, LoadType loadType,
}
static void addLibrary(StringRef name, bool isNeeded, bool isWeak,
- bool isReexport, bool isExplicit, LoadType loadType) {
+ bool isReexport, bool isHidden, bool isExplicit,
+ LoadType loadType) {
if (Optional<StringRef> path = findLibrary(name)) {
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
- addFile(*path, loadType, /*isLazy=*/false, isExplicit))) {
+ addFile(*path, loadType, /*isLazy=*/false, isExplicit,
+ /*isBundleLoader=*/false, isHidden))) {
if (isNeeded)
dylibFile->forceNeeded = true;
if (isWeak)
@@ -473,7 +476,7 @@ void macho::parseLCLinkerOption(InputFile *f, unsigned argc, StringRef data) {
StringRef arg = argv[i];
if (arg.consume_front("-l")) {
addLibrary(arg, /*isNeeded=*/false, /*isWeak=*/false,
- /*isReexport=*/false, /*isExplicit=*/false,
+ /*isReexport=*/false, /*isHidden=*/false, /*isExplicit=*/false,
LoadType::LCLinkerOption);
} else if (arg == "-framework") {
StringRef name = argv[++i];
@@ -1035,12 +1038,19 @@ static void createFiles(const InputArgList &args) {
case OPT_force_load:
addFile(rerootPath(arg->getValue()), LoadType::CommandLineForce);
break;
+ case OPT_load_hidden:
+ addFile(rerootPath(arg->getValue()), LoadType::CommandLine,
+ /*isLazy=*/false, /*isExplicit=*/true, /*isBundleLoader=*/false,
+ /*isForceHidden=*/true);
+ break;
case OPT_l:
case OPT_needed_l:
case OPT_reexport_l:
case OPT_weak_l:
+ case OPT_hidden_l:
addLibrary(arg->getValue(), opt.getID() == OPT_needed_l,
opt.getID() == OPT_weak_l, opt.getID() == OPT_reexport_l,
+ opt.getID() == OPT_hidden_l,
/*isExplicit=*/true, LoadType::CommandLine);
break;
case OPT_framework:
diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp
index b52d5e851c62..d8e474d15cfd 100644
--- a/lld/MachO/DriverUtils.cpp
+++ b/lld/MachO/DriverUtils.cpp
@@ -150,6 +150,7 @@ std::string macho::createResponseFile(const InputArgList &args) {
break;
case OPT_force_load:
case OPT_weak_library:
+ case OPT_load_hidden:
os << arg->getSpelling() << " "
<< quote(rewriteInputPath(arg->getValue())) << "\n";
break;
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index e3bf553e5334..b463d7817594 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -768,7 +768,7 @@ void ObjFile::parseRelocations(ArrayRef<SectionHeader> sectionHeaders,
template <class NList>
static macho::Symbol *createDefined(const NList &sym, StringRef name,
InputSection *isec, uint64_t value,
- uint64_t size) {
+ uint64_t size, bool forceHidden) {
// Symbol scope is determined by sym.n_type & (N_EXT | N_PEXT):
// N_EXT: Global symbols. These go in the symbol table during the link,
// and also in the export table of the output so that the dynamic
@@ -787,7 +787,10 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
(sym.n_desc & (N_WEAK_DEF | N_WEAK_REF)) == (N_WEAK_DEF | N_WEAK_REF);
if (sym.n_type & N_EXT) {
- bool isPrivateExtern = sym.n_type & N_PEXT;
+ // -load_hidden makes us treat global symbols as linkage unit scoped.
+ // Duplicates are reported but the symbol does not go in the export trie.
+ bool isPrivateExtern = sym.n_type & N_PEXT || forceHidden;
+
// lld's behavior for merging symbols is slightly different from ld64:
// ld64 picks the winning symbol based on several criteria (see
// pickBetweenRegularAtoms() in ld64's SymbolTable.cpp), while lld
@@ -844,11 +847,12 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
// InputSection. They cannot be weak.
template <class NList>
static macho::Symbol *createAbsolute(const NList &sym, InputFile *file,
- StringRef name) {
+ StringRef name, bool forceHidden) {
if (sym.n_type & N_EXT) {
+ bool isPrivateExtern = sym.n_type & N_PEXT || forceHidden;
return symtab->addDefined(
name, file, nullptr, sym.n_value, /*size=*/0,
- /*isWeakDef=*/false, sym.n_type & N_PEXT, sym.n_desc & N_ARM_THUMB_DEF,
+ /*isWeakDef=*/false, isPrivateExtern, sym.n_desc & N_ARM_THUMB_DEF,
/*isReferencedDynamically=*/false, sym.n_desc & N_NO_DEAD_STRIP,
/*isWeakDefCanBeHidden=*/false);
}
@@ -864,15 +868,16 @@ template <class NList>
macho::Symbol *ObjFile::parseNonSectionSymbol(const NList &sym,
StringRef name) {
uint8_t type = sym.n_type & N_TYPE;
+ bool isPrivateExtern = sym.n_type & N_PEXT || forceHidden;
switch (type) {
case N_UNDF:
return sym.n_value == 0
? symtab->addUndefined(name, this, sym.n_desc & N_WEAK_REF)
: symtab->addCommon(name, this, sym.n_value,
1 << GET_COMM_ALIGN(sym.n_desc),
- sym.n_type & N_PEXT);
+ isPrivateExtern);
case N_ABS:
- return createAbsolute(sym, this, name);
+ return createAbsolute(sym, this, name, forceHidden);
case N_PBUD:
case N_INDR:
error("TODO: support symbols of type " + std::to_string(type));
@@ -944,7 +949,8 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
" at misaligned offset");
continue;
}
- symbols[symIndex] = createDefined(sym, name, isec, 0, isec->getSize());
+ symbols[symIndex] =
+ createDefined(sym, name, isec, 0, isec->getSize(), forceHidden);
}
continue;
}
@@ -979,8 +985,8 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
// 4. If we have a literal section (e.g. __cstring and __literal4).
if (!subsectionsViaSymbols || symbolOffset == 0 ||
sym.n_desc & N_ALT_ENTRY || !isa<ConcatInputSection>(isec)) {
- symbols[symIndex] =
- createDefined(sym, name, isec, symbolOffset, symbolSize);
+ symbols[symIndex] = createDefined(sym, name, isec, symbolOffset,
+ symbolSize, forceHidden);
continue;
}
auto *concatIsec = cast<ConcatInputSection>(isec);
@@ -998,8 +1004,8 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
// By construction, the symbol will be at offset zero in the new
// subsection.
- symbols[symIndex] =
- createDefined(sym, name, nextIsec, /*value=*/0, symbolSize);
+ symbols[symIndex] = createDefined(sym, name, nextIsec, /*value=*/0,
+ symbolSize, forceHidden);
// TODO: ld64 appears to preserve the original alignment as well as each
// subsection's offset from the last aligned address. We should consider
// emulating that behavior.
@@ -1036,8 +1042,8 @@ OpaqueFile::OpaqueFile(MemoryBufferRef mb, StringRef segName,
}
ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName,
- bool lazy)
- : InputFile(ObjKind, mb, lazy), modTime(modTime) {
+ bool lazy, bool forceHidden)
+ : InputFile(ObjKind, mb, lazy), modTime(modTime), forceHidden(forceHidden) {
this->archiveName = std::string(archiveName);
if (lazy) {
if (target->wordSize == 8)
@@ -2061,26 +2067,27 @@ void DylibFile::checkAppExtensionSafety(bool dylibIsAppExtensionSafe) const {
warn("using '-application_extension' with unsafe dylib: " + toString(this));
}
-ArchiveFile::ArchiveFile(std::unique_ptr<object::Archive> &&f)
- : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)) {}
+ArchiveFile::ArchiveFile(std::unique_ptr<object::Archive> &&f, bool forceHidden)
+ : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)),
+ forceHidden(forceHidden) {}
void ArchiveFile::addLazySymbols() {
for (const object::Archive::Symbol &sym : file->symbols())
symtab->addLazyArchive(sym.getName(), this, sym);
}
-static Expected<InputFile *> loadArchiveMember(MemoryBufferRef mb,
- uint32_t modTime,
- StringRef archiveName,
- uint64_t offsetInArchive) {
+static Expected<InputFile *>
+loadArchiveMember(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName,
+ uint64_t offsetInArchive, bool forceHidden) {
if (config->zeroModTime)
modTime = 0;
switch (identify_magic(mb.getBuffer())) {
case file_magic::macho_object:
- return make<ObjFile>(mb, modTime, archiveName);
+ return make<ObjFile>(mb, modTime, archiveName, /*lazy=*/false, forceHidden);
case file_magic::bitcode:
- return make<BitcodeFile>(mb, archiveName, offsetInArchive);
+ return make<BitcodeFile>(mb, archiveName, offsetInArchive, /*lazy=*/false,
+ forceHidden);
default:
return createStringError(inconvertibleErrorCode(),
mb.getBufferIdentifier() +
@@ -2104,8 +2111,8 @@ Error ArchiveFile::fetch(const object::Archive::Child &c, StringRef reason) {
if (!modTime)
return modTime.takeError();
- Expected<InputFile *> file =
- loadArchiveMember(*mb, toTimeT(*modTime), getName(), c.getChildOffset());
+ Expected<InputFile *> file = loadArchiveMember(
+ *mb, toTimeT(*modTime), getName(), c.getChildOffset(), forceHidden);
if (!file)
return file.takeError();
@@ -2153,7 +2160,8 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
case GlobalValue::DefaultVisibility:
break;
}
- isPrivateExtern = isPrivateExtern || objSym.canBeOmittedFromSymbolTable();
+ isPrivateExtern = isPrivateExtern || objSym.canBeOmittedFromSymbolTable() ||
+ file.forceHidden;
if (objSym.isCommon())
return symtab->addCommon(name, &file, objSym.getCommonSize(),
@@ -2168,8 +2176,8 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
}
BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive, bool lazy)
- : InputFile(BitcodeKind, mb, lazy) {
+ uint64_t offsetInArchive, bool lazy, bool forceHidden)
+ : InputFile(BitcodeKind, mb, lazy), forceHidden(forceHidden) {
this->archiveName = std::string(archiveName);
std::string path = mb.getBufferIdentifier().str();
// ThinLTO assumes that all MemoryBufferRefs given to it have a unique
diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h
index 5deb05272a6b..ea6802814e4c 100644
--- a/lld/MachO/InputFiles.h
+++ b/lld/MachO/InputFiles.h
@@ -156,7 +156,7 @@ struct FDE {
class ObjFile final : public InputFile {
public:
ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName,
- bool lazy = false);
+ bool lazy = false, bool forceHidden = false);
ArrayRef<llvm::MachO::data_in_code_entry> getDataInCode() const;
template <class LP> void parse();
@@ -171,6 +171,7 @@ public:
std::unique_ptr<lld::DWARFCache> dwarfCache;
Section *addrSigSection = nullptr;
const uint32_t modTime;
+ bool forceHidden;
std::vector<ConcatInputSection *> debugSections;
std::vector<CallGraphEntry> callGraph;
llvm::DenseMap<ConcatInputSection *, FDE> fdes;
@@ -259,7 +260,8 @@ private:
// .a file
class ArchiveFile final : public InputFile {
public:
- explicit ArchiveFile(std::unique_ptr<llvm::object::Archive> &&file);
+ explicit ArchiveFile(std::unique_ptr<llvm::object::Archive> &&file,
+ bool forceHidden);
void addLazySymbols();
void fetch(const llvm::object::Archive::Symbol &);
// LLD normally doesn't use Error for error-handling, but the underlying
@@ -273,16 +275,20 @@ private:
// Keep track of children fetched from the archive by tracking
// which address offsets have been fetched already.
llvm::DenseSet<uint64_t> seen;
+ // Load all symbols with hidden visibility (-load_hidden).
+ bool forceHidden;
};
class BitcodeFile final : public InputFile {
public:
explicit BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive, bool lazy = false);
+ uint64_t offsetInArchive, bool lazy = false,
+ bool forceHidden = false);
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
void parse();
std::unique_ptr<llvm::lto::InputFile> obj;
+ bool forceHidden;
private:
void parseLazy();
diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp
index 76b11d9da4f8..ca073f8ac6f3 100644
--- a/lld/MachO/InputSection.cpp
+++ b/lld/MachO/InputSection.cpp
@@ -67,7 +67,7 @@ std::string InputSection::getLocation(uint64_t off) const {
// First, try to find a symbol that's near the offset. Use it as a reference
// point.
if (auto *sym = getContainingSymbol(off))
- return (toString(getFile()) + ":(symbol " + sym->getName() + "+0x" +
+ return (toString(getFile()) + ":(symbol " + toString(*sym) + "+0x" +
Twine::utohexstr(off - sym->value) + ")")
.str();
diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index b3d74a83f582..064862fb1bb0 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -240,6 +240,14 @@ def force_load : Separate<["-"], "force_load">,
def force_load_swift_libs : Flag<["-"], "force_load_swift_libs">,
HelpText<"Apply -force_load to libraries listed in LC_LINKER_OPTIONS whose names start with 'swift'">,
Group<grp_libs>;
+def load_hidden : Separate<["-"], "load_hidden">,
+ MetaVarName<"<path>">,
+ HelpText<"Load all symbols from static library with hidden visibility">,
+ Group<grp_libs>;
+def hidden_l : Joined<["-"], "hidden-l">,
+ MetaVarName<"<name>">,
+ HelpText<"Like -l<name>, but load all symbols with hidden visibility">,
+ Group<grp_libs>;
def grp_content : OptionGroup<"content">, HelpText<"ADDITIONAL CONTENT">;
@@ -1174,7 +1182,7 @@ def allow_simulator_linking_to_macosx_dylibs : Flag<["-"], "allow_simulator_link
HelpText<"This option is undocumented in ld64">,
Flags<[HelpHidden]>,
Group<grp_undocumented>;
-def bitcode_process_mode : Flag<["-"], "bitcode_process_mode">,
+def bitcode_process_mode : Separate<["-"], "bitcode_process_mode">,
HelpText<"This option is undocumented in ld64">,
Flags<[HelpHidden]>,
Group<grp_undocumented>;
diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index afdd46d8a7de..29c2d98c6625 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -70,7 +70,7 @@ public:
// Sections in __LINKEDIT are special: their offsets are recorded in the
// load commands like LC_DYLD_INFO_ONLY and LC_SYMTAB, instead of in section
// headers.
- bool isHidden() const override final { return true; }
+ bool isHidden() const final { return true; }
virtual uint64_t getRawSize() const = 0;
@@ -80,9 +80,7 @@ public:
//
// NOTE: This assumes that the extra bytes required for alignment can be
// zero-valued bytes.
- uint64_t getSize() const override final {
- return llvm::alignTo(getRawSize(), align);
- }
+ uint64_t getSize() const final { return llvm::alignTo(getRawSize(), align); }
};
// The header of the Mach-O file, which must have a file offset of zero.
diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h
index 2cb983c40d19..b9ac0a5bca39 100644
--- a/lldb/include/lldb/Core/Disassembler.h
+++ b/lldb/include/lldb/Core/Disassembler.h
@@ -83,7 +83,10 @@ public:
/// The control flow kind of this instruction, or
/// eInstructionControlFlowKindUnknown if the instruction
/// can't be classified.
- lldb::InstructionControlFlowKind GetControlFlowKind(const ArchSpec &arch);
+ virtual lldb::InstructionControlFlowKind
+ GetControlFlowKind(const ExecutionContext *exe_ctx) {
+ return lldb::eInstructionControlFlowKindUnknown;
+ }
virtual void
CalculateMnemonicOperandsAndComment(const ExecutionContext *exe_ctx) = 0;
@@ -223,6 +226,9 @@ public:
virtual bool IsCall() { return false; }
+ static const char *GetNameForInstructionControlFlowKind(
+ lldb::InstructionControlFlowKind instruction_control_flow_kind);
+
protected:
Address m_address; // The section offset address of this instruction
// We include an address class in the Instruction class to
diff --git a/lldb/include/lldb/Target/MemoryTagManager.h b/lldb/include/lldb/Target/MemoryTagManager.h
index 28a8acc34632..b082224c38ed 100644
--- a/lldb/include/lldb/Target/MemoryTagManager.h
+++ b/lldb/include/lldb/Target/MemoryTagManager.h
@@ -113,6 +113,21 @@ public:
UnpackTagsData(const std::vector<uint8_t> &tags,
size_t granules = 0) const = 0;
+ // Unpack tags from a corefile segment containing compressed tags
+ // (compression that may be different from the one used for GDB transport).
+ //
+ // This method asumes that:
+ // * addr and len have been granule aligned by a tag manager
+ // * addr >= tag_segment_virtual_address
+ //
+ // 'reader' will always be a wrapper around a CoreFile in real use
+ // but allows testing without having to mock a CoreFile.
+ typedef std::function<size_t(lldb::offset_t, size_t, void *)> CoreReaderFn;
+ std::vector<lldb::addr_t> virtual UnpackTagsFromCoreFileSegment(
+ CoreReaderFn reader, lldb::addr_t tag_segment_virtual_address,
+ lldb::addr_t tag_segment_data_address, lldb::addr_t addr,
+ size_t len) const = 0;
+
// Pack uncompressed tags into their storage format (e.g. for gdb QMemTags).
// Checks that each tag is within the expected value range.
// We do not check the number of tags or range they apply to because
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index a55659225ef1..505e211e09b6 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1715,8 +1715,8 @@ public:
/// an error saying so.
/// If it does, either the memory tags or an error describing a
/// failure to read or unpack them.
- llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr,
- size_t len);
+ virtual llvm::Expected<std::vector<lldb::addr_t>>
+ ReadMemoryTags(lldb::addr_t addr, size_t len);
/// Write memory tags for a range of memory.
/// (calls DoWriteMemoryTags to do the target specific work)
diff --git a/lldb/include/lldb/Target/TraceCursor.h b/lldb/include/lldb/Target/TraceCursor.h
index f6337e3d3d3f..95b022331634 100644
--- a/lldb/include/lldb/Target/TraceCursor.h
+++ b/lldb/include/lldb/Target/TraceCursor.h
@@ -215,7 +215,7 @@ public:
/// of this cursor.
ExecutionContextRef &GetExecutionContextRef();
- /// Instruction, event or error information
+ /// Trace item information (instructions, errors and events)
/// \{
/// \return
@@ -255,27 +255,35 @@ public:
/// The load address of the instruction the cursor is pointing at.
virtual lldb::addr_t GetLoadAddress() const = 0;
- /// Get the hardware counter of a given type associated with the current
- /// instruction. Each architecture might support different counters. It might
- /// happen that only some instructions of an entire trace have a given counter
- /// associated with them.
- ///
- /// \param[in] counter_type
- /// The counter type.
- /// \return
- /// The value of the counter or \b llvm::None if not available.
- virtual llvm::Optional<uint64_t>
- GetCounter(lldb::TraceCounter counter_type) const = 0;
-
/// Get the CPU associated with the current trace item.
///
/// This call might not be O(1), so it's suggested to invoke this method
- /// whenever a cpu change event is fired.
+ /// whenever an eTraceEventCPUChanged event is fired.
///
/// \return
/// The requested CPU id, or \a llvm::None if this information is
/// not available for the current item.
virtual llvm::Optional<lldb::cpu_id_t> GetCPU() const = 0;
+
+ /// Get the last hardware clock value that was emitted before the current
+ /// trace item.
+ ///
+ /// This call might not be O(1), so it's suggested to invoke this method
+ /// whenever an eTraceEventHWClockTick event is fired.
+ ///
+ /// \return
+ /// The requested HW clock value, or \a llvm::None if this information is
+ /// not available for the current item.
+ virtual llvm::Optional<uint64_t> GetHWClock() const = 0;
+
+ /// Get the approximate wall clock time in nanoseconds at which the current
+ /// trace item was executed. Each trace plug-in has a different definition for
+ /// what time 0 means.
+ ///
+ /// \return
+ /// The approximate wall clock time for the trace item, or \a llvm::None
+ /// if not available.
+ virtual llvm::Optional<double> GetWallClockTime() const = 0;
/// \}
protected:
diff --git a/lldb/include/lldb/Target/TraceDumper.h b/lldb/include/lldb/Target/TraceDumper.h
index bbc1a55873d7..ada779990e07 100644
--- a/lldb/include/lldb/Target/TraceDumper.h
+++ b/lldb/include/lldb/Target/TraceDumper.h
@@ -29,9 +29,9 @@ struct TraceDumperOptions {
bool json = false;
/// When dumping in JSON format, pretty print the output.
bool pretty_print_json = false;
- /// For each instruction, print the corresponding timestamp counter if
+ /// For each trace item, print the corresponding timestamp in nanoseconds if
/// available.
- bool show_tsc = false;
+ bool show_timestamps = false;
/// Dump the events that happened between instructions.
bool show_events = false;
/// For each instruction, print the instruction kind.
@@ -61,7 +61,8 @@ public:
struct TraceItem {
lldb::user_id_t id;
lldb::addr_t load_address;
- llvm::Optional<uint64_t> tsc;
+ llvm::Optional<double> timestamp;
+ llvm::Optional<uint64_t> hw_clock;
llvm::Optional<llvm::StringRef> error;
llvm::Optional<lldb::TraceEvent> event;
llvm::Optional<SymbolInfo> symbol_info;
diff --git a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
index bf9409743a6d..5930cd9970e7 100644
--- a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -91,8 +91,8 @@ struct LinuxPerfZeroTscConversion {
/// nanoseconds) is defined by the kernel at boot time and has no particularly
/// useful meaning. On the other hand, this value is constant for an entire
/// trace session.
- // See 'time_zero' section of
- // https://man7.org/linux/man-pages/man2/perf_event_open.2.html
+ /// See 'time_zero' section of
+ /// https://man7.org/linux/man-pages/man2/perf_event_open.2.html
///
/// \param[in] tsc
/// The TSC value to be converted.
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 974cc293709e..2566a43daac8 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -1159,12 +1159,6 @@ enum SaveCoreStyle {
eSaveCoreStackOnly = 3,
};
-// Type of counter values associated with instructions in a trace.
-enum TraceCounter {
- // Timestamp counter, like the one offered by Intel CPUs (TSC).
- eTraceCounterTSC = 0,
-};
-
/// Events that might happen during a trace session.
enum TraceEvent {
/// Tracing was disabled for some time due to a software trigger
@@ -1174,6 +1168,8 @@ enum TraceEvent {
/// Event due to CPU change for a thread. This event is also fired when
/// suddenly it's not possible to identify the cpu of a given thread.
eTraceEventCPUChanged,
+ /// Event due to a CPU HW clock tick
+ eTraceEventHWClockTick,
};
// Enum used to identify which kind of item a \a TraceCursor is pointing at
diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp
index a11e2b719727..e65e12fe557a 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.cpp
+++ b/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -216,8 +216,7 @@ CommandObjectDisassemble::CommandObjectDisassemble(
"Disassemble specified instructions in the current target. "
"Defaults to the current function for the current thread and "
"stack frame.",
- "disassemble [<cmd-options>]", eCommandRequiresTarget),
- m_options() {}
+ "disassemble [<cmd-options>]", eCommandRequiresTarget) {}
CommandObjectDisassemble::~CommandObjectDisassemble() = default;
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index 0fb50420f70f..083309121b66 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -187,7 +187,7 @@ CommandObjectExpression::CommandObjectExpression(
m_format_options(eFormatDefault),
m_repl_option(LLDB_OPT_SET_1, false, "repl", 'r', "Drop into REPL", false,
true),
- m_command_options(), m_expr_line_count(0) {
+ m_expr_line_count(0) {
SetHelpLong(
R"(
Single and multi-line expressions:
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
index ca0384cf9453..5051f9aeec85 100644
--- a/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -1659,7 +1659,7 @@ class CommandObjectMemoryRegion : public CommandObjectParsed {
public:
class OptionGroupMemoryRegion : public OptionGroup {
public:
- OptionGroupMemoryRegion() : OptionGroup(), m_all(false, false) {}
+ OptionGroupMemoryRegion() : m_all(false, false) {}
~OptionGroupMemoryRegion() override = default;
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index 1371b9dbda1e..fe0cb0945cde 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -2162,7 +2162,7 @@ public:
break;
}
case 't': {
- m_dumper_options.show_tsc = true;
+ m_dumper_options.show_timestamps = true;
break;
}
case 'e': {
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 78221db18e65..cc47db575306 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1146,15 +1146,17 @@ let Command = "thread trace dump instructions" in {
Desc<"Dump in simple JSON format.">;
def thread_trace_dump_instructions_pretty_print: Option<"pretty-json", "J">,
Group<1>,
- Desc<"Dump in JSON format but pretty printing the output for easier readability.">;
+ Desc<"Dump in JSON format but pretty printing the output for easier "
+ "readability.">;
def thread_trace_dump_instructions_show_kind : Option<"kind", "k">, Group<1>,
Desc<"Show instruction control flow kind. Refer to the enum "
"`InstructionControlFlowKind` for a list of control flow kind. "
"As an important note, far jumps, far calls and far returns often indicate "
"calls to and from kernel.">;
- def thread_trace_dump_instructions_show_tsc : Option<"tsc", "t">, Group<1>,
- Desc<"For each instruction, print the corresponding timestamp counter if "
- "available.">;
+ def thread_trace_dump_instructions_show_timestamps: Option<"time", "t">,
+ Group<1>,
+ Desc<"For each trace item, print the corresponding wall clock timestamp "
+ "if available.">;
def thread_trace_dump_instructions_show_events : Option<"events", "e">,
Group<1>,
Desc<"Dump the events that happened during the execution of the target.">;
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
index 7a9e214748a7..4c57be44dc9c 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -571,340 +571,36 @@ Instruction::Instruction(const Address &address, AddressClass addr_class)
Instruction::~Instruction() = default;
-namespace x86 {
-
-/// These are the three values deciding instruction control flow kind.
-/// InstructionLengthDecode function decodes an instruction and get this struct.
-///
-/// primary_opcode
-/// Primary opcode of the instruction.
-/// For one-byte opcode instruction, it's the first byte after prefix.
-/// For two- and three-byte opcodes, it's the second byte.
-///
-/// opcode_len
-/// The length of opcode in bytes. Valid opcode lengths are 1, 2, or 3.
-///
-/// modrm
-/// ModR/M byte of the instruction.
-/// Bits[7:6] indicate MOD. Bits[5:3] specify a register and R/M bits[2:0]
-/// may contain a register or specify an addressing mode, depending on MOD.
-struct InstructionOpcodeAndModrm {
- uint8_t primary_opcode;
- uint8_t opcode_len;
- uint8_t modrm;
-};
-
-/// Determine the InstructionControlFlowKind based on opcode and modrm bytes.
-/// Refer to http://ref.x86asm.net/coder.html for the full list of opcode and
-/// instruction set.
-///
-/// \param[in] opcode_and_modrm
-/// Contains primary_opcode byte, its length, and ModR/M byte.
-/// Refer to the struct InstructionOpcodeAndModrm for details.
-///
-/// \return
-/// The control flow kind of the instruction or
-/// eInstructionControlFlowKindOther if the instruction doesn't affect
-/// the control flow of the program.
-lldb::InstructionControlFlowKind
-MapOpcodeIntoControlFlowKind(InstructionOpcodeAndModrm opcode_and_modrm) {
- uint8_t opcode = opcode_and_modrm.primary_opcode;
- uint8_t opcode_len = opcode_and_modrm.opcode_len;
- uint8_t modrm = opcode_and_modrm.modrm;
-
- if (opcode_len > 2)
- return lldb::eInstructionControlFlowKindOther;
-
- if (opcode >= 0x70 && opcode <= 0x7F) {
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindCondJump;
- else
- return lldb::eInstructionControlFlowKindOther;
- }
-
- if (opcode >= 0x80 && opcode <= 0x8F) {
- if (opcode_len == 2)
- return lldb::eInstructionControlFlowKindCondJump;
- else
- return lldb::eInstructionControlFlowKindOther;
- }
-
- switch (opcode) {
- case 0x9A:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarCall;
- break;
- case 0xFF:
- if (opcode_len == 1) {
- uint8_t modrm_reg = (modrm >> 3) & 7;
- if (modrm_reg == 2)
- return lldb::eInstructionControlFlowKindCall;
- else if (modrm_reg == 3)
- return lldb::eInstructionControlFlowKindFarCall;
- else if (modrm_reg == 4)
- return lldb::eInstructionControlFlowKindJump;
- else if (modrm_reg == 5)
- return lldb::eInstructionControlFlowKindFarJump;
- }
- break;
- case 0xE8:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindCall;
- break;
- case 0xCD:
- case 0xCC:
- case 0xCE:
- case 0xF1:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarCall;
- break;
- case 0xCF:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarReturn;
- break;
- case 0xE9:
- case 0xEB:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindJump;
- break;
- case 0xEA:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarJump;
- break;
- case 0xE3:
- case 0xE0:
- case 0xE1:
- case 0xE2:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindCondJump;
- break;
- case 0xC3:
- case 0xC2:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindReturn;
- break;
- case 0xCB:
- case 0xCA:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarReturn;
- break;
- case 0x05:
- case 0x34:
- if (opcode_len == 2)
- return lldb::eInstructionControlFlowKindFarCall;
- break;
- case 0x35:
- case 0x07:
- if (opcode_len == 2)
- return lldb::eInstructionControlFlowKindFarReturn;
- break;
- case 0x01:
- if (opcode_len == 2) {
- switch (modrm) {
- case 0xc1:
- return lldb::eInstructionControlFlowKindFarCall;
- case 0xc2:
- case 0xc3:
- return lldb::eInstructionControlFlowKindFarReturn;
- default:
- break;
- }
- }
- break;
- default:
- break;
- }
-
- return lldb::eInstructionControlFlowKindOther;
-}
-
-/// Decode an instruction into opcode, modrm and opcode_len.
-/// Refer to http://ref.x86asm.net/coder.html for the instruction bytes layout.
-/// Opcodes in x86 are generally the first byte of instruction, though two-byte
-/// instructions and prefixes exist. ModR/M is the byte following the opcode
-/// and adds additional information for how the instruction is executed.
-///
-/// \param[in] inst_bytes
-/// Raw bytes of the instruction
-///
-///
-/// \param[in] bytes_len
-/// The length of the inst_bytes array.
-///
-/// \param[in] is_exec_mode_64b
-/// If true, the execution mode is 64 bit.
-///
-/// \return
-/// Returns decoded instruction as struct InstructionOpcodeAndModrm, holding
-/// primary_opcode, opcode_len and modrm byte. Refer to the struct definition
-/// for more details.
-/// Otherwise if the given instruction is invalid, returns None.
-llvm::Optional<InstructionOpcodeAndModrm>
-InstructionLengthDecode(const uint8_t *inst_bytes, int bytes_len,
- bool is_exec_mode_64b) {
- int op_idx = 0;
- bool prefix_done = false;
- InstructionOpcodeAndModrm ret = {0, 0, 0};
-
- // In most cases, the primary_opcode is the first byte of the instruction
- // but some instructions have a prefix to be skipped for these calculations.
- // The following mapping is inspired from libipt's instruction decoding logic
- // in `src/pt_ild.c`
- while (!prefix_done) {
- if (op_idx >= bytes_len)
- return llvm::None;
-
- ret.primary_opcode = inst_bytes[op_idx];
- switch (ret.primary_opcode) {
- // prefix_ignore
- case 0x26:
- case 0x2e:
- case 0x36:
- case 0x3e:
- case 0x64:
- case 0x65:
- // prefix_osz, prefix_asz
- case 0x66:
- case 0x67:
- // prefix_lock, prefix_f2, prefix_f3
- case 0xf0:
- case 0xf2:
- case 0xf3:
- op_idx++;
- break;
-
- // prefix_rex
- case 0x40:
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x44:
- case 0x45:
- case 0x46:
- case 0x47:
- case 0x48:
- case 0x49:
- case 0x4a:
- case 0x4b:
- case 0x4c:
- case 0x4d:
- case 0x4e:
- case 0x4f:
- if (is_exec_mode_64b)
- op_idx++;
- else
- prefix_done = true;
- break;
-
- // prefix_vex_c4, c5
- case 0xc5:
- if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
- prefix_done = true;
- break;
- }
-
- ret.opcode_len = 2;
- ret.primary_opcode = inst_bytes[op_idx + 2];
- ret.modrm = inst_bytes[op_idx + 3];
- return ret;
-
- case 0xc4:
- if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
- prefix_done = true;
- break;
- }
- ret.opcode_len = inst_bytes[op_idx + 1] & 0x1f;
- ret.primary_opcode = inst_bytes[op_idx + 3];
- ret.modrm = inst_bytes[op_idx + 4];
- return ret;
-
- // prefix_evex
- case 0x62:
- if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
- prefix_done = true;
- break;
- }
- ret.opcode_len = inst_bytes[op_idx + 1] & 0x03;
- ret.primary_opcode = inst_bytes[op_idx + 4];
- ret.modrm = inst_bytes[op_idx + 5];
- return ret;
-
- default:
- prefix_done = true;
- break;
- }
- } // prefix done
-
- ret.primary_opcode = inst_bytes[op_idx];
- ret.modrm = inst_bytes[op_idx + 1];
- ret.opcode_len = 1;
-
- // If the first opcode is 0F, it's two- or three- byte opcodes.
- if (ret.primary_opcode == 0x0F) {
- ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
-
- if (ret.primary_opcode == 0x38) {
- ret.opcode_len = 3;
- ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
- ret.modrm = inst_bytes[op_idx + 1];
- } else if (ret.primary_opcode == 0x3A) {
- ret.opcode_len = 3;
- ret.primary_opcode = inst_bytes[++op_idx];
- ret.modrm = inst_bytes[op_idx + 1];
- } else if ((ret.primary_opcode & 0xf8) == 0x38) {
- ret.opcode_len = 0;
- ret.primary_opcode = inst_bytes[++op_idx];
- ret.modrm = inst_bytes[op_idx + 1];
- } else if (ret.primary_opcode == 0x0F) {
- ret.opcode_len = 3;
- // opcode is 0x0F, no needs to update
- ret.modrm = inst_bytes[op_idx + 1];
- } else {
- ret.opcode_len = 2;
- ret.modrm = inst_bytes[op_idx + 1];
- }
- }
-
- return ret;
-}
-
-lldb::InstructionControlFlowKind GetControlFlowKind(bool is_exec_mode_64b,
- Opcode m_opcode) {
- llvm::Optional<InstructionOpcodeAndModrm> ret = llvm::None;
-
- if (m_opcode.GetOpcodeBytes() == nullptr || m_opcode.GetByteSize() <= 0) {
- // x86_64 and i386 instructions are categorized as Opcode::Type::eTypeBytes
- return lldb::eInstructionControlFlowKindUnknown;
- }
-
- // Opcode bytes will be decoded into primary_opcode, modrm and opcode length.
- // These are the three values deciding instruction control flow kind.
- ret = InstructionLengthDecode((const uint8_t *)m_opcode.GetOpcodeBytes(),
- m_opcode.GetByteSize(), is_exec_mode_64b);
- if (!ret)
- return lldb::eInstructionControlFlowKindUnknown;
- else
- return MapOpcodeIntoControlFlowKind(ret.value());
-}
-
-} // namespace x86
-
-lldb::InstructionControlFlowKind
-Instruction::GetControlFlowKind(const ArchSpec &arch) {
- if (arch.GetTriple().getArch() == llvm::Triple::x86)
- return x86::GetControlFlowKind(/*is_exec_mode_64b=*/false, m_opcode);
- else if (arch.GetTriple().getArch() == llvm::Triple::x86_64)
- return x86::GetControlFlowKind(/*is_exec_mode_64b=*/true, m_opcode);
- else
- return eInstructionControlFlowKindUnknown; // not implemented
-}
-
AddressClass Instruction::GetAddressClass() {
if (m_address_class == AddressClass::eInvalid)
m_address_class = m_address.GetAddressClass();
return m_address_class;
}
+const char *Instruction::GetNameForInstructionControlFlowKind(
+ lldb::InstructionControlFlowKind instruction_control_flow_kind) {
+ switch (instruction_control_flow_kind) {
+ case eInstructionControlFlowKindUnknown:
+ return "unknown";
+ case eInstructionControlFlowKindOther:
+ return "other";
+ case eInstructionControlFlowKindCall:
+ return "call";
+ case eInstructionControlFlowKindReturn:
+ return "return";
+ case eInstructionControlFlowKindJump:
+ return "jump";
+ case eInstructionControlFlowKindCondJump:
+ return "cond jump";
+ case eInstructionControlFlowKindFarCall:
+ return "far call";
+ case eInstructionControlFlowKindFarReturn:
+ return "far return";
+ case eInstructionControlFlowKindFarJump:
+ return "far jump";
+ }
+}
+
void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
bool show_address, bool show_bytes,
bool show_control_flow_kind,
@@ -946,35 +642,10 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
}
if (show_control_flow_kind) {
- switch (GetControlFlowKind(exe_ctx->GetTargetRef().GetArchitecture())) {
- case eInstructionControlFlowKindUnknown:
- ss.Printf("%-12s", "unknown");
- break;
- case eInstructionControlFlowKindOther:
- ss.Printf("%-12s", "other");
- break;
- case eInstructionControlFlowKindCall:
- ss.Printf("%-12s", "call");
- break;
- case eInstructionControlFlowKindReturn:
- ss.Printf("%-12s", "return");
- break;
- case eInstructionControlFlowKindJump:
- ss.Printf("%-12s", "jump");
- break;
- case eInstructionControlFlowKindCondJump:
- ss.Printf("%-12s", "cond jump");
- break;
- case eInstructionControlFlowKindFarCall:
- ss.Printf("%-12s", "far call");
- break;
- case eInstructionControlFlowKindFarReturn:
- ss.Printf("%-12s", "far return");
- break;
- case eInstructionControlFlowKindFarJump:
- ss.Printf("%-12s", "far jump");
- break;
- }
+ lldb::InstructionControlFlowKind instruction_control_flow_kind =
+ GetControlFlowKind(exe_ctx);
+ ss.Printf("%-12s", GetNameForInstructionControlFlowKind(
+ instruction_control_flow_kind));
}
const size_t opcode_pos = ss.GetSizeOfLastLine();
diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp
index f35eb47ff683..4a0f0240bd19 100644
--- a/lldb/source/Host/common/Host.cpp
+++ b/lldb/source/Host/common/Host.cpp
@@ -172,7 +172,7 @@ MonitorChildProcessThreadFunction(::pid_t pid,
::sigaction(SIGUSR1, &sigUsr1Action, nullptr);
#endif // __linux__
- while(1) {
+ while (true) {
log = GetLog(LLDBLog::Process);
LLDB_LOG(log, "::waitpid({0}, &status, 0)...", pid);
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
index fb404e985f80..973884283f46 100644
--- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
@@ -85,6 +85,324 @@ private:
std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_up;
};
+namespace x86 {
+
+/// These are the three values deciding instruction control flow kind.
+/// InstructionLengthDecode function decodes an instruction and get this struct.
+///
+/// primary_opcode
+/// Primary opcode of the instruction.
+/// For one-byte opcode instruction, it's the first byte after prefix.
+/// For two- and three-byte opcodes, it's the second byte.
+///
+/// opcode_len
+/// The length of opcode in bytes. Valid opcode lengths are 1, 2, or 3.
+///
+/// modrm
+/// ModR/M byte of the instruction.
+/// Bits[7:6] indicate MOD. Bits[5:3] specify a register and R/M bits[2:0]
+/// may contain a register or specify an addressing mode, depending on MOD.
+struct InstructionOpcodeAndModrm {
+ uint8_t primary_opcode;
+ uint8_t opcode_len;
+ uint8_t modrm;
+};
+
+/// Determine the InstructionControlFlowKind based on opcode and modrm bytes.
+/// Refer to http://ref.x86asm.net/coder.html for the full list of opcode and
+/// instruction set.
+///
+/// \param[in] opcode_and_modrm
+/// Contains primary_opcode byte, its length, and ModR/M byte.
+/// Refer to the struct InstructionOpcodeAndModrm for details.
+///
+/// \return
+/// The control flow kind of the instruction or
+/// eInstructionControlFlowKindOther if the instruction doesn't affect
+/// the control flow of the program.
+lldb::InstructionControlFlowKind
+MapOpcodeIntoControlFlowKind(InstructionOpcodeAndModrm opcode_and_modrm) {
+ uint8_t opcode = opcode_and_modrm.primary_opcode;
+ uint8_t opcode_len = opcode_and_modrm.opcode_len;
+ uint8_t modrm = opcode_and_modrm.modrm;
+
+ if (opcode_len > 2)
+ return lldb::eInstructionControlFlowKindOther;
+
+ if (opcode >= 0x70 && opcode <= 0x7F) {
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindCondJump;
+ else
+ return lldb::eInstructionControlFlowKindOther;
+ }
+
+ if (opcode >= 0x80 && opcode <= 0x8F) {
+ if (opcode_len == 2)
+ return lldb::eInstructionControlFlowKindCondJump;
+ else
+ return lldb::eInstructionControlFlowKindOther;
+ }
+
+ switch (opcode) {
+ case 0x9A:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarCall;
+ break;
+ case 0xFF:
+ if (opcode_len == 1) {
+ uint8_t modrm_reg = (modrm >> 3) & 7;
+ if (modrm_reg == 2)
+ return lldb::eInstructionControlFlowKindCall;
+ else if (modrm_reg == 3)
+ return lldb::eInstructionControlFlowKindFarCall;
+ else if (modrm_reg == 4)
+ return lldb::eInstructionControlFlowKindJump;
+ else if (modrm_reg == 5)
+ return lldb::eInstructionControlFlowKindFarJump;
+ }
+ break;
+ case 0xE8:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindCall;
+ break;
+ case 0xCD:
+ case 0xCC:
+ case 0xCE:
+ case 0xF1:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarCall;
+ break;
+ case 0xCF:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarReturn;
+ break;
+ case 0xE9:
+ case 0xEB:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindJump;
+ break;
+ case 0xEA:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarJump;
+ break;
+ case 0xE3:
+ case 0xE0:
+ case 0xE1:
+ case 0xE2:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindCondJump;
+ break;
+ case 0xC3:
+ case 0xC2:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindReturn;
+ break;
+ case 0xCB:
+ case 0xCA:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarReturn;
+ break;
+ case 0x05:
+ case 0x34:
+ if (opcode_len == 2)
+ return lldb::eInstructionControlFlowKindFarCall;
+ break;
+ case 0x35:
+ case 0x07:
+ if (opcode_len == 2)
+ return lldb::eInstructionControlFlowKindFarReturn;
+ break;
+ case 0x01:
+ if (opcode_len == 2) {
+ switch (modrm) {
+ case 0xc1:
+ return lldb::eInstructionControlFlowKindFarCall;
+ case 0xc2:
+ case 0xc3:
+ return lldb::eInstructionControlFlowKindFarReturn;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return lldb::eInstructionControlFlowKindOther;
+}
+
+/// Decode an instruction into opcode, modrm and opcode_len.
+/// Refer to http://ref.x86asm.net/coder.html for the instruction bytes layout.
+/// Opcodes in x86 are generally the first byte of instruction, though two-byte
+/// instructions and prefixes exist. ModR/M is the byte following the opcode
+/// and adds additional information for how the instruction is executed.
+///
+/// \param[in] inst_bytes
+/// Raw bytes of the instruction
+///
+///
+/// \param[in] bytes_len
+/// The length of the inst_bytes array.
+///
+/// \param[in] is_exec_mode_64b
+/// If true, the execution mode is 64 bit.
+///
+/// \return
+/// Returns decoded instruction as struct InstructionOpcodeAndModrm, holding
+/// primary_opcode, opcode_len and modrm byte. Refer to the struct definition
+/// for more details.
+/// Otherwise if the given instruction is invalid, returns None.
+llvm::Optional<InstructionOpcodeAndModrm>
+InstructionLengthDecode(const uint8_t *inst_bytes, int bytes_len,
+ bool is_exec_mode_64b) {
+ int op_idx = 0;
+ bool prefix_done = false;
+ InstructionOpcodeAndModrm ret = {0, 0, 0};
+
+ // In most cases, the primary_opcode is the first byte of the instruction
+ // but some instructions have a prefix to be skipped for these calculations.
+ // The following mapping is inspired from libipt's instruction decoding logic
+ // in `src/pt_ild.c`
+ while (!prefix_done) {
+ if (op_idx >= bytes_len)
+ return llvm::None;
+
+ ret.primary_opcode = inst_bytes[op_idx];
+ switch (ret.primary_opcode) {
+ // prefix_ignore
+ case 0x26:
+ case 0x2e:
+ case 0x36:
+ case 0x3e:
+ case 0x64:
+ case 0x65:
+ // prefix_osz, prefix_asz
+ case 0x66:
+ case 0x67:
+ // prefix_lock, prefix_f2, prefix_f3
+ case 0xf0:
+ case 0xf2:
+ case 0xf3:
+ op_idx++;
+ break;
+
+ // prefix_rex
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ if (is_exec_mode_64b)
+ op_idx++;
+ else
+ prefix_done = true;
+ break;
+
+ // prefix_vex_c4, c5
+ case 0xc5:
+ if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
+ prefix_done = true;
+ break;
+ }
+
+ ret.opcode_len = 2;
+ ret.primary_opcode = inst_bytes[op_idx + 2];
+ ret.modrm = inst_bytes[op_idx + 3];
+ return ret;
+
+ case 0xc4:
+ if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
+ prefix_done = true;
+ break;
+ }
+ ret.opcode_len = inst_bytes[op_idx + 1] & 0x1f;
+ ret.primary_opcode = inst_bytes[op_idx + 3];
+ ret.modrm = inst_bytes[op_idx + 4];
+ return ret;
+
+ // prefix_evex
+ case 0x62:
+ if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
+ prefix_done = true;
+ break;
+ }
+ ret.opcode_len = inst_bytes[op_idx + 1] & 0x03;
+ ret.primary_opcode = inst_bytes[op_idx + 4];
+ ret.modrm = inst_bytes[op_idx + 5];
+ return ret;
+
+ default:
+ prefix_done = true;
+ break;
+ }
+ } // prefix done
+
+ ret.primary_opcode = inst_bytes[op_idx];
+ ret.modrm = inst_bytes[op_idx + 1];
+ ret.opcode_len = 1;
+
+ // If the first opcode is 0F, it's two- or three- byte opcodes.
+ if (ret.primary_opcode == 0x0F) {
+ ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
+
+ if (ret.primary_opcode == 0x38) {
+ ret.opcode_len = 3;
+ ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
+ ret.modrm = inst_bytes[op_idx + 1];
+ } else if (ret.primary_opcode == 0x3A) {
+ ret.opcode_len = 3;
+ ret.primary_opcode = inst_bytes[++op_idx];
+ ret.modrm = inst_bytes[op_idx + 1];
+ } else if ((ret.primary_opcode & 0xf8) == 0x38) {
+ ret.opcode_len = 0;
+ ret.primary_opcode = inst_bytes[++op_idx];
+ ret.modrm = inst_bytes[op_idx + 1];
+ } else if (ret.primary_opcode == 0x0F) {
+ ret.opcode_len = 3;
+ // opcode is 0x0F, no needs to update
+ ret.modrm = inst_bytes[op_idx + 1];
+ } else {
+ ret.opcode_len = 2;
+ ret.modrm = inst_bytes[op_idx + 1];
+ }
+ }
+
+ return ret;
+}
+
+lldb::InstructionControlFlowKind GetControlFlowKind(bool is_exec_mode_64b,
+ Opcode m_opcode) {
+ llvm::Optional<InstructionOpcodeAndModrm> ret = llvm::None;
+
+ if (m_opcode.GetOpcodeBytes() == nullptr || m_opcode.GetByteSize() <= 0) {
+ // x86_64 and i386 instructions are categorized as Opcode::Type::eTypeBytes
+ return lldb::eInstructionControlFlowKindUnknown;
+ }
+
+ // Opcode bytes will be decoded into primary_opcode, modrm and opcode length.
+ // These are the three values deciding instruction control flow kind.
+ ret = InstructionLengthDecode((const uint8_t *)m_opcode.GetOpcodeBytes(),
+ m_opcode.GetByteSize(), is_exec_mode_64b);
+ if (!ret)
+ return lldb::eInstructionControlFlowKindUnknown;
+ else
+ return MapOpcodeIntoControlFlowKind(ret.value());
+}
+
+} // namespace x86
+
class InstructionLLVMC : public lldb_private::Instruction {
public:
InstructionLLVMC(DisassemblerLLVMC &disasm,
@@ -223,6 +541,19 @@ public:
}
}
+ lldb::InstructionControlFlowKind
+ GetControlFlowKind(const lldb_private::ExecutionContext *exe_ctx) override {
+ DisassemblerScope disasm(*this, exe_ctx);
+ if (disasm){
+ if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86)
+ return x86::GetControlFlowKind(/*is_64b=*/false, m_opcode);
+ else if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
+ return x86::GetControlFlowKind(/*is_64b=*/true, m_opcode);
+ }
+
+ return eInstructionControlFlowKindUnknown;
+ }
+
void CalculateMnemonicOperandsAndComment(
const lldb_private::ExecutionContext *exe_ctx) override {
DataExtractor data;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index f8443d608ac3..71242925862b 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -191,12 +191,12 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
ClangASTImporter::NamespaceMapSP namespace_map =
m_ast_importer_sp->GetNamespaceMap(namespace_context);
- LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)",
- namespace_map.get(), namespace_map->size());
-
if (!namespace_map)
return nullptr;
+ LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)",
+ namespace_map.get(), namespace_map->size());
+
for (const ClangASTImporter::NamespaceMapItem &item : *namespace_map) {
LLDB_LOG(log, " CTD Searching namespace {0} in module {1}",
item.second.GetName(), item.first->GetFileSpec().GetFilename());
@@ -1430,9 +1430,7 @@ static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map,
std::vector<PairType> sorted_items;
sorted_items.reserve(source_map.size());
sorted_items.assign(source_map.begin(), source_map.end());
- llvm::sort(sorted_items, [](const PairType &lhs, const PairType &rhs) {
- return lhs.second < rhs.second;
- });
+ llvm::sort(sorted_items, llvm::less_second());
for (const auto &item : sorted_items) {
DeclFromUser<D> user_decl(const_cast<D *>(item.first));
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index fad0f724e4c8..ec3dc28a3a8c 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -722,8 +722,9 @@ ClangExpressionParser::ClangExpressionParser(
m_llvm_context = std::make_unique<LLVMContext>();
m_code_generator.reset(CreateLLVMCodeGen(
m_compiler->getDiagnostics(), module_name,
- m_compiler->getHeaderSearchOpts(), m_compiler->getPreprocessorOpts(),
- m_compiler->getCodeGenOpts(), *m_llvm_context));
+ &m_compiler->getVirtualFileSystem(), m_compiler->getHeaderSearchOpts(),
+ m_compiler->getPreprocessorOpts(), m_compiler->getCodeGenOpts(),
+ *m_llvm_context));
}
ClangExpressionParser::~ClangExpressionParser() = default;
diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
index 5bc745cf3b8b..b00a17736679 100644
--- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
+++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -14453,10 +14453,10 @@ bool EmulateInstructionARM::TestEmulation(Stream *out_stream, ArchSpec &arch,
return false;
}
- success = before_state.CompareState(after_state);
+ success = before_state.CompareState(after_state, out_stream);
if (!success)
out_stream->Printf(
- "TestEmulation: 'before' and 'after' states do not match.\n");
+ "TestEmulation: State after emulation does not match 'after' state.\n");
return success;
}
diff --git a/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
index 569482c7b23b..da679a3e8547 100644
--- a/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
+++ b/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
@@ -97,7 +97,7 @@ uint64_t EmulationStateARM::ReadPseudoRegisterValue(uint32_t reg_num,
uint32_t idx = reg_num - dwarf_d0;
if (idx < 16)
value = (uint64_t)m_vfp_regs.s_regs[idx * 2] |
- ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] >> 32);
+ ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] << 32);
else
value = m_vfp_regs.d_regs[idx - 16];
} else
@@ -251,27 +251,67 @@ bool EmulationStateARM::WritePseudoRegister(
reg_value.GetAsUInt64());
}
-bool EmulationStateARM::CompareState(EmulationStateARM &other_state) {
+bool EmulationStateARM::CompareState(EmulationStateARM &other_state,
+ Stream *out_stream) {
bool match = true;
for (int i = 0; match && i < 17; ++i) {
- if (m_gpr[i] != other_state.m_gpr[i])
+ if (m_gpr[i] != other_state.m_gpr[i]) {
match = false;
+ out_stream->Printf("r%d: 0x%x != 0x%x\n", i, m_gpr[i],
+ other_state.m_gpr[i]);
+ }
}
for (int i = 0; match && i < 32; ++i) {
- if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i])
+ if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i]) {
match = false;
+ out_stream->Printf("s%d: 0x%x != 0x%x\n", i, m_vfp_regs.s_regs[i],
+ other_state.m_vfp_regs.s_regs[i]);
+ }
}
for (int i = 0; match && i < 16; ++i) {
- if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i])
+ if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i]) {
match = false;
+ out_stream->Printf("d%d: 0x%" PRIx64 " != 0x%" PRIx64 "\n", i + 16,
+ m_vfp_regs.d_regs[i],
+ other_state.m_vfp_regs.d_regs[i]);
+ }
+ }
+
+ // other_state is the expected state. If it has memory, check it.
+ if (!other_state.m_memory.empty() && m_memory != other_state.m_memory) {
+ match = false;
+ out_stream->Printf("memory does not match\n");
+ out_stream->Printf("got memory:\n");
+ for (auto p : m_memory)
+ out_stream->Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);
+ out_stream->Printf("expected memory:\n");
+ for (auto p : other_state.m_memory)
+ out_stream->Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);
}
return match;
}
+bool EmulationStateARM::LoadRegistersStateFromDictionary(
+ OptionValueDictionary *reg_dict, char kind, int first_reg, int num) {
+ StreamString sstr;
+ for (int i = 0; i < num; ++i) {
+ sstr.Clear();
+ sstr.Printf("%c%d", kind, i);
+ OptionValueSP value_sp =
+ reg_dict->GetValueForKey(ConstString(sstr.GetString()));
+ if (value_sp.get() == nullptr)
+ return false;
+ uint64_t reg_value = value_sp->GetUInt64Value();
+ StorePseudoRegisterValue(first_reg + i, reg_value);
+ }
+
+ return true;
+}
+
bool EmulationStateARM::LoadStateFromDictionary(
OptionValueDictionary *test_data) {
static ConstString memory_key("memory");
@@ -321,18 +361,8 @@ bool EmulationStateARM::LoadStateFromDictionary(
// Load General Registers
OptionValueDictionary *reg_dict = value_sp->GetAsDictionary();
-
- StreamString sstr;
- for (int i = 0; i < 16; ++i) {
- sstr.Clear();
- sstr.Printf("r%d", i);
- ConstString reg_name(sstr.GetString());
- value_sp = reg_dict->GetValueForKey(reg_name);
- if (value_sp.get() == nullptr)
- return false;
- uint64_t reg_value = value_sp->GetUInt64Value();
- StorePseudoRegisterValue(dwarf_r0 + i, reg_value);
- }
+ if (!LoadRegistersStateFromDictionary(reg_dict, 'r', dwarf_r0, 16))
+ return false;
static ConstString cpsr_name("cpsr");
value_sp = reg_dict->GetValueForKey(cpsr_name);
@@ -341,16 +371,13 @@ bool EmulationStateARM::LoadStateFromDictionary(
StorePseudoRegisterValue(dwarf_cpsr, value_sp->GetUInt64Value());
// Load s/d Registers
- for (int i = 0; i < 32; ++i) {
- sstr.Clear();
- sstr.Printf("s%d", i);
- ConstString reg_name(sstr.GetString());
- value_sp = reg_dict->GetValueForKey(reg_name);
- if (value_sp.get() == nullptr)
- return false;
- uint64_t reg_value = value_sp->GetUInt64Value();
- StorePseudoRegisterValue(dwarf_s0 + i, reg_value);
- }
-
- return true;
+ // To prevent you giving both types in a state and overwriting
+ // one or the other, we'll expect to get either all S registers,
+ // or all D registers. Not a mix of the two.
+ bool found_s_registers =
+ LoadRegistersStateFromDictionary(reg_dict, 's', dwarf_s0, 32);
+ bool found_d_registers =
+ LoadRegistersStateFromDictionary(reg_dict, 'd', dwarf_d0, 32);
+
+ return found_s_registers != found_d_registers;
}
diff --git a/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h b/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h
index 28bc5d98649d..bc885dab9ac7 100644
--- a/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h
+++ b/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h
@@ -36,7 +36,8 @@ public:
bool LoadStateFromDictionary(lldb_private::OptionValueDictionary *test_data);
- bool CompareState(EmulationStateARM &other_state);
+ bool CompareState(EmulationStateARM &other_state,
+ lldb_private::Stream *out_stream);
static size_t
ReadPseudoMemory(lldb_private::EmulateInstruction *instruction, void *baton,
@@ -61,6 +62,10 @@ public:
const lldb_private::RegisterValue &reg_value);
private:
+ bool LoadRegistersStateFromDictionary(
+ lldb_private::OptionValueDictionary *reg_dict, char kind, int first_reg,
+ int num);
+
uint32_t m_gpr[17] = {0};
struct _sd_regs {
uint32_t s_regs[32]; // sregs 0 - 31 & dregs 0 - 15
diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
index acb131b8a775..c396cb061c01 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
+++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
@@ -348,7 +348,7 @@ llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
lldb_private::minidump::MinidumpContext_x86_64
GetThreadContext_64(RegisterContext *reg_ctx) {
- lldb_private::minidump::MinidumpContext_x86_64 thread_context;
+ lldb_private::minidump::MinidumpContext_x86_64 thread_context = {};
thread_context.p1_home = {};
thread_context.context_flags = static_cast<uint32_t>(
lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag |
@@ -534,7 +534,7 @@ Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) {
helper_data.AppendData(
&thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64));
- Exception exp_record;
+ Exception exp_record = {};
exp_record.ExceptionCode =
static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
diff --git a/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp b/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
index b71de4cadb18..7e25bc4ea2a2 100644
--- a/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
+++ b/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
@@ -247,6 +247,71 @@ MemoryTagManagerAArch64MTE::UnpackTagsData(const std::vector<uint8_t> &tags,
return unpacked;
}
+std::vector<lldb::addr_t>
+MemoryTagManagerAArch64MTE::UnpackTagsFromCoreFileSegment(
+ CoreReaderFn reader, lldb::addr_t tag_segment_virtual_address,
+ lldb::addr_t tag_segment_data_address, lldb::addr_t addr,
+ size_t len) const {
+ // We can assume by now that addr and len have been granule aligned by a tag
+ // manager. However because we have 2 tags per byte we need to round the range
+ // up again to align to 2 granule boundaries.
+ const size_t granule = GetGranuleSize();
+ const size_t two_granules = granule * 2;
+ lldb::addr_t aligned_addr = addr;
+ size_t aligned_len = len;
+
+ // First align the start address down.
+ if (aligned_addr % two_granules) {
+ assert(aligned_addr % two_granules == granule);
+ aligned_addr -= granule;
+ aligned_len += granule;
+ }
+
+ // Then align the length up.
+ bool aligned_length_up = false;
+ if (aligned_len % two_granules) {
+ assert(aligned_len % two_granules == granule);
+ aligned_len += granule;
+ aligned_length_up = true;
+ }
+
+ // ProcessElfCore should have validated this when it found the segment.
+ assert(aligned_addr >= tag_segment_virtual_address);
+
+ // By now we know that aligned_addr is aligned to a 2 granule boundary.
+ const size_t offset_granules =
+ (aligned_addr - tag_segment_virtual_address) / granule;
+ // 2 tags per byte.
+ const size_t file_offset_in_bytes = offset_granules / 2;
+
+ // By now we know that aligned_len is at least 2 granules.
+ const size_t tag_bytes_to_read = aligned_len / granule / 2;
+ std::vector<uint8_t> tag_data(tag_bytes_to_read);
+ const size_t bytes_copied =
+ reader(tag_segment_data_address + file_offset_in_bytes, tag_bytes_to_read,
+ tag_data.data());
+ UNUSED_IF_ASSERT_DISABLED(bytes_copied);
+ assert(bytes_copied == tag_bytes_to_read);
+
+ std::vector<lldb::addr_t> tags;
+ tags.reserve(2 * tag_data.size());
+ // No need to check the range of the tag value here as each occupies only 4
+ // bits.
+ for (auto tag_byte : tag_data) {
+ tags.push_back(tag_byte & 0xf);
+ tags.push_back(tag_byte >> 4);
+ }
+
+ // If we aligned the address down, don't return the extra first tag.
+ if (addr != aligned_addr)
+ tags.erase(tags.begin());
+ // If we aligned the length up, don't return the extra last tag.
+ if (aligned_length_up)
+ tags.pop_back();
+
+ return tags;
+}
+
llvm::Expected<std::vector<uint8_t>> MemoryTagManagerAArch64MTE::PackTags(
const std::vector<lldb::addr_t> &tags) const {
std::vector<uint8_t> packed;
diff --git a/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h b/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
index 7cda728b140f..365e176e5b1d 100644
--- a/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
+++ b/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
@@ -44,6 +44,12 @@ public:
UnpackTagsData(const std::vector<uint8_t> &tags,
size_t granules = 0) const override;
+ std::vector<lldb::addr_t>
+ UnpackTagsFromCoreFileSegment(CoreReaderFn reader,
+ lldb::addr_t tag_segment_virtual_address,
+ lldb::addr_t tag_segment_data_address,
+ lldb::addr_t addr, size_t len) const override;
+
llvm::Expected<std::vector<uint8_t>>
PackTags(const std::vector<lldb::addr_t> &tags) const override;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
index 11b300bc44fb..691e7db3fc79 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
@@ -95,7 +95,7 @@ static size_t k_num_register_infos =
RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(
Thread &thread, uint32_t concrete_frame_idx)
- : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc() {
+ : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc(), dbg() {
uint32_t i;
for (i = 0; i < kNumErrors; i++) {
gpr_errs[i] = -1;
diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
index 7469e7633e71..89ecc757a68f 100644
--- a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
+++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -23,7 +23,8 @@ using namespace lldb_private;
ThreadMemory::ThreadMemory(Process &process, tid_t tid,
const ValueObjectSP &thread_info_valobj_sp)
: Thread(process, tid), m_backing_thread_sp(),
- m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue() {}
+ m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(),
+ m_register_data_addr(LLDB_INVALID_ADDRESS) {}
ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid,
llvm::StringRef name, llvm::StringRef queue,
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 58b4fe3add1b..24d3c4bd0ba2 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -144,6 +144,18 @@ lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment(
return addr;
}
+lldb::addr_t ProcessElfCore::AddAddressRangeFromMemoryTagSegment(
+ const elf::ELFProgramHeader &header) {
+ // If lldb understood multiple kinds of tag segments we would record the type
+ // of the segment here also. As long as there is only 1 type lldb looks for,
+ // there is no need.
+ FileRange file_range(header.p_offset, header.p_filesz);
+ m_core_tag_ranges.Append(
+ VMRangeToFileOffset::Entry(header.p_vaddr, header.p_memsz, file_range));
+
+ return header.p_vaddr;
+}
+
// Process Control
Status ProcessElfCore::DoLoadCore() {
Status error;
@@ -170,9 +182,12 @@ Status ProcessElfCore::DoLoadCore() {
bool ranges_are_sorted = true;
lldb::addr_t vm_addr = 0;
+ lldb::addr_t tag_addr = 0;
/// Walk through segments and Thread and Address Map information.
/// PT_NOTE - Contains Thread and Register information
/// PT_LOAD - Contains a contiguous range of Process Address Space
+ /// PT_AARCH64_MEMTAG_MTE - Contains AArch64 MTE memory tags for a range of
+ /// Process Address Space.
for (const elf::ELFProgramHeader &H : segments) {
DataExtractor data = core->GetSegmentData(H);
@@ -187,12 +202,18 @@ Status ProcessElfCore::DoLoadCore() {
if (vm_addr > last_addr)
ranges_are_sorted = false;
vm_addr = last_addr;
+ } else if (H.p_type == llvm::ELF::PT_AARCH64_MEMTAG_MTE) {
+ lldb::addr_t last_addr = AddAddressRangeFromMemoryTagSegment(H);
+ if (tag_addr > last_addr)
+ ranges_are_sorted = false;
+ tag_addr = last_addr;
}
}
if (!ranges_are_sorted) {
m_core_aranges.Sort();
m_core_range_infos.Sort();
+ m_core_tag_ranges.Sort();
}
// Even if the architecture is set in the target, we need to override it to
@@ -310,6 +331,15 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
? MemoryRegionInfo::eYes
: MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eYes);
+
+ // A region is memory tagged if there is a memory tag segment that covers
+ // the exact same range.
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+ const VMRangeToFileOffset::Entry *tag_entry =
+ m_core_tag_ranges.FindEntryStartsAt(permission_entry->GetRangeBase());
+ if (tag_entry &&
+ tag_entry->GetRangeEnd() == permission_entry->GetRangeEnd())
+ region_info.SetMemoryTagged(MemoryRegionInfo::eYes);
} else if (load_addr < permission_entry->GetRangeBase()) {
region_info.GetRange().SetRangeBase(load_addr);
region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
@@ -317,6 +347,7 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
region_info.SetWritable(MemoryRegionInfo::eNo);
region_info.SetExecutable(MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eNo);
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
}
return Status();
}
@@ -327,6 +358,7 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
region_info.SetWritable(MemoryRegionInfo::eNo);
region_info.SetExecutable(MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eNo);
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
return Status();
}
@@ -376,6 +408,38 @@ size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
return bytes_copied;
}
+llvm::Expected<std::vector<lldb::addr_t>>
+ProcessElfCore::ReadMemoryTags(lldb::addr_t addr, size_t len) {
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile == nullptr)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No core object file.");
+
+ llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
+ GetMemoryTagManager();
+ if (!tag_manager_or_err)
+ return tag_manager_or_err.takeError();
+
+ // LLDB only supports AArch64 MTE tag segments so we do not need to worry
+ // about the segment type here. If you got here then you must have a tag
+ // manager (meaning you are debugging AArch64) and all the segments in this
+ // list will have had type PT_AARCH64_MEMTAG_MTE.
+ const VMRangeToFileOffset::Entry *tag_entry =
+ m_core_tag_ranges.FindEntryThatContains(addr);
+ // If we don't have a tag segment or the range asked for extends outside the
+ // segment.
+ if (!tag_entry || (addr + len) >= tag_entry->GetRangeEnd())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No tag segment that covers this range.");
+
+ const MemoryTagManager *tag_manager = *tag_manager_or_err;
+ return tag_manager->UnpackTagsFromCoreFileSegment(
+ [core_objfile](lldb::offset_t offset, size_t length, void *dst) {
+ return core_objfile->CopyData(offset, length, dst);
+ },
+ tag_entry->GetRangeBase(), tag_entry->data.GetRangeBase(), addr, len);
+}
+
void ProcessElfCore::Clear() {
m_thread_list.Clear();
@@ -610,9 +674,9 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) {
// To be extracted from struct netbsd_elfcore_procinfo
// Used to sanity check of the LWPs of the process
uint32_t nlwps = 0;
- uint32_t signo; // killing signal
- uint32_t siglwp; // LWP target of killing signal
- uint32_t pr_pid;
+ uint32_t signo = 0; // killing signal
+ uint32_t siglwp = 0; // LWP target of killing signal
+ uint32_t pr_pid = 0;
for (const auto &note : notes) {
llvm::StringRef name = note.info.n_name;
@@ -764,7 +828,7 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) {
}
llvm::Error ProcessElfCore::parseOpenBSDNotes(llvm::ArrayRef<CoreNote> notes) {
- ThreadData thread_data;
+ ThreadData thread_data = {};
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.
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index fd36e5027816..03c23378e3c1 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -86,6 +86,11 @@ public:
size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
lldb_private::Status &error) override;
+ // We do not implement DoReadMemoryTags. Instead all the work is done in
+ // ReadMemoryTags which avoids having to unpack and repack tags.
+ llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr,
+ size_t len) override;
+
lldb::addr_t GetImageInfoAddress() override;
lldb_private::ArchSpec GetArchitecture();
@@ -105,6 +110,8 @@ protected:
DoGetMemoryRegionInfo(lldb::addr_t load_addr,
lldb_private::MemoryRegionInfo &region_info) override;
+ bool SupportsMemoryTagging() override { return !m_core_tag_ranges.IsEmpty(); }
+
private:
struct NT_FILE_Entry {
lldb::addr_t start;
@@ -139,6 +146,9 @@ private:
// Permissions for all ranges
VMRangeToPermissions m_core_range_infos;
+ // Memory tag ranges found in the core
+ VMRangeToFileOffset m_core_tag_ranges;
+
// NT_FILE entries found from the NOTE segment
std::vector<NT_FILE_Entry> m_nt_file_entries;
@@ -154,6 +164,10 @@ private:
lldb::addr_t
AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header);
+ // Parse a contiguous address range from a memory tag segment
+ lldb::addr_t
+ AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader &header);
+
llvm::Expected<std::vector<lldb_private::CoreNote>>
parseSegment(const lldb_private::DataExtractor &segment);
llvm::Error parseFreeBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index c44ace96dd55..580cdde57d80 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -4265,3 +4265,21 @@ bool GDBRemoteCommunicationClient::UsesNativeSignals() {
// check whether it is an old version of lldb-server.
return GetThreadSuffixSupported();
}
+
+llvm::Expected<int> GDBRemoteCommunicationClient::KillProcess(lldb::pid_t pid) {
+ StringExtractorGDBRemote response;
+ GDBRemoteCommunication::ScopedTimeout(*this, seconds(3));
+
+ if (SendPacketAndWaitForResponse("k", response, GetPacketTimeout()) !=
+ PacketResult::Success)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "failed to send k packet");
+
+ char packet_cmd = response.GetChar(0);
+ if (packet_cmd == 'W' || packet_cmd == 'X')
+ return response.GetHexU8();
+
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "unexpected response to k packet: %s",
+ response.GetStringRef().str().c_str());
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index d367f75cee0e..3d838d6d8074 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -521,6 +521,8 @@ public:
bool GetSaveCoreSupported() const;
+ llvm::Expected<int> KillProcess(lldb::pid_t pid);
+
protected:
LazyBool m_supports_not_sending_acks = eLazyBoolCalculate;
LazyBool m_supports_thread_suffix = eLazyBoolCalculate;
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 5f18706f67e5..3e1a6fb6620a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -2394,7 +2394,6 @@ Status ProcessGDBRemote::DoDetach(bool keep_stopped) {
}
Status ProcessGDBRemote::DoDestroy() {
- Status error;
Log *log = GetLog(GDBRLog::Process);
LLDB_LOGF(log, "ProcessGDBRemote::DoDestroy()");
@@ -2404,54 +2403,35 @@ Status ProcessGDBRemote::DoDestroy() {
if (m_gdb_comm.IsConnected()) {
if (m_public_state.GetValue() != eStateAttaching) {
- StringExtractorGDBRemote response;
- GDBRemoteCommunication::ScopedTimeout(m_gdb_comm,
- std::chrono::seconds(3));
-
- if (m_gdb_comm.SendPacketAndWaitForResponse("k", response,
- GetInterruptTimeout()) ==
- GDBRemoteCommunication::PacketResult::Success) {
- char packet_cmd = response.GetChar(0);
+ llvm::Expected<int> kill_res = m_gdb_comm.KillProcess(GetID());
- if (packet_cmd == 'W' || packet_cmd == 'X') {
+ if (kill_res) {
+ exit_status = kill_res.get();
#if defined(__APPLE__)
- // For Native processes on Mac OS X, we launch through the Host
- // Platform, then hand the process off to debugserver, which becomes
- // the parent process through "PT_ATTACH". Then when we go to kill
- // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then
- // we call waitpid which returns with no error and the correct
- // status. But amusingly enough that doesn't seem to actually reap
- // the process, but instead it is left around as a Zombie. Probably
- // the kernel is in the process of switching ownership back to lldb
- // which was the original parent, and gets confused in the handoff.
- // Anyway, so call waitpid here to finally reap it.
- PlatformSP platform_sp(GetTarget().GetPlatform());
- if (platform_sp && platform_sp->IsHost()) {
- int status;
- ::pid_t reap_pid;
- reap_pid = waitpid(GetID(), &status, WNOHANG);
- LLDB_LOGF(log, "Reaped pid: %d, status: %d.\n", reap_pid, status);
- }
-#endif
- SetLastStopPacket(response);
- ClearThreadIDList();
- exit_status = response.GetHexU8();
- } else {
- LLDB_LOGF(log,
- "ProcessGDBRemote::DoDestroy - got unexpected response "
- "to k packet: %s",
- response.GetStringRef().data());
- exit_string.assign("got unexpected response to k packet: ");
- exit_string.append(std::string(response.GetStringRef()));
+ // For Native processes on Mac OS X, we launch through the Host
+ // Platform, then hand the process off to debugserver, which becomes
+ // the parent process through "PT_ATTACH". Then when we go to kill
+ // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then
+ // we call waitpid which returns with no error and the correct
+ // status. But amusingly enough that doesn't seem to actually reap
+ // the process, but instead it is left around as a Zombie. Probably
+ // the kernel is in the process of switching ownership back to lldb
+ // which was the original parent, and gets confused in the handoff.
+ // Anyway, so call waitpid here to finally reap it.
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ if (platform_sp && platform_sp->IsHost()) {
+ int status;
+ ::pid_t reap_pid;
+ reap_pid = waitpid(GetID(), &status, WNOHANG);
+ LLDB_LOGF(log, "Reaped pid: %d, status: %d.\n", reap_pid, status);
}
+#endif
+ ClearThreadIDList();
+ exit_string.assign("killed");
} else {
- LLDB_LOGF(log, "ProcessGDBRemote::DoDestroy - failed to send k packet");
- exit_string.assign("failed to send the k packet");
+ exit_string.assign(llvm::toString(kill_res.takeError()));
}
} else {
- LLDB_LOGF(log,
- "ProcessGDBRemote::DoDestroy - killed or interrupted while "
- "attaching");
exit_string.assign("killed or interrupted while attaching.");
}
} else {
@@ -2465,7 +2445,7 @@ Status ProcessGDBRemote::DoDestroy() {
StopAsyncThread();
KillDebugserverProcess();
- return error;
+ return Status();
}
void ProcessGDBRemote::SetLastStopPacket(
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
index c91c111d8df3..64219e1a960b 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -233,7 +233,8 @@ ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
const FileSpec &core_file,
DataBufferSP core_data)
: PostMortemProcess(target_sp, listener_sp), m_core_file(core_file),
- m_core_data(std::move(core_data)), m_is_wow64(false) {}
+ m_core_data(std::move(core_data)), m_active_exception(nullptr),
+ m_is_wow64(false) {}
ProcessMinidump::~ProcessMinidump() {
Clear();
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
index 6317b140f7e8..7d730ecdd1f3 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -475,7 +475,7 @@ llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
}
VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) {
- VariableInfo result;
+ VariableInfo result = {};
if (sym.kind() == S_REGREL32) {
RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
index 0859c5a20b7e..02f1d2f24d8c 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -44,11 +44,65 @@ void IntelPTError::log(llvm::raw_ostream &OS) const {
OS << formatv(": {0:x+16}", m_address);
}
-int64_t DecodedThread::GetItemsCount() const {
- return static_cast<int64_t>(m_item_kinds.size());
+bool DecodedThread::TSCRange::InRange(uint64_t item_index) const {
+ return item_index >= first_item_index &&
+ item_index < first_item_index + items_count;
+}
+
+bool DecodedThread::NanosecondsRange::InRange(uint64_t item_index) const {
+ return item_index >= first_item_index &&
+ item_index < first_item_index + items_count;
+}
+
+double DecodedThread::NanosecondsRange::GetInterpolatedTime(
+ uint64_t item_index, uint64_t begin_of_time_nanos,
+ const LinuxPerfZeroTscConversion &tsc_conversion) const {
+ uint64_t items_since_last_tsc = item_index - first_item_index;
+
+ auto interpolate = [&](uint64_t next_range_start_ns) {
+ if (next_range_start_ns == nanos) {
+ // If the resolution of the conversion formula is bad enough to consider
+ // these two timestamps as equal, then we just increase the next one by 1
+ // for correction
+ next_range_start_ns++;
+ }
+ long double item_duration =
+ static_cast<long double>(items_count) / (next_range_start_ns - nanos);
+ return (nanos - begin_of_time_nanos) + items_since_last_tsc * item_duration;
+ };
+
+ if (!next_range) {
+ // If this is the last TSC range, so we have to extrapolate. In this case,
+ // we assume that each instruction took one TSC, which is what an
+ // instruction would take if no parallelism is achieved and the frequency
+ // multiplier is 1.
+ return interpolate(tsc_conversion.ToNanos(tsc + items_count));
+ }
+ if (items_count < (next_range->tsc - tsc)) {
+ // If the numbers of items in this range is less than the total TSC duration
+ // of this range, i.e. each instruction taking longer than 1 TSC, then we
+ // can assume that something else happened between these TSCs (e.g. a
+ // context switch, change to kernel, decoding errors, etc). In this case, we
+ // also assume that each instruction took 1 TSC. A proper way to improve
+ // this would be to analize the next events in the trace looking for context
+ // switches or trace disablement events, but for now, as we only want an
+ // approximation, we keep it simple. We are also guaranteed that the time in
+ // nanos of the next range is different to the current one, just because of
+ // the definition of a NanosecondsRange.
+ return interpolate(
+ std::min(tsc_conversion.ToNanos(tsc + items_count), next_range->nanos));
+ }
+
+ // In this case, each item took less than 1 TSC, so some parallelism was
+ // achieved, which is an indication that we didn't suffered of any kind of
+ // interruption.
+ return interpolate(next_range->nanos);
}
-lldb::addr_t DecodedThread::GetInstructionLoadAddress(size_t item_index) const {
+uint64_t DecodedThread::GetItemsCount() const { return m_item_kinds.size(); }
+
+lldb::addr_t
+DecodedThread::GetInstructionLoadAddress(uint64_t item_index) const {
return m_item_data[item_index].load_address;
}
@@ -58,33 +112,69 @@ DecodedThread::TraceItemStorage &
DecodedThread::CreateNewTraceItem(lldb::TraceItemKind kind) {
m_item_kinds.push_back(kind);
m_item_data.emplace_back();
+ if (m_last_tsc)
+ (*m_last_tsc)->second.items_count++;
+ if (m_last_nanoseconds)
+ (*m_last_nanoseconds)->second.items_count++;
return m_item_data.back();
}
-void DecodedThread::NotifyTsc(uint64_t tsc) {
- if (!m_last_tsc || *m_last_tsc != tsc) {
- m_timestamps.emplace(m_item_kinds.size(), tsc);
- m_last_tsc = tsc;
+void DecodedThread::NotifyTsc(TSC tsc) {
+ if (m_last_tsc && (*m_last_tsc)->second.tsc == tsc)
+ return;
+
+ m_last_tsc =
+ m_tscs.emplace(GetItemsCount(), TSCRange{tsc, 0, GetItemsCount()}).first;
+
+ if (m_tsc_conversion) {
+ uint64_t nanos = m_tsc_conversion->ToNanos(tsc);
+ if (!m_last_nanoseconds || (*m_last_nanoseconds)->second.nanos != nanos) {
+ m_last_nanoseconds =
+ m_nanoseconds
+ .emplace(GetItemsCount(), NanosecondsRange{nanos, tsc, nullptr, 0,
+ GetItemsCount()})
+ .first;
+ if (*m_last_nanoseconds != m_nanoseconds.begin()) {
+ auto prev_range = prev(*m_last_nanoseconds);
+ prev_range->second.next_range = &(*m_last_nanoseconds)->second;
+ }
+ }
}
+ AppendEvent(lldb::eTraceEventHWClockTick);
}
void DecodedThread::NotifyCPU(lldb::cpu_id_t cpu_id) {
if (!m_last_cpu || *m_last_cpu != cpu_id) {
- m_cpus.emplace(m_item_kinds.size(), cpu_id);
+ m_cpus.emplace(GetItemsCount(), cpu_id);
m_last_cpu = cpu_id;
AppendEvent(lldb::eTraceEventCPUChanged);
}
}
Optional<lldb::cpu_id_t>
-DecodedThread::GetCPUByIndex(uint64_t insn_index) const {
- // Could possibly optimize the search
- auto it = m_cpus.upper_bound(insn_index);
+DecodedThread::GetCPUByIndex(uint64_t item_index) const {
+ auto it = m_cpus.upper_bound(item_index);
if (it == m_cpus.begin())
return None;
return prev(it)->second;
}
+Optional<DecodedThread::TSCRange>
+DecodedThread::GetTSCRangeByIndex(uint64_t item_index) const {
+ auto next_it = m_tscs.upper_bound(item_index);
+ if (next_it == m_tscs.begin())
+ return None;
+ return prev(next_it)->second;
+}
+
+Optional<DecodedThread::NanosecondsRange>
+DecodedThread::GetNanosecondsRangeByIndex(uint64_t item_index) {
+ auto next_it = m_nanoseconds.upper_bound(item_index);
+ if (next_it == m_nanoseconds.begin())
+ return None;
+ return prev(next_it)->second;
+}
+
void DecodedThread::AppendEvent(lldb::TraceEvent event) {
CreateNewTraceItem(lldb::eTraceItemKindEvent).event = event;
m_events_stats.RecordEvent(event);
@@ -134,90 +224,24 @@ void DecodedThread::EventsStats::RecordEvent(lldb::TraceEvent event) {
total_count++;
}
-Optional<DecodedThread::TscRange> DecodedThread::CalculateTscRange(
- size_t insn_index,
- const Optional<DecodedThread::TscRange> &hint_range) const {
- // We first try to check the given hint range in case we are traversing the
- // trace in short jumps. If that fails, then we do the more expensive
- // arbitrary lookup.
- if (hint_range) {
- Optional<TscRange> candidate_range;
- if (insn_index < hint_range->GetStartInstructionIndex())
- candidate_range = hint_range->Prev();
- else if (insn_index > hint_range->GetEndInstructionIndex())
- candidate_range = hint_range->Next();
- else
- candidate_range = hint_range;
-
- if (candidate_range && candidate_range->InRange(insn_index))
- return candidate_range;
- }
- // Now we do a more expensive lookup
- auto it = m_timestamps.upper_bound(insn_index);
- if (it == m_timestamps.begin())
- return None;
-
- return TscRange(--it, *this);
-}
-
-lldb::TraceItemKind DecodedThread::GetItemKindByIndex(size_t item_index) const {
+lldb::TraceItemKind
+DecodedThread::GetItemKindByIndex(uint64_t item_index) const {
return static_cast<lldb::TraceItemKind>(m_item_kinds[item_index]);
}
-const char *DecodedThread::GetErrorByIndex(size_t item_index) const {
+const char *DecodedThread::GetErrorByIndex(uint64_t item_index) const {
return m_item_data[item_index].error;
}
-DecodedThread::DecodedThread(ThreadSP thread_sp) : m_thread_sp(thread_sp) {}
-
-lldb::TraceCursorUP DecodedThread::CreateNewCursor() {
- return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this());
-}
+DecodedThread::DecodedThread(
+ ThreadSP thread_sp,
+ const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion)
+ : m_thread_sp(thread_sp), m_tsc_conversion(tsc_conversion) {}
size_t DecodedThread::CalculateApproximateMemoryUsage() const {
return sizeof(TraceItemStorage) * m_item_data.size() +
sizeof(uint8_t) * m_item_kinds.size() +
- (sizeof(size_t) + sizeof(uint64_t)) * m_timestamps.size() +
- (sizeof(size_t) + sizeof(lldb::cpu_id_t)) * m_cpus.size();
-}
-
-DecodedThread::TscRange::TscRange(std::map<size_t, uint64_t>::const_iterator it,
- const DecodedThread &decoded_thread)
- : m_it(it), m_decoded_thread(&decoded_thread) {
- auto next_it = m_it;
- ++next_it;
- m_end_index = (next_it == m_decoded_thread->m_timestamps.end())
- ? std::numeric_limits<uint64_t>::max()
- : next_it->first - 1;
-}
-
-size_t DecodedThread::TscRange::GetTsc() const { return m_it->second; }
-
-size_t DecodedThread::TscRange::GetStartInstructionIndex() const {
- return m_it->first;
-}
-
-size_t DecodedThread::TscRange::GetEndInstructionIndex() const {
- return m_end_index;
-}
-
-bool DecodedThread::TscRange::InRange(size_t insn_index) const {
- return GetStartInstructionIndex() <= insn_index &&
- insn_index <= GetEndInstructionIndex();
-}
-
-Optional<DecodedThread::TscRange> DecodedThread::TscRange::Next() const {
- auto next_it = m_it;
- ++next_it;
- if (next_it == m_decoded_thread->m_timestamps.end())
- return None;
- return TscRange(next_it, *m_decoded_thread);
-}
-
-Optional<DecodedThread::TscRange> DecodedThread::TscRange::Prev() const {
- if (m_it == m_decoded_thread->m_timestamps.begin())
- return None;
- auto prev_it = m_it;
- --prev_it;
- return TscRange(prev_it, *m_decoded_thread);
+ (sizeof(uint64_t) + sizeof(TSC)) * m_tscs.size() +
+ (sizeof(uint64_t) + sizeof(uint64_t)) * m_nanoseconds.size() +
+ (sizeof(uint64_t) + sizeof(lldb::cpu_id_t)) * m_cpus.size();
}
diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
index bd1a90aaf250..9376a0af169d 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
@@ -71,45 +71,7 @@ private:
/// stopped at. See \a Trace::GetCursorPosition for more information.
class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
public:
- /// \class TscRange
- /// Class that represents the trace range associated with a given TSC.
- /// It provides efficient iteration to the previous or next TSC range in the
- /// decoded trace.
- ///
- /// TSC timestamps are emitted by the decoder infrequently, which means
- /// that each TSC covers a range of instruction indices, which can be used to
- /// speed up TSC lookups.
- class TscRange {
- public:
- /// Check if this TSC range includes the given instruction index.
- bool InRange(size_t insn_index) const;
-
- /// Get the next range chronologically.
- llvm::Optional<TscRange> Next() const;
-
- /// Get the previous range chronologically.
- llvm::Optional<TscRange> Prev() const;
-
- /// Get the TSC value.
- size_t GetTsc() const;
- /// Get the smallest instruction index that has this TSC.
- size_t GetStartInstructionIndex() const;
- /// Get the largest instruction index that has this TSC.
- size_t GetEndInstructionIndex() const;
-
- private:
- friend class DecodedThread;
-
- TscRange(std::map<size_t, uint64_t>::const_iterator it,
- const DecodedThread &decoded_thread);
-
- /// The iterator pointing to the beginning of the range.
- std::map<size_t, uint64_t>::const_iterator m_it;
- /// The largest instruction index that has this TSC.
- size_t m_end_index;
-
- const DecodedThread *m_decoded_thread;
- };
+ using TSC = uint64_t;
// Struct holding counts for libipts errors;
struct LibiptErrorsStats {
@@ -120,6 +82,61 @@ public:
void RecordError(int libipt_error_code);
};
+ /// A structure that represents a maximal range of trace items associated to
+ /// the same TSC value.
+ struct TSCRange {
+ TSC tsc;
+ /// Number of trace items in this range.
+ uint64_t items_count;
+ /// Index of the first trace item in this range.
+ uint64_t first_item_index;
+
+ /// \return
+ /// \b true if and only if the given \p item_index is covered by this
+ /// range.
+ bool InRange(uint64_t item_index) const;
+ };
+
+ /// A structure that represents a maximal range of trace items associated to
+ /// the same non-interpolated timestamps in nanoseconds.
+ struct NanosecondsRange {
+ /// The nanoseconds value for this range.
+ uint64_t nanos;
+ /// The corresponding TSC value for this range.
+ TSC tsc;
+ /// A nullable pointer to the next range.
+ NanosecondsRange *next_range;
+ /// Number of trace items in this range.
+ uint64_t items_count;
+ /// Index of the first trace item in this range.
+ uint64_t first_item_index;
+
+ /// Calculate an interpolated timestamp in nanoseconds for the given item
+ /// index. It's guaranteed that two different item indices will produce
+ /// different interpolated values.
+ ///
+ /// \param[in] item_index
+ /// The index of the item whose timestamp will be estimated. It has to be
+ /// part of this range.
+ ///
+ /// \param[in] beginning_of_time_nanos
+ /// The timestamp at which tracing started.
+ ///
+ /// \param[in] tsc_conversion
+ /// The tsc -> nanos conversion utility
+ ///
+ /// \return
+ /// An interpolated timestamp value for the given trace item.
+ double
+ GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos,
+ const LinuxPerfZeroTscConversion &tsc_conversion) const;
+
+ /// \return
+ /// \b true if and only if the given \p item_index is covered by this
+ /// range.
+ bool InRange(uint64_t item_index) const;
+ };
+
// Struct holding counts for events;
struct EventsStats {
/// A count for each individual event kind. We use an unordered map instead
@@ -130,39 +147,21 @@ public:
void RecordEvent(lldb::TraceEvent event);
};
- DecodedThread(lldb::ThreadSP thread_sp);
-
- /// Utility constructor that initializes the trace with a provided error.
- DecodedThread(lldb::ThreadSP thread_sp, llvm::Error &&err);
+ DecodedThread(
+ lldb::ThreadSP thread_sp,
+ const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion);
/// Get the total number of instruction, errors and events from the decoded
/// trace.
- int64_t GetItemsCount() const;
-
- /// Construct the TSC range that covers the given instruction index.
- /// This operation is O(logn) and should be used sparingly.
- /// If the trace was collected with TSC support, all the instructions of
- /// the trace will have associated TSCs. This means that this method will
- /// only return \b llvm::None if there are no TSCs whatsoever in the trace.
- ///
- /// \param[in] insn_index
- /// The instruction index in question.
- ///
- /// \param[in] hint_range
- /// An optional range that might include the given index or might be a
- /// neighbor of it. It might help speed it traversals of the trace with
- /// short jumps.
- llvm::Optional<TscRange> CalculateTscRange(
- size_t insn_index,
- const llvm::Optional<DecodedThread::TscRange> &hint_range) const;
+ uint64_t GetItemsCount() const;
/// \return
/// The error associated with a given trace item.
- const char *GetErrorByIndex(size_t item_index) const;
+ const char *GetErrorByIndex(uint64_t item_index) const;
/// \return
/// The trace item kind given an item index.
- lldb::TraceItemKind GetItemKindByIndex(size_t item_index) const;
+ lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const;
/// \return
/// The underlying event type for the given trace item index.
@@ -177,12 +176,31 @@ public:
/// The requested cpu id, or \a llvm::None if not available.
llvm::Optional<lldb::cpu_id_t> GetCPUByIndex(uint64_t item_index) const;
+ /// Get a maximal range of trace items that include the given \p item_index
+ /// that have the same TSC value.
+ ///
+ /// \param[in] item_index
+ /// The trace item index to compare with.
+ ///
+ /// \return
+ /// The requested TSC range, or \a llvm::None if not available.
+ llvm::Optional<DecodedThread::TSCRange>
+ GetTSCRangeByIndex(uint64_t item_index) const;
+
+ /// Get a maximal range of trace items that include the given \p item_index
+ /// that have the same nanoseconds timestamp without interpolation.
+ ///
+ /// \param[in] item_index
+ /// The trace item index to compare with.
+ ///
+ /// \return
+ /// The requested nanoseconds range, or \a llvm::None if not available.
+ llvm::Optional<DecodedThread::NanosecondsRange>
+ GetNanosecondsRangeByIndex(uint64_t item_index);
+
/// \return
/// The load address of the instruction at the given index.
- lldb::addr_t GetInstructionLoadAddress(size_t item_index) const;
-
- /// Get a new cursor for the decoded thread.
- lldb::TraceCursorUP CreateNewCursor();
+ lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const;
/// Return an object with statistics of the TSC decoding errors that happened.
/// A TSC error is not a fatal error and doesn't create gaps in the trace.
@@ -214,7 +232,7 @@ public:
/// Notify this object that a new tsc has been seen.
/// If this a new TSC, an event will be created.
- void NotifyTsc(uint64_t tsc);
+ void NotifyTsc(TSC tsc);
/// Notify this object that a CPU has been seen.
/// If this a new CPU, an event will be created.
@@ -262,15 +280,22 @@ private:
/// it in TraceItemStorage to avoid padding.
std::vector<uint8_t> m_item_kinds;
- /// This map contains the TSCs of the decoded instructions. It maps
- /// `instruction index -> TSC`, where `instruction index` is the first index
- /// at which the mapped TSC appears. We use this representation because TSCs
- /// are sporadic and we can think of them as ranges. If TSCs are present in
- /// the trace, all instructions will have an associated TSC, including the
- /// first one. Otherwise, this map will be empty.
- std::map<uint64_t, uint64_t> m_timestamps;
+ /// This map contains the TSCs of the decoded trace items. It maps
+ /// `item index -> TSC`, where `item index` is the first index
+ /// at which the mapped TSC first appears. We use this representation because
+ /// TSCs are sporadic and we can think of them as ranges.
+ std::map<uint64_t, TSCRange> m_tscs;
/// This is the chronologically last TSC that has been added.
- llvm::Optional<uint64_t> m_last_tsc = llvm::None;
+ llvm::Optional<std::map<uint64_t, TSCRange>::iterator> m_last_tsc =
+ llvm::None;
+ /// This map contains the non-interpolated nanoseconds timestamps of the
+ /// decoded trace items. It maps `item index -> nanoseconds`, where `item
+ /// index` is the first index at which the mapped nanoseconds first appears.
+ /// We use this representation because timestamps are sporadic and we think of
+ /// them as ranges.
+ std::map<uint64_t, NanosecondsRange> m_nanoseconds;
+ llvm::Optional<std::map<uint64_t, NanosecondsRange>::iterator>
+ m_last_nanoseconds = llvm::None;
// The cpu information is stored as a map. It maps `instruction index -> CPU`
// A CPU is associated with the next instructions that follow until the next
@@ -279,6 +304,9 @@ private:
/// This is the chronologically last CPU ID.
llvm::Optional<uint64_t> m_last_cpu = llvm::None;
+ /// TSC -> nanos conversion utility.
+ llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
+
/// Statistics of all tracing events.
EventsStats m_events_stats;
/// Statistics of libipt errors when decoding TSCs.
diff --git a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
index a98337a4e058..234b9f917d32 100644
--- a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
@@ -285,9 +285,23 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
for (size_t i = 0; i < executions.size(); i++) {
const IntelPTThreadContinousExecution &execution = executions[i];
- decoded_thread.NotifyCPU(execution.thread_execution.cpu_id);
auto variant = execution.thread_execution.variant;
+ // We report the TSCs we are sure of
+ switch (variant) {
+ case ThreadContinuousExecution::Variant::Complete:
+ decoded_thread.NotifyTsc(execution.thread_execution.tscs.complete.start);
+ break;
+ case ThreadContinuousExecution::Variant::OnlyStart:
+ decoded_thread.NotifyTsc(
+ execution.thread_execution.tscs.only_start.start);
+ break;
+ default:
+ break;
+ }
+
+ decoded_thread.NotifyCPU(execution.thread_execution.cpu_id);
+
// If we haven't seen a PSB yet, then it's fine not to show errors
if (has_seen_psbs) {
if (execution.intelpt_subtraces.empty()) {
@@ -299,12 +313,12 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
}
// If the first execution is incomplete because it doesn't have a previous
- // context switch in its cpu, all good.
+ // context switch in its cpu, all good, otherwise we report the error.
if (variant == ThreadContinuousExecution::Variant::OnlyEnd ||
variant == ThreadContinuousExecution::Variant::HintedStart) {
decoded_thread.AppendCustomError(
- formatv("Thread execution starting on cpu id = {0} doesn't "
- "have a matching context switch in.",
+ formatv("Unable to find the context switch in for the thread "
+ "execution starting on cpu id = {0}",
execution.thread_execution.cpu_id)
.str());
}
@@ -318,6 +332,18 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
decoder.DecodePSB(intel_pt_execution.psb_offset);
}
+ // We report the TSCs we are sure of
+ switch (variant) {
+ case ThreadContinuousExecution::Variant::Complete:
+ decoded_thread.NotifyTsc(execution.thread_execution.tscs.complete.end);
+ break;
+ case ThreadContinuousExecution::Variant::OnlyEnd:
+ decoded_thread.NotifyTsc(execution.thread_execution.tscs.only_end.end);
+ break;
+ default:
+ break;
+ }
+
// If we haven't seen a PSB yet, then it's fine not to show errors
if (has_seen_psbs) {
// If the last execution is incomplete because it doesn't have a following
@@ -326,8 +352,8 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
i + 1 != executions.size()) ||
variant == ThreadContinuousExecution::Variant::HintedEnd) {
decoded_thread.AppendCustomError(
- formatv("Thread execution on cpu id = {0} doesn't have a "
- "matching context switch out",
+ formatv("Unable to find the context switch out for the thread "
+ "execution on cpu id = {0}",
execution.thread_execution.cpu_id)
.str());
}
@@ -380,3 +406,22 @@ lldb_private::trace_intel_pt::SplitTraceInContinuousExecutions(
}
return executions;
}
+
+Expected<Optional<uint64_t>>
+lldb_private::trace_intel_pt::FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt,
+ ArrayRef<uint8_t> buffer) {
+ Expected<PtInsnDecoderUP> decoder_up =
+ CreateInstructionDecoder(trace_intel_pt, buffer);
+ if (!decoder_up)
+ return decoder_up.takeError();
+
+ pt_insn_decoder *decoder = decoder_up.get().get();
+ int status = pte_ok;
+ if (IsLibiptError(status = pt_insn_sync_forward(decoder)))
+ return None;
+
+ uint64_t tsc;
+ if (IsLibiptError(pt_insn_time(decoder, &tsc, nullptr, nullptr)))
+ return None;
+ return tsc;
+}
diff --git a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
index cad4d39fcf24..66f3798cd600 100644
--- a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
@@ -94,6 +94,16 @@ llvm::Expected<std::vector<IntelPTThreadSubtrace>>
SplitTraceInContinuousExecutions(TraceIntelPT &trace_intel_pt,
llvm::ArrayRef<uint8_t> buffer);
+/// Find the lowest TSC in the given trace.
+///
+/// \return
+/// The lowest TSC value in this trace if available, \a llvm::None if the
+/// trace is empty or the trace contains no timing information, or an \a
+/// llvm::Error if it was not possible to set up the decoder.
+llvm::Expected<llvm::Optional<uint64_t>>
+FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt,
+ llvm::ArrayRef<uint8_t> buffer);
+
} // namespace trace_intel_pt
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
index d3ac61f7e658..920992d9d636 100644
--- a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
@@ -23,6 +23,21 @@ using namespace llvm;
ThreadDecoder::ThreadDecoder(const ThreadSP &thread_sp, TraceIntelPT &trace)
: m_thread_sp(thread_sp), m_trace(trace) {}
+Expected<Optional<uint64_t>> ThreadDecoder::FindLowestTSC() {
+ Optional<uint64_t> lowest_tsc;
+ Error err = m_trace.OnThreadBufferRead(
+ m_thread_sp->GetID(), [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
+ Expected<Optional<uint64_t>> tsc = FindLowestTSCInTrace(m_trace, data);
+ if (!tsc)
+ return tsc.takeError();
+ lowest_tsc = *tsc;
+ return Error::success();
+ });
+ if (err)
+ return std::move(err);
+ return lowest_tsc;
+}
+
Expected<DecodedThreadSP> ThreadDecoder::Decode() {
if (!m_decoded_thread.hasValue()) {
if (Expected<DecodedThreadSP> decoded_thread = DoDecode()) {
@@ -38,8 +53,8 @@ llvm::Expected<DecodedThreadSP> ThreadDecoder::DoDecode() {
return m_trace.GetThreadTimer(m_thread_sp->GetID())
.TimeTask(
"Decoding instructions", [&]() -> Expected<DecodedThreadSP> {
- DecodedThreadSP decoded_thread_sp =
- std::make_shared<DecodedThread>(m_thread_sp);
+ DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(
+ m_thread_sp, m_trace.GetPerfZeroTscConversion());
Error err = m_trace.OnThreadBufferRead(
m_thread_sp->GetID(), [&](llvm::ArrayRef<uint8_t> data) {
diff --git a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
index 5c77ad93d27a..d580bc4dd335 100644
--- a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
@@ -36,6 +36,12 @@ public:
/// A \a DecodedThread instance.
llvm::Expected<DecodedThreadSP> Decode();
+ /// \return
+ /// The lowest TSC value in this trace if available, \a llvm::None if the
+ /// trace is empty or the trace contains no timing information, or an \a
+ /// llvm::Error if it was not possible to set up the decoder.
+ llvm::Expected<llvm::Optional<uint64_t>> FindLowestTSC();
+
ThreadDecoder(const ThreadDecoder &other) = delete;
ThreadDecoder &operator=(const ThreadDecoder &other) = delete;
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
index 185c02b6bcd9..a4d86fb48ebe 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
@@ -17,28 +17,55 @@ using namespace lldb_private;
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
-TraceCursorIntelPT::TraceCursorIntelPT(ThreadSP thread_sp,
- DecodedThreadSP decoded_thread_sp)
- : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp) {
+TraceCursorIntelPT::TraceCursorIntelPT(
+ ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp,
+ const Optional<LinuxPerfZeroTscConversion> &tsc_conversion,
+ Optional<uint64_t> beginning_of_time_nanos)
+ : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp),
+ m_tsc_conversion(tsc_conversion),
+ m_beginning_of_time_nanos(beginning_of_time_nanos) {
Seek(0, SeekType::End);
}
-void TraceCursorIntelPT::CalculateTscRange() {
- // If we failed, then we look for the exact range
- if (!m_tsc_range || !m_tsc_range->InRange(m_pos))
- m_tsc_range = m_decoded_thread_sp->CalculateTscRange(
- m_pos, /*hit_range=*/m_tsc_range);
-}
-
void TraceCursorIntelPT::Next() {
m_pos += IsForwards() ? 1 : -1;
+ ClearTimingRangesIfInvalid();
+}
+
+void TraceCursorIntelPT::ClearTimingRangesIfInvalid() {
+ if (m_tsc_range_calculated) {
+ if (!m_tsc_range || m_pos < 0 || !m_tsc_range->InRange(m_pos)) {
+ m_tsc_range = None;
+ m_tsc_range_calculated = false;
+ }
+ }
+
+ if (m_nanoseconds_range_calculated) {
+ if (!m_nanoseconds_range || m_pos < 0 ||
+ !m_nanoseconds_range->InRange(m_pos)) {
+ m_nanoseconds_range = None;
+ m_nanoseconds_range_calculated = false;
+ }
+ }
+}
- // We try to go to a neighbor tsc range that might contain the current pos
- if (m_tsc_range && !m_tsc_range->InRange(m_pos))
- m_tsc_range = IsForwards() ? m_tsc_range->Next() : m_tsc_range->Prev();
+const Optional<DecodedThread::TSCRange> &
+TraceCursorIntelPT::GetTSCRange() const {
+ if (!m_tsc_range_calculated) {
+ m_tsc_range_calculated = true;
+ m_tsc_range = m_decoded_thread_sp->GetTSCRangeByIndex(m_pos);
+ }
+ return m_tsc_range;
+}
- // If we failed, this call will fix it
- CalculateTscRange();
+const Optional<DecodedThread::NanosecondsRange> &
+TraceCursorIntelPT::GetNanosecondsRange() const {
+ if (!m_nanoseconds_range_calculated) {
+ m_nanoseconds_range_calculated = true;
+ m_nanoseconds_range =
+ m_decoded_thread_sp->GetNanosecondsRangeByIndex(m_pos);
+ }
+ return m_nanoseconds_range;
}
bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
@@ -52,13 +79,15 @@ bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
case TraceCursor::SeekType::Current:
m_pos += offset;
}
- CalculateTscRange();
+
+ ClearTimingRangesIfInvalid();
return HasValue();
}
bool TraceCursorIntelPT::HasValue() const {
- return m_pos >= 0 && m_pos < m_decoded_thread_sp->GetItemsCount();
+ return m_pos >= 0 &&
+ static_cast<uint64_t>(m_pos) < m_decoded_thread_sp->GetItemsCount();
}
lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const {
@@ -73,15 +102,18 @@ lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const {
return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos);
}
-Optional<uint64_t>
-TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) const {
- switch (counter_type) {
- case lldb::eTraceCounterTSC:
- if (m_tsc_range)
- return m_tsc_range->GetTsc();
- else
- return llvm::None;
- }
+Optional<uint64_t> TraceCursorIntelPT::GetHWClock() const {
+ if (const Optional<DecodedThread::TSCRange> &range = GetTSCRange())
+ return range->tsc;
+ return None;
+}
+
+Optional<double> TraceCursorIntelPT::GetWallClockTime() const {
+ if (const Optional<DecodedThread::NanosecondsRange> &range =
+ GetNanosecondsRange())
+ return range->GetInterpolatedTime(m_pos, *m_beginning_of_time_nanos,
+ *m_tsc_conversion);
+ return None;
}
Optional<lldb::cpu_id_t> TraceCursorIntelPT::GetCPU() const {
@@ -96,13 +128,12 @@ bool TraceCursorIntelPT::GoToId(user_id_t id) {
if (!HasId(id))
return false;
m_pos = id;
- m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos, m_tsc_range);
-
+ ClearTimingRangesIfInvalid();
return true;
}
bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const {
- return static_cast<int64_t>(id) < m_decoded_thread_sp->GetItemsCount();
+ return id < m_decoded_thread_sp->GetItemsCount();
}
user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
index 2e0f67e67dfc..3cd9ab831f5e 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
@@ -16,8 +16,10 @@ namespace trace_intel_pt {
class TraceCursorIntelPT : public TraceCursor {
public:
- TraceCursorIntelPT(lldb::ThreadSP thread_sp,
- DecodedThreadSP decoded_thread_sp);
+ TraceCursorIntelPT(
+ lldb::ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp,
+ const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion,
+ llvm::Optional<uint64_t> beginning_of_time_nanos);
bool Seek(int64_t offset, SeekType origin) override;
@@ -29,13 +31,12 @@ public:
lldb::addr_t GetLoadAddress() const override;
- llvm::Optional<uint64_t>
- GetCounter(lldb::TraceCounter counter_type) const override;
-
lldb::TraceEvent GetEventType() const override;
llvm::Optional<lldb::cpu_id_t> GetCPU() const override;
+ llvm::Optional<uint64_t> GetHWClock() const override;
+
lldb::TraceItemKind GetItemKind() const override;
bool GoToId(lldb::user_id_t id) override;
@@ -44,16 +45,43 @@ public:
bool HasId(lldb::user_id_t id) const override;
+ llvm::Optional<double> GetWallClockTime() const override;
+
private:
- /// Calculate the tsc range for the current position if needed.
- void CalculateTscRange();
+ /// Clear the current TSC and nanoseconds ranges if after moving they are not
+ /// valid anymore.
+ void ClearTimingRangesIfInvalid();
+
+ /// Get or calculate the TSC range that includes the current trace item.
+ const llvm::Optional<DecodedThread::TSCRange> &GetTSCRange() const;
+
+ /// Get or calculate the TSC range that includes the current trace item.
+ const llvm::Optional<DecodedThread::NanosecondsRange> &
+ GetNanosecondsRange() const;
/// Storage of the actual instructions
DecodedThreadSP m_decoded_thread_sp;
/// Internal instruction index currently pointing at.
int64_t m_pos;
- /// Tsc range covering the current instruction.
- llvm::Optional<DecodedThread::TscRange> m_tsc_range;
+
+ /// Timing information and cached values.
+ /// \{
+
+ /// TSC -> nanos conversion utility. \a None if not available at all.
+ llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
+ /// Lowest nanoseconds timestamp seen in any thread trace, \a None if not
+ /// available at all.
+ llvm::Optional<uint64_t> m_beginning_of_time_nanos;
+ /// Range of trace items with the same TSC that includes the current trace
+ /// item, \a None if not calculated or not available.
+ llvm::Optional<DecodedThread::TSCRange> mutable m_tsc_range;
+ bool mutable m_tsc_range_calculated = false;
+ /// Range of trace items with the same non-interpolated timestamps in
+ /// nanoseconds that includes the current trace item, \a None if not
+ /// calculated or not available.
+ llvm::Optional<DecodedThread::NanosecondsRange> mutable m_nanoseconds_range;
+ bool mutable m_nanoseconds_range_calculated = false;
+ /// \}
};
} // namespace trace_intel_pt
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index 57433ffb14cb..f3f0a513e3fa 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -8,6 +8,8 @@
#include "TraceIntelPT.h"
+#include "TraceCursorIntelPT.h"
+
#include "../common/ThreadPostMortemTrace.h"
#include "CommandObjectTraceStartIntelPT.h"
#include "DecodedThread.h"
@@ -138,11 +140,53 @@ Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) {
return it->second->Decode();
}
+Expected<Optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() {
+ Storage &storage = GetUpdatedStorage();
+ if (storage.beginning_of_time_nanos_calculated)
+ return storage.beginning_of_time_nanos;
+ storage.beginning_of_time_nanos_calculated = true;
+
+ if (!storage.tsc_conversion)
+ return None;
+
+ Optional<uint64_t> lowest_tsc;
+
+ if (storage.multicpu_decoder) {
+ if (Expected<Optional<uint64_t>> tsc =
+ storage.multicpu_decoder->FindLowestTSC()) {
+ lowest_tsc = *tsc;
+ } else {
+ return tsc.takeError();
+ }
+ }
+
+ for (auto &decoder : storage.thread_decoders) {
+ Expected<Optional<uint64_t>> tsc = decoder.second->FindLowestTSC();
+ if (!tsc)
+ return tsc.takeError();
+
+ if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
+ lowest_tsc = **tsc;
+ }
+
+ if (lowest_tsc) {
+ storage.beginning_of_time_nanos =
+ storage.tsc_conversion->ToNanos(*lowest_tsc);
+ }
+ return storage.beginning_of_time_nanos;
+}
+
llvm::Expected<lldb::TraceCursorUP>
TraceIntelPT::CreateNewCursor(Thread &thread) {
- if (Expected<DecodedThreadSP> decoded_thread = Decode(thread))
- return decoded_thread.get()->CreateNewCursor();
- else
+ if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) {
+ if (Expected<Optional<uint64_t>> beginning_of_time =
+ FindBeginningOfTimeNanos())
+ return std::make_unique<TraceCursorIntelPT>(
+ thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion,
+ *beginning_of_time);
+ else
+ return beginning_of_time.takeError();
+ } else
return decoded_thread.takeError();
}
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
index d3e58374867d..7f2c3f8dda5d 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -220,6 +220,13 @@ private:
/// returned if the decoder couldn't be properly set up.
llvm::Expected<DecodedThreadSP> Decode(Thread &thread);
+ /// \return
+ /// The lowest timestamp in nanoseconds in all traces if available, \a
+ /// llvm::None if all the traces were empty or no trace contained no
+ /// timing information, or an \a llvm::Error if it was not possible to set
+ /// up the decoder for some trace.
+ llvm::Expected<llvm::Optional<uint64_t>> FindBeginningOfTimeNanos();
+
// Dump out trace info in JSON format
void DumpTraceInfoAsJson(Thread &thread, Stream &s, bool verbose);
@@ -236,6 +243,8 @@ private:
/// It is provided by either a trace bundle or a live process to convert TSC
/// counters to and from nanos. It might not be available on all hosts.
llvm::Optional<LinuxPerfZeroTscConversion> tsc_conversion;
+ llvm::Optional<uint64_t> beginning_of_time_nanos;
+ bool beginning_of_time_nanos_calculated = false;
} m_storage;
/// It is provided by either a trace bundle or a live process' "cpuInfo"
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
index e547032f739d..08f54b582e3f 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
@@ -35,6 +35,28 @@ bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {
return m_tids.count(tid);
}
+Expected<Optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() {
+ Optional<uint64_t> lowest_tsc;
+ TraceIntelPTSP trace_sp = GetTrace();
+
+ Error err = GetTrace()->OnAllCpusBinaryDataRead(
+ IntelPTDataKinds::kIptTrace,
+ [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
+ for (auto &cpu_id_to_buffer : buffers) {
+ Expected<Optional<uint64_t>> tsc =
+ FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second);
+ if (!tsc)
+ return tsc.takeError();
+ if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
+ lowest_tsc = **tsc;
+ }
+ return Error::success();
+ });
+ if (err)
+ return std::move(err);
+ return lowest_tsc;
+}
+
Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
return std::move(err);
@@ -48,8 +70,8 @@ Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
if (it != m_decoded_threads.end())
return it->second;
- DecodedThreadSP decoded_thread_sp =
- std::make_shared<DecodedThread>(thread.shared_from_this());
+ DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(
+ thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion());
Error err = trace_sp->OnAllCpusBinaryDataRead(
IntelPTDataKinds::kIptTrace,
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h
index 3b7926760f3c..87c370e88ae6 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h
@@ -66,6 +66,12 @@ public:
/// The total number of PSB blocks in all cores.
size_t GetTotalPSBBlocksCount() const;
+ /// \return
+ /// The lowest TSC value in this trace if available, \a llvm::None if the
+ /// trace is empty or the trace contains no timing information, or an \a
+ /// llvm::Error if it was not possible to set up the decoder.
+ llvm::Expected<llvm::Optional<uint64_t>> FindLowestTSC();
+
private:
/// Traverse the context switch traces and the basic intel pt continuous
/// subtraces and produce a list of continuous executions for each process and
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
index 92eec139e07c..c796cbc75c1b 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -968,7 +968,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the
// epilogue started executed
- bool prologue_completed_is_aligned;
+ bool prologue_completed_is_aligned = false;
std::vector<bool> prologue_completed_saved_registers;
while (current_func_text_offset < size) {
diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp
index 4ee5a3e76ae4..f83bdcdc1c74 100644
--- a/lldb/source/Symbol/Type.cpp
+++ b/lldb/source/Symbol/Type.cpp
@@ -162,8 +162,8 @@ Type::Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name,
}
Type::Type()
- : std::enable_shared_from_this<Type>(), UserID(0),
- m_name("<INVALID TYPE>") {
+ : std::enable_shared_from_this<Type>(), UserID(0), m_name("<INVALID TYPE>"),
+ m_payload(0) {
m_byte_size = 0;
m_byte_size_has_value = false;
}
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 046706637691..b2f1318ca91d 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -433,7 +433,8 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0),
m_memory_cache(*this), m_allocated_memory_cache(*this),
m_should_detach(false), m_next_event_action_up(), m_public_run_lock(),
- m_private_run_lock(), m_finalizing(false),
+ m_private_run_lock(), m_currently_handling_do_on_removals(false),
+ m_resume_requested(false), m_finalizing(false),
m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false),
m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false),
m_can_interpret_function_calls(false), m_run_thread_plan_lock(),
@@ -2566,8 +2567,8 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state,
if (state == eStateStopped || state == eStateCrashed) {
DidLaunch();
-
- // Now that we know the process type, update its signal responses from the
+
+ // Now that we know the process type, update its signal responses from the
// ones stored in the Target:
if (m_unix_signals_sp) {
StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream();
@@ -2935,7 +2936,7 @@ void Process::CompleteAttach() {
}
}
}
- // Now that we know the process type, update its signal responses from the
+ // Now that we know the process type, update its signal responses from the
// ones stored in the Target:
if (m_unix_signals_sp) {
StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream();
@@ -4550,9 +4551,9 @@ public:
private:
lldb::ThreadPlanSP m_thread_plan_sp;
bool m_already_reset = false;
- bool m_private;
- bool m_is_controlling;
- bool m_okay_to_discard;
+ bool m_private = false;
+ bool m_is_controlling = false;
+ bool m_okay_to_discard = false;
};
} // anonymous namespace
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index a0f97d7e7cff..2da40ba2bf61 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1525,7 +1525,7 @@ RegisterContextUnwind::SavedLocationForRegister(
// unwindplan_regloc has valid contents about where to retrieve the register
if (unwindplan_regloc.IsUnspecified()) {
- lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc = {};
new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
UnwindLogMsg("save location for %s (%d) is unspecified, continue searching",
@@ -1731,7 +1731,7 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() {
addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS;
addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS;
- UnwindLLDB::RegisterLocation regloc;
+ UnwindLLDB::RegisterLocation regloc = {};
if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB),
regloc) ==
UnwindLLDB::RegisterSearchResult::eRegisterFound) {
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index e87cf5af3e39..4fb5ba0b735e 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -1145,26 +1145,34 @@ bool StackFrame::HasDebugInformation() {
ValueObjectSP
StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp,
DynamicValueType use_dynamic) {
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
ValueObjectSP valobj_sp;
- if (IsHistorical()) {
- return valobj_sp;
- }
- VariableList *var_list = GetVariableList(true);
- if (var_list) {
- // Make sure the variable is a frame variable
- const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get());
- const uint32_t num_variables = var_list->GetSize();
- if (var_idx < num_variables) {
- valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx);
- if (!valobj_sp) {
- if (m_variable_list_value_objects.GetSize() < num_variables)
- m_variable_list_value_objects.Resize(num_variables);
- valobj_sp = ValueObjectVariable::Create(this, variable_sp);
- m_variable_list_value_objects.SetValueObjectAtIndex(var_idx, valobj_sp);
+ { // Scope for stack frame mutex. We need to drop this mutex before we figure
+ // out the dynamic value. That will require converting the StackID in the
+ // VO back to a StackFrame, which will in turn require locking the
+ // StackFrameList. If we still hold the StackFrame mutex, we could suffer
+ // lock inversion against the pattern of getting the StackFrameList and
+ // then the stack frame, which is fairly common.
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (IsHistorical()) {
+ return valobj_sp;
+ }
+ VariableList *var_list = GetVariableList(true);
+ if (var_list) {
+ // Make sure the variable is a frame variable
+ const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get());
+ const uint32_t num_variables = var_list->GetSize();
+ if (var_idx < num_variables) {
+ valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx);
+ if (!valobj_sp) {
+ if (m_variable_list_value_objects.GetSize() < num_variables)
+ m_variable_list_value_objects.Resize(num_variables);
+ valobj_sp = ValueObjectVariable::Create(this, variable_sp);
+ m_variable_list_value_objects.SetValueObjectAtIndex(var_idx,
+ valobj_sp);
+ }
}
}
- }
+ } // End of StackFrame mutex scope.
if (use_dynamic != eNoDynamicValues && valobj_sp) {
ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue(use_dynamic);
if (dynamic_sp)
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
index a9f774aa6109..7e9bb963bb5d 100644
--- a/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -104,7 +104,10 @@ ThreadPlanCallFunction::ThreadPlanCallFunction(
m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
m_debug_execution(options.GetDebug()),
m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function),
- m_function_sp(0), m_takedown_done(false),
+ m_start_addr(), m_function_sp(0), m_subplan_sp(),
+ m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr),
+ m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(),
+ m_return_valobj_sp(), m_takedown_done(false),
m_should_clear_objc_exception_bp(false),
m_should_clear_cxx_exception_bp(false),
m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) {
@@ -134,7 +137,10 @@ ThreadPlanCallFunction::ThreadPlanCallFunction(
m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
m_debug_execution(options.GetDebug()),
m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function),
- m_function_sp(0), m_takedown_done(false),
+ m_start_addr(), m_function_sp(0), m_subplan_sp(),
+ m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr),
+ m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(),
+ m_return_valobj_sp(), m_takedown_done(false),
m_should_clear_objc_exception_bp(false),
m_should_clear_cxx_exception_bp(false),
m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(CompilerType()) {}
diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp
index f5331428038b..7e0925307644 100644
--- a/lldb/source/Target/ThreadPlanTracer.cpp
+++ b/lldb/source/Target/ThreadPlanTracer.cpp
@@ -36,11 +36,11 @@ using namespace lldb_private;
ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp)
: m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
- m_enabled(false), m_stream_sp(stream_sp) {}
+ m_enabled(false), m_stream_sp(stream_sp), m_thread(nullptr) {}
ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
: m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
- m_enabled(false), m_stream_sp() {}
+ m_enabled(false), m_stream_sp(), m_thread(nullptr) {}
Stream *ThreadPlanTracer::GetLogStream() {
if (m_stream_sp)
diff --git a/lldb/source/Target/TraceCursor.cpp b/lldb/source/Target/TraceCursor.cpp
index f99b0d28c154..de3f9bf1b33d 100644
--- a/lldb/source/Target/TraceCursor.cpp
+++ b/lldb/source/Target/TraceCursor.cpp
@@ -50,6 +50,8 @@ const char *TraceCursor::EventKindToString(lldb::TraceEvent event_kind) {
return "software disabled tracing";
case lldb::eTraceEventCPUChanged:
return "CPU core changed";
+ case lldb::eTraceEventHWClockTick:
+ return "HW clock tick";
}
llvm_unreachable("Fully covered switch above");
}
diff --git a/lldb/source/Target/TraceDumper.cpp b/lldb/source/Target/TraceDumper.cpp
index 739105e9e9fb..5b71e9e4e97a 100644
--- a/lldb/source/Target/TraceDumper.cpp
+++ b/lldb/source/Target/TraceDumper.cpp
@@ -128,16 +128,26 @@ public:
m_s.Format(" {0}: ", item.id);
- if (m_options.show_tsc) {
- m_s.Format("[tsc={0}] ",
- item.tsc ? std::to_string(*item.tsc) : "unavailable");
+ if (m_options.show_timestamps) {
+ m_s.Format("[{0}] ", item.timestamp
+ ? formatv("{0:3} ns", *item.timestamp).str()
+ : "unavailable");
}
if (item.event) {
m_s << "(event) " << TraceCursor::EventKindToString(*item.event);
- if (*item.event == eTraceEventCPUChanged) {
+ switch (*item.event) {
+ case eTraceEventCPUChanged:
m_s.Format(" [new CPU={0}]",
item.cpu_id ? std::to_string(*item.cpu_id) : "unavailable");
+ break;
+ case eTraceEventHWClockTick:
+ m_s.Format(" [{0}]", item.hw_clock ? std::to_string(*item.hw_clock)
+ : "unavailable");
+ break;
+ case eTraceEventDisabledHW:
+ case eTraceEventDisabledSW:
+ break;
}
} else if (item.error) {
m_s << "(error) " << *item.error;
@@ -181,7 +191,8 @@ class OutputWriterJSON : public TraceDumper::OutputWriter {
| {
"loadAddress": string decimal,
"id": decimal,
- "tsc"?: string decimal,
+ "hwClock"?: string decimal,
+ "timestamp_ns"?: string decimal,
"module"?: string,
"symbol"?: string,
"line"?: decimal,
@@ -202,8 +213,17 @@ public:
void DumpEvent(const TraceDumper::TraceItem &item) {
m_j.attribute("event", TraceCursor::EventKindToString(*item.event));
- if (item.event == eTraceEventCPUChanged)
+ switch (*item.event) {
+ case eTraceEventCPUChanged:
m_j.attribute("cpuId", item.cpu_id);
+ break;
+ case eTraceEventHWClockTick:
+ m_j.attribute("hwClock", item.hw_clock);
+ break;
+ case eTraceEventDisabledHW:
+ case eTraceEventDisabledSW:
+ break;
+ }
}
void DumpInstruction(const TraceDumper::TraceItem &item) {
@@ -234,10 +254,11 @@ public:
void TraceItem(const TraceDumper::TraceItem &item) override {
m_j.object([&] {
m_j.attribute("id", item.id);
- if (m_options.show_tsc)
- m_j.attribute(
- "tsc",
- item.tsc ? Optional<std::string>(std::to_string(*item.tsc)) : None);
+ if (m_options.show_timestamps)
+ m_j.attribute("timestamp_ns", item.timestamp
+ ? Optional<std::string>(
+ std::to_string(*item.timestamp))
+ : None);
if (item.event) {
DumpEvent(item);
@@ -286,11 +307,11 @@ TraceDumper::TraceDumper(lldb::TraceCursorUP &&cursor_up, Stream &s,
}
TraceDumper::TraceItem TraceDumper::CreatRawTraceItem() {
- TraceItem item;
+ TraceItem item = {};
item.id = m_cursor_up->GetId();
- if (m_options.show_tsc)
- item.tsc = m_cursor_up->GetCounter(lldb::eTraceCounterTSC);
+ if (m_options.show_timestamps)
+ item.timestamp = m_cursor_up->GetWallClockTime();
return item;
}
@@ -366,8 +387,17 @@ Optional<lldb::user_id_t> TraceDumper::DumpInstructions(size_t count) {
if (!m_options.show_events)
continue;
item.event = m_cursor_up->GetEventType();
- if (*item.event == eTraceEventCPUChanged)
+ switch (*item.event) {
+ case eTraceEventCPUChanged:
item.cpu_id = m_cursor_up->GetCPU();
+ break;
+ case eTraceEventHWClockTick:
+ item.hw_clock = m_cursor_up->GetHWClock();
+ break;
+ case eTraceEventDisabledHW:
+ case eTraceEventDisabledSW:
+ break;
+ }
} else if (m_cursor_up->IsError()) {
item.error = m_cursor_up->GetError();
} else {
diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index c14414c46419..a6d19d342822 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -907,6 +907,8 @@ class SmallDenseMap
public:
explicit SmallDenseMap(unsigned NumInitBuckets = 0) {
+ if (NumInitBuckets > InlineBuckets)
+ NumInitBuckets = NextPowerOf2(NumInitBuckets - 1);
init(NumInitBuckets);
}
diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h
index d1615d903e98..e164dc01c840 100644
--- a/llvm/include/llvm/ADT/Optional.h
+++ b/llvm/include/llvm/ADT/Optional.h
@@ -318,7 +318,9 @@ public:
template <typename U> constexpr T value_or(U &&alt) const & {
return has_value() ? value() : std::forward<U>(alt);
}
- template <typename U> constexpr T getValueOr(U &&alt) const & {
+ template <typename U>
+ [[deprecated("Use value_or instead.")]] constexpr T
+ getValueOr(U &&alt) const & {
return has_value() ? value() : std::forward<U>(alt);
}
@@ -337,7 +339,8 @@ public:
template <typename U> T value_or(U &&alt) && {
return has_value() ? std::move(value()) : std::forward<U>(alt);
}
- template <typename U> T getValueOr(U &&alt) && {
+ template <typename U>
+ [[deprecated("Use value_or instead.")]] T getValueOr(U &&alt) && {
return has_value() ? std::move(value()) : std::forward<U>(alt);
}
diff --git a/llvm/include/llvm/Analysis/DDG.h b/llvm/include/llvm/Analysis/DDG.h
index 7649e630b23d..bc599cb1f9a1 100644
--- a/llvm/include/llvm/Analysis/DDG.h
+++ b/llvm/include/llvm/Analysis/DDG.h
@@ -348,37 +348,37 @@ public:
DDGBuilder(DataDependenceGraph &G, DependenceInfo &D,
const BasicBlockListType &BBs)
: AbstractDependenceGraphBuilder(G, D, BBs) {}
- DDGNode &createRootNode() final override {
+ DDGNode &createRootNode() final {
auto *RN = new RootDDGNode();
assert(RN && "Failed to allocate memory for DDG root node.");
Graph.addNode(*RN);
return *RN;
}
- DDGNode &createFineGrainedNode(Instruction &I) final override {
+ DDGNode &createFineGrainedNode(Instruction &I) final {
auto *SN = new SimpleDDGNode(I);
assert(SN && "Failed to allocate memory for simple DDG node.");
Graph.addNode(*SN);
return *SN;
}
- DDGNode &createPiBlock(const NodeListType &L) final override {
+ DDGNode &createPiBlock(const NodeListType &L) final {
auto *Pi = new PiBlockDDGNode(L);
assert(Pi && "Failed to allocate memory for pi-block node.");
Graph.addNode(*Pi);
return *Pi;
}
- DDGEdge &createDefUseEdge(DDGNode &Src, DDGNode &Tgt) final override {
+ DDGEdge &createDefUseEdge(DDGNode &Src, DDGNode &Tgt) final {
auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::RegisterDefUse);
assert(E && "Failed to allocate memory for edge");
Graph.connect(Src, Tgt, *E);
return *E;
}
- DDGEdge &createMemoryEdge(DDGNode &Src, DDGNode &Tgt) final override {
+ DDGEdge &createMemoryEdge(DDGNode &Src, DDGNode &Tgt) final {
auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::MemoryDependence);
assert(E && "Failed to allocate memory for edge");
Graph.connect(Src, Tgt, *E);
return *E;
}
- DDGEdge &createRootedEdge(DDGNode &Src, DDGNode &Tgt) final override {
+ DDGEdge &createRootedEdge(DDGNode &Src, DDGNode &Tgt) final {
auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::Rooted);
assert(E && "Failed to allocate memory for edge");
assert(isa<RootDDGNode>(Src) && "Expected root node");
@@ -386,7 +386,7 @@ public:
return *E;
}
- const NodeListType &getNodesInPiBlock(const DDGNode &N) final override {
+ const NodeListType &getNodesInPiBlock(const DDGNode &N) final {
auto *PiNode = dyn_cast<const PiBlockDDGNode>(&N);
assert(PiNode && "Expected a pi-block node.");
return PiNode->getNodes();
@@ -394,11 +394,10 @@ public:
/// Return true if the two nodes \pSrc and \pTgt are both simple nodes and
/// the consecutive instructions after merging belong to the same basic block.
- bool areNodesMergeable(const DDGNode &Src,
- const DDGNode &Tgt) const final override;
- void mergeNodes(DDGNode &Src, DDGNode &Tgt) final override;
- bool shouldSimplify() const final override;
- bool shouldCreatePiBlocks() const final override;
+ bool areNodesMergeable(const DDGNode &Src, const DDGNode &Tgt) const final;
+ void mergeNodes(DDGNode &Src, DDGNode &Tgt) final;
+ bool shouldSimplify() const final;
+ bool shouldCreatePiBlocks() const final;
};
raw_ostream &operator<<(raw_ostream &OS, const DDGNode &N);
diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h
index 422f63db749f..5cc85c4677cb 100644
--- a/llvm/include/llvm/Analysis/MemoryBuiltins.h
+++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h
@@ -30,7 +30,6 @@ namespace llvm {
class AllocaInst;
class AAResults;
class Argument;
-class CallInst;
class ConstantPointerNull;
class DataLayout;
class ExtractElementInst;
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index da4410fcac14..6ea6d2361eba 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -49,7 +49,6 @@ class InstCombiner;
class OptimizationRemarkEmitter;
class IntrinsicInst;
class LoadInst;
-class LoopAccessInfo;
class Loop;
class LoopInfo;
class LoopVectorizationLegality;
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 1fd025761127..a0bb50db8c54 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -900,6 +900,26 @@ enum {
#include "ELFRelocs/CSKY.def"
};
+// LoongArch Specific e_flags
+enum : unsigned {
+ // Reference: https://github.com/loongson/LoongArch-Documentation.
+ // The last commit hash (main branch) is
+ // 99016636af64d02dee05e39974d4c1e55875c45b.
+ // Note that there is an open PR
+ // https://github.com/loongson/LoongArch-Documentation/pull/47
+ // talking about using 0x1, 0x2, 0x3 for ILP32S/F/D and use EI_CLASS to
+ // distinguish LP64 and ILP32. If this PR get merged, we will update
+ // the definition here.
+ // Base ABI Types.
+ EF_LOONGARCH_BASE_ABI_LP64S = 0x1, // LP64 soft-float ABI
+ EF_LOONGARCH_BASE_ABI_LP64F = 0x2, // LP64 single-float ABI
+ EF_LOONGARCH_BASE_ABI_LP64D = 0x3, // LP64 double-float ABI
+ EF_LOONGARCH_BASE_ABI_ILP32S = 0x5, // ILP32 soft-float ABI
+ EF_LOONGARCH_BASE_ABI_ILP32F = 0x6, // ILP32 single-float ABI
+ EF_LOONGARCH_BASE_ABI_ILP32D = 0x7, // ILP32 double-float ABI
+ EF_LOONGARCH_BASE_ABI_MASK = 0x7, // Mask for selecting base ABI
+};
+
// ELF Relocation types for LoongArch
enum {
#include "ELFRelocs/LoongArch.def"
@@ -1366,6 +1386,8 @@ enum {
// These all contain stack unwind tables.
PT_ARM_EXIDX = 0x70000001,
PT_ARM_UNWIND = 0x70000001,
+ // MTE memory tag segment type
+ PT_AARCH64_MEMTAG_MTE = 0x70000002,
// MIPS program header types.
PT_MIPS_REGINFO = 0x70000000, // Register usage information.
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h
index dd213bf68e62..87dae64c5f90 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h
@@ -39,14 +39,14 @@ public:
class CSEConfigFull : public CSEConfigBase {
public:
virtual ~CSEConfigFull() = default;
- virtual bool shouldCSEOpc(unsigned Opc) override;
+ bool shouldCSEOpc(unsigned Opc) override;
};
// Commonly used for O0 config.
class CSEConfigConstantOnly : public CSEConfigBase {
public:
virtual ~CSEConfigConstantOnly() = default;
- virtual bool shouldCSEOpc(unsigned Opc) override;
+ bool shouldCSEOpc(unsigned Opc) override;
};
// Returns the standard expected CSEConfig for the given optimization level.
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
index f7fafdc57401..e40f00433870 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
@@ -590,7 +590,7 @@ private:
assert(irt && "irt is null!");
}
- virtual void addSuccessorWithProb(
+ void addSuccessorWithProb(
MachineBasicBlock *Src, MachineBasicBlock *Dst,
BranchProbability Prob = BranchProbability::getUnknown()) override {
IRT->addSuccessorWithProb(Src, Dst, Prob);
diff --git a/llvm/include/llvm/CodeGen/LiveIntervals.h b/llvm/include/llvm/CodeGen/LiveIntervals.h
index b26aa773c9ea..0c846c6671a7 100644
--- a/llvm/include/llvm/CodeGen/LiveIntervals.h
+++ b/llvm/include/llvm/CodeGen/LiveIntervals.h
@@ -39,7 +39,6 @@ namespace llvm {
extern cl::opt<bool> UseSegmentSetForPhysRegs;
-class AAResults;
class BitVector;
class LiveIntervalCalc;
class MachineBlockFrequencyInfo;
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index c531ddf8e906..389fbce72ad0 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -53,6 +53,7 @@
#include <iterator>
#include <string>
#include <tuple>
+#include <utility>
namespace llvm {
@@ -2079,6 +2080,11 @@ public:
bool isConstant() const;
+ /// If this BuildVector is constant and represents the numerical series
+ /// <a, a+n, a+2n, a+3n, ...> where a is integer and n is a non-zero integer,
+ /// the value <a,n> is returned.
+ Optional<std::pair<APInt, APInt>> isConstantSequence() const;
+
/// Recast bit data \p SrcBitElements to \p DstEltSizeInBits wide elements.
/// Undef elements are treated as zero, and entirely undefined elements are
/// flagged in \p DstUndefElements.
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index a1c9061baee6..72f69f4c6b77 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -38,7 +38,6 @@
namespace llvm {
-class AAResults;
class DFAPacketizer;
class InstrItineraryData;
class LiveIntervals;
diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
index 3961100e00e1..4729e5f806d8 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
@@ -245,7 +245,7 @@ public:
/// Link debug info for added objFiles. Object
/// files are linked all together.
- bool link();
+ Error link();
/// A number of methods setting various linking options:
diff --git a/llvm/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h b/llvm/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h
index 6cd5c8d1d668..93525b716791 100644
--- a/llvm/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h
+++ b/llvm/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h
@@ -32,15 +32,12 @@ public:
template <typename ChildType>
class NullEnumerator : public IPDBEnumChildren<ChildType> {
- virtual uint32_t getChildCount() const override { return 0; }
- virtual std::unique_ptr<ChildType>
- getChildAtIndex(uint32_t Index) const override {
+ uint32_t getChildCount() const override { return 0; }
+ std::unique_ptr<ChildType> getChildAtIndex(uint32_t Index) const override {
return nullptr;
}
- virtual std::unique_ptr<ChildType> getNext() override {
- return nullptr;
- }
- virtual void reset() override {}
+ std::unique_ptr<ChildType> getNext() override { return nullptr; }
+ void reset() override {}
};
} // end namespace pdb
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h b/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
index 9a2bc9b09350..d68dccac3fa9 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
@@ -126,6 +126,24 @@ enum EdgeKind_x86_64 : Edge::Kind {
///
BranchPCRel32,
+ /// A 32-bit PC-relative relocation.
+ ///
+ /// Represents a data/control flow instruction using PC-relative addressing
+ /// to a target.
+ ///
+ /// The fixup expression for this kind includes an implicit offset to account
+ /// for the PC (unlike the Delta edges) so that a PCRel32 with a target
+ /// T and addend zero is a call/branch to the start (offset zero) of T.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - (Fixup + 4) + Addend : int32
+ ///
+ /// Errors:
+ /// - The result of the fixup expression must fit into an int32, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ PCRel32,
+
/// A 32-bit PC-relative branch to a pointer jump stub.
///
/// The target of this relocation should be a pointer jump stub of the form:
@@ -343,7 +361,9 @@ enum EdgeKind_x86_64 : Edge::Kind {
/// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
/// phase will result in an assert/unreachable during the fixup phase.
///
- RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable
+ RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable,
+ // First platform specific relocation.
+ FirstPlatformRelocation
};
/// Returns a string name for the given x86-64 edge. For debugging purposes
@@ -395,6 +415,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
break;
}
+ case PCRel32:
case BranchPCRel32:
case BranchPCRel32ToPtrJumpStub:
case BranchPCRel32ToPtrJumpStubBypassable:
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h
index 69d8cf5d2980..37fe5a98b093 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_EXECUTORSHAREDMEMORYMAPPERSERVICE
-#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_EXECUTORSHAREDMEMORYMAPPERSERVICE
+#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_EXECUTORSHAREDMEMORYMAPPERSERVICE_H
+#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_EXECUTORSHAREDMEMORYMAPPERSERVICE_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
@@ -75,4 +75,4 @@ private:
} // namespace rt_bootstrap
} // namespace orc
} // namespace llvm
-#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_EXECUTORSHAREDMEMORYMAPPERSERVICE
+#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_EXECUTORSHAREDMEMORYMAPPERSERVICE_H
diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 083fed5de4a3..480a559e2226 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -848,6 +848,8 @@ public:
void setOrdering(AtomicOrdering Ordering) {
assert(Ordering != AtomicOrdering::NotAtomic &&
"atomicrmw instructions can only be atomic.");
+ assert(Ordering != AtomicOrdering::Unordered &&
+ "atomicrmw instructions cannot be unordered.");
setSubclassData<AtomicOrderingField>(Ordering);
}
diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h
index fc9111a4f512..4ff48c3669d5 100644
--- a/llvm/include/llvm/IR/IntrinsicInst.h
+++ b/llvm/include/llvm/IR/IntrinsicInst.h
@@ -84,7 +84,7 @@ public:
}
}
- // Checks if the intrinsic is an annotation.
+ /// Checks if the intrinsic is an annotation.
bool isAssumeLikeIntrinsic() const {
switch (getIntrinsicID()) {
default: break;
@@ -107,7 +107,11 @@ public:
return false;
}
- // Methods for support type inquiry through isa, cast, and dyn_cast:
+ /// Check if the intrinsic might lower into a regular function call in the
+ /// course of IR transformations
+ static bool mayLowerToFunctionCall(Intrinsic::ID IID);
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const CallInst *I) {
if (const Function *CF = I->getCalledFunction())
return CF->isIntrinsic();
@@ -1356,9 +1360,6 @@ public:
}
};
-// Defined in Statepoint.h -- NOT a subclass of IntrinsicInst
-class GCStatepointInst;
-
/// Common base class for representing values projected from a statepoint.
/// Currently, the only projections available are gc.result and gc.relocate.
class GCProjectionInst : public IntrinsicInst {
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index c523e3773de4..d46fa4fbf5b5 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1759,6 +1759,12 @@ def int_type_checked_load : DefaultAttrsIntrinsic<[llvm_ptr_ty, llvm_i1_ty],
[llvm_ptr_ty, llvm_i32_ty, llvm_metadata_ty],
[IntrNoMem, IntrWillReturn]>;
+// Test whether a pointer is associated with a type metadata identifier. Used
+// for public visibility classes that may later be refined to private
+// visibility.
+def int_public_type_test : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty],
+ [IntrNoMem, IntrWillReturn, IntrSpeculatable]>;
+
// Create a branch funnel that implements an indirect call to a limited set of
// callees. This needs to be a musttail call.
def int_icall_branch_funnel : DefaultAttrsIntrinsic<[], [llvm_vararg_ty], []>;
diff --git a/llvm/include/llvm/IR/ModuleSummaryIndex.h b/llvm/include/llvm/IR/ModuleSummaryIndex.h
index f1dd29926278..468773ac5909 100644
--- a/llvm/include/llvm/IR/ModuleSummaryIndex.h
+++ b/llvm/include/llvm/IR/ModuleSummaryIndex.h
@@ -1122,6 +1122,9 @@ private:
/// every summary of a GV is synchronized.
bool WithDSOLocalPropagation = false;
+ /// Indicates that we have whole program visibility.
+ bool WithWholeProgramVisibility = false;
+
/// Indicates that summary-based synthetic entry count propagation has run
bool HasSyntheticEntryCounts = false;
@@ -1280,6 +1283,9 @@ public:
bool withDSOLocalPropagation() const { return WithDSOLocalPropagation; }
void setWithDSOLocalPropagation() { WithDSOLocalPropagation = true; }
+ bool withWholeProgramVisibility() const { return WithWholeProgramVisibility; }
+ void setWithWholeProgramVisibility() { WithWholeProgramVisibility = true; }
+
bool isReadOnly(const GlobalVarSummary *GVS) const {
return WithAttributePropagation && GVS->maybeReadOnly();
}
diff --git a/llvm/include/llvm/IR/PrintPasses.h b/llvm/include/llvm/IR/PrintPasses.h
index 1fa7c1893e20..e721db999341 100644
--- a/llvm/include/llvm/IR/PrintPasses.h
+++ b/llvm/include/llvm/IR/PrintPasses.h
@@ -10,10 +10,25 @@
#define LLVM_IR_PRINTPASSES_H
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
#include <vector>
namespace llvm {
+enum class ChangePrinter {
+ None,
+ Verbose,
+ Quiet,
+ DiffVerbose,
+ DiffQuiet,
+ ColourDiffVerbose,
+ ColourDiffQuiet,
+ DotCfgVerbose,
+ DotCfgQuiet
+};
+
+extern cl::opt<ChangePrinter> PrintChanged;
+
// Returns true if printing before/after some pass is enabled, whether all
// passes or a specific pass.
bool shouldPrintBeforeSomePass();
diff --git a/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h b/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h
index 96f82a9276e0..fdd6ec74bce6 100644
--- a/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h
+++ b/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h
@@ -102,6 +102,9 @@ struct LTOCodeGenerator {
void setShouldInternalize(bool Value) { ShouldInternalize = Value; }
void setShouldEmbedUselists(bool Value) { ShouldEmbedUselists = Value; }
+ void setSaveIRBeforeOptPath(std::string Value) {
+ SaveIRBeforeOptPath = Value;
+ }
/// Restore linkage of globals
///
@@ -237,6 +240,7 @@ private:
bool ShouldRestoreGlobalsLinkage = false;
std::unique_ptr<ToolOutputFile> DiagnosticOutputFile;
std::unique_ptr<ToolOutputFile> StatsFile = nullptr;
+ std::string SaveIRBeforeOptPath;
lto::Config Config;
};
diff --git a/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h b/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h
index de069ff95c2f..ebe81fd8d121 100644
--- a/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h
+++ b/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h
@@ -171,6 +171,29 @@ public:
// It should help move much of the target specific code from llvm-objdump to
// respective target disassemblers.
+ /// Suggest a distance to skip in a buffer of data to find the next
+ /// place to look for the start of an instruction. For example, if
+ /// all instructions have a fixed alignment, this might advance to
+ /// the next multiple of that alignment.
+ ///
+ /// If not overridden, the default is 1.
+ ///
+ /// \param Address - The address, in the memory space of region, of the
+ /// starting point (typically the first byte of something
+ /// that did not decode as a valid instruction at all).
+ /// \param Bytes - A reference to the actual bytes at Address. May be
+ /// needed in order to determine the width of an
+ /// unrecognized instruction (e.g. in Thumb this is a simple
+ /// consistent criterion that doesn't require knowing the
+ /// specific instruction). The caller can pass as much data
+ /// as they have available, and the function is required to
+ /// make a reasonable default choice if not enough data is
+ /// available to make a better one.
+ /// \return - A number of bytes to skip. Must always be greater than
+ /// zero. May be greater than the size of Bytes.
+ virtual uint64_t suggestBytesToSkip(ArrayRef<uint8_t> Bytes,
+ uint64_t Address) const;
+
private:
MCContext &Ctx;
diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
index 30287cde5de7..b4d2178f5724 100644
--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
+++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
@@ -381,13 +381,13 @@ public:
protected:
// Create a representation of the IR.
- virtual void generateIRRepresentation(Any IR, StringRef PassID,
- IRDataT<EmptyData> &Output) override;
+ void generateIRRepresentation(Any IR, StringRef PassID,
+ IRDataT<EmptyData> &Output) override;
// Called when an interesting IR has changed.
- virtual void handleAfter(StringRef PassID, std::string &Name,
- const IRDataT<EmptyData> &Before,
- const IRDataT<EmptyData> &After, Any) override;
+ void handleAfter(StringRef PassID, std::string &Name,
+ const IRDataT<EmptyData> &Before,
+ const IRDataT<EmptyData> &After, Any) override;
void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
StringRef Divider, bool InModule, unsigned Minor,
diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h
index 7da336b9f61b..b96d6c70dae4 100644
--- a/llvm/include/llvm/ProfileData/SampleProfReader.h
+++ b/llvm/include/llvm/ProfileData/SampleProfReader.h
@@ -585,14 +585,14 @@ public:
: SampleProfileReader(std::move(B), C, Format) {}
/// Read and validate the file header.
- virtual std::error_code readHeader() override;
+ std::error_code readHeader() override;
/// Read sample profiles from the associated file.
std::error_code readImpl() override;
/// It includes all the names that have samples either in outline instance
/// or inline instance.
- virtual std::vector<StringRef> *getNameTable() override { return &NameTable; }
+ std::vector<StringRef> *getNameTable() override { return &NameTable; }
protected:
/// Read a numeric value of type T from the profile.
@@ -656,7 +656,7 @@ private:
class SampleProfileReaderRawBinary : public SampleProfileReaderBinary {
private:
- virtual std::error_code verifySPMagic(uint64_t Magic) override;
+ std::error_code verifySPMagic(uint64_t Magic) override;
public:
SampleProfileReaderRawBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
@@ -710,14 +710,14 @@ protected:
std::error_code readCSNameTableSec();
std::error_code readProfileSymbolList();
- virtual std::error_code readHeader() override;
- virtual std::error_code verifySPMagic(uint64_t Magic) override = 0;
+ std::error_code readHeader() override;
+ std::error_code verifySPMagic(uint64_t Magic) override = 0;
virtual std::error_code readOneSection(const uint8_t *Start, uint64_t Size,
const SecHdrTableEntry &Entry);
// placeholder for subclasses to dispatch their own section readers.
virtual std::error_code readCustomSection(const SecHdrTableEntry &Entry) = 0;
- virtual ErrorOr<StringRef> readStringFromTable() override;
- virtual ErrorOr<SampleContext> readSampleContextFromTable() override;
+ ErrorOr<StringRef> readStringFromTable() override;
+ ErrorOr<SampleContext> readSampleContextFromTable() override;
ErrorOr<SampleContextFrames> readContextFromTable();
std::unique_ptr<ProfileSymbolList> ProfSymList;
@@ -770,27 +770,26 @@ public:
uint64_t getSectionSize(SecType Type);
/// Get the total size of header and all sections.
uint64_t getFileSize();
- virtual bool dumpSectionInfo(raw_ostream &OS = dbgs()) override;
+ bool dumpSectionInfo(raw_ostream &OS = dbgs()) override;
/// Collect functions with definitions in Module M. Return true if
/// the reader has been given a module.
bool collectFuncsFromModule() override;
/// Return whether names in the profile are all MD5 numbers.
- virtual bool useMD5() override { return MD5StringBuf.get(); }
+ bool useMD5() override { return MD5StringBuf.get(); }
- virtual std::unique_ptr<ProfileSymbolList> getProfileSymbolList() override {
+ std::unique_ptr<ProfileSymbolList> getProfileSymbolList() override {
return std::move(ProfSymList);
};
- virtual void setSkipFlatProf(bool Skip) override { SkipFlatProf = Skip; }
+ void setSkipFlatProf(bool Skip) override { SkipFlatProf = Skip; }
};
class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
private:
- virtual std::error_code verifySPMagic(uint64_t Magic) override;
- virtual std::error_code
- readCustomSection(const SecHdrTableEntry &Entry) override {
+ std::error_code verifySPMagic(uint64_t Magic) override;
+ std::error_code readCustomSection(const SecHdrTableEntry &Entry) override {
// Update the data reader pointer to the end of the section.
Data = End;
return sampleprof_error::success;
@@ -814,11 +813,11 @@ private:
DenseMap<StringRef, uint64_t> FuncOffsetTable;
/// The set containing the functions to use when compiling a module.
DenseSet<StringRef> FuncsToUse;
- virtual std::error_code verifySPMagic(uint64_t Magic) override;
- virtual std::error_code readNameTable() override;
+ std::error_code verifySPMagic(uint64_t Magic) override;
+ std::error_code readNameTable() override;
/// Read a string indirectly via the name table.
- virtual ErrorOr<StringRef> readStringFromTable() override;
- virtual std::error_code readHeader() override;
+ ErrorOr<StringRef> readStringFromTable() override;
+ std::error_code readHeader() override;
std::error_code readFuncOffsetTable();
public:
@@ -837,7 +836,7 @@ public:
bool collectFuncsFromModule() override;
/// Return whether names in the profile are all MD5 numbers.
- virtual bool useMD5() override { return true; }
+ bool useMD5() override { return true; }
};
using InlineCallStack = SmallVector<FunctionSamples *, 10>;
diff --git a/llvm/include/llvm/ProfileData/SampleProfWriter.h b/llvm/include/llvm/ProfileData/SampleProfWriter.h
index aa7f1cbdd7e8..b1ed0335e9c9 100644
--- a/llvm/include/llvm/ProfileData/SampleProfWriter.h
+++ b/llvm/include/llvm/ProfileData/SampleProfWriter.h
@@ -122,14 +122,13 @@ public:
SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
: SampleProfileWriter(OS) {}
- virtual std::error_code writeSample(const FunctionSamples &S) override;
+ std::error_code writeSample(const FunctionSamples &S) override;
protected:
virtual MapVector<StringRef, uint32_t> &getNameTable() { return NameTable; }
virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
virtual std::error_code writeNameTable();
- virtual std::error_code
- writeHeader(const SampleProfileMap &ProfileMap) override;
+ std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
std::error_code writeSummary();
virtual std::error_code writeContextIdx(const SampleContext &Context);
std::error_code writeNameIdx(StringRef FName);
@@ -187,14 +186,14 @@ const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary {
using SampleProfileWriterBinary::SampleProfileWriterBinary;
public:
- virtual std::error_code write(const SampleProfileMap &ProfileMap) override;
+ std::error_code write(const SampleProfileMap &ProfileMap) override;
- virtual void setToCompressAllSections() override;
+ void setToCompressAllSections() override;
void setToCompressSection(SecType Type);
- virtual std::error_code writeSample(const FunctionSamples &S) override;
+ std::error_code writeSample(const FunctionSamples &S) override;
// Set to use MD5 to represent string in NameTable.
- virtual void setUseMD5() override {
+ void setUseMD5() override {
UseMD5 = true;
addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagMD5Name);
// MD5 will be stored as plain uint64_t instead of variable-length
@@ -205,15 +204,15 @@ public:
// Set the profile to be partial. It means the profile is for
// common/shared code. The common profile is usually merged from
// profiles collected from running other targets.
- virtual void setPartialProfile() override {
+ void setPartialProfile() override {
addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagPartial);
}
- virtual void setProfileSymbolList(ProfileSymbolList *PSL) override {
+ void setProfileSymbolList(ProfileSymbolList *PSL) override {
ProfSymList = PSL;
};
- virtual void resetSecLayout(SectionLayout SL) override {
+ void resetSecLayout(SectionLayout SL) override {
verifySecLayout(SL);
#ifndef NDEBUG
// Make sure resetSecLayout is called before any flag setting.
@@ -242,7 +241,7 @@ protected:
addSecFlag(SectionHdrLayout[SectionIdx], Flag);
}
- virtual void addContext(const SampleContext &Context) override;
+ void addContext(const SampleContext &Context) override;
// placeholder for subclasses to dispatch their own section writers.
virtual std::error_code writeCustomSection(SecType Type) = 0;
@@ -258,9 +257,8 @@ protected:
const SampleProfileMap &ProfileMap);
// Helper function to write name table.
- virtual std::error_code writeNameTable() override;
- virtual std::error_code
- writeContextIdx(const SampleContext &Context) override;
+ std::error_code writeNameTable() override;
+ std::error_code writeContextIdx(const SampleContext &Context) override;
std::error_code writeCSNameIdx(const SampleContext &Context);
std::error_code writeCSNameTableSection();
@@ -288,8 +286,7 @@ protected:
private:
void allocSecHdrTable();
std::error_code writeSecHdrTable();
- virtual std::error_code
- writeHeader(const SampleProfileMap &ProfileMap) override;
+ std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
std::error_code compressAndOutput();
// We will swap the raw_ostream held by LocalBufStream and that
@@ -334,14 +331,13 @@ private:
std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap);
std::error_code writeCtxSplitLayout(const SampleProfileMap &ProfileMap);
- virtual std::error_code
- writeSections(const SampleProfileMap &ProfileMap) override;
+ std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
- virtual std::error_code writeCustomSection(SecType Type) override {
+ std::error_code writeCustomSection(SecType Type) override {
return sampleprof_error::success;
};
- virtual void verifySecLayout(SectionLayout SL) override {
+ void verifySecLayout(SectionLayout SL) override {
assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
"Unsupported layout");
}
@@ -381,8 +377,8 @@ class SampleProfileWriterCompactBinary : public SampleProfileWriterBinary {
using SampleProfileWriterBinary::SampleProfileWriterBinary;
public:
- virtual std::error_code writeSample(const FunctionSamples &S) override;
- virtual std::error_code write(const SampleProfileMap &ProfileMap) override;
+ std::error_code writeSample(const FunctionSamples &S) override;
+ std::error_code write(const SampleProfileMap &ProfileMap) override;
protected:
/// The table mapping from function name to the offset of its FunctionSample
@@ -391,9 +387,8 @@ protected:
/// The offset of the slot to be filled with the offset of FuncOffsetTable
/// towards profile start.
uint64_t TableOffset;
- virtual std::error_code writeNameTable() override;
- virtual std::error_code
- writeHeader(const SampleProfileMap &ProfileMap) override;
+ std::error_code writeNameTable() override;
+ std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
std::error_code writeFuncOffsetTable();
};
diff --git a/llvm/include/llvm/Support/BinaryByteStream.h b/llvm/include/llvm/Support/BinaryByteStream.h
index dc4adba26f16..9dc09b4e97f7 100644
--- a/llvm/include/llvm/Support/BinaryByteStream.h
+++ b/llvm/include/llvm/Support/BinaryByteStream.h
@@ -192,9 +192,7 @@ public:
Error commit() override { return Error::success(); }
/// Return the properties of this stream.
- virtual BinaryStreamFlags getFlags() const override {
- return BSF_Write | BSF_Append;
- }
+ BinaryStreamFlags getFlags() const override { return BSF_Write | BSF_Append; }
MutableArrayRef<uint8_t> data() { return Data; }
};
diff --git a/llvm/include/llvm/Support/DXILOperationCommon.h b/llvm/include/llvm/Support/DXILOperationCommon.h
new file mode 100644
index 000000000000..09365411b3e7
--- /dev/null
+++ b/llvm/include/llvm/Support/DXILOperationCommon.h
@@ -0,0 +1,63 @@
+//===-- DXILOperationCommon.h - DXIL Operation ------------------*- 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 is created to share common definitions used by both the
+// DXILOpBuilder and the table
+// generator.
+// Documentation for DXIL can be found in
+// https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DXILOPERATIONCOMMON_H
+#define LLVM_SUPPORT_DXILOPERATIONCOMMON_H
+
+#include "llvm/ADT/StringSwitch.h"
+
+namespace llvm {
+namespace DXIL {
+
+enum class ParameterKind : uint8_t {
+ INVALID = 0,
+ VOID,
+ HALF,
+ FLOAT,
+ DOUBLE,
+ I1,
+ I8,
+ I16,
+ I32,
+ I64,
+ OVERLOAD,
+ CBUFFER_RET,
+ RESOURCE_RET,
+ DXIL_HANDLE,
+};
+
+inline ParameterKind parameterTypeNameToKind(StringRef Name) {
+ return StringSwitch<ParameterKind>(Name)
+ .Case("void", ParameterKind::VOID)
+ .Case("half", ParameterKind::HALF)
+ .Case("float", ParameterKind::FLOAT)
+ .Case("double", ParameterKind::DOUBLE)
+ .Case("i1", ParameterKind::I1)
+ .Case("i8", ParameterKind::I8)
+ .Case("i16", ParameterKind::I16)
+ .Case("i32", ParameterKind::I32)
+ .Case("i64", ParameterKind::I64)
+ .Case("$o", ParameterKind::OVERLOAD)
+ .Case("dx.types.Handle", ParameterKind::DXIL_HANDLE)
+ .Case("dx.types.CBufRet", ParameterKind::CBUFFER_RET)
+ .Case("dx.types.ResRet", ParameterKind::RESOURCE_RET)
+ .Default(ParameterKind::INVALID);
+}
+
+} // namespace DXIL
+} // namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h
index 3c2c2c8b8ceb..f2d3388a328f 100644
--- a/llvm/include/llvm/Support/Error.h
+++ b/llvm/include/llvm/Support/Error.h
@@ -1141,7 +1141,7 @@ private:
class ECError : public ErrorInfo<ECError> {
friend Error errorCodeToError(std::error_code);
- virtual void anchor() override;
+ void anchor() override;
public:
void setErrorCode(std::error_code EC) { this->EC = EC; }
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index 8079aa436933..94ecae9fc995 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -747,6 +747,12 @@ inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
return (Value + Align - 1) / Align * Align;
}
+inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
+ assert(Align != 0 && (Align & (Align - 1)) == 0 &&
+ "Align must be a power of 2");
+ return (Value + Align - 1) & -Align;
+}
+
/// If non-zero \p Skew is specified, the return value will be a minimal integer
/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for
/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p
diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h
index 58adb41cb0ef..f025cde4a16b 100644
--- a/llvm/include/llvm/Support/raw_ostream.h
+++ b/llvm/include/llvm/Support/raw_ostream.h
@@ -710,7 +710,7 @@ class buffer_ostream : public raw_svector_ostream {
raw_ostream &OS;
SmallVector<char, 0> Buffer;
- virtual void anchor() override;
+ void anchor() override;
public:
buffer_ostream(raw_ostream &OS) : raw_svector_ostream(Buffer), OS(OS) {}
@@ -721,7 +721,7 @@ class buffer_unique_ostream : public raw_svector_ostream {
std::unique_ptr<raw_ostream> OS;
SmallVector<char, 0> Buffer;
- virtual void anchor() override;
+ void anchor() override;
public:
buffer_unique_ostream(std::unique_ptr<raw_ostream> OS)
diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
index ef4fc85b245d..5b8b852962f4 100644
--- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
+++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
@@ -141,6 +141,8 @@ def : GINodeEquiv<G_FMINNUM, fminnum>;
def : GINodeEquiv<G_FMAXNUM, fmaxnum>;
def : GINodeEquiv<G_FMINNUM_IEEE, fminnum_ieee>;
def : GINodeEquiv<G_FMAXNUM_IEEE, fmaxnum_ieee>;
+def : GINodeEquiv<G_FMAXIMUM, fmaximum>;
+def : GINodeEquiv<G_FMINIMUM, fminimum>;
def : GINodeEquiv<G_READCYCLECOUNTER, readcyclecounter>;
def : GINodeEquiv<G_ROTR, rotr>;
def : GINodeEquiv<G_ROTL, rotl>;
diff --git a/llvm/include/llvm/Transforms/IPO.h b/llvm/include/llvm/Transforms/IPO.h
index 0b0f30be4dc9..52f0bc9346bf 100644
--- a/llvm/include/llvm/Transforms/IPO.h
+++ b/llvm/include/llvm/Transforms/IPO.h
@@ -21,8 +21,6 @@
namespace llvm {
struct InlineParams;
-class StringRef;
-class ModuleSummaryIndex;
class ModulePass;
class Pass;
class BasicBlock;
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 8466f5612d99..794e85f877be 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -2837,7 +2837,7 @@ struct IRAttribute : public BaseType {
IRAttribute(const IRPosition &IRP) : BaseType(IRP) {}
/// See AbstractAttribute::initialize(...).
- virtual void initialize(Attributor &A) override {
+ void initialize(Attributor &A) override {
const IRPosition &IRP = this->getIRPosition();
if (isa<UndefValue>(IRP.getAssociatedValue()) ||
this->hasAttr(getAttrKind(), /* IgnoreSubsumingPositions */ false,
diff --git a/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h b/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h
index 47c137e70a7f..a2296a064213 100644
--- a/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h
+++ b/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h
@@ -239,7 +239,9 @@ struct VTableSlotSummary {
StringRef TypeID;
uint64_t ByteOffset;
};
-
+bool hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO);
+void updatePublicTypeTestCalls(Module &M,
+ bool WholeProgramVisibilityEnabledInLTO);
void updateVCallVisibilityInModule(
Module &M, bool WholeProgramVisibilityEnabledInLTO,
const DenseSet<GlobalValue::GUID> &DynamicExportSymbols);
diff --git a/llvm/include/llvm/Transforms/Utils/MatrixUtils.h b/llvm/include/llvm/Transforms/Utils/MatrixUtils.h
index 39a0d4bf40cc..ffad57002935 100644
--- a/llvm/include/llvm/Transforms/Utils/MatrixUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/MatrixUtils.h
@@ -25,9 +25,9 @@ class IRBuilderBase;
/// A helper struct to create IR loop nests for tiling in IR of the following
/// form:
-/// for CurrentColumn = 0..NumColumns
-/// for CurrentRow = 0..NumRows
-/// for CurrentInner = 0..NumInner
+/// for ColumnLoop.Index = 0..NumColumns
+/// for RowLoop.Index = 0..NumRows
+/// for KLoop.Index = 0..NumInner
struct TileInfo {
/// Number of rows of the matrix.
unsigned NumRows;
@@ -42,26 +42,21 @@ struct TileInfo {
/// Number of rows/columns in a tile.
unsigned TileSize = -1;
- /// Start row of the current tile to compute.
- Value *CurrentRow;
-
- /// Start column of the current tile to compute.
- Value *CurrentCol;
-
- /// Current tile offset during the tile computation.
- Value *CurrentK;
-
- /// Header of the outermost loop iterating from 0..NumColumns.
- BasicBlock *ColumnLoopHeader = nullptr;
-
- /// Header of the second loop iterating from 0..NumRows.
- BasicBlock *RowLoopHeader = nullptr;
- /// Latch of the second loop iterating from 0..NumRows.
- BasicBlock *RowLoopLatch = nullptr;
- /// Header of the innermost loop iterating from 0..NumInner.
- BasicBlock *InnerLoopHeader = nullptr;
- /// Latch of the innermost loop iterating from 0..NumInner.
- BasicBlock *InnerLoopLatch = nullptr;
+ /// Properties of a single loop used when generating the tiled loop nest.
+ struct MatrixLoop {
+ /// The index updated on every iteration.
+ Value *Index = nullptr;
+ /// The header and latch of the loop.
+ BasicBlock *Header = nullptr;
+ BasicBlock *Latch = nullptr;
+ };
+
+ /// The loop iterating on the rows.
+ MatrixLoop RowLoop;
+ /// The loop iterating on the columns.
+ MatrixLoop ColumnLoop;
+ /// The loop iterating on k (inner dimension).
+ MatrixLoop KLoop;
TileInfo(unsigned NumRows, unsigned NumColumns, unsigned NumInner,
unsigned TileSize)
@@ -72,9 +67,9 @@ struct TileInfo {
/// for the inner loop body and sets {Column,Row,Inner}LoopHeader/Latch
/// fields.
///
- /// for CurrentColumn = 0..NumColumns
- /// for CurrentRow = 0..NumRows
- /// for CurrentInner = 0..NumInner
+ /// for ColumnLoop.Index = 0..NumColumns
+ /// for RowLoop.Index = 0..NumRows
+ /// for InnerLoop.Index = 0..NumInner
BasicBlock *CreateTiledLoops(BasicBlock *Start, BasicBlock *End,
IRBuilderBase &B, DomTreeUpdater &DTU,
LoopInfo &LI);
diff --git a/llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h b/llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h
index 8dc0f1e26a92..56cc15658675 100644
--- a/llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h
+++ b/llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h
@@ -102,9 +102,9 @@ struct AutoInitRemark : public MemoryOpRemark {
static bool canHandle(const Instruction *I);
protected:
- virtual std::string explainSource(StringRef Type) const override;
- virtual StringRef remarkName(RemarkKind RK) const override;
- virtual DiagnosticKind diagnosticKind() const override {
+ std::string explainSource(StringRef Type) const override;
+ StringRef remarkName(RemarkKind RK) const override;
+ DiagnosticKind diagnosticKind() const override {
return DK_OptimizationRemarkMissed;
}
};
diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
index 79a44b667445..1b2482a2363d 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -208,7 +208,7 @@ private:
Value *optimizeIsAscii(CallInst *CI, IRBuilderBase &B);
Value *optimizeToAscii(CallInst *CI, IRBuilderBase &B);
Value *optimizeAtoi(CallInst *CI, IRBuilderBase &B);
- Value *optimizeStrtol(CallInst *CI, IRBuilderBase &B);
+ Value *optimizeStrToInt(CallInst *CI, IRBuilderBase &B, bool AsSigned);
// Formatting and IO Library Call Optimizations
Value *optimizeErrorReporting(CallInst *CI, IRBuilderBase &B,
diff --git a/llvm/lib/Analysis/CodeMetrics.cpp b/llvm/lib/Analysis/CodeMetrics.cpp
index 6d9084215dee..ded842b92ae1 100644
--- a/llvm/lib/Analysis/CodeMetrics.cpp
+++ b/llvm/lib/Analysis/CodeMetrics.cpp
@@ -133,7 +133,8 @@ void CodeMetrics::analyzeBasicBlock(
// When preparing for LTO, liberally consider calls as inline
// candidates.
if (!Call->isNoInline() && IsLoweredToCall &&
- ((F->hasInternalLinkage() && F->hasOneUse()) || PrepareForLTO)) {
+ ((F->hasInternalLinkage() && F->hasOneLiveUse()) ||
+ PrepareForLTO)) {
++NumInlineCandidates;
}
diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp
index 9f8a5e472f01..8192ed56caf0 100644
--- a/llvm/lib/Analysis/InlineCost.cpp
+++ b/llvm/lib/Analysis/InlineCost.cpp
@@ -185,8 +185,8 @@ private:
public:
InlineCostAnnotationWriter(InlineCostCallAnalyzer *ICCA) : ICCA(ICCA) {}
- virtual void emitInstructionAnnot(const Instruction *I,
- formatted_raw_ostream &OS) override;
+ void emitInstructionAnnot(const Instruction *I,
+ formatted_raw_ostream &OS) override;
};
/// Carry out call site analysis, in order to evaluate inlinability.
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 4691aebbdfe1..21fe448218bc 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -1591,12 +1591,6 @@ static Value *simplifyAndOfICmpsWithSameOperands(ICmpInst *Op0, ICmpInst *Op1) {
!match(Op1, m_ICmp(Pred1, m_Specific(A), m_Specific(B))))
return nullptr;
- // We have (icmp Pred0, A, B) & (icmp Pred1, A, B).
- // If Op1 is always implied true by Op0, then Op0 is a subset of Op1, and we
- // can eliminate Op1 from this 'and'.
- if (ICmpInst::isImpliedTrueByMatchingCmp(Pred0, Pred1))
- return Op0;
-
// Check for any combination of predicates that are guaranteed to be disjoint.
if ((Pred0 == ICmpInst::getInversePredicate(Pred1)) ||
(Pred0 == ICmpInst::ICMP_EQ && ICmpInst::isFalseWhenEqual(Pred1)) ||
@@ -1616,12 +1610,6 @@ static Value *simplifyOrOfICmpsWithSameOperands(ICmpInst *Op0, ICmpInst *Op1) {
!match(Op1, m_ICmp(Pred1, m_Specific(A), m_Specific(B))))
return nullptr;
- // We have (icmp Pred0, A, B) | (icmp Pred1, A, B).
- // If Op1 is always implied true by Op0, then Op0 is a subset of Op1, and we
- // can eliminate Op0 from this 'or'.
- if (ICmpInst::isImpliedTrueByMatchingCmp(Pred0, Pred1))
- return Op1;
-
// Check for any combination of predicates that cover the entire range of
// possibilities.
if ((Pred0 == ICmpInst::getInversePredicate(Pred1)) ||
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index bed684b7652a..aa35f253bc5f 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1500,9 +1500,7 @@ bool llvm::sortPtrAccesses(ArrayRef<Value *> VL, Type *ElemTy,
Value *Ptr0 = VL[0];
using DistOrdPair = std::pair<int64_t, int>;
- auto Compare = [](const DistOrdPair &L, const DistOrdPair &R) {
- return L.first < R.first;
- };
+ auto Compare = llvm::less_first();
std::set<DistOrdPair, decltype(Compare)> Offsets(Compare);
Offsets.emplace(0, 0);
int Cnt = 1;
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index 31e4380e4379..413ec6dd4b42 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -115,9 +115,7 @@ struct AllocFnsTy {
// FIXME: certain users need more information. E.g., SimplifyLibCalls needs to
// know which functions are nounwind, noalias, nocapture parameters, etc.
static const std::pair<LibFunc, AllocFnsTy> AllocationFnData[] = {
- {LibFunc_malloc, {MallocLike, 1, 0, -1, -1, MallocFamily::Malloc}},
{LibFunc_vec_malloc, {MallocLike, 1, 0, -1, -1, MallocFamily::VecMalloc}},
- {LibFunc_valloc, {MallocLike, 1, 0, -1, -1, MallocFamily::Malloc}},
{LibFunc_Znwj, {OpNewLike, 1, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned int)
{LibFunc_ZnwjRKSt9nothrow_t, {MallocLike, 2, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned int, nothrow)
{LibFunc_ZnwjSt11align_val_t, {OpNewLike, 2, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new(unsigned int, align_val_t)
@@ -142,13 +140,9 @@ static const std::pair<LibFunc, AllocFnsTy> AllocationFnData[] = {
{LibFunc_msvc_new_array_int_nothrow, {MallocLike, 2, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned int, nothrow)
{LibFunc_msvc_new_array_longlong, {OpNewLike, 1, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned long long)
{LibFunc_msvc_new_array_longlong_nothrow, {MallocLike, 2, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned long long, nothrow)
- {LibFunc_aligned_alloc, {AlignedAllocLike, 2, 1, -1, 0, MallocFamily::Malloc}},
{LibFunc_memalign, {AlignedAllocLike, 2, 1, -1, 0, MallocFamily::Malloc}},
- {LibFunc_calloc, {CallocLike, 2, 0, 1, -1, MallocFamily::Malloc}},
{LibFunc_vec_calloc, {CallocLike, 2, 0, 1, -1, MallocFamily::VecMalloc}},
- {LibFunc_realloc, {ReallocLike, 2, 1, -1, -1, MallocFamily::Malloc}},
{LibFunc_vec_realloc, {ReallocLike, 2, 1, -1, -1, MallocFamily::VecMalloc}},
- {LibFunc_reallocf, {ReallocLike, 2, 1, -1, -1, MallocFamily::Malloc}},
{LibFunc_strdup, {StrDupLike, 1, -1, -1, -1, MallocFamily::Malloc}},
{LibFunc_dunder_strdup, {StrDupLike, 1, -1, -1, -1, MallocFamily::Malloc}},
{LibFunc_strndup, {StrDupLike, 2, 1, -1, -1, MallocFamily::Malloc}},
@@ -488,7 +482,6 @@ struct FreeFnsTy {
// clang-format off
static const std::pair<LibFunc, FreeFnsTy> FreeFnData[] = {
- {LibFunc_free, {1, MallocFamily::Malloc}},
{LibFunc_vec_free, {1, MallocFamily::VecMalloc}},
{LibFunc_ZdlPv, {1, MallocFamily::CPPNew}}, // operator delete(void*)
{LibFunc_ZdaPv, {1, MallocFamily::CPPNewArray}}, // operator delete[](void*)
diff --git a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
index c52b27a38fe9..efe60586979a 100644
--- a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
+++ b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
@@ -164,7 +164,8 @@ static void addIntrinsicToSummary(
SetVector<FunctionSummary::ConstVCall> &TypeCheckedLoadConstVCalls,
DominatorTree &DT) {
switch (CI->getCalledFunction()->getIntrinsicID()) {
- case Intrinsic::type_test: {
+ case Intrinsic::type_test:
+ case Intrinsic::public_type_test: {
auto *TypeMDVal = cast<MetadataAsValue>(CI->getArgOperand(1));
auto *TypeId = dyn_cast<MDString>(TypeMDVal->getMetadata());
if (!TypeId)
diff --git a/llvm/lib/Analysis/PHITransAddr.cpp b/llvm/lib/Analysis/PHITransAddr.cpp
index 7571bd0059cc..5b0fbca23891 100644
--- a/llvm/lib/Analysis/PHITransAddr.cpp
+++ b/llvm/lib/Analysis/PHITransAddr.cpp
@@ -21,6 +21,10 @@
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+static cl::opt<bool> EnableAddPhiTranslation(
+ "gvn-add-phi-translation", cl::init(false), cl::Hidden,
+ cl::desc("Enable phi-translation of add instructions"));
+
static bool CanPHITrans(Instruction *Inst) {
if (isa<PHINode>(Inst) ||
isa<GetElementPtrInst>(Inst))
@@ -410,14 +414,14 @@ InsertPHITranslatedSubExpr(Value *InVal, BasicBlock *CurBB,
return Result;
}
-#if 0
- // FIXME: This code works, but it is unclear that we actually want to insert
- // a big chain of computation in order to make a value available in a block.
- // This needs to be evaluated carefully to consider its cost trade offs.
-
// Handle add with a constant RHS.
- if (Inst->getOpcode() == Instruction::Add &&
+ if (EnableAddPhiTranslation && Inst->getOpcode() == Instruction::Add &&
isa<ConstantInt>(Inst->getOperand(1))) {
+
+ // FIXME: This code works, but it is unclear that we actually want to insert
+ // a big chain of computation in order to make a value available in a block.
+ // This needs to be evaluated carefully to consider its cost trade offs.
+
// PHI translate the LHS.
Value *OpVal = InsertPHITranslatedSubExpr(Inst->getOperand(0),
CurBB, PredBB, DT, NewInsts);
@@ -431,7 +435,6 @@ InsertPHITranslatedSubExpr(Value *InVal, BasicBlock *CurBB,
NewInsts.push_back(Res);
return Res;
}
-#endif
return nullptr;
}
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index d46248aa3889..2958a5054afc 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -11153,20 +11153,6 @@ bool ScalarEvolution::isBasicBlockEntryGuardedByCond(const BasicBlock *BB,
return true;
}
- // Try to prove (Pred, LHS, RHS) using isImpliedViaGuard.
- auto ProveViaGuard = [&](const BasicBlock *Block) {
- if (isImpliedViaGuard(Block, Pred, LHS, RHS))
- return true;
- if (ProvingStrictComparison) {
- auto ProofFn = [&](ICmpInst::Predicate P) {
- return isImpliedViaGuard(Block, P, LHS, RHS);
- };
- if (SplitAndProve(ProofFn))
- return true;
- }
- return false;
- };
-
// Try to prove (Pred, LHS, RHS) using isImpliedCond.
auto ProveViaCond = [&](const Value *Condition, bool Inverse) {
const Instruction *CtxI = &BB->front();
@@ -11193,9 +11179,6 @@ bool ScalarEvolution::isBasicBlockEntryGuardedByCond(const BasicBlock *BB,
PredBB = BB->getSinglePredecessor();
for (std::pair<const BasicBlock *, const BasicBlock *> Pair(PredBB, BB);
Pair.first; Pair = getPredecessorWithUniqueSuccessorForBB(Pair.first)) {
- if (ProveViaGuard(Pair.first))
- return true;
-
const BranchInst *BlockEntryPredicate =
dyn_cast<BranchInst>(Pair.first->getTerminator());
if (!BlockEntryPredicate || BlockEntryPredicate->isUnconditional())
@@ -11218,6 +11201,15 @@ bool ScalarEvolution::isBasicBlockEntryGuardedByCond(const BasicBlock *BB,
return true;
}
+ // Check conditions due to any @llvm.experimental.guard intrinsics.
+ auto *GuardDecl = F.getParent()->getFunction(
+ Intrinsic::getName(Intrinsic::experimental_guard));
+ if (GuardDecl)
+ for (const auto *GU : GuardDecl->users())
+ if (const auto *Guard = dyn_cast<IntrinsicInst>(GU))
+ if (Guard->getFunction() == BB->getParent() && DT.dominates(Guard, BB))
+ if (ProveViaCond(Guard->getArgOperand(0), false))
+ return true;
return false;
}
diff --git a/llvm/lib/Analysis/TypeMetadataUtils.cpp b/llvm/lib/Analysis/TypeMetadataUtils.cpp
index 201e64770766..e128187bac49 100644
--- a/llvm/lib/Analysis/TypeMetadataUtils.cpp
+++ b/llvm/lib/Analysis/TypeMetadataUtils.cpp
@@ -75,7 +75,9 @@ void llvm::findDevirtualizableCallsForTypeTest(
SmallVectorImpl<DevirtCallSite> &DevirtCalls,
SmallVectorImpl<CallInst *> &Assumes, const CallInst *CI,
DominatorTree &DT) {
- assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::type_test);
+ assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::type_test ||
+ CI->getCalledFunction()->getIntrinsicID() ==
+ Intrinsic::public_type_test);
const Module *M = CI->getParent()->getParent()->getParent();
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 1f3798d1338e..2dd671b4ab9e 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4266,9 +4266,10 @@ bool llvm::getConstantDataArrayInfo(const Value *V,
return true;
}
-/// This function computes the length of a null-terminated C string pointed to
-/// by V. If successful, it returns true and returns the string in Str.
-/// If unsuccessful, it returns false.
+/// Extract bytes from the initializer of the constant array V, which need
+/// not be a nul-terminated string. On success, store the bytes in Str and
+/// return true. When TrimAtNul is set, Str will contain only the bytes up
+/// to but not including the first nul. Return false on failure.
bool llvm::getConstantStringInfo(const Value *V, StringRef &Str,
uint64_t Offset, bool TrimAtNul) {
ConstantDataArraySlice Slice;
@@ -6543,7 +6544,6 @@ bool llvm::matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
static bool isTruePredicate(CmpInst::Predicate Pred, const Value *LHS,
const Value *RHS, const DataLayout &DL,
unsigned Depth) {
- assert(!LHS->getType()->isVectorTy() && "TODO: extend to handle vectors!");
if (ICmpInst::isTrueWhenEqual(Pred) && LHS == RHS)
return true;
@@ -6656,14 +6656,12 @@ static Optional<bool> isImpliedCondMatchingOperands(CmpInst::Predicate APred,
/// Return true if "icmp APred X, C1" implies "icmp BPred X, C2" is true.
/// Return false if "icmp APred X, C1" implies "icmp BPred X, C2" is false.
/// Otherwise, return None if we can't infer anything.
-static Optional<bool>
-isImpliedCondMatchingImmOperands(CmpInst::Predicate APred,
- const ConstantInt *C1,
- CmpInst::Predicate BPred,
- const ConstantInt *C2) {
- ConstantRange DomCR =
- ConstantRange::makeExactICmpRegion(APred, C1->getValue());
- ConstantRange CR = ConstantRange::makeExactICmpRegion(BPred, C2->getValue());
+static Optional<bool> isImpliedCondMatchingImmOperands(CmpInst::Predicate APred,
+ const APInt &C1,
+ CmpInst::Predicate BPred,
+ const APInt &C2) {
+ ConstantRange DomCR = ConstantRange::makeExactICmpRegion(APred, C1);
+ ConstantRange CR = ConstantRange::makeExactICmpRegion(BPred, C2);
ConstantRange Intersection = DomCR.intersectWith(CR);
ConstantRange Difference = DomCR.difference(CR);
if (Intersection.isEmptySet())
@@ -6701,14 +6699,9 @@ static Optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
// Can we infer anything when the LHS operands match and the RHS operands are
// constants (not necessarily matching)?
- if (ALHS == BLHS && isa<ConstantInt>(ARHS) && isa<ConstantInt>(BRHS)) {
- if (Optional<bool> Implication = isImpliedCondMatchingImmOperands(
- APred, cast<ConstantInt>(ARHS), BPred, cast<ConstantInt>(BRHS)))
- return Implication;
- // No amount of additional analysis will infer the second condition, so
- // early exit.
- return None;
- }
+ const APInt *AC, *BC;
+ if (ALHS == BLHS && match(ARHS, m_APInt(AC)) && match(BRHS, m_APInt(BC)))
+ return isImpliedCondMatchingImmOperands(APred, *AC, BPred, *BC);
if (APred == BPred)
return isImpliedCondOperands(APred, ALHS, ARHS, BLHS, BRHS, DL, Depth);
@@ -6761,14 +6754,8 @@ llvm::isImpliedCondition(const Value *LHS, CmpInst::Predicate RHSPred,
if (RHSOp0->getType()->isVectorTy() != LHS->getType()->isVectorTy())
return None;
- Type *OpTy = LHS->getType();
- assert(OpTy->isIntOrIntVectorTy(1) && "Expected integer type only!");
-
- // FIXME: Extending the code below to handle vectors.
- if (OpTy->isVectorTy())
- return None;
-
- assert(OpTy->isIntegerTy(1) && "implied by above");
+ assert(LHS->getType()->isIntOrIntVectorTy(1) &&
+ "Expected integer type only!");
// Both LHS and RHS are icmps.
const ICmpInst *LHSCmp = dyn_cast<ICmpInst>(LHS);
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 1d6c21bd66d1..1943b5db94c3 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -7788,7 +7788,7 @@ static Expected<bool> getEnableSplitLTOUnitFlag(BitstreamCursor &Stream,
case bitc::FS_FLAGS: { // [flags]
uint64_t Flags = Record[0];
// Scan flags.
- assert(Flags <= 0x7f && "Unexpected bits in flag");
+ assert(Flags <= 0xff && "Unexpected bits in flag");
return Flags & 0x8;
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index e0050a47a6f6..32a10ad41d1f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2795,12 +2795,7 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) {
DL.getTypeAllocSize(Op->getType()).getFixedSize())
return OpExpr;
- // Otherwise the pointer is smaller than the resultant integer, mask off
- // the high bits so we are sure to get a proper truncation if the input is
- // a constant expr.
- unsigned InBits = DL.getTypeAllocSizeInBits(Op->getType());
- const MCExpr *MaskExpr = MCConstantExpr::create(~0ULL >> (64-InBits), Ctx);
- return MCBinaryExpr::createAnd(OpExpr, MaskExpr, Ctx);
+ break; // Error
}
case Instruction::Sub: {
diff --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.h b/llvm/lib/CodeGen/AsmPrinter/WasmException.h
index 2abbe37cb6d9..419b569d123c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/WasmException.h
+++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.h
@@ -28,7 +28,7 @@ public:
void endModule() override;
void beginFunction(const MachineFunction *MF) override {}
- virtual void markFunctionEnd() override;
+ void markFunctionEnd() override;
void endFunction(const MachineFunction *MF) override;
protected:
diff --git a/llvm/lib/CodeGen/AtomicExpandPass.cpp b/llvm/lib/CodeGen/AtomicExpandPass.cpp
index f21c1bf4e914..ad51bab8f30b 100644
--- a/llvm/lib/CodeGen/AtomicExpandPass.cpp
+++ b/llvm/lib/CodeGen/AtomicExpandPass.cpp
@@ -515,9 +515,14 @@ void AtomicExpand::expandAtomicStore(StoreInst *SI) {
// It is the responsibility of the target to only signal expansion via
// shouldExpandAtomicRMW in cases where this is required and possible.
IRBuilder<> Builder(SI);
+ AtomicOrdering Ordering = SI->getOrdering();
+ assert(Ordering != AtomicOrdering::NotAtomic);
+ AtomicOrdering RMWOrdering = Ordering == AtomicOrdering::Unordered
+ ? AtomicOrdering::Monotonic
+ : Ordering;
AtomicRMWInst *AI = Builder.CreateAtomicRMW(
AtomicRMWInst::Xchg, SI->getPointerOperand(), SI->getValueOperand(),
- SI->getAlign(), SI->getOrdering());
+ SI->getAlign(), RMWOrdering);
SI->eraseFromParent();
// Now we have an appropriate swap instruction, lower it as usual.
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index b6c762b93ca5..b8f6fc9bbcde 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -2568,8 +2568,6 @@ struct ExtAddrMode : public TargetLowering::AddrMode {
}
};
-} // end anonymous namespace
-
#ifndef NDEBUG
static inline raw_ostream &operator<<(raw_ostream &OS, const ExtAddrMode &AM) {
AM.print(OS);
@@ -2617,6 +2615,8 @@ LLVM_DUMP_METHOD void ExtAddrMode::dump() const {
}
#endif
+} // end anonymous namespace
+
namespace {
/// This class provides transaction based operation on the IR.
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index da054b9c14fb..05a25bc3078e 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -1142,7 +1142,8 @@ bool CombinerHelper::matchCombineDivRem(MachineInstr &MI,
if (MI.getParent() == UseMI.getParent() &&
((IsDiv && UseMI.getOpcode() == RemOpcode) ||
(!IsDiv && UseMI.getOpcode() == DivOpcode)) &&
- matchEqualDefs(MI.getOperand(2), UseMI.getOperand(2))) {
+ matchEqualDefs(MI.getOperand(2), UseMI.getOperand(2)) &&
+ matchEqualDefs(MI.getOperand(1), UseMI.getOperand(1))) {
OtherMI = &UseMI;
return true;
}
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index dbdcfe0b6f0b..2f9187bbf2ad 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -151,11 +151,11 @@ public:
LLVM_DEBUG(dbgs() << "Checking DILocation from " << *CurrInst
<< " was copied to " << MI);
#endif
- // We allow insts in the entry block to have a debug loc line of 0 because
+ // We allow insts in the entry block to have no debug loc because
// they could have originated from constants, and we don't want a jumpy
// debug experience.
assert((CurrInst->getDebugLoc() == MI.getDebugLoc() ||
- MI.getDebugLoc().getLine() == 0) &&
+ (MI.getParent()->isEntryBlock() && !MI.getDebugLoc())) &&
"Line info was not transferred to all instructions");
}
};
@@ -3020,11 +3020,9 @@ bool IRTranslator::translate(const Instruction &Inst) {
bool IRTranslator::translate(const Constant &C, Register Reg) {
// We only emit constants into the entry block from here. To prevent jumpy
- // debug behaviour set the line to 0.
+ // debug behaviour remove debug line.
if (auto CurrInstDL = CurBuilder->getDL())
- EntryBuilder->setDebugLoc(DILocation::get(C.getContext(), 0, 0,
- CurrInstDL.getScope(),
- CurrInstDL.getInlinedAt()));
+ EntryBuilder->setDebugLoc(DebugLoc());
if (auto CI = dyn_cast<ConstantInt>(&C))
EntryBuilder->buildConstant(Reg, *CI);
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
index ef49d3888f2b..191596dbf53e 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
@@ -1330,7 +1330,7 @@ bool InstrRefBasedLDV::transferDebugPHI(MachineInstr &MI) {
const MachineOperand &MO = MI.getOperand(0);
unsigned InstrNum = MI.getOperand(1).getImm();
- auto EmitBadPHI = [this, &MI, InstrNum](void) -> bool {
+ auto EmitBadPHI = [this, &MI, InstrNum]() -> bool {
// Helper lambda to do any accounting when we fail to find a location for
// a DBG_PHI. This can happen if DBG_PHIs are malformed, or refer to a
// dead stack slot, for example.
@@ -3136,8 +3136,7 @@ bool InstrRefBasedLDV::emitTransfers(
MI->getDebugLoc()->getInlinedAt());
Insts.emplace_back(AllVarsNumbering.find(Var)->second, MI);
}
- llvm::sort(Insts,
- [](const auto &A, const auto &B) { return A.first < B.first; });
+ llvm::sort(Insts, llvm::less_first());
// Insert either before or after the designated point...
if (P.MBB) {
diff --git a/llvm/lib/CodeGen/LiveRangeEdit.cpp b/llvm/lib/CodeGen/LiveRangeEdit.cpp
index 2aafb746aa2c..abf36b3f4c67 100644
--- a/llvm/lib/CodeGen/LiveRangeEdit.cpp
+++ b/llvm/lib/CodeGen/LiveRangeEdit.cpp
@@ -300,13 +300,15 @@ void LiveRangeEdit::eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink) {
SmallVector<unsigned, 8> RegsToErase;
bool ReadsPhysRegs = false;
bool isOrigDef = false;
- unsigned Dest;
+ Register Dest;
+ unsigned DestSubReg;
// Only optimize rematerialize case when the instruction has one def, since
// otherwise we could leave some dead defs in the code. This case is
// extremely rare.
if (VRM && MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
MI->getDesc().getNumDefs() == 1) {
Dest = MI->getOperand(0).getReg();
+ DestSubReg = MI->getOperand(0).getSubReg();
unsigned Original = VRM->getOriginal(Dest);
LiveInterval &OrigLI = LIS.getInterval(Original);
VNInfo *OrigVNI = OrigLI.getVNInfoAt(Idx);
@@ -384,8 +386,18 @@ void LiveRangeEdit::eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink) {
if (isOrigDef && DeadRemats && !HasLiveVRegUses &&
TII.isTriviallyReMaterializable(*MI)) {
LiveInterval &NewLI = createEmptyIntervalFrom(Dest, false);
- VNInfo *VNI = NewLI.getNextValue(Idx, LIS.getVNInfoAllocator());
+ VNInfo::Allocator &Alloc = LIS.getVNInfoAllocator();
+ VNInfo *VNI = NewLI.getNextValue(Idx, Alloc);
NewLI.addSegment(LiveInterval::Segment(Idx, Idx.getDeadSlot(), VNI));
+
+ if (DestSubReg) {
+ const TargetRegisterInfo *TRI = MRI.getTargetRegisterInfo();
+ auto *SR = NewLI.createSubRange(
+ Alloc, TRI->getSubRegIndexLaneMask(DestSubReg));
+ SR->addSegment(LiveInterval::Segment(Idx, Idx.getDeadSlot(),
+ SR->getNextValue(Idx, Alloc)));
+ }
+
pop_back();
DeadRemats->insert(MI);
const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
diff --git a/llvm/lib/CodeGen/MachineFunctionPass.cpp b/llvm/lib/CodeGen/MachineFunctionPass.cpp
index 99494122d608..477310f59112 100644
--- a/llvm/lib/CodeGen/MachineFunctionPass.cpp
+++ b/llvm/lib/CodeGen/MachineFunctionPass.cpp
@@ -26,6 +26,7 @@
#include "llvm/CodeGen/Passes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/PrintPasses.h"
using namespace llvm;
using namespace ore;
@@ -70,6 +71,17 @@ bool MachineFunctionPass::runOnFunction(Function &F) {
if (ShouldEmitSizeRemarks)
CountBefore = MF.getInstructionCount();
+ // For --print-changed, if the function name is a candidate, save the
+ // serialized MF to be compared later.
+ // TODO Implement --filter-passes.
+ SmallString<0> BeforeStr, AfterStr;
+ bool ShouldPrintChanged = PrintChanged != ChangePrinter::None &&
+ isFunctionInPrintList(MF.getName());
+ if (ShouldPrintChanged) {
+ raw_svector_ostream OS(BeforeStr);
+ MF.print(OS);
+ }
+
bool RV = runOnMachineFunction(MF);
if (ShouldEmitSizeRemarks) {
@@ -97,6 +109,23 @@ bool MachineFunctionPass::runOnFunction(Function &F) {
MFProps.set(SetProperties);
MFProps.reset(ClearedProperties);
+
+ // For --print-changed, print if the serialized MF has changed. Modes other
+ // than quiet/verbose are unimplemented and treated the same as 'quiet'.
+ if (ShouldPrintChanged) {
+ raw_svector_ostream OS(AfterStr);
+ MF.print(OS);
+ if (BeforeStr != AfterStr) {
+ StringRef Arg;
+ if (const PassInfo *PI = Pass::lookupPassInfo(getPassID()))
+ Arg = PI->getPassArgument();
+ errs() << ("*** IR Dump After " + getPassName() + " (" + Arg + ") on " +
+ MF.getName() + " ***\n" + AfterStr);
+ } else if (PrintChanged == ChangePrinter::Verbose) {
+ errs() << ("*** IR Dump After " + getPassName() + " on " + MF.getName() +
+ " omitted because no change ***\n");
+ }
+ }
return RV;
}
diff --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
index 1115c2a27956..87e2f9f20021 100644
--- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
+++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
@@ -18,6 +18,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/InitializePasses.h"
@@ -69,6 +70,8 @@ static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) {
static bool lowerObjCCall(Function &F, const char *NewFn,
bool setNonLazyBind = false) {
+ assert(IntrinsicInst::mayLowerToFunctionCall(F.getIntrinsicID()) &&
+ "Pre-ISel intrinsics do lower into regular function calls");
if (F.use_empty())
return false;
@@ -107,7 +110,9 @@ static bool lowerObjCCall(Function &F, const char *NewFn,
IRBuilder<> Builder(CI->getParent(), CI->getIterator());
SmallVector<Value *, 8> Args(CI->args());
- CallInst *NewCI = Builder.CreateCall(FCache, Args);
+ SmallVector<llvm::OperandBundleDef, 1> BundleList;
+ CI->getOperandBundlesAsDefs(BundleList);
+ CallInst *NewCI = Builder.CreateCall(FCache, Args, BundleList);
NewCI->setName(CI->getName());
// Try to set the most appropriate TailCallKind based on both the current
diff --git a/llvm/lib/CodeGen/ProcessImplicitDefs.cpp b/llvm/lib/CodeGen/ProcessImplicitDefs.cpp
index 7327f9e52efc..54bb4a31ef49 100644
--- a/llvm/lib/CodeGen/ProcessImplicitDefs.cpp
+++ b/llvm/lib/CodeGen/ProcessImplicitDefs.cpp
@@ -47,7 +47,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- virtual MachineFunctionProperties getRequiredProperties() const override {
+ MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::IsSSA);
}
diff --git a/llvm/lib/CodeGen/RegAllocGreedy.cpp b/llvm/lib/CodeGen/RegAllocGreedy.cpp
index 4a54d7ebf8a9..9c6cb7c3a4e2 100644
--- a/llvm/lib/CodeGen/RegAllocGreedy.cpp
+++ b/llvm/lib/CodeGen/RegAllocGreedy.cpp
@@ -135,6 +135,12 @@ static cl::opt<bool> GreedyRegClassPriorityTrumpsGlobalness(
"more important then whether the range is global"),
cl::Hidden);
+static cl::opt<bool> GreedyReverseLocalAssignment(
+ "greedy-reverse-local-assignment",
+ cl::desc("Reverse allocation order of local live ranges, such that "
+ "shorter local live ranges will tend to be allocated first"),
+ cl::Hidden);
+
static RegisterRegAlloc greedyRegAlloc("greedy", "greedy register allocator",
createGreedyRegisterAllocator);
@@ -297,11 +303,10 @@ void RAGreedy::enqueue(PQueue &CurQueue, const LiveInterval *LI) {
} else {
// Giant live ranges fall back to the global assignment heuristic, which
// prevents excessive spilling in pathological cases.
- bool ReverseLocal = TRI->reverseLocalAssignment();
const TargetRegisterClass &RC = *MRI->getRegClass(Reg);
- bool ForceGlobal =
- !ReverseLocal && (Size / SlotIndex::InstrDist) >
- (2 * RegClassInfo.getNumAllocatableRegs(&RC));
+ bool ForceGlobal = !ReverseLocalAssignment &&
+ (Size / SlotIndex::InstrDist) >
+ (2 * RegClassInfo.getNumAllocatableRegs(&RC));
unsigned GlobalBit = 0;
if (Stage == RS_Assign && !ForceGlobal && !LI->empty() &&
@@ -309,7 +314,7 @@ void RAGreedy::enqueue(PQueue &CurQueue, const LiveInterval *LI) {
// Allocate original local ranges in linear instruction order. Since they
// are singly defined, this produces optimal coloring in the absence of
// global interference and other constraints.
- if (!ReverseLocal)
+ if (!ReverseLocalAssignment)
Prio = LI->beginIndex().getInstrDistance(Indexes->getLastIndex());
else {
// Allocating bottom up may allow many short LRGs to be assigned first
@@ -2528,6 +2533,10 @@ bool RAGreedy::runOnMachineFunction(MachineFunction &mf) {
? GreedyRegClassPriorityTrumpsGlobalness
: TRI->regClassPriorityTrumpsGlobalness(*MF);
+ ReverseLocalAssignment = GreedyReverseLocalAssignment.getNumOccurrences()
+ ? GreedyReverseLocalAssignment
+ : TRI->reverseLocalAssignment();
+
ExtraInfo.emplace();
EvictAdvisor =
getAnalysis<RegAllocEvictionAdvisorAnalysis>().getAdvisor(*MF, *this);
diff --git a/llvm/lib/CodeGen/RegAllocGreedy.h b/llvm/lib/CodeGen/RegAllocGreedy.h
index 316b12d0213b..483f59ed8e8e 100644
--- a/llvm/lib/CodeGen/RegAllocGreedy.h
+++ b/llvm/lib/CodeGen/RegAllocGreedy.h
@@ -270,6 +270,8 @@ private:
/// machine function.
bool RegClassPriorityTrumpsGlobalness;
+ bool ReverseLocalAssignment;
+
public:
RAGreedy(const RegClassFilterFunc F = allocateAllRegClasses);
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index edb0756e8c3b..654879115ff9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -4877,9 +4877,16 @@ SDValue DAGCombiner::visitSMUL_LOHI(SDNode *N) {
if (SDValue Res = SimplifyNodeWithTwoResults(N, ISD::MUL, ISD::MULHS))
return Res;
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
EVT VT = N->getValueType(0);
SDLoc DL(N);
+ // canonicalize constant to RHS (vector doesn't have to splat)
+ if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
+ !DAG.isConstantIntBuildVectorOrConstantInt(N1))
+ return DAG.getNode(ISD::SMUL_LOHI, DL, N->getVTList(), N1, N0);
+
// If the type is twice as wide is legal, transform the mulhu to a wider
// multiply plus a shift.
if (VT.isSimple() && !VT.isVector()) {
@@ -4887,8 +4894,8 @@ SDValue DAGCombiner::visitSMUL_LOHI(SDNode *N) {
unsigned SimpleSize = Simple.getSizeInBits();
EVT NewVT = EVT::getIntegerVT(*DAG.getContext(), SimpleSize*2);
if (TLI.isOperationLegal(ISD::MUL, NewVT)) {
- SDValue Lo = DAG.getNode(ISD::SIGN_EXTEND, DL, NewVT, N->getOperand(0));
- SDValue Hi = DAG.getNode(ISD::SIGN_EXTEND, DL, NewVT, N->getOperand(1));
+ SDValue Lo = DAG.getNode(ISD::SIGN_EXTEND, DL, NewVT, N0);
+ SDValue Hi = DAG.getNode(ISD::SIGN_EXTEND, DL, NewVT, N1);
Lo = DAG.getNode(ISD::MUL, DL, NewVT, Lo, Hi);
// Compute the high part as N1.
Hi = DAG.getNode(ISD::SRL, DL, NewVT, Lo,
@@ -4908,19 +4915,26 @@ SDValue DAGCombiner::visitUMUL_LOHI(SDNode *N) {
if (SDValue Res = SimplifyNodeWithTwoResults(N, ISD::MUL, ISD::MULHU))
return Res;
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
EVT VT = N->getValueType(0);
SDLoc DL(N);
+ // canonicalize constant to RHS (vector doesn't have to splat)
+ if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
+ !DAG.isConstantIntBuildVectorOrConstantInt(N1))
+ return DAG.getNode(ISD::UMUL_LOHI, DL, N->getVTList(), N1, N0);
+
// (umul_lohi N0, 0) -> (0, 0)
- if (isNullConstant(N->getOperand(1))) {
+ if (isNullConstant(N1)) {
SDValue Zero = DAG.getConstant(0, DL, VT);
return CombineTo(N, Zero, Zero);
}
// (umul_lohi N0, 1) -> (N0, 0)
- if (isOneConstant(N->getOperand(1))) {
+ if (isOneConstant(N1)) {
SDValue Zero = DAG.getConstant(0, DL, VT);
- return CombineTo(N, N->getOperand(0), Zero);
+ return CombineTo(N, N0, Zero);
}
// If the type is twice as wide is legal, transform the mulhu to a wider
@@ -4930,8 +4944,8 @@ SDValue DAGCombiner::visitUMUL_LOHI(SDNode *N) {
unsigned SimpleSize = Simple.getSizeInBits();
EVT NewVT = EVT::getIntegerVT(*DAG.getContext(), SimpleSize*2);
if (TLI.isOperationLegal(ISD::MUL, NewVT)) {
- SDValue Lo = DAG.getNode(ISD::ZERO_EXTEND, DL, NewVT, N->getOperand(0));
- SDValue Hi = DAG.getNode(ISD::ZERO_EXTEND, DL, NewVT, N->getOperand(1));
+ SDValue Lo = DAG.getNode(ISD::ZERO_EXTEND, DL, NewVT, N0);
+ SDValue Hi = DAG.getNode(ISD::ZERO_EXTEND, DL, NewVT, N1);
Lo = DAG.getNode(ISD::MUL, DL, NewVT, Lo, Hi);
// Compute the high part as N1.
Hi = DAG.getNode(ISD::SRL, DL, NewVT, Lo,
@@ -7247,6 +7261,7 @@ static SDValue extractShiftForRotate(SelectionDAG &DAG, SDValue OppShift,
// Otherwise if matching a general funnel shift, it should be clear.
static bool matchRotateSub(SDValue Pos, SDValue Neg, unsigned EltSize,
SelectionDAG &DAG, bool IsRotate) {
+ const auto &TLI = DAG.getTargetLoweringInfo();
// If EltSize is a power of 2 then:
//
// (a) (Pos == 0 ? 0 : EltSize - Pos) == (EltSize - Pos) & (EltSize - 1)
@@ -7278,19 +7293,20 @@ static bool matchRotateSub(SDValue Pos, SDValue Neg, unsigned EltSize,
// always invokes undefined behavior for 32-bit X.
//
// Below, Mask == EltSize - 1 when using [A] and is all-ones otherwise.
+ // This allows us to peek through any operations that only affect Mask's
+ // un-demanded bits.
//
- // NOTE: We can only do this when matching an AND and not a general
- // funnel shift.
+ // NOTE: We can only do this when matching operations which won't modify the
+ // least Log2(EltSize) significant bits and not a general funnel shift.
unsigned MaskLoBits = 0;
- if (IsRotate && Neg.getOpcode() == ISD::AND && isPowerOf2_64(EltSize)) {
- if (ConstantSDNode *NegC = isConstOrConstSplat(Neg.getOperand(1))) {
- KnownBits Known = DAG.computeKnownBits(Neg.getOperand(0));
- unsigned Bits = Log2_64(EltSize);
- if (NegC->getAPIntValue().getActiveBits() <= Bits &&
- ((NegC->getAPIntValue() | Known.Zero).countTrailingOnes() >= Bits)) {
- Neg = Neg.getOperand(0);
- MaskLoBits = Bits;
- }
+ if (IsRotate && isPowerOf2_64(EltSize)) {
+ unsigned Bits = Log2_64(EltSize);
+ APInt DemandedBits =
+ APInt::getLowBitsSet(Neg.getScalarValueSizeInBits(), Bits);
+ if (SDValue Inner =
+ TLI.SimplifyMultipleUseDemandedBits(Neg, DemandedBits, DAG)) {
+ Neg = Inner;
+ MaskLoBits = Bits;
}
}
@@ -7302,15 +7318,15 @@ static bool matchRotateSub(SDValue Pos, SDValue Neg, unsigned EltSize,
return false;
SDValue NegOp1 = Neg.getOperand(1);
- // On the RHS of [A], if Pos is Pos' & (EltSize - 1), just replace Pos with
- // Pos'. The truncation is redundant for the purpose of the equality.
- if (MaskLoBits && Pos.getOpcode() == ISD::AND) {
- if (ConstantSDNode *PosC = isConstOrConstSplat(Pos.getOperand(1))) {
- KnownBits Known = DAG.computeKnownBits(Pos.getOperand(0));
- if (PosC->getAPIntValue().getActiveBits() <= MaskLoBits &&
- ((PosC->getAPIntValue() | Known.Zero).countTrailingOnes() >=
- MaskLoBits))
- Pos = Pos.getOperand(0);
+ // On the RHS of [A], if Pos is the result of operation on Pos' that won't
+ // affect Mask's demanded bits, just replace Pos with Pos'. These operations
+ // are redundant for the purpose of the equality.
+ if (MaskLoBits) {
+ APInt DemandedBits =
+ APInt::getLowBitsSet(Pos.getScalarValueSizeInBits(), MaskLoBits);
+ if (SDValue Inner =
+ TLI.SimplifyMultipleUseDemandedBits(Pos, DemandedBits, DAG)) {
+ Pos = Inner;
}
}
@@ -14988,7 +15004,7 @@ SDValue DAGCombiner::visitFMA(SDNode *N) {
// FMA nodes have flags that propagate to the created nodes.
SelectionDAG::FlagInserter FlagsInserter(DAG, N);
- bool UnsafeFPMath =
+ bool CanReassociate =
Options.UnsafeFPMath || N->getFlags().hasAllowReassociation();
// Constant fold FMA.
@@ -15012,7 +15028,8 @@ SDValue DAGCombiner::visitFMA(SDNode *N) {
CostN1 == TargetLowering::NegatibleCost::Cheaper))
return DAG.getNode(ISD::FMA, DL, VT, NegN0, NegN1, N2);
- if (UnsafeFPMath) {
+ // FIXME: use fast math flags instead of Options.UnsafeFPMath
+ if (Options.UnsafeFPMath) {
if (N0CFP && N0CFP->isZero())
return N2;
if (N1CFP && N1CFP->isZero())
@@ -15029,7 +15046,7 @@ SDValue DAGCombiner::visitFMA(SDNode *N) {
!DAG.isConstantFPBuildVectorOrConstantFP(N1))
return DAG.getNode(ISD::FMA, SDLoc(N), VT, N1, N0, N2);
- if (UnsafeFPMath) {
+ if (CanReassociate) {
// (fma x, c1, (fmul x, c2)) -> (fmul x, c1+c2)
if (N2.getOpcode() == ISD::FMUL && N0 == N2.getOperand(0) &&
DAG.isConstantFPBuildVectorOrConstantFP(N1) &&
@@ -15070,7 +15087,7 @@ SDValue DAGCombiner::visitFMA(SDNode *N) {
}
}
- if (UnsafeFPMath) {
+ if (CanReassociate) {
// (fma x, c, x) -> (fmul x, (c+1))
if (N1CFP && N0 == N2) {
return DAG.getNode(
@@ -19697,8 +19714,11 @@ static SDValue scalarizeExtractedBinop(SDNode *ExtElt, SelectionDAG &DAG,
// extract.
SDValue Op0 = Vec.getOperand(0);
SDValue Op1 = Vec.getOperand(1);
+ APInt SplatVal;
if (isAnyConstantBuildVector(Op0, true) ||
- isAnyConstantBuildVector(Op1, true)) {
+ ISD::isConstantSplatVector(Op0.getNode(), SplatVal) ||
+ isAnyConstantBuildVector(Op1, true) ||
+ ISD::isConstantSplatVector(Op1.getNode(), SplatVal)) {
// extractelt (binop X, C), IndexC --> binop (extractelt X, IndexC), C'
// extractelt (binop C, X), IndexC --> binop C', (extractelt X, IndexC)
SDLoc DL(ExtElt);
@@ -19775,6 +19795,9 @@ SDValue DAGCombiner::visitEXTRACT_VECTOR_ELT(SDNode *N) {
// converts.
}
+ if (SDValue BO = scalarizeExtractedBinop(N, DAG, LegalOperations))
+ return BO;
+
if (VecVT.isScalableVector())
return SDValue();
@@ -19820,9 +19843,6 @@ SDValue DAGCombiner::visitEXTRACT_VECTOR_ELT(SDNode *N) {
}
}
- if (SDValue BO = scalarizeExtractedBinop(N, DAG, LegalOperations))
- return BO;
-
// Transform: (EXTRACT_VECTOR_ELT( VECTOR_SHUFFLE )) -> EXTRACT_VECTOR_ELT.
// We only perform this optimization before the op legalization phase because
// we may introduce new vector instructions which are not backed by TD
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 441437351852..195c0e6a836f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -2529,8 +2529,7 @@ bool SelectionDAG::MaskedValueIsZero(SDValue V, const APInt &Mask,
/// DemandedElts. We use this predicate to simplify operations downstream.
bool SelectionDAG::MaskedVectorIsZero(SDValue V, const APInt &DemandedElts,
unsigned Depth /* = 0 */) const {
- APInt Mask = APInt::getAllOnes(V.getScalarValueSizeInBits());
- return Mask.isSubsetOf(computeKnownBits(V, DemandedElts, Depth).Zero);
+ return computeKnownBits(V, DemandedElts, Depth).isZero();
}
/// MaskedValueIsAllOnes - Return true if '(Op & Mask) == Mask'.
@@ -9089,6 +9088,15 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTList,
}
break;
}
+ case ISD::SMUL_LOHI:
+ case ISD::UMUL_LOHI: {
+ assert(VTList.NumVTs == 2 && Ops.size() == 2 && "Invalid mul lo/hi op!");
+ assert(VTList.VTs[0].isInteger() && VTList.VTs[0] == VTList.VTs[1] &&
+ VTList.VTs[0] == Ops[0].getValueType() &&
+ VTList.VTs[0] == Ops[1].getValueType() &&
+ "Binary operator types must match!");
+ break;
+ }
case ISD::STRICT_FP_EXTEND:
assert(VTList.NumVTs == 2 && Ops.size() == 2 &&
"Invalid STRICT_FP_EXTEND!");
@@ -11682,6 +11690,35 @@ bool BuildVectorSDNode::isConstant() const {
return true;
}
+Optional<std::pair<APInt, APInt>>
+BuildVectorSDNode::isConstantSequence() const {
+ unsigned NumOps = getNumOperands();
+ if (NumOps < 2)
+ return None;
+
+ if (!isa<ConstantSDNode>(getOperand(0)) ||
+ !isa<ConstantSDNode>(getOperand(1)))
+ return None;
+
+ unsigned EltSize = getValueType(0).getScalarSizeInBits();
+ APInt Start = getConstantOperandAPInt(0).trunc(EltSize);
+ APInt Stride = getConstantOperandAPInt(1).trunc(EltSize) - Start;
+
+ if (Stride.isZero())
+ return None;
+
+ for (unsigned i = 2; i < NumOps; ++i) {
+ if (!isa<ConstantSDNode>(getOperand(i)))
+ return None;
+
+ APInt Val = getConstantOperandAPInt(i).trunc(EltSize);
+ if (Val != (Start + (Stride * i)))
+ return None;
+ }
+
+ return std::make_pair(Start, Stride);
+}
+
bool ShuffleVectorSDNode::isSplatMask(const int *Mask, EVT VT) {
// Find the first non-undef value in the shuffle mask.
unsigned i, e;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
index 4a3ab00614b3..d1915fd4e7ae 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -198,7 +198,7 @@ public:
SDAGSwitchLowering(SelectionDAGBuilder *sdb, FunctionLoweringInfo &funcinfo)
: SwitchCG::SwitchLowering(funcinfo), SDB(sdb) {}
- virtual void addSuccessorWithProb(
+ void addSuccessorWithProb(
MachineBasicBlock *Src, MachineBasicBlock *Dst,
BranchProbability Prob = BranchProbability::getUnknown()) override {
SDB->addSuccessorWithProb(Src, Dst, Prob);
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index cd4f0ae42bcd..6205e74837c0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -654,6 +654,14 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, const APInt &DemandedBits,
SDValue TargetLowering::SimplifyMultipleUseDemandedBits(
SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts,
SelectionDAG &DAG, unsigned Depth) const {
+ EVT VT = Op.getValueType();
+
+ // Pretend we don't know anything about scalable vectors for now.
+ // TODO: We can probably do more work on simplifying the operations for
+ // scalable vectors, but for now we just bail out.
+ if (VT.isScalableVector())
+ return SDValue();
+
// Limit search depth.
if (Depth >= SelectionDAG::MaxRecursionDepth)
return SDValue();
@@ -664,7 +672,7 @@ SDValue TargetLowering::SimplifyMultipleUseDemandedBits(
// Not demanding any bits/elts from Op.
if (DemandedBits == 0 || DemandedElts == 0)
- return DAG.getUNDEF(Op.getValueType());
+ return DAG.getUNDEF(VT);
bool IsLE = DAG.getDataLayout().isLittleEndian();
unsigned NumElts = DemandedElts.getBitWidth();
@@ -894,6 +902,13 @@ SDValue TargetLowering::SimplifyMultipleUseDemandedBits(
SDValue Op, const APInt &DemandedBits, SelectionDAG &DAG,
unsigned Depth) const {
EVT VT = Op.getValueType();
+
+ // Pretend we don't know anything about scalable vectors for now.
+ // TODO: We can probably do more work on simplifying the operations for
+ // scalable vectors, but for now we just bail out.
+ if (VT.isScalableVector())
+ return SDValue();
+
APInt DemandedElts = VT.isVector()
? APInt::getAllOnes(VT.getVectorNumElements())
: APInt(1, 1);
diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 62b7f629f403..3e14edb5f730 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -2343,7 +2343,7 @@ void DWARFLinker::addObjectFile(DWARFFile &File) {
updateAccelKind(*ObjectContexts.back().File.Dwarf);
}
-bool DWARFLinker::link() {
+Error DWARFLinker::link() {
assert(Options.NoOutput || TheDwarfEmitter);
// A unique ID that identifies each compile unit.
@@ -2410,6 +2410,55 @@ bool DWARFLinker::link() {
if (!OptContext.File.Dwarf)
continue;
+ // Check whether type units are presented.
+ if (!OptContext.File.Dwarf->types_section_units().empty()) {
+ reportWarning("type units are not currently supported: file will "
+ "be skipped",
+ OptContext.File);
+ OptContext.Skip = true;
+ continue;
+ }
+
+ // Check for unsupported sections. Following sections can be referenced
+ // from .debug_info section. Current DWARFLinker implementation does not
+ // support or update references to these tables. Thus we report warning
+ // and skip corresponding object file.
+ if (!OptContext.File.Dwarf->getDWARFObj()
+ .getRnglistsSection()
+ .Data.empty()) {
+ reportWarning("'.debug_rnglists' is not currently supported: file "
+ "will be skipped",
+ OptContext.File);
+ OptContext.Skip = true;
+ continue;
+ }
+
+ if (!OptContext.File.Dwarf->getDWARFObj()
+ .getLoclistsSection()
+ .Data.empty()) {
+ reportWarning("'.debug_loclists' is not currently supported: file "
+ "will be skipped",
+ OptContext.File);
+ OptContext.Skip = true;
+ continue;
+ }
+
+ if (!OptContext.File.Dwarf->getDWARFObj().getMacroSection().Data.empty()) {
+ reportWarning("'.debug_macro' is not currently supported: file "
+ "will be skipped",
+ OptContext.File);
+ OptContext.Skip = true;
+ continue;
+ }
+
+ if (OptContext.File.Dwarf->getDWARFObj().getMacinfoSection().size() > 1) {
+ reportWarning("'.debug_macinfo' is not currently supported: file "
+ "will be skipped",
+ OptContext.File);
+ OptContext.Skip = true;
+ continue;
+ }
+
// In a first phase, just read in the debug info and load all clang modules.
OptContext.CompileUnits.reserve(
OptContext.File.Dwarf->getNumCompileUnits());
@@ -2660,7 +2709,7 @@ bool DWARFLinker::link() {
"---------------\n\n";
}
- return true;
+ return Error::success();
}
bool DWARFLinker::verify(const DWARFFile &File) {
diff --git a/llvm/lib/DWP/DWP.cpp b/llvm/lib/DWP/DWP.cpp
index 44e39c019e0c..346f4dfd290d 100644
--- a/llvm/lib/DWP/DWP.cpp
+++ b/llvm/lib/DWP/DWP.cpp
@@ -18,6 +18,7 @@
#include "llvm/Object/Decompressor.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/MemoryBuffer.h"
+#include <limits>
using namespace llvm;
using namespace llvm::object;
@@ -654,6 +655,12 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
IndexVersion)];
C.Offset = InfoSectionOffset;
C.Length = Header.Length + 4;
+
+ if (std::numeric_limits<uint32_t>::max() - InfoSectionOffset <
+ C.Length)
+ return make_error<DWPError>(
+ "debug information section offset is greater than 4GB");
+
UnitOffset += C.Length;
if (Header.Version < 5 ||
Header.UnitType == dwarf::DW_UT_split_compile) {
diff --git a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp
index dc07eaeaf615..3a6162db75c4 100644
--- a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp
@@ -18,13 +18,19 @@ static const char *CommonSectionName = "__common";
namespace llvm {
namespace jitlink {
+static Triple createTripleWithCOFFFormat(Triple T) {
+ T.setObjectFormat(Triple::COFF);
+ return T;
+}
+
COFFLinkGraphBuilder::COFFLinkGraphBuilder(
const object::COFFObjectFile &Obj, Triple TT,
LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
: Obj(Obj),
- G(std::make_unique<LinkGraph>(
- Obj.getFileName().str(), Triple(std::move(TT)), getPointerSize(Obj),
- getEndianness(Obj), std::move(GetEdgeKindName))) {
+ G(std::make_unique<LinkGraph>(Obj.getFileName().str(),
+ createTripleWithCOFFFormat(TT),
+ getPointerSize(Obj), getEndianness(Obj),
+ std::move(GetEdgeKindName))) {
LLVM_DEBUG({
dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName()
<< "\"\n";
@@ -128,16 +134,6 @@ Error COFFLinkGraphBuilder::graphifySections() {
if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec))
SectionName = *SecNameOrErr;
- bool IsDiscardable =
- (*Sec)->Characteristics &
- (COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_LNK_INFO);
- if (IsDiscardable) {
- LLVM_DEBUG(dbgs() << " " << SecIndex << ": \"" << SectionName
- << "\" is discardable: "
- "No graph section will be created.\n");
- continue;
- }
-
// FIXME: Skip debug info sections
LLVM_DEBUG({
@@ -145,6 +141,8 @@ Error COFFLinkGraphBuilder::graphifySections() {
<< "Creating section for \"" << SectionName << "\"\n";
});
+ // FIXME: Revisit crash when dropping IMAGE_SCN_MEM_DISCARDABLE sections
+
// Get the section's memory protection flags.
MemProt Prot = MemProt::None;
if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)
@@ -190,6 +188,7 @@ Error COFFLinkGraphBuilder::graphifySymbols() {
LLVM_DEBUG(dbgs() << " Creating graph symbols...\n");
SymbolSets.resize(Obj.getNumberOfSections() + 1);
+ PendingComdatExports.resize(Obj.getNumberOfSections() + 1);
GraphSymbols.resize(Obj.getNumberOfSymbols());
for (COFFSymbolIndex SymIndex = 0;
@@ -232,18 +231,16 @@ Error COFFLinkGraphBuilder::graphifySymbols() {
<< getCOFFSectionName(SectionIndex, Sec, *Sym)
<< " (index: " << SectionIndex << ") \n";
});
- GSym =
- &G->addExternalSymbol(SymbolName, Sym->getValue(), Linkage::Strong);
+ if (!ExternalSymbols.count(SymbolName))
+ ExternalSymbols[SymbolName] =
+ &G->addExternalSymbol(SymbolName, Sym->getValue(), Linkage::Strong);
+ GSym = ExternalSymbols[SymbolName];
} else if (Sym->isWeakExternal()) {
- COFFSymbolIndex TagIndex =
- Sym->getAux<object::coff_aux_weak_external>()->TagIndex;
- assert(Sym->getAux<object::coff_aux_weak_external>()->Characteristics !=
- COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY &&
- "IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY is not supported.");
- assert(Sym->getAux<object::coff_aux_weak_external>()->Characteristics !=
- COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY &&
- "IMAGE_WEAK_EXTERN_SEARCH_LIBRARY is not supported.");
- WeakAliasRequests.push_back({SymIndex, TagIndex, SymbolName});
+ auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>();
+ COFFSymbolIndex TagIndex = WeakExternal->TagIndex;
+ uint32_t Characteristics = WeakExternal->Characteristics;
+ WeakExternalRequests.push_back(
+ {SymIndex, TagIndex, Characteristics, SymbolName});
} else {
Expected<jitlink::Symbol *> NewGSym =
createDefinedSymbol(SymIndex, SymbolName, *Sym, Sec);
@@ -279,35 +276,41 @@ Error COFFLinkGraphBuilder::graphifySymbols() {
Error COFFLinkGraphBuilder::flushWeakAliasRequests() {
// Export the weak external symbols and alias it
- for (auto &WeakAlias : WeakAliasRequests) {
- if (auto *Target = getGraphSymbol(WeakAlias.Target)) {
+ for (auto &WeakExternal : WeakExternalRequests) {
+ if (auto *Target = getGraphSymbol(WeakExternal.Target)) {
Expected<object::COFFSymbolRef> AliasSymbol =
- Obj.getSymbol(WeakAlias.Alias);
+ Obj.getSymbol(WeakExternal.Alias);
if (!AliasSymbol)
return AliasSymbol.takeError();
+ // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and
+ // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way.
+ Scope S =
+ WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
+ ? Scope::Default
+ : Scope::Local;
+
// FIXME: Support this when there's a way to handle this.
if (!Target->isDefined())
return make_error<JITLinkError>("Weak external symbol with external "
"symbol as alternative not supported.");
jitlink::Symbol *NewSymbol = &G->addDefinedSymbol(
- Target->getBlock(), Target->getOffset(), WeakAlias.SymbolName,
- Target->getSize(), Linkage::Weak, Scope::Default,
- Target->isCallable(), false);
- setGraphSymbol(AliasSymbol->getSectionNumber(), WeakAlias.Alias,
+ Target->getBlock(), Target->getOffset(), WeakExternal.SymbolName,
+ Target->getSize(), Linkage::Weak, S, Target->isCallable(), false);
+ setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias,
*NewSymbol);
LLVM_DEBUG({
- dbgs() << " " << WeakAlias.Alias
+ dbgs() << " " << WeakExternal.Alias
<< ": Creating weak external symbol for COFF symbol \""
- << WeakAlias.SymbolName << "\" in section "
+ << WeakExternal.SymbolName << "\" in section "
<< AliasSymbol->getSectionNumber() << "\n";
dbgs() << " " << *NewSymbol << "\n";
});
} else
return make_error<JITLinkError>("Weak symbol alias requested but actual "
"symbol not found for symbol " +
- formatv("{0:d}", WeakAlias.Alias));
+ formatv("{0:d}", WeakExternal.Alias));
}
return Error::success();
}
@@ -324,6 +327,8 @@ Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() {
SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());
SecIndex++) {
auto &SymbolSet = SymbolSets[SecIndex];
+ if (SymbolSet.empty())
+ continue;
jitlink::Block *B = getGraphBlock(SecIndex);
orc::ExecutorAddrDiff LastOffset = B->getSize();
orc::ExecutorAddrDiff LastDifferentOffset = B->getSize();
@@ -394,25 +399,35 @@ Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol(
formatv("{0:d}", SymIndex));
Block *B = getGraphBlock(Symbol.getSectionNumber());
+ if (!B) {
+ LLVM_DEBUG({
+ dbgs() << " " << SymIndex
+ << ": Skipping graph symbol since section was not created for "
+ "COFF symbol \""
+ << SymbolName << "\" in section " << Symbol.getSectionNumber()
+ << "\n";
+ });
+ return nullptr;
+ }
+
if (Symbol.isExternal()) {
// This is not a comdat sequence, export the symbol as it is
- if (!isComdatSection(Section))
+ if (!isComdatSection(Section)) {
+
return &G->addDefinedSymbol(
*B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default,
Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
- else {
- if (!PendingComdatExport)
+ } else {
+ if (!PendingComdatExports[Symbol.getSectionNumber()])
return make_error<JITLinkError>("No pending COMDAT export for symbol " +
formatv("{0:d}", SymIndex));
- if (PendingComdatExport->SectionIndex != Symbol.getSectionNumber())
- return make_error<JITLinkError>(
- "COMDAT export section number mismatch for symbol " +
- formatv("{0:d}", SymIndex));
+
return exportCOMDATSymbol(SymIndex, SymbolName, Symbol);
}
}
- if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC) {
+ if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC ||
+ Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) {
const object::coff_aux_section_definition *Definition =
Symbol.getSectionDefinition();
if (!Definition || !isComdatSection(Section)) {
@@ -422,12 +437,14 @@ Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol(
Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
}
if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
- // FIXME: don't dead strip this when parent section is alive
- return &G->addDefinedSymbol(
+ auto Target = Definition->getNumber(Symbol.isBigObj());
+ auto GSym = &G->addDefinedSymbol(
*B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,
Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
+ getGraphBlock(Target)->addEdge(Edge::KeepAlive, 0, *GSym, 0);
+ return GSym;
}
- if (PendingComdatExport)
+ if (PendingComdatExports[Symbol.getSectionNumber()])
return make_error<JITLinkError>(
"COMDAT export request already exists before symbol " +
formatv("{0:d}", SymIndex));
@@ -474,10 +491,16 @@ Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest(
break;
}
case COFF::IMAGE_COMDAT_SELECT_LARGEST: {
- // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST when LinkGraph is able to
- // handle this.
- return make_error<JITLinkError>(
- "IMAGE_COMDAT_SELECT_LARGEST is not supported.");
+ // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is
+ // able to handle this.
+ LLVM_DEBUG({
+ dbgs() << " " << SymIndex
+ << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used"
+ " in section "
+ << Symbol.getSectionNumber() << "\n";
+ });
+ L = Linkage::Weak;
+ break;
}
case COFF::IMAGE_COMDAT_SELECT_NEWEST: {
// Even link.exe doesn't support this selection properly.
@@ -489,7 +512,7 @@ Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest(
formatv("{0:d}", Definition->Selection));
}
}
- PendingComdatExport = {SymIndex, Symbol.getSectionNumber(), L};
+ PendingComdatExports[Symbol.getSectionNumber()] = {SymIndex, L};
return &G->addAnonymousSymbol(*B, Symbol.getValue(), Definition->Length,
false, false);
}
@@ -499,6 +522,7 @@ Expected<Symbol *>
COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex,
StringRef SymbolName,
object::COFFSymbolRef Symbol) {
+ auto &PendingComdatExport = PendingComdatExports[Symbol.getSectionNumber()];
COFFSymbolIndex TargetIndex = PendingComdatExport->SymbolIndex;
Linkage L = PendingComdatExport->Linkage;
jitlink::Symbol *Target = getGraphSymbol(TargetIndex);
diff --git a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h
index 4dc1b14dc4a2..f925f6d7aeef 100644
--- a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h
+++ b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h
@@ -111,19 +111,19 @@ private:
// COMDAT sequence.
struct ComdatExportRequest {
COFFSymbolIndex SymbolIndex;
- COFFSectionIndex SectionIndex;
jitlink::Linkage Linkage;
};
- Optional<ComdatExportRequest> PendingComdatExport;
+ std::vector<Optional<ComdatExportRequest>> PendingComdatExports;
// This represents a pending request to create a weak external symbol with a
// name.
- struct WeakAliasRequest {
+ struct WeakExternalRequest {
COFFSymbolIndex Alias;
COFFSymbolIndex Target;
+ uint32_t Characteristics;
StringRef SymbolName;
};
- std::vector<WeakAliasRequest> WeakAliasRequests;
+ std::vector<WeakExternalRequest> WeakExternalRequests;
// Per COFF section jitlink symbol set sorted by offset.
// Used for calculating implicit size of defined symbols.
@@ -162,6 +162,8 @@ private:
Section *CommonSection = nullptr;
std::vector<Block *> GraphBlocks;
std::vector<Symbol *> GraphSymbols;
+
+ DenseMap<StringRef, Symbol *> ExternalSymbols;
};
template <typename RelocHandlerFunction>
diff --git a/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp
index 3d36ad1ed767..e2040dc95acc 100644
--- a/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp
@@ -12,8 +12,8 @@
#include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h"
#include "COFFLinkGraphBuilder.h"
-#include "EHFrameSupportImpl.h"
#include "JITLinkGeneric.h"
+#include "SEHFrameSupport.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
#include "llvm/Object/COFF.h"
@@ -26,6 +26,11 @@ using namespace llvm::jitlink;
namespace {
+enum EdgeKind_coff_x86_64 : Edge::Kind {
+ PCRel32 = x86_64::FirstPlatformRelocation,
+ Pointer32NB,
+};
+
class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {
friend class JITLinker<COFFJITLinker_x86_64>;
@@ -43,27 +48,7 @@ private:
class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
private:
- uint64_t ImageBase = 0;
- enum COFFX86RelocationKind {
- COFFAddr32NB,
- COFFRel32,
- };
-
- static Expected<COFFX86RelocationKind>
- getRelocationKind(const uint32_t Type) {
- switch (Type) {
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB:
- return COFFAddr32NB;
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32:
- return COFFRel32;
- }
-
- return make_error<JITLinkError>("Unsupported x86_64 relocation:" +
- formatv("{0:d}", Type));
- }
-
Error addRelocations() override {
-
LLVM_DEBUG(dbgs() << "Processing relocations:\n");
for (const auto &RelSect : sections())
@@ -74,21 +59,9 @@ private:
return Error::success();
}
- uint64_t getImageBase() {
- if (!ImageBase) {
- ImageBase = std::numeric_limits<uint64_t>::max();
- for (const auto &Block : getGraph().blocks()) {
- if (Block->getAddress().getValue())
- ImageBase = std::min(ImageBase, Block->getAddress().getValue());
- }
- }
- return ImageBase;
- }
-
Error addSingleRelocation(const object::RelocationRef &Rel,
const object::SectionRef &FixupSect,
Block &BlockToFix) {
-
const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel);
auto SymbolIt = Rel.getSymbol();
if (SymbolIt == getObject().symbol_end()) {
@@ -110,62 +83,122 @@ private:
SymIndex, FixupSect.getIndex()),
inconvertibleErrorCode());
- Expected<COFFX86RelocationKind> RelocKind =
- getRelocationKind(Rel.getType());
- if (!RelocKind)
- return RelocKind.takeError();
-
int64_t Addend = 0;
orc::ExecutorAddr FixupAddress =
orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset();
Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
Edge::Kind Kind = Edge::Invalid;
+ const char *FixupPtr = BlockToFix.getContent().data() + Offset;
- switch (*RelocKind) {
- case COFFAddr32NB: {
- Kind = x86_64::Pointer32;
- Offset -= getImageBase();
+ switch (Rel.getType()) {
+ case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: {
+ Kind = EdgeKind_coff_x86_64::Pointer32NB;
+ Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
break;
}
- case COFFRel32: {
- Kind = x86_64::BranchPCRel32;
+ case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: {
+ Kind = EdgeKind_coff_x86_64::PCRel32;
+ Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
break;
}
+ case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: {
+ Kind = EdgeKind_coff_x86_64::PCRel32;
+ Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
+ Addend -= 1;
+ break;
+ }
+ default: {
+ return make_error<JITLinkError>("Unsupported x86_64 relocation:" +
+ formatv("{0:d}", Rel.getType()));
+ }
};
Edge GE(Kind, Offset, *GraphSymbol, Addend);
LLVM_DEBUG({
dbgs() << " ";
- printEdge(dbgs(), BlockToFix, GE, x86_64::getEdgeKindName(Kind));
+ printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind));
dbgs() << "\n";
});
BlockToFix.addEdge(std::move(GE));
+
return Error::success();
}
- /// Return the string name of the given COFF x86_64 edge kind.
- const char *getCOFFX86RelocationKindName(COFFX86RelocationKind R) {
- switch (R) {
- case COFFAddr32NB:
- return "COFFAddr32NB";
- case COFFRel32:
- return "COFFRel32";
+public:
+ COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T)
+ : COFFLinkGraphBuilder(Obj, std::move(T), getCOFFX86RelocationKindName) {}
+};
+
+class COFFLinkGraphLowering_x86_64 {
+public:
+ // Lowers COFF x86_64 specific edges to generic x86_64 edges.
+ Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) {
+ for (auto *B : G.blocks()) {
+ for (auto &E : B->edges()) {
+ switch (E.getKind()) {
+ case EdgeKind_coff_x86_64::Pointer32NB: {
+ auto ImageBase = getImageBaseAddress(G, Ctx);
+ if (!ImageBase)
+ return ImageBase.takeError();
+ E.setAddend(E.getAddend() - *ImageBase);
+ E.setKind(x86_64::Pointer32);
+ break;
+ }
+ case EdgeKind_coff_x86_64::PCRel32: {
+ E.setKind(x86_64::PCRel32);
+ break;
+ }
+ default:
+ break;
+ }
+ }
}
+ return Error::success();
}
-public:
- COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T)
- : COFFLinkGraphBuilder(Obj, std::move(T), x86_64::getEdgeKindName) {}
+private:
+ static StringRef getImageBaseSymbolName() { return "__ImageBase"; }
+ Expected<JITTargetAddress> getImageBaseAddress(LinkGraph &G,
+ JITLinkContext &Ctx) {
+ if (this->ImageBase)
+ return this->ImageBase;
+ for (auto *S : G.defined_symbols())
+ if (S->getName() == getImageBaseSymbolName()) {
+ this->ImageBase = S->getAddress().getValue();
+ return this->ImageBase;
+ }
+
+ JITLinkContext::LookupMap Symbols;
+ Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol;
+ JITTargetAddress ImageBase;
+ Error Err = Error::success();
+ Ctx.lookup(Symbols,
+ createLookupContinuation([&](Expected<AsyncLookupResult> LR) {
+ ErrorAsOutParameter EAO(&Err);
+ if (!LR) {
+ Err = LR.takeError();
+ return;
+ }
+ auto &ImageBaseSymbol = LR->begin()->second;
+ ImageBase = ImageBaseSymbol.getAddress();
+ }));
+ if (Err)
+ return std::move(Err);
+ this->ImageBase = ImageBase;
+ return ImageBase;
+ }
+ JITTargetAddress ImageBase = 0;
};
-Error buildTables_COFF_x86_64(LinkGraph &G) {
- LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
+Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) {
+ LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n");
+ COFFLinkGraphLowering_x86_64 GraphLowering;
+
+ if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx))
+ return Err;
- x86_64::GOTTableManager GOT;
- x86_64::PLTTableManager PLT(GOT);
- visitExistingEdges(G, GOT, PLT);
return Error::success();
}
} // namespace
@@ -173,6 +206,18 @@ Error buildTables_COFF_x86_64(LinkGraph &G) {
namespace llvm {
namespace jitlink {
+/// Return the string name of the given COFF x86_64 edge kind.
+const char *getCOFFX86RelocationKindName(Edge::Kind R) {
+ switch (R) {
+ case PCRel32:
+ return "PCRel32";
+ case Pointer32NB:
+ return "Pointer32NB";
+ default:
+ return x86_64::getEdgeKindName(R);
+ }
+}
+
Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) {
LLVM_DEBUG({
@@ -194,16 +239,16 @@ void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,
const Triple &TT = G->getTargetTriple();
if (Ctx->shouldAddDefaultTargetPasses(TT)) {
// Add a mark-live pass.
- if (auto MarkLive = Ctx->getMarkLivePass(TT))
+ if (auto MarkLive = Ctx->getMarkLivePass(TT)) {
Config.PrePrunePasses.push_back(std::move(MarkLive));
- else
+ Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata"));
+ } else
Config.PrePrunePasses.push_back(markAllSymbolsLive);
- // Add an in-place GOT/Stubs/TLSInfoEntry build pass.
- Config.PostPrunePasses.push_back(buildTables_COFF_x86_64);
-
- // Add GOT/Stubs optimizer pass.
- Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
+ // Add COFF edge lowering passes.
+ JITLinkContext *CtxPtr = Ctx.get();
+ Config.PreFixupPasses.push_back(
+ [CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); });
}
if (auto Err = Ctx->modifyPassConfig(*G, Config))
diff --git a/llvm/lib/ExecutionEngine/JITLink/SEHFrameSupport.h b/llvm/lib/ExecutionEngine/JITLink/SEHFrameSupport.h
new file mode 100644
index 000000000000..f7689e4e4043
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/SEHFrameSupport.h
@@ -0,0 +1,61 @@
+//===------- SEHFrameSupport.h - JITLink seh-frame utils --------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// SEHFrame utils for JITLink.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_JITLINK_SEHFRAMESUPPORT_H
+#define LLVM_EXECUTIONENGINE_JITLINK_SEHFRAMESUPPORT_H
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace jitlink {
+/// This pass adds keep-alive edge from SEH frame sections
+/// to the parent function content block.
+class SEHFrameKeepAlivePass {
+public:
+ SEHFrameKeepAlivePass(StringRef SEHFrameSectionName)
+ : SEHFrameSectionName(SEHFrameSectionName) {}
+
+ Error operator()(LinkGraph &G) {
+ auto *S = G.findSectionByName(SEHFrameSectionName);
+ if (!S)
+ return Error::success();
+
+ // Simply consider every block pointed by seh frame block as parants.
+ // This adds some unnecessary keep-alive edges to unwind info blocks,
+ // (xdata) but these blocks are usually dead by default, so they wouldn't
+ // count for the fate of seh frame block.
+ for (auto *B : S->blocks()) {
+ auto &DummySymbol = G.addAnonymousSymbol(*B, 0, 0, false, false);
+ DenseSet<Block *> Children;
+ for (auto &E : B->edges()) {
+ auto &Sym = E.getTarget();
+ if (!Sym.isDefined())
+ continue;
+ Children.insert(&Sym.getBlock());
+ }
+ for (auto *Child : Children)
+ Child->addEdge(Edge(Edge::KeepAlive, 0, DummySymbol, 0));
+ }
+ return Error::success();
+ }
+
+private:
+ StringRef SEHFrameSectionName;
+};
+
+} // end namespace jitlink
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_JITLINK_SEHFRAMESUPPORT_H \ No newline at end of file
diff --git a/llvm/lib/ExecutionEngine/JITLink/x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/x86_64.cpp
index df9979b47e88..393250a5578b 100644
--- a/llvm/lib/ExecutionEngine/JITLink/x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/x86_64.cpp
@@ -36,6 +36,8 @@ const char *getEdgeKindName(Edge::Kind K) {
return "NegDelta32";
case Delta64FromGOT:
return "Delta64FromGOT";
+ case PCRel32:
+ return "PCRel32";
case BranchPCRel32:
return "BranchPCRel32";
case BranchPCRel32ToPtrJumpStub:
diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp
index 356b81b4f1c5..3de15db3f1c6 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp
@@ -150,16 +150,39 @@ static Expected<MaterializationUnit::Interface>
getCOFFObjectFileSymbolInfo(ExecutionSession &ES,
const object::COFFObjectFile &Obj) {
MaterializationUnit::Interface I;
-
+ std::vector<Optional<object::coff_aux_section_definition>> ComdatDefs(
+ Obj.getNumberOfSections() + 1);
for (auto &Sym : Obj.symbols()) {
Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
if (!SymFlagsOrErr)
// TODO: Test this error.
return SymFlagsOrErr.takeError();
- // Skip symbols not defined in this object file.
- if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
- continue;
+ // Handle comdat symbols
+ auto COFFSym = Obj.getCOFFSymbol(Sym);
+ bool IsWeak = false;
+ if (auto *Def = COFFSym.getSectionDefinition()) {
+ auto Sec = Obj.getSection(COFFSym.getSectionNumber());
+ if (!Sec)
+ return Sec.takeError();
+ if (((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT) &&
+ Def->Selection != COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ ComdatDefs[COFFSym.getSectionNumber()] = *Def;
+ continue;
+ }
+ }
+ if (!COFF::isReservedSectionNumber(COFFSym.getSectionNumber()) &&
+ ComdatDefs[COFFSym.getSectionNumber()]) {
+ auto Def = ComdatDefs[COFFSym.getSectionNumber()];
+ if (Def->Selection != COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) {
+ IsWeak = true;
+ }
+ ComdatDefs[COFFSym.getSectionNumber()] = None;
+ } else {
+ // Skip symbols not defined in this object file.
+ if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
+ continue;
+ }
// Skip symbols that are not global.
if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
@@ -180,12 +203,13 @@ getCOFFObjectFileSymbolInfo(ExecutionSession &ES,
if (!SymFlags)
return SymFlags.takeError();
*SymFlags |= JITSymbolFlags::Exported;
- auto COFFSym = Obj.getCOFFSymbol(Sym);
// Weak external is always a function
- if (COFFSym.isWeakExternal()) {
+ if (COFFSym.isWeakExternal())
*SymFlags |= JITSymbolFlags::Callable;
- }
+
+ if (IsWeak)
+ *SymFlags |= JITSymbolFlags::Weak;
I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags);
}
diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp
index bf13b6c325ec..5d4cfceefb3e 100644
--- a/llvm/lib/FileCheck/FileCheck.cpp
+++ b/llvm/lib/FileCheck/FileCheck.cpp
@@ -1424,6 +1424,8 @@ void Pattern::printVariableDefs(const SourceMgr &SM,
// Sort variable captures by the order in which they matched the input.
// Ranges shouldn't be overlapping, so we can just compare the start.
llvm::sort(VarCaptures, [](const VarCapture &A, const VarCapture &B) {
+ if (&A == &B)
+ return false;
assert(A.Range.Start != B.Range.Start &&
"unexpected overlapping variable captures");
return A.Range.Start.getPointer() < B.Range.Start.getPointer();
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 26171f537244..f5039eb5126c 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -1627,6 +1627,10 @@ AtomicCmpXchgInst::AtomicCmpXchgInst(Value *Ptr, Value *Cmp, Value *NewVal,
void AtomicRMWInst::Init(BinOp Operation, Value *Ptr, Value *Val,
Align Alignment, AtomicOrdering Ordering,
SyncScope::ID SSID) {
+ assert(Ordering != AtomicOrdering::NotAtomic &&
+ "atomicrmw instructions can only be atomic.");
+ assert(Ordering != AtomicOrdering::Unordered &&
+ "atomicrmw instructions cannot be unordered.");
Op<0>() = Ptr;
Op<1>() = Val;
setOperation(Operation);
diff --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp
index c50d6901c9da..8ca75f58e403 100644
--- a/llvm/lib/IR/IntrinsicInst.cpp
+++ b/llvm/lib/IR/IntrinsicInst.cpp
@@ -32,6 +32,39 @@
using namespace llvm;
+bool IntrinsicInst::mayLowerToFunctionCall(Intrinsic::ID IID) {
+ switch (IID) {
+ case Intrinsic::objc_autorelease:
+ case Intrinsic::objc_autoreleasePoolPop:
+ case Intrinsic::objc_autoreleasePoolPush:
+ case Intrinsic::objc_autoreleaseReturnValue:
+ case Intrinsic::objc_copyWeak:
+ case Intrinsic::objc_destroyWeak:
+ case Intrinsic::objc_initWeak:
+ case Intrinsic::objc_loadWeak:
+ case Intrinsic::objc_loadWeakRetained:
+ case Intrinsic::objc_moveWeak:
+ case Intrinsic::objc_release:
+ case Intrinsic::objc_retain:
+ case Intrinsic::objc_retainAutorelease:
+ case Intrinsic::objc_retainAutoreleaseReturnValue:
+ case Intrinsic::objc_retainAutoreleasedReturnValue:
+ case Intrinsic::objc_retainBlock:
+ case Intrinsic::objc_storeStrong:
+ case Intrinsic::objc_storeWeak:
+ case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:
+ case Intrinsic::objc_retainedObject:
+ case Intrinsic::objc_unretainedObject:
+ case Intrinsic::objc_unretainedPointer:
+ case Intrinsic::objc_retain_autorelease:
+ case Intrinsic::objc_sync_enter:
+ case Intrinsic::objc_sync_exit:
+ return true;
+ default:
+ return false;
+ }
+}
+
//===----------------------------------------------------------------------===//
/// DbgVariableIntrinsic - This is the common base class for debug info
/// intrinsics for variables.
diff --git a/llvm/lib/IR/ModuleSummaryIndex.cpp b/llvm/lib/IR/ModuleSummaryIndex.cpp
index 0ca40a675fe4..3e82987801c7 100644
--- a/llvm/lib/IR/ModuleSummaryIndex.cpp
+++ b/llvm/lib/IR/ModuleSummaryIndex.cpp
@@ -105,11 +105,13 @@ uint64_t ModuleSummaryIndex::getFlags() const {
Flags |= 0x20;
if (withDSOLocalPropagation())
Flags |= 0x40;
+ if (withWholeProgramVisibility())
+ Flags |= 0x80;
return Flags;
}
void ModuleSummaryIndex::setFlags(uint64_t Flags) {
- assert(Flags <= 0x7f && "Unexpected bits in flag");
+ assert(Flags <= 0xff && "Unexpected bits in flag");
// 1 bit: WithGlobalValueDeadStripping flag.
// Set on combined index only.
if (Flags & 0x1)
@@ -139,6 +141,10 @@ void ModuleSummaryIndex::setFlags(uint64_t Flags) {
// Set on combined index only.
if (Flags & 0x40)
setWithDSOLocalPropagation();
+ // 1 bit: WithWholeProgramVisibility flag.
+ // Set on combined index only.
+ if (Flags & 0x80)
+ setWithWholeProgramVisibility();
}
// Collect for the given module the list of function it defines
diff --git a/llvm/lib/IR/PrintPasses.cpp b/llvm/lib/IR/PrintPasses.cpp
index 83b8c93e766f..fe2da5ca114f 100644
--- a/llvm/lib/IR/PrintPasses.cpp
+++ b/llvm/lib/IR/PrintPasses.cpp
@@ -29,6 +29,50 @@ static cl::opt<bool> PrintAfterAll("print-after-all",
llvm::cl::desc("Print IR after each pass"),
cl::init(false), cl::Hidden);
+// Print out the IR after passes, similar to -print-after-all except that it
+// only prints the IR after passes that change the IR. Those passes that do not
+// make changes to the IR are reported as not making any changes. In addition,
+// the initial IR is also reported. Other hidden options affect the output from
+// this option. -filter-passes will limit the output to the named passes that
+// actually change the IR and other passes are reported as filtered out. The
+// specified passes will either be reported as making no changes (with no IR
+// reported) or the changed IR will be reported. Also, the -filter-print-funcs
+// and -print-module-scope options will do similar filtering based on function
+// name, reporting changed IRs as functions(or modules if -print-module-scope is
+// specified) for a particular function or indicating that the IR has been
+// filtered out. The extra options can be combined, allowing only changed IRs
+// for certain passes on certain functions to be reported in different formats,
+// with the rest being reported as filtered out. The -print-before-changed
+// option will print the IR as it was before each pass that changed it. The
+// optional value of quiet will only report when the IR changes, suppressing all
+// other messages, including the initial IR. The values "diff" and "diff-quiet"
+// will present the changes in a form similar to a patch, in either verbose or
+// quiet mode, respectively. The lines that are removed and added are prefixed
+// with '-' and '+', respectively. The -filter-print-funcs and -filter-passes
+// can be used to filter the output. This reporter relies on the linux diff
+// utility to do comparisons and insert the prefixes. For systems that do not
+// have the necessary facilities, the error message will be shown in place of
+// the expected output.
+cl::opt<ChangePrinter> llvm::PrintChanged(
+ "print-changed", cl::desc("Print changed IRs"), cl::Hidden,
+ cl::ValueOptional, cl::init(ChangePrinter::None),
+ cl::values(
+ clEnumValN(ChangePrinter::Quiet, "quiet", "Run in quiet mode"),
+ clEnumValN(ChangePrinter::DiffVerbose, "diff",
+ "Display patch-like changes"),
+ clEnumValN(ChangePrinter::DiffQuiet, "diff-quiet",
+ "Display patch-like changes in quiet mode"),
+ clEnumValN(ChangePrinter::ColourDiffVerbose, "cdiff",
+ "Display patch-like changes with color"),
+ clEnumValN(ChangePrinter::ColourDiffQuiet, "cdiff-quiet",
+ "Display patch-like changes in quiet mode with color"),
+ clEnumValN(ChangePrinter::DotCfgVerbose, "dot-cfg",
+ "Create a website with graphical changes"),
+ clEnumValN(ChangePrinter::DotCfgQuiet, "dot-cfg-quiet",
+ "Create a website with graphical changes in quiet mode"),
+ // Sentinel value for unspecified option.
+ clEnumValN(ChangePrinter::Verbose, "", "")));
+
static cl::opt<bool>
PrintModuleScope("print-module-scope",
cl::desc("When printing IR for print-[before|after]{-all} "
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index a9e04ba760ca..cc7be24c1dbd 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -1103,6 +1103,8 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
updateVCallVisibilityInModule(*RegularLTO.CombinedModule,
Conf.HasWholeProgramVisibility,
DynamicExportSymbols);
+ updatePublicTypeTestCalls(*RegularLTO.CombinedModule,
+ Conf.HasWholeProgramVisibility);
if (Conf.PreOptModuleHook &&
!Conf.PreOptModuleHook(0, *RegularLTO.CombinedModule))
@@ -1482,6 +1484,8 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
std::set<GlobalValue::GUID> ExportedGUIDs;
+ if (hasWholeProgramVisibility(Conf.HasWholeProgramVisibility))
+ ThinLTO.CombinedIndex.setWithWholeProgramVisibility();
// If allowed, upgrade public vcall visibility to linkage unit visibility in
// the summaries before whole program devirtualization below.
updateVCallVisibilityInIndex(ThinLTO.CombinedIndex,
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
index e248e58e4e4e..2e32469b4926 100644
--- a/llvm/lib/LTO/LTOBackend.cpp
+++ b/llvm/lib/LTO/LTOBackend.cpp
@@ -40,6 +40,7 @@
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO/WholeProgramDevirt.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
#include "llvm/Transforms/Utils/SplitModule.h"
@@ -560,6 +561,8 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
// the module, if applicable.
Mod.setPartialSampleProfileRatio(CombinedIndex);
+ updatePublicTypeTestCalls(Mod, CombinedIndex.withWholeProgramVisibility());
+
if (Conf.CodeGenOnly) {
codegen(Conf, TM.get(), AddStream, Task, Mod, CombinedIndex);
return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp
index 2abf249cbd62..2f7c485b9fc8 100644
--- a/llvm/lib/LTO/LTOCodeGenerator.cpp
+++ b/llvm/lib/LTO/LTOCodeGenerator.cpp
@@ -520,6 +520,8 @@ bool LTOCodeGenerator::optimize() {
// linker option in the old LTO API, but this call allows it to be specified
// via the internal option. Must be done before WPD invoked via the optimizer
// pipeline run below.
+ updatePublicTypeTestCalls(*MergedModule,
+ /* WholeProgramVisibilityEnabledInLTO */ false);
updateVCallVisibilityInModule(*MergedModule,
/* WholeProgramVisibilityEnabledInLTO */ false,
// FIXME: This needs linker information via a
@@ -539,6 +541,16 @@ bool LTOCodeGenerator::optimize() {
// Add an appropriate DataLayout instance for this module...
MergedModule->setDataLayout(TargetMach->createDataLayout());
+ if (!SaveIRBeforeOptPath.empty()) {
+ std::error_code EC;
+ raw_fd_ostream OS(SaveIRBeforeOptPath, EC, sys::fs::OF_None);
+ if (EC)
+ report_fatal_error(Twine("Failed to open ") + SaveIRBeforeOptPath +
+ " to save optimized bitcode\n");
+ WriteBitcodeToFile(*MergedModule, OS,
+ /* ShouldPreserveUseListOrder */ true);
+ }
+
ModuleSummaryIndex CombinedIndex(false);
TargetMach = createTargetMachine();
if (!opt(Config, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false,
diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
index a1041b3c85f5..2c723bef7d12 100644
--- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
+++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
@@ -452,6 +452,10 @@ ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index,
bool DisableCodeGen, StringRef SaveTempsDir,
bool Freestanding, unsigned OptLevel, unsigned count,
bool DebugPassManager) {
+ // See comment at call to updateVCallVisibilityInIndex() for why
+ // WholeProgramVisibilityEnabledInLTO is false.
+ updatePublicTypeTestCalls(TheModule,
+ /* WholeProgramVisibilityEnabledInLTO */ false);
// "Benchmark"-like optimization: single-source case
bool SingleModule = (ModuleMap.size() == 1);
@@ -1047,6 +1051,8 @@ void ThinLTOCodeGenerator::run() {
// Currently there is no support for enabling whole program visibility via a
// linker option in the old LTO API, but this call allows it to be specified
// via the internal option. Must be done before WPD below.
+ if (hasWholeProgramVisibility(/* WholeProgramVisibilityEnabledInLTO */ false))
+ Index->setWithWholeProgramVisibility();
updateVCallVisibilityInIndex(*Index,
/* WholeProgramVisibilityEnabledInLTO */ false,
// FIXME: This needs linker information via a
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
index 0b4e9866d50a..f6360c4e2f21 100644
--- a/llvm/lib/MC/ELFObjectWriter.cpp
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -293,9 +293,8 @@ public:
: ELFObjectWriter(std::move(MOTW)), OS(OS), DwoOS(DwoOS),
IsLittleEndian(IsLittleEndian) {}
- virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc,
- const MCSectionELF *From,
- const MCSectionELF *To) override {
+ bool checkRelocation(MCContext &Ctx, SMLoc Loc, const MCSectionELF *From,
+ const MCSectionELF *To) override {
if (isDwoSection(*From)) {
Ctx.reportError(Loc, "A dwo section may not contain relocations");
return false;
diff --git a/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp b/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp
index cf98cb8ff59f..3ee43398ff65 100644
--- a/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp
+++ b/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp
@@ -20,6 +20,11 @@ MCDisassembler::onSymbolStart(SymbolInfoTy &Symbol, uint64_t &Size,
return None;
}
+uint64_t MCDisassembler::suggestBytesToSkip(ArrayRef<uint8_t> Bytes,
+ uint64_t Address) const {
+ return 1;
+}
+
bool MCDisassembler::tryAddingSymbolicOperand(MCInst &Inst, int64_t Value,
uint64_t Address, bool IsBranch,
uint64_t Offset, uint64_t OpSize,
diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp
index d46ae2247535..8a43a477c1c7 100644
--- a/llvm/lib/MC/XCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/XCOFFObjectWriter.cpp
@@ -253,7 +253,7 @@ class XCOFFObjectWriter : public MCObjectWriter {
CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec);
- virtual void reset() override;
+ void reset() override;
void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override;
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 8b44c09023f1..b127e1b43b8e 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -434,41 +434,13 @@ Error SectionWriter::visit(const OwnedDataSection &Sec) {
return Error::success();
}
-static constexpr std::array<uint8_t, 4> ZlibGnuMagic = {{'Z', 'L', 'I', 'B'}};
-
-static bool isDataGnuCompressed(ArrayRef<uint8_t> Data) {
- return Data.size() > ZlibGnuMagic.size() &&
- std::equal(ZlibGnuMagic.begin(), ZlibGnuMagic.end(), Data.data());
-}
-
-template <class ELFT>
-static std::tuple<uint64_t, uint64_t>
-getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) {
- const bool IsGnuDebug = isDataGnuCompressed(Data);
- const uint64_t DecompressedSize =
- IsGnuDebug
- ? support::endian::read64be(Data.data() + ZlibGnuMagic.size())
- : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())->ch_size;
- const uint64_t DecompressedAlign =
- IsGnuDebug ? 1
- : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())
- ->ch_addralign;
-
- return std::make_tuple(DecompressedSize, DecompressedAlign);
-}
-
template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) {
- const size_t DataOffset = isDataGnuCompressed(Sec.OriginalData)
- ? (ZlibGnuMagic.size() + sizeof(Sec.Size))
- : sizeof(Elf_Chdr_Impl<ELFT>);
-
- ArrayRef<uint8_t> CompressedContent(Sec.OriginalData.data() + DataOffset,
- Sec.OriginalData.size() - DataOffset);
+ ArrayRef<uint8_t> Compressed =
+ Sec.OriginalData.slice(sizeof(Elf_Chdr_Impl<ELFT>));
SmallVector<uint8_t, 128> DecompressedContent;
- if (Error Err =
- compression::zlib::uncompress(CompressedContent, DecompressedContent,
- static_cast<size_t>(Sec.Size)))
+ if (Error Err = compression::zlib::uncompress(Compressed, DecompressedContent,
+ static_cast<size_t>(Sec.Size)))
return createStringError(errc::invalid_argument,
"'" + Sec.Name + "': " + toString(std::move(Err)));
@@ -518,7 +490,7 @@ Error BinarySectionWriter::visit(const CompressedSection &Sec) {
template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const CompressedSection &Sec) {
uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
- Elf_Chdr_Impl<ELFT> Chdr;
+ Elf_Chdr_Impl<ELFT> Chdr = {};
switch (Sec.CompressionType) {
case DebugCompressionType::None:
std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
@@ -1731,15 +1703,11 @@ Expected<SectionBase &> ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) {
if (!Name)
return Name.takeError();
- if (Name->startswith(".zdebug") || (Shdr.sh_flags & ELF::SHF_COMPRESSED)) {
- uint64_t DecompressedSize, DecompressedAlign;
- std::tie(DecompressedSize, DecompressedAlign) =
- getDecompressedSizeAndAlignment<ELFT>(*Data);
- return Obj.addSection<CompressedSection>(
- CompressedSection(*Data, DecompressedSize, DecompressedAlign));
- }
-
- return Obj.addSection<Section>(*Data);
+ if (!(Shdr.sh_flags & ELF::SHF_COMPRESSED))
+ return Obj.addSection<Section>(*Data);
+ auto *Chdr = reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data->data());
+ return Obj.addSection<CompressedSection>(
+ CompressedSection(*Data, Chdr->ch_size, Chdr->ch_addralign));
}
}
}
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 799db5034532..2c3ea3a5f6d6 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -115,13 +115,13 @@ public:
Error visit(const OwnedDataSection &Sec) override;
Error visit(const StringTableSection &Sec) override;
Error visit(const DynamicRelocationSection &Sec) override;
- virtual Error visit(const SymbolTableSection &Sec) override = 0;
- virtual Error visit(const RelocationSection &Sec) override = 0;
- virtual Error visit(const GnuDebugLinkSection &Sec) override = 0;
- virtual Error visit(const GroupSection &Sec) override = 0;
- virtual Error visit(const SectionIndexSection &Sec) override = 0;
- virtual Error visit(const CompressedSection &Sec) override = 0;
- virtual Error visit(const DecompressedSection &Sec) override = 0;
+ Error visit(const SymbolTableSection &Sec) override = 0;
+ Error visit(const RelocationSection &Sec) override = 0;
+ Error visit(const GnuDebugLinkSection &Sec) override = 0;
+ Error visit(const GroupSection &Sec) override = 0;
+ Error visit(const SectionIndexSection &Sec) override = 0;
+ Error visit(const CompressedSection &Sec) override = 0;
+ Error visit(const DecompressedSection &Sec) override = 0;
explicit SectionWriter(WritableMemoryBuffer &Buf) : Out(Buf) {}
};
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index b778006cf66e..9ad2c4135167 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -518,6 +518,14 @@ void ScalarBitSetTraits<ELFYAML::ELF_EF>::bitset(IO &IO,
BCaseMask(EF_AVR_ARCH_XMEGA7, EF_AVR_ARCH_MASK);
BCase(EF_AVR_LINKRELAX_PREPARED);
break;
+ case ELF::EM_LOONGARCH:
+ BCaseMask(EF_LOONGARCH_BASE_ABI_ILP32S, EF_LOONGARCH_BASE_ABI_MASK);
+ BCaseMask(EF_LOONGARCH_BASE_ABI_ILP32F, EF_LOONGARCH_BASE_ABI_MASK);
+ BCaseMask(EF_LOONGARCH_BASE_ABI_ILP32D, EF_LOONGARCH_BASE_ABI_MASK);
+ BCaseMask(EF_LOONGARCH_BASE_ABI_LP64S, EF_LOONGARCH_BASE_ABI_MASK);
+ BCaseMask(EF_LOONGARCH_BASE_ABI_LP64F, EF_LOONGARCH_BASE_ABI_MASK);
+ BCaseMask(EF_LOONGARCH_BASE_ABI_LP64D, EF_LOONGARCH_BASE_ABI_MASK);
+ break;
case ELF::EM_RISCV:
BCase(EF_RISCV_RVC);
BCaseMask(EF_RISCV_FLOAT_ABI_SOFT, EF_RISCV_FLOAT_ABI);
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 3b3eefcc29ca..945ef512391b 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -1249,6 +1249,9 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
// flattening of blocks.
OptimizePM.addPass(DivRemPairsPass());
+ // Try to annotate calls that were created during optimization.
+ OptimizePM.addPass(TailCallElimPass());
+
// LoopSink (and other loop passes since the last simplifyCFG) might have
// resulted in single-entry-single-exit or empty blocks. Clean up the CFG.
OptimizePM.addPass(
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index baea0eb53ef9..a0c63fb33369 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -53,64 +53,6 @@ cl::opt<bool> PreservedCFGCheckerInstrumentation::VerifyPreservedCFG(
#endif
);
-// An option that prints out the IR after passes, similar to
-// -print-after-all except that it only prints the IR after passes that
-// change the IR. Those passes that do not make changes to the IR are
-// reported as not making any changes. In addition, the initial IR is
-// also reported. Other hidden options affect the output from this
-// option. -filter-passes will limit the output to the named passes
-// that actually change the IR and other passes are reported as filtered out.
-// The specified passes will either be reported as making no changes (with
-// no IR reported) or the changed IR will be reported. Also, the
-// -filter-print-funcs and -print-module-scope options will do similar
-// filtering based on function name, reporting changed IRs as functions(or
-// modules if -print-module-scope is specified) for a particular function
-// or indicating that the IR has been filtered out. The extra options
-// can be combined, allowing only changed IRs for certain passes on certain
-// functions to be reported in different formats, with the rest being
-// reported as filtered out. The -print-before-changed option will print
-// the IR as it was before each pass that changed it. The optional
-// value of quiet will only report when the IR changes, suppressing
-// all other messages, including the initial IR. The values "diff" and
-// "diff-quiet" will present the changes in a form similar to a patch, in
-// either verbose or quiet mode, respectively. The lines that are removed
-// and added are prefixed with '-' and '+', respectively. The
-// -filter-print-funcs and -filter-passes can be used to filter the output.
-// This reporter relies on the linux diff utility to do comparisons and
-// insert the prefixes. For systems that do not have the necessary
-// facilities, the error message will be shown in place of the expected output.
-//
-enum class ChangePrinter {
- None,
- Verbose,
- Quiet,
- DiffVerbose,
- DiffQuiet,
- ColourDiffVerbose,
- ColourDiffQuiet,
- DotCfgVerbose,
- DotCfgQuiet,
-};
-static cl::opt<ChangePrinter> PrintChanged(
- "print-changed", cl::desc("Print changed IRs"), cl::Hidden,
- cl::ValueOptional, cl::init(ChangePrinter::None),
- cl::values(
- clEnumValN(ChangePrinter::Quiet, "quiet", "Run in quiet mode"),
- clEnumValN(ChangePrinter::DiffVerbose, "diff",
- "Display patch-like changes"),
- clEnumValN(ChangePrinter::DiffQuiet, "diff-quiet",
- "Display patch-like changes in quiet mode"),
- clEnumValN(ChangePrinter::ColourDiffVerbose, "cdiff",
- "Display patch-like changes with color"),
- clEnumValN(ChangePrinter::ColourDiffQuiet, "cdiff-quiet",
- "Display patch-like changes in quiet mode with color"),
- clEnumValN(ChangePrinter::DotCfgVerbose, "dot-cfg",
- "Create a website with graphical changes"),
- clEnumValN(ChangePrinter::DotCfgQuiet, "dot-cfg-quiet",
- "Create a website with graphical changes in quiet mode"),
- // Sentinel value for unspecified option.
- clEnumValN(ChangePrinter::Verbose, "", "")));
-
// An option that supports the -print-changed option. See
// the description for -print-changed for an explanation of the use
// of this option. Note that this option has no effect without -print-changed.
diff --git a/llvm/lib/Support/ARMAttributeParser.cpp b/llvm/lib/Support/ARMAttributeParser.cpp
index adb5d3f0964d..03c0c7aac423 100644
--- a/llvm/lib/Support/ARMAttributeParser.cpp
+++ b/llvm/lib/Support/ARMAttributeParser.cpp
@@ -85,7 +85,7 @@ Error ARMAttributeParser::CPU_arch(AttrType tag) {
static const char *strings[] = {
"Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6",
"ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M",
- "ARM v7E-M", "ARM v8", nullptr,
+ "ARM v7E-M", "ARM v8-A", "ARM v8-R",
"ARM v8-M Baseline", "ARM v8-M Mainline", nullptr, nullptr, nullptr,
"ARM v8.1-M Mainline", "ARM v9-A"
};
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index e070ce2efa6b..72f0fc94940c 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -255,6 +255,12 @@ static bool isZeroingInactiveLanes(SDValue Op) {
return false;
case Intrinsic::aarch64_sve_ptrue:
case Intrinsic::aarch64_sve_pnext:
+ case Intrinsic::aarch64_sve_cmpeq:
+ case Intrinsic::aarch64_sve_cmpne:
+ case Intrinsic::aarch64_sve_cmpge:
+ case Intrinsic::aarch64_sve_cmpgt:
+ case Intrinsic::aarch64_sve_cmphs:
+ case Intrinsic::aarch64_sve_cmphi:
case Intrinsic::aarch64_sve_cmpeq_wide:
case Intrinsic::aarch64_sve_cmpne_wide:
case Intrinsic::aarch64_sve_cmpge_wide:
@@ -265,6 +271,11 @@ static bool isZeroingInactiveLanes(SDValue Op) {
case Intrinsic::aarch64_sve_cmphi_wide:
case Intrinsic::aarch64_sve_cmplo_wide:
case Intrinsic::aarch64_sve_cmpls_wide:
+ case Intrinsic::aarch64_sve_fcmpeq:
+ case Intrinsic::aarch64_sve_fcmpne:
+ case Intrinsic::aarch64_sve_fcmpge:
+ case Intrinsic::aarch64_sve_fcmpgt:
+ case Intrinsic::aarch64_sve_fcmpuo:
return true;
}
}
@@ -879,6 +890,8 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
if (Subtarget->supportsAddressTopByteIgnored())
setTargetDAGCombine(ISD::LOAD);
+ setTargetDAGCombine(ISD::MSTORE);
+
setTargetDAGCombine(ISD::MUL);
setTargetDAGCombine({ISD::SELECT, ISD::VSELECT});
@@ -974,6 +987,8 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(Op, VT, Custom);
if (Subtarget->hasFullFP16()) {
+ setOperationAction(ISD::ConstantFP, MVT::f16, Legal);
+
setOperationAction(ISD::SINT_TO_FP, MVT::v8i8, Custom);
setOperationAction(ISD::UINT_TO_FP, MVT::v8i8, Custom);
setOperationAction(ISD::SINT_TO_FP, MVT::v16i8, Custom);
@@ -1619,6 +1634,7 @@ void AArch64TargetLowering::addTypeForFixedLengthSVE(MVT VT) {
setOperationAction(ISD::ANY_EXTEND, VT, Custom);
setOperationAction(ISD::BITCAST, VT, Custom);
setOperationAction(ISD::BITREVERSE, VT, Custom);
+ setOperationAction(ISD::BUILD_VECTOR, VT, Custom);
setOperationAction(ISD::BSWAP, VT, Custom);
setOperationAction(ISD::CONCAT_VECTORS, VT, Custom);
setOperationAction(ISD::CTLZ, VT, Custom);
@@ -11126,6 +11142,20 @@ SDValue AArch64TargetLowering::LowerBUILD_VECTOR(SDValue Op,
SelectionDAG &DAG) const {
EVT VT = Op.getValueType();
+ if (useSVEForFixedLengthVectorVT(VT)) {
+ if (auto SeqInfo = cast<BuildVectorSDNode>(Op)->isConstantSequence()) {
+ SDLoc DL(Op);
+ EVT ContainerVT = getContainerForFixedLengthVector(DAG, VT);
+ SDValue Start = DAG.getConstant(SeqInfo->first, DL, ContainerVT);
+ SDValue Steps = DAG.getStepVector(DL, ContainerVT, SeqInfo->second);
+ SDValue Seq = DAG.getNode(ISD::ADD, DL, ContainerVT, Start, Steps);
+ return convertFromScalableVector(DAG, Op.getValueType(), Seq);
+ }
+
+ // Revert to common legalisation for all other variants.
+ return SDValue();
+ }
+
// Try to build a simple constant vector.
Op = NormalizeBuildVector(Op, DAG);
if (VT.isInteger()) {
@@ -12772,6 +12802,12 @@ bool AArch64TargetLowering::shouldSinkOperands(
if (isSplatShuffle(II->getOperand(1)))
Ops.push_back(&II->getOperandUse(1));
return !Ops.empty();
+ case Intrinsic::aarch64_sve_ptest_first:
+ case Intrinsic::aarch64_sve_ptest_last:
+ if (auto *IIOp = dyn_cast<IntrinsicInst>(II->getOperand(0)))
+ if (IIOp->getIntrinsicID() == Intrinsic::aarch64_sve_ptrue)
+ Ops.push_back(&II->getOperandUse(0));
+ return !Ops.empty();
case Intrinsic::aarch64_sme_write_horiz:
case Intrinsic::aarch64_sme_write_vert:
case Intrinsic::aarch64_sme_writeq_horiz:
@@ -17142,7 +17178,8 @@ static SDValue performSpliceCombine(SDNode *N, SelectionDAG &DAG) {
return SDValue();
}
-static SDValue performUnpackCombine(SDNode *N, SelectionDAG &DAG) {
+static SDValue performUnpackCombine(SDNode *N, SelectionDAG &DAG,
+ const AArch64Subtarget *Subtarget) {
assert((N->getOpcode() == AArch64ISD::UUNPKHI ||
N->getOpcode() == AArch64ISD::UUNPKLO) &&
"Unexpected Opcode!");
@@ -17151,6 +17188,42 @@ static SDValue performUnpackCombine(SDNode *N, SelectionDAG &DAG) {
if (N->getOperand(0).isUndef())
return DAG.getUNDEF(N->getValueType(0));
+ // If this is a masked load followed by an UUNPKLO, fold this into a masked
+ // extending load. We can do this even if this is already a masked
+ // {z,}extload.
+ if (N->getOperand(0).getOpcode() == ISD::MLOAD &&
+ N->getOpcode() == AArch64ISD::UUNPKLO) {
+ MaskedLoadSDNode *MLD = cast<MaskedLoadSDNode>(N->getOperand(0));
+ SDValue Mask = MLD->getMask();
+ SDLoc DL(N);
+
+ if (MLD->isUnindexed() && MLD->getExtensionType() != ISD::SEXTLOAD &&
+ SDValue(MLD, 0).hasOneUse() && Mask->getOpcode() == AArch64ISD::PTRUE &&
+ (MLD->getPassThru()->isUndef() ||
+ isZerosVector(MLD->getPassThru().getNode()))) {
+ unsigned MinSVESize = Subtarget->getMinSVEVectorSizeInBits();
+ unsigned PgPattern = Mask->getConstantOperandVal(0);
+ EVT VT = N->getValueType(0);
+
+ // Ensure we can double the size of the predicate pattern
+ unsigned NumElts = getNumElementsFromSVEPredPattern(PgPattern);
+ if (NumElts &&
+ NumElts * VT.getVectorElementType().getSizeInBits() <= MinSVESize) {
+ Mask =
+ getPTrue(DAG, DL, VT.changeVectorElementType(MVT::i1), PgPattern);
+ SDValue PassThru = DAG.getConstant(0, DL, VT);
+ SDValue NewLoad = DAG.getMaskedLoad(
+ VT, DL, MLD->getChain(), MLD->getBasePtr(), MLD->getOffset(), Mask,
+ PassThru, MLD->getMemoryVT(), MLD->getMemOperand(),
+ MLD->getAddressingMode(), ISD::ZEXTLOAD);
+
+ DAG.ReplaceAllUsesOfValueWith(SDValue(MLD, 1), NewLoad.getValue(1));
+
+ return NewLoad;
+ }
+ }
+ }
+
return SDValue();
}
@@ -17484,6 +17557,50 @@ static SDValue performSTORECombine(SDNode *N,
return SDValue();
}
+static SDValue performMSTORECombine(SDNode *N,
+ TargetLowering::DAGCombinerInfo &DCI,
+ SelectionDAG &DAG,
+ const AArch64Subtarget *Subtarget) {
+ MaskedStoreSDNode *MST = cast<MaskedStoreSDNode>(N);
+ SDValue Value = MST->getValue();
+ SDValue Mask = MST->getMask();
+ SDLoc DL(N);
+
+ // If this is a UZP1 followed by a masked store, fold this into a masked
+ // truncating store. We can do this even if this is already a masked
+ // truncstore.
+ if (Value.getOpcode() == AArch64ISD::UZP1 && Value->hasOneUse() &&
+ MST->isUnindexed() && Mask->getOpcode() == AArch64ISD::PTRUE &&
+ Value.getValueType().isInteger()) {
+ Value = Value.getOperand(0);
+ if (Value.getOpcode() == ISD::BITCAST) {
+ EVT HalfVT =
+ Value.getValueType().getHalfNumVectorElementsVT(*DAG.getContext());
+ EVT InVT = Value.getOperand(0).getValueType();
+
+ if (HalfVT.widenIntegerVectorElementType(*DAG.getContext()) == InVT) {
+ unsigned MinSVESize = Subtarget->getMinSVEVectorSizeInBits();
+ unsigned PgPattern = Mask->getConstantOperandVal(0);
+
+ // Ensure we can double the size of the predicate pattern
+ unsigned NumElts = getNumElementsFromSVEPredPattern(PgPattern);
+ if (NumElts && NumElts * InVT.getVectorElementType().getSizeInBits() <=
+ MinSVESize) {
+ Mask = getPTrue(DAG, DL, InVT.changeVectorElementType(MVT::i1),
+ PgPattern);
+ return DAG.getMaskedStore(MST->getChain(), DL, Value.getOperand(0),
+ MST->getBasePtr(), MST->getOffset(), Mask,
+ MST->getMemoryVT(), MST->getMemOperand(),
+ MST->getAddressingMode(),
+ /*IsTruncating=*/true);
+ }
+ }
+ }
+ }
+
+ return SDValue();
+}
+
/// \return true if part of the index was folded into the Base.
static bool foldIndexIntoBase(SDValue &BasePtr, SDValue &Index, SDValue Scale,
SDLoc DL, SelectionDAG &DAG) {
@@ -18191,7 +18308,9 @@ static SDValue tryToWidenSetCCOperands(SDNode *Op, SelectionDAG &DAG) {
Op0ExtV, Op1ExtV, Op->getOperand(2));
}
-static SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG) {
+static SDValue performSETCCCombine(SDNode *N,
+ TargetLowering::DAGCombinerInfo &DCI,
+ SelectionDAG &DAG) {
assert(N->getOpcode() == ISD::SETCC && "Unexpected opcode!");
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
@@ -18234,6 +18353,21 @@ static SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG) {
}
}
+ // setcc (iN (bitcast (vNi1 X))), 0, (eq|ne)
+ // ==> setcc (iN (zext (i1 (vecreduce_or (vNi1 X))))), 0, (eq|ne)
+ if (DCI.isBeforeLegalize() && VT.isScalarInteger() &&
+ (Cond == ISD::SETEQ || Cond == ISD::SETNE) && isNullConstant(RHS) &&
+ LHS->getOpcode() == ISD::BITCAST) {
+ EVT ToVT = LHS->getValueType(0);
+ EVT FromVT = LHS->getOperand(0).getValueType();
+ if (FromVT.isFixedLengthVector() &&
+ FromVT.getVectorElementType() == MVT::i1) {
+ LHS = DAG.getNode(ISD::VECREDUCE_OR, DL, MVT::i1, LHS->getOperand(0));
+ LHS = DAG.getNode(ISD::ZERO_EXTEND, DL, ToVT, LHS);
+ return DAG.getSetCC(DL, VT, LHS, RHS, Cond);
+ }
+ }
+
return SDValue();
}
@@ -19376,13 +19510,15 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
case ISD::VSELECT:
return performVSelectCombine(N, DCI.DAG);
case ISD::SETCC:
- return performSETCCCombine(N, DAG);
+ return performSETCCCombine(N, DCI, DAG);
case ISD::LOAD:
if (performTBISimplification(N->getOperand(1), DCI, DAG))
return SDValue(N, 0);
break;
case ISD::STORE:
return performSTORECombine(N, DCI, DAG, Subtarget);
+ case ISD::MSTORE:
+ return performMSTORECombine(N, DCI, DAG, Subtarget);
case ISD::MGATHER:
case ISD::MSCATTER:
return performMaskedGatherScatterCombine(N, DCI, DAG);
@@ -19407,7 +19543,7 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
return performSpliceCombine(N, DAG);
case AArch64ISD::UUNPKLO:
case AArch64ISD::UUNPKHI:
- return performUnpackCombine(N, DAG);
+ return performUnpackCombine(N, DAG, Subtarget);
case AArch64ISD::UZP1:
return performUzpCombine(N, DAG);
case AArch64ISD::SETCC_MERGE_ZERO:
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index a7b7e5270888..926e7305bab9 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -4052,6 +4052,12 @@ def : InstAlias<"fmov $Rd, #0.0", (FMOVWHr FPR16:$Rd, WZR), 0>,
def : InstAlias<"fmov $Rd, #0.0", (FMOVWSr FPR32:$Rd, WZR), 0>;
def : InstAlias<"fmov $Rd, #0.0", (FMOVXDr FPR64:$Rd, XZR), 0>;
+// Pattern for FP16 immediates
+let Predicates = [HasFullFP16] in {
+ def : Pat<(f16 fpimm:$in),
+ (FMOVWHr (MOVi32imm (bitcast_fpimm_to_i32 f16:$in)))>;
+}
+
//===----------------------------------------------------------------------===//
// Floating point conversion instruction.
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
index 4032c4667bc7..9b040860cc3c 100644
--- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
@@ -287,6 +287,8 @@ def AArch64fadda_p_node : SDNode<"AArch64ISD::FADDA_PRED", SDT_AArch64ReduceWith
def AArch64fadda_p : PatFrags<(ops node:$op1, node:$op2, node:$op3),
[(AArch64fadda_p_node node:$op1, node:$op2, node:$op3),
(AArch64fadda_p_node (SVEAllActive), node:$op2,
+ (vselect node:$op1, node:$op3, (splat_vector (f16 fpimm_minus0)))),
+ (AArch64fadda_p_node (SVEAllActive), node:$op2,
(vselect node:$op1, node:$op3, (splat_vector (f32 fpimm_minus0)))),
(AArch64fadda_p_node (SVEAllActive), node:$op2,
(vselect node:$op1, node:$op3, (splat_vector (f64 fpimm_minus0))))]>;
@@ -337,6 +339,22 @@ def AArch64bic : PatFrags<(ops node:$op1, node:$op2),
def AArch64subr : PatFrag<(ops node:$op1, node:$op2),
(sub node:$op2, node:$op1)>;
+def AArch64add_m1 : PatFrags<(ops node:$pred, node:$op1, node:$op2),
+ [(int_aarch64_sve_add node:$pred, node:$op1, node:$op2),
+ (add node:$op1, (vselect node:$pred, node:$op2, (SVEDup0)))]>;
+def AArch64sub_m1 : PatFrags<(ops node:$pred, node:$op1, node:$op2),
+ [(int_aarch64_sve_sub node:$pred, node:$op1, node:$op2),
+ (sub node:$op1, (vselect node:$pred, node:$op2, (SVEDup0)))]>;
+def AArch64mla_m1 : PatFrags<(ops node:$pred, node:$op1, node:$op2, node:$op3),
+ [(int_aarch64_sve_mla node:$pred, node:$op1, node:$op2, node:$op3),
+ (add node:$op1, (AArch64mul_p_oneuse node:$pred, node:$op2, node:$op3)),
+ // add(a, select(mask, mul(b, c), splat(0))) -> mla(a, mask, b, c)
+ (add node:$op1, (vselect node:$pred, (AArch64mul_p_oneuse (SVEAllActive), node:$op2, node:$op3), (SVEDup0)))]>;
+def AArch64mls_m1 : PatFrags<(ops node:$pred, node:$op1, node:$op2, node:$op3),
+ [(int_aarch64_sve_mls node:$pred, node:$op1, node:$op2, node:$op3),
+ (sub node:$op1, (AArch64mul_p_oneuse node:$pred, node:$op2, node:$op3)),
+ // sub(a, select(mask, mul(b, c), splat(0))) -> mls(a, mask, b, c)
+ (sub node:$op1, (vselect node:$pred, (AArch64mul_p_oneuse (SVEAllActive), node:$op2, node:$op3), (SVEDup0)))]>;
let Predicates = [HasSVE] in {
defm RDFFR_PPz : sve_int_rdffr_pred<0b0, "rdffr", int_aarch64_sve_rdffr_z>;
@@ -359,8 +377,8 @@ let Predicates = [HasSVEorSME] in {
defm EOR_ZZZ : sve_int_bin_cons_log<0b10, "eor", xor>;
defm BIC_ZZZ : sve_int_bin_cons_log<0b11, "bic", AArch64bic>;
- defm ADD_ZPmZ : sve_int_bin_pred_arit_0<0b000, "add", "ADD_ZPZZ", int_aarch64_sve_add, DestructiveBinaryComm>;
- defm SUB_ZPmZ : sve_int_bin_pred_arit_0<0b001, "sub", "SUB_ZPZZ", int_aarch64_sve_sub, DestructiveBinaryCommWithRev, "SUBR_ZPmZ">;
+ defm ADD_ZPmZ : sve_int_bin_pred_arit_0<0b000, "add", "ADD_ZPZZ", AArch64add_m1, DestructiveBinaryComm>;
+ defm SUB_ZPmZ : sve_int_bin_pred_arit_0<0b001, "sub", "SUB_ZPZZ", AArch64sub_m1, DestructiveBinaryCommWithRev, "SUBR_ZPmZ">;
defm SUBR_ZPmZ : sve_int_bin_pred_arit_0<0b011, "subr", "SUBR_ZPZZ", int_aarch64_sve_subr, DestructiveBinaryCommWithRev, "SUB_ZPmZ", /*isReverseInstr*/ 1>;
defm ORR_ZPmZ : sve_int_bin_pred_log<0b000, "orr", "ORR_ZPZZ", int_aarch64_sve_orr, DestructiveBinaryComm>;
@@ -391,8 +409,8 @@ let Predicates = [HasSVEorSME] in {
defm MAD_ZPmZZ : sve_int_mladdsub_vvv_pred<0b0, "mad", int_aarch64_sve_mad>;
defm MSB_ZPmZZ : sve_int_mladdsub_vvv_pred<0b1, "msb", int_aarch64_sve_msb>;
- defm MLA_ZPmZZ : sve_int_mlas_vvv_pred<0b0, "mla", int_aarch64_sve_mla, add, AArch64mul_p_oneuse>;
- defm MLS_ZPmZZ : sve_int_mlas_vvv_pred<0b1, "mls", int_aarch64_sve_mls, sub, AArch64mul_p_oneuse>;
+ defm MLA_ZPmZZ : sve_int_mlas_vvv_pred<0b0, "mla", AArch64mla_m1>;
+ defm MLS_ZPmZZ : sve_int_mlas_vvv_pred<0b1, "mls", AArch64mls_m1>;
// SVE predicated integer reductions.
defm SADDV_VPZ : sve_int_reduce_0_saddv<0b000, "saddv", AArch64saddv_p>;
@@ -712,6 +730,12 @@ let Predicates = [HasSVEorSME] in {
(DUP_ZI_D $a, $b)>;
// Duplicate immediate FP into all vector elements.
+ def : Pat<(nxv2f16 (splat_vector (f16 fpimm:$val))),
+ (DUP_ZR_H (MOVi32imm (bitcast_fpimm_to_i32 f16:$val)))>;
+ def : Pat<(nxv4f16 (splat_vector (f16 fpimm:$val))),
+ (DUP_ZR_H (MOVi32imm (bitcast_fpimm_to_i32 f16:$val)))>;
+ def : Pat<(nxv8f16 (splat_vector (f16 fpimm:$val))),
+ (DUP_ZR_H (MOVi32imm (bitcast_fpimm_to_i32 f16:$val)))>;
def : Pat<(nxv2f32 (splat_vector (f32 fpimm:$val))),
(DUP_ZR_S (MOVi32imm (bitcast_fpimm_to_i32 f32:$val)))>;
def : Pat<(nxv4f32 (splat_vector (f32 fpimm:$val))),
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index 1b65589416c3..2f20232e452d 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -350,6 +350,14 @@ DecodeStatus AArch64Disassembler::getInstruction(MCInst &MI, uint64_t &Size,
return MCDisassembler::Fail;
}
+uint64_t AArch64Disassembler::suggestBytesToSkip(ArrayRef<uint8_t> Bytes,
+ uint64_t Address) const {
+ // AArch64 instructions are always 4 bytes wide, so there's no point
+ // in skipping any smaller number of bytes if an instruction can't
+ // be decoded.
+ return 4;
+}
+
static MCSymbolizer *
createAArch64ExternalSymbolizer(const Triple &TT, LLVMOpInfoCallback GetOpInfo,
LLVMSymbolLookupCallback SymbolLookUp,
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h
index 6761d449a7f4..b9f78546b89b 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h
@@ -30,6 +30,9 @@ public:
MCDisassembler::DecodeStatus
getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes,
uint64_t Address, raw_ostream &CStream) const override;
+
+ uint64_t suggestBytesToSkip(ArrayRef<uint8_t> Bytes,
+ uint64_t Address) const override;
};
} // end namespace llvm
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64O0PreLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64O0PreLegalizerCombiner.cpp
index 04bc91318da8..d655caa80ba8 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64O0PreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64O0PreLegalizerCombiner.cpp
@@ -66,8 +66,8 @@ public:
report_fatal_error("Invalid rule identifier");
}
- virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
- MachineIRBuilder &B) const override;
+ bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
+ MachineIRBuilder &B) const override;
};
bool AArch64O0PreLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
index ba206bac68d1..dfb531cda7e9 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
@@ -355,8 +355,8 @@ public:
report_fatal_error("Invalid rule identifier");
}
- virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
- MachineIRBuilder &B) const override;
+ bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
+ MachineIRBuilder &B) const override;
};
bool AArch64PostLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp
index d7959a82c484..eab1de94e9c8 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp
@@ -997,8 +997,8 @@ public:
report_fatal_error("Invalid rule identifier");
}
- virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
- MachineIRBuilder &B) const override;
+ bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
+ MachineIRBuilder &B) const override;
};
bool AArch64PostLegalizerLoweringInfo::combine(GISelChangeObserver &Observer,
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp
index 275949c5ee64..50bae68b4d33 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp
@@ -370,8 +370,8 @@ public:
report_fatal_error("Invalid rule identifier");
}
- virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
- MachineIRBuilder &B) const override;
+ bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
+ MachineIRBuilder &B) const override;
};
bool AArch64PreLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
diff --git a/llvm/lib/Target/AArch64/SVEInstrFormats.td b/llvm/lib/Target/AArch64/SVEInstrFormats.td
index 7cdd4c4af95e..36daecf634d7 100644
--- a/llvm/lib/Target/AArch64/SVEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SVEInstrFormats.td
@@ -2958,8 +2958,7 @@ class sve_int_mlas_vvv_pred<bits<2> sz8_64, bits<1> opc, string asm,
let ElementSize = zprty.ElementSize;
}
-multiclass sve_int_mlas_vvv_pred<bits<1> opc, string asm, SDPatternOperator op,
- SDPatternOperator outerop, SDPatternOperator mulop> {
+multiclass sve_int_mlas_vvv_pred<bits<1> opc, string asm, SDPatternOperator op> {
def _B : sve_int_mlas_vvv_pred<0b00, opc, asm, ZPR8>;
def _H : sve_int_mlas_vvv_pred<0b01, opc, asm, ZPR16>;
def _S : sve_int_mlas_vvv_pred<0b10, opc, asm, ZPR32>;
@@ -2969,15 +2968,6 @@ multiclass sve_int_mlas_vvv_pred<bits<1> opc, string asm, SDPatternOperator op,
def : SVE_4_Op_Pat<nxv8i16, op, nxv8i1, nxv8i16, nxv8i16, nxv8i16, !cast<Instruction>(NAME # _H)>;
def : SVE_4_Op_Pat<nxv4i32, op, nxv4i1, nxv4i32, nxv4i32, nxv4i32, !cast<Instruction>(NAME # _S)>;
def : SVE_4_Op_Pat<nxv2i64, op, nxv2i1, nxv2i64, nxv2i64, nxv2i64, !cast<Instruction>(NAME # _D)>;
-
- def : Pat<(outerop nxv16i8:$Op1, (mulop nxv16i1:$pred, nxv16i8:$Op2, nxv16i8:$Op3)),
- (!cast<Instruction>(NAME # _B) $pred, $Op1, $Op2, $Op3)>;
- def : Pat<(outerop nxv8i16:$Op1, (mulop nxv8i1:$pred, nxv8i16:$Op2, nxv8i16:$Op3)),
- (!cast<Instruction>(NAME # _H) $pred, $Op1, $Op2, $Op3)>;
- def : Pat<(outerop nxv4i32:$Op1, (mulop nxv4i1:$pred, nxv4i32:$Op2, nxv4i32:$Op3)),
- (!cast<Instruction>(NAME # _S) $pred, $Op1, $Op2, $Op3)>;
- def : Pat<(outerop nxv2i64:$Op1, (mulop nxv2i1:$pred, nxv2i64:$Op2, nxv2i64:$Op3)),
- (!cast<Instruction>(NAME # _D) $pred, $Op1, $Op2, $Op3)>;
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp b/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp
index b4a8766d682e..56a9a30bc59a 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp
@@ -29,6 +29,8 @@
#include "AMDGPU.h"
#include "Utils/AMDGPUBaseInfo.h"
#include "Utils/AMDGPUMemoryUtils.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/IR/Constants.h"
@@ -43,6 +45,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/OptimizedStructLayout.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
+#include <tuple>
#include <vector>
#define DEBUG_TYPE "amdgpu-lower-module-lds"
@@ -97,6 +100,9 @@ class AMDGPULowerModuleLDS : public ModulePass {
static void
removeFromUsedLists(Module &M,
const std::vector<GlobalVariable *> &LocalVars) {
+ // The verifier rejects used lists containing an inttoptr of a constant
+ // so remove the variables from these lists before replaceAllUsesWith
+
SmallPtrSet<Constant *, 32> LocalVarsSet;
for (GlobalVariable *LocalVar : LocalVars)
if (Constant *C = dyn_cast<Constant>(LocalVar->stripPointerCasts()))
@@ -146,12 +152,59 @@ public:
}
bool runOnModule(Module &M) override {
+ LLVMContext &Ctx = M.getContext();
CallGraph CG = CallGraph(M);
bool Changed = superAlignLDSGlobals(M);
+
+ // Move variables used by functions into amdgcn.module.lds
std::vector<GlobalVariable *> ModuleScopeVariables =
AMDGPU::findVariablesToLower(M, nullptr);
- Changed |= processUsedLDS(CG, M, ModuleScopeVariables);
+ if (!ModuleScopeVariables.empty()) {
+ std::string VarName = "llvm.amdgcn.module.lds";
+
+ GlobalVariable *SGV;
+ DenseMap<GlobalVariable *, Constant *> LDSVarsToConstantGEP;
+ std::tie(SGV, LDSVarsToConstantGEP) =
+ createLDSVariableReplacement(M, VarName, ModuleScopeVariables);
+
+ appendToCompilerUsed(
+ M, {static_cast<GlobalValue *>(
+ ConstantExpr::getPointerBitCastOrAddrSpaceCast(
+ cast<Constant>(SGV), Type::getInt8PtrTy(Ctx)))});
+
+ removeFromUsedLists(M, ModuleScopeVariables);
+ replaceLDSVariablesWithStruct(M, ModuleScopeVariables, SGV,
+ LDSVarsToConstantGEP,
+ [](Use &) { return true; });
+
+ // This ensures the variable is allocated when called functions access it.
+ // It also lets other passes, specifically PromoteAlloca, accurately
+ // calculate how much LDS will be used by the kernel after lowering.
+ IRBuilder<> Builder(Ctx);
+ for (Function &Func : M.functions()) {
+ if (!Func.isDeclaration() && AMDGPU::isKernelCC(&Func)) {
+ const CallGraphNode *N = CG[&Func];
+ const bool CalleesRequireModuleLDS = N->size() > 0;
+
+ if (CalleesRequireModuleLDS) {
+ // If a function this kernel might call requires module LDS,
+ // annotate the kernel to let later passes know it will allocate
+ // this structure, even if not apparent from the IR.
+ markUsedByKernel(Builder, &Func, SGV);
+ } else {
+ // However if we are certain this kernel cannot call a function that
+ // requires module LDS, annotate the kernel so the backend can elide
+ // the allocation without repeating callgraph walks.
+ Func.addFnAttr("amdgpu-elide-module-lds");
+ }
+ }
+ }
+
+ Changed = true;
+ }
+
+ // Move variables used by kernels into per-kernel instances
for (Function &F : M.functions()) {
if (F.isDeclaration())
continue;
@@ -159,9 +212,37 @@ public:
// Only lower compute kernels' LDS.
if (!AMDGPU::isKernel(F.getCallingConv()))
continue;
+
std::vector<GlobalVariable *> KernelUsedVariables =
AMDGPU::findVariablesToLower(M, &F);
- Changed |= processUsedLDS(CG, M, KernelUsedVariables, &F);
+
+ // Replace all constant uses with instructions if they belong to the
+ // current kernel. Unnecessary, removing will cause test churn.
+ for (size_t I = 0; I < KernelUsedVariables.size(); I++) {
+ GlobalVariable *GV = KernelUsedVariables[I];
+ for (User *U : make_early_inc_range(GV->users())) {
+ if (ConstantExpr *C = dyn_cast<ConstantExpr>(U))
+ AMDGPU::replaceConstantUsesInFunction(C, &F);
+ }
+ GV->removeDeadConstantUsers();
+ }
+
+ if (!KernelUsedVariables.empty()) {
+ std::string VarName =
+ (Twine("llvm.amdgcn.kernel.") + F.getName() + ".lds").str();
+ GlobalVariable *SGV;
+ DenseMap<GlobalVariable *, Constant *> LDSVarsToConstantGEP;
+ std::tie(SGV, LDSVarsToConstantGEP) =
+ createLDSVariableReplacement(M, VarName, KernelUsedVariables);
+
+ removeFromUsedLists(M, KernelUsedVariables);
+ replaceLDSVariablesWithStruct(
+ M, KernelUsedVariables, SGV, LDSVarsToConstantGEP, [&F](Use &U) {
+ Instruction *I = dyn_cast<Instruction>(U.getUser());
+ return I && I->getFunction() == &F;
+ });
+ Changed = true;
+ }
}
return Changed;
@@ -212,16 +293,18 @@ private:
return Changed;
}
- bool processUsedLDS(CallGraph const &CG, Module &M,
- std::vector<GlobalVariable *> const &LDSVarsToTransform,
- Function *F = nullptr) {
+ std::tuple<GlobalVariable *, DenseMap<GlobalVariable *, Constant *>>
+ createLDSVariableReplacement(
+ Module &M, std::string VarName,
+ std::vector<GlobalVariable *> const &LDSVarsToTransform) {
+ // Create a struct instance containing LDSVarsToTransform and map from those
+ // variables to ConstantExprGEP
+ // Variables may be introduced to meet alignment requirements. No aliasing
+ // metadata is useful for these as they have no uses. Erased before return.
+
LLVMContext &Ctx = M.getContext();
const DataLayout &DL = M.getDataLayout();
-
- if (LDSVarsToTransform.empty()) {
- // No variables to rewrite, no changes made.
- return false;
- }
+ assert(!LDSVarsToTransform.empty());
SmallVector<OptimizedStructLayoutField, 8> LayoutFields;
LayoutFields.reserve(LDSVarsToTransform.size());
@@ -234,9 +317,10 @@ private:
performOptimizedStructLayout(LayoutFields);
std::vector<GlobalVariable *> LocalVars;
+ BitVector IsPaddingField;
LocalVars.reserve(LDSVarsToTransform.size()); // will be at least this large
+ IsPaddingField.reserve(LDSVarsToTransform.size());
{
- // This usually won't need to insert any padding, perhaps avoid the alloc
uint64_t CurrentOffset = 0;
for (size_t I = 0; I < LayoutFields.size(); I++) {
GlobalVariable *FGV = static_cast<GlobalVariable *>(
@@ -256,10 +340,12 @@ private:
M, ATy, false, GlobalValue::InternalLinkage, UndefValue::get(ATy),
"", nullptr, GlobalValue::NotThreadLocal, AMDGPUAS::LOCAL_ADDRESS,
false));
+ IsPaddingField.push_back(true);
CurrentOffset += Padding;
}
LocalVars.push_back(FGV);
+ IsPaddingField.push_back(false);
CurrentOffset += LayoutFields[I].Size;
}
}
@@ -270,9 +356,6 @@ private:
LocalVars.cbegin(), LocalVars.cend(), std::back_inserter(LocalVarTypes),
[](const GlobalVariable *V) -> Type * { return V->getValueType(); });
- std::string VarName(
- F ? (Twine("llvm.amdgcn.kernel.") + F->getName() + ".lds").str()
- : "llvm.amdgcn.module.lds");
StructType *LDSTy = StructType::create(Ctx, LocalVarTypes, VarName + ".t");
Align StructAlign =
@@ -283,62 +366,65 @@ private:
VarName, nullptr, GlobalValue::NotThreadLocal, AMDGPUAS::LOCAL_ADDRESS,
false);
SGV->setAlignment(StructAlign);
- if (!F) {
- appendToCompilerUsed(
- M, {static_cast<GlobalValue *>(
- ConstantExpr::getPointerBitCastOrAddrSpaceCast(
- cast<Constant>(SGV), Type::getInt8PtrTy(Ctx)))});
+
+ DenseMap<GlobalVariable *, Constant *> Map;
+ Type *I32 = Type::getInt32Ty(Ctx);
+ for (size_t I = 0; I < LocalVars.size(); I++) {
+ GlobalVariable *GV = LocalVars[I];
+ Constant *GEPIdx[] = {ConstantInt::get(I32, 0), ConstantInt::get(I32, I)};
+ Constant *GEP = ConstantExpr::getGetElementPtr(LDSTy, SGV, GEPIdx, true);
+ if (IsPaddingField[I]) {
+ assert(GV->use_empty());
+ GV->eraseFromParent();
+ } else {
+ Map[GV] = GEP;
+ }
}
+ assert(Map.size() == LDSVarsToTransform.size());
+ return {SGV, std::move(Map)};
+ }
- // The verifier rejects used lists containing an inttoptr of a constant
- // so remove the variables from these lists before replaceAllUsesWith
- removeFromUsedLists(M, LocalVars);
+ template <typename PredicateTy>
+ void replaceLDSVariablesWithStruct(
+ Module &M, std::vector<GlobalVariable *> const &LDSVarsToTransform,
+ GlobalVariable *SGV,
+ DenseMap<GlobalVariable *, Constant *> &LDSVarsToConstantGEP,
+ PredicateTy Predicate) {
+ LLVMContext &Ctx = M.getContext();
+ const DataLayout &DL = M.getDataLayout();
// Create alias.scope and their lists. Each field in the new structure
// does not alias with all other fields.
SmallVector<MDNode *> AliasScopes;
SmallVector<Metadata *> NoAliasList;
- if (LocalVars.size() > 1) {
+ const size_t NumberVars = LDSVarsToTransform.size();
+ if (NumberVars > 1) {
MDBuilder MDB(Ctx);
- AliasScopes.reserve(LocalVars.size());
+ AliasScopes.reserve(NumberVars);
MDNode *Domain = MDB.createAnonymousAliasScopeDomain();
- for (size_t I = 0; I < LocalVars.size(); I++) {
+ for (size_t I = 0; I < NumberVars; I++) {
MDNode *Scope = MDB.createAnonymousAliasScope(Domain);
AliasScopes.push_back(Scope);
}
NoAliasList.append(&AliasScopes[1], AliasScopes.end());
}
- // Replace uses of ith variable with a constantexpr to the ith field of the
- // instance that will be allocated by AMDGPUMachineFunction
- Type *I32 = Type::getInt32Ty(Ctx);
- for (size_t I = 0; I < LocalVars.size(); I++) {
- GlobalVariable *GV = LocalVars[I];
- Constant *GEPIdx[] = {ConstantInt::get(I32, 0), ConstantInt::get(I32, I)};
- Constant *GEP = ConstantExpr::getGetElementPtr(LDSTy, SGV, GEPIdx);
- if (F) {
- // Replace all constant uses with instructions if they belong to the
- // current kernel.
- for (User *U : make_early_inc_range(GV->users())) {
- if (ConstantExpr *C = dyn_cast<ConstantExpr>(U))
- AMDGPU::replaceConstantUsesInFunction(C, F);
- }
-
- GV->removeDeadConstantUsers();
+ // Replace uses of ith variable with a constantexpr to the corresponding
+ // field of the instance that will be allocated by AMDGPUMachineFunction
+ for (size_t I = 0; I < NumberVars; I++) {
+ GlobalVariable *GV = LDSVarsToTransform[I];
+ Constant *GEP = LDSVarsToConstantGEP[GV];
- GV->replaceUsesWithIf(GEP, [F](Use &U) {
- Instruction *I = dyn_cast<Instruction>(U.getUser());
- return I && I->getFunction() == F;
- });
- } else {
- GV->replaceAllUsesWith(GEP);
- }
+ GV->replaceUsesWithIf(GEP, Predicate);
if (GV->use_empty()) {
GV->eraseFromParent();
}
- uint64_t Off = DL.getStructLayout(LDSTy)->getElementOffset(I);
- Align A = commonAlignment(StructAlign, Off);
+ APInt APOff(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
+ GEP->stripAndAccumulateInBoundsConstantOffsets(DL, APOff);
+ uint64_t Offset = APOff.getZExtValue();
+
+ Align A = commonAlignment(SGV->getAlign().valueOrOne(), Offset);
if (I)
NoAliasList[I - 1] = AliasScopes[I - 1];
@@ -349,32 +435,6 @@ private:
refineUsesAlignmentAndAA(GEP, A, DL, AliasScope, NoAlias);
}
-
- // This ensures the variable is allocated when called functions access it.
- // It also lets other passes, specifically PromoteAlloca, accurately
- // calculate how much LDS will be used by the kernel after lowering.
- if (!F) {
- IRBuilder<> Builder(Ctx);
- for (Function &Func : M.functions()) {
- if (!Func.isDeclaration() && AMDGPU::isKernelCC(&Func)) {
- const CallGraphNode *N = CG[&Func];
- const bool CalleesRequireModuleLDS = N->size() > 0;
-
- if (CalleesRequireModuleLDS) {
- // If a function this kernel might call requires module LDS,
- // annotate the kernel to let later passes know it will allocate
- // this structure, even if not apparent from the IR.
- markUsedByKernel(Builder, &Func, SGV);
- } else {
- // However if we are certain this kernel cannot call a function that
- // requires module LDS, annotate the kernel so the backend can elide
- // the allocation without repeating callgraph walks.
- Func.addFnAttr("amdgpu-elide-module-lds");
- }
- }
- }
- }
- return true;
}
void refineUsesAlignmentAndAA(Value *Ptr, Align A, const DataLayout &DL,
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMIRFormatter.h b/llvm/lib/Target/AMDGPU/AMDGPUMIRFormatter.h
index 753f7edc9385..98b5031071cf 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMIRFormatter.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMIRFormatter.h
@@ -29,7 +29,7 @@ public:
virtual ~AMDGPUMIRFormatter() = default;
/// Implement target specific parsing of target custom pseudo source value.
- virtual bool
+ bool
parseCustomPseudoSourceValue(StringRef Src, MachineFunction &MF,
PerFunctionMIParsingState &PFS,
const PseudoSourceValue *&PSV,
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUPreLegalizerCombiner.cpp b/llvm/lib/Target/AMDGPU/AMDGPUPreLegalizerCombiner.cpp
index bfe2e9b66ed4..98e9907068f2 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUPreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUPreLegalizerCombiner.cpp
@@ -191,8 +191,8 @@ public:
report_fatal_error("Invalid rule identifier");
}
- virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
- MachineIRBuilder &B) const override;
+ bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
+ MachineIRBuilder &B) const override;
};
bool AMDGPUPreLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
diff --git a/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp b/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp
index 04da14cc4916..859deae86f35 100644
--- a/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp
@@ -9,6 +9,18 @@
/// \file
/// This contains a MachineSchedStrategy implementation for maximizing wave
/// occupancy on GCN hardware.
+///
+/// This pass will apply multiple scheduling stages to the same function.
+/// Regions are first recorded in GCNScheduleDAGMILive::schedule. The actual
+/// entry point for the scheduling of those regions is
+/// GCNScheduleDAGMILive::runSchedStages.
+
+/// Generally, the reason for having multiple scheduling stages is to account
+/// for the kernel-wide effect of register usage on occupancy. Usually, only a
+/// few scheduling regions will have register pressure high enough to limit
+/// occupancy for the kernel, so constraints can be relaxed to improve ILP in
+/// other regions.
+///
//===----------------------------------------------------------------------===//
#include "GCNSchedStrategy.h"
@@ -20,9 +32,9 @@
using namespace llvm;
GCNMaxOccupancySchedStrategy::GCNMaxOccupancySchedStrategy(
- const MachineSchedContext *C) :
- GenericScheduler(C), TargetOccupancy(0), HasClusteredNodes(false),
- HasExcessPressure(false), MF(nullptr) { }
+ const MachineSchedContext *C)
+ : GenericScheduler(C), TargetOccupancy(0), MF(nullptr),
+ HasClusteredNodes(false), HasExcessPressure(false) {}
void GCNMaxOccupancySchedStrategy::initialize(ScheduleDAGMI *DAG) {
GenericScheduler::initialize(DAG);
@@ -302,210 +314,30 @@ SUnit *GCNMaxOccupancySchedStrategy::pickNode(bool &IsTopNode) {
return SU;
}
-GCNScheduleDAGMILive::GCNScheduleDAGMILive(MachineSchedContext *C,
- std::unique_ptr<MachineSchedStrategy> S) :
- ScheduleDAGMILive(C, std::move(S)),
- ST(MF.getSubtarget<GCNSubtarget>()),
- MFI(*MF.getInfo<SIMachineFunctionInfo>()),
- StartingOccupancy(MFI.getOccupancy()),
- MinOccupancy(StartingOccupancy), Stage(Collect), RegionIdx(0) {
+GCNScheduleDAGMILive::GCNScheduleDAGMILive(
+ MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S)
+ : ScheduleDAGMILive(C, std::move(S)), ST(MF.getSubtarget<GCNSubtarget>()),
+ MFI(*MF.getInfo<SIMachineFunctionInfo>()),
+ StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy) {
LLVM_DEBUG(dbgs() << "Starting occupancy is " << StartingOccupancy << ".\n");
}
void GCNScheduleDAGMILive::schedule() {
- if (Stage == Collect) {
- // Just record regions at the first pass.
- Regions.push_back(std::make_pair(RegionBegin, RegionEnd));
- return;
- }
-
- std::vector<MachineInstr*> Unsched;
- Unsched.reserve(NumRegionInstrs);
- for (auto &I : *this) {
- Unsched.push_back(&I);
- }
-
- GCNRegPressure PressureBefore;
- if (LIS) {
- PressureBefore = Pressure[RegionIdx];
-
- LLVM_DEBUG(dbgs() << "Pressure before scheduling:\nRegion live-ins:";
- GCNRPTracker::printLiveRegs(dbgs(), LiveIns[RegionIdx], MRI);
- dbgs() << "Region live-in pressure: ";
- llvm::getRegPressure(MRI, LiveIns[RegionIdx]).print(dbgs());
- dbgs() << "Region register pressure: ";
- PressureBefore.print(dbgs()));
- }
-
- GCNMaxOccupancySchedStrategy &S = (GCNMaxOccupancySchedStrategy&)*SchedImpl;
- // Set HasClusteredNodes to true for late stages where we have already
- // collected it. That way pickNode() will not scan SDep's when not needed.
- S.HasClusteredNodes = Stage > InitialSchedule;
- S.HasExcessPressure = false;
- ScheduleDAGMILive::schedule();
- Regions[RegionIdx] = std::make_pair(RegionBegin, RegionEnd);
- RescheduleRegions[RegionIdx] = false;
- if (Stage == InitialSchedule && S.HasClusteredNodes)
- RegionsWithClusters[RegionIdx] = true;
- if (S.HasExcessPressure)
- RegionsWithHighRP[RegionIdx] = true;
-
- if (!LIS)
- return;
-
- // Check the results of scheduling.
- auto PressureAfter = getRealRegPressure();
-
- LLVM_DEBUG(dbgs() << "Pressure after scheduling: ";
- PressureAfter.print(dbgs()));
-
- if (PressureAfter.getSGPRNum() <= S.SGPRCriticalLimit &&
- PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) <= S.VGPRCriticalLimit) {
- Pressure[RegionIdx] = PressureAfter;
- RegionsWithMinOcc[RegionIdx] =
- PressureAfter.getOccupancy(ST) == MinOccupancy;
-
- LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n");
- return;
- }
-
- unsigned WavesAfter =
- std::min(S.TargetOccupancy, PressureAfter.getOccupancy(ST));
- unsigned WavesBefore =
- std::min(S.TargetOccupancy, PressureBefore.getOccupancy(ST));
- LLVM_DEBUG(dbgs() << "Occupancy before scheduling: " << WavesBefore
- << ", after " << WavesAfter << ".\n");
-
- // We may not be able to keep the current target occupancy because of the just
- // scheduled region. We might still be able to revert scheduling if the
- // occupancy before was higher, or if the current schedule has register
- // pressure higher than the excess limits which could lead to more spilling.
- unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
-
- // Allow memory bound functions to drop to 4 waves if not limited by an
- // attribute.
- if (WavesAfter < WavesBefore && WavesAfter < MinOccupancy &&
- WavesAfter >= MFI.getMinAllowedOccupancy()) {
- LLVM_DEBUG(dbgs() << "Function is memory bound, allow occupancy drop up to "
- << MFI.getMinAllowedOccupancy() << " waves\n");
- NewOccupancy = WavesAfter;
- }
-
- if (NewOccupancy < MinOccupancy) {
- MinOccupancy = NewOccupancy;
- MFI.limitOccupancy(MinOccupancy);
- RegionsWithMinOcc.reset();
- LLVM_DEBUG(dbgs() << "Occupancy lowered for the function to "
- << MinOccupancy << ".\n");
- }
-
- unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF);
- unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF);
- if (PressureAfter.getVGPRNum(false) > MaxVGPRs ||
- PressureAfter.getAGPRNum() > MaxVGPRs ||
- PressureAfter.getSGPRNum() > MaxSGPRs) {
- RescheduleRegions[RegionIdx] = true;
- RegionsWithHighRP[RegionIdx] = true;
- }
-
- // If this condition is true, then either the occupancy before and after
- // scheduling is the same, or we are allowing the occupancy to drop because
- // the function is memory bound. Even if we are OK with the current occupancy,
- // we still need to verify that we will not introduce any extra chance of
- // spilling.
- if (WavesAfter >= MinOccupancy) {
- if (Stage == UnclusteredReschedule &&
- !PressureAfter.less(ST, PressureBefore)) {
- LLVM_DEBUG(dbgs() << "Unclustered reschedule did not help.\n");
- } else if (WavesAfter > MFI.getMinWavesPerEU() ||
- PressureAfter.less(ST, PressureBefore) ||
- !RescheduleRegions[RegionIdx]) {
- Pressure[RegionIdx] = PressureAfter;
- RegionsWithMinOcc[RegionIdx] =
- PressureAfter.getOccupancy(ST) == MinOccupancy;
- if (!RegionsWithClusters[RegionIdx] &&
- (Stage + 1) == UnclusteredReschedule)
- RescheduleRegions[RegionIdx] = false;
- return;
- } else {
- LLVM_DEBUG(dbgs() << "New pressure will result in more spilling.\n");
- }
- }
-
- RegionsWithMinOcc[RegionIdx] =
- PressureBefore.getOccupancy(ST) == MinOccupancy;
- LLVM_DEBUG(dbgs() << "Attempting to revert scheduling.\n");
- RescheduleRegions[RegionIdx] = RegionsWithClusters[RegionIdx] ||
- (Stage + 1) != UnclusteredReschedule;
- RegionEnd = RegionBegin;
- int SkippedDebugInstr = 0;
- for (MachineInstr *MI : Unsched) {
- if (MI->isDebugInstr()) {
- ++SkippedDebugInstr;
- continue;
- }
-
- if (MI->getIterator() != RegionEnd) {
- BB->remove(MI);
- BB->insert(RegionEnd, MI);
- if (!MI->isDebugInstr())
- LIS->handleMove(*MI, true);
- }
- // Reset read-undef flags and update them later.
- for (auto &Op : MI->operands())
- if (Op.isReg() && Op.isDef())
- Op.setIsUndef(false);
- RegisterOperands RegOpers;
- RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, false);
- if (!MI->isDebugInstr()) {
- if (ShouldTrackLaneMasks) {
- // Adjust liveness and add missing dead+read-undef flags.
- SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot();
- RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI);
- } else {
- // Adjust for missing dead-def flags.
- RegOpers.detectDeadDefs(*MI, *LIS);
- }
- }
- RegionEnd = MI->getIterator();
- ++RegionEnd;
- LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
- }
-
- // After reverting schedule, debug instrs will now be at the end of the block
- // and RegionEnd will point to the first debug instr. Increment RegionEnd
- // pass debug instrs to the actual end of the scheduling region.
- while (SkippedDebugInstr-- > 0)
- ++RegionEnd;
-
- // If Unsched.front() instruction is a debug instruction, this will actually
- // shrink the region since we moved all debug instructions to the end of the
- // block. Find the first instruction that is not a debug instruction.
- RegionBegin = Unsched.front()->getIterator();
- if (RegionBegin->isDebugInstr()) {
- for (MachineInstr *MI : Unsched) {
- if (MI->isDebugInstr())
- continue;
- RegionBegin = MI->getIterator();
- break;
- }
- }
-
- // Then move the debug instructions back into their correct place and set
- // RegionBegin and RegionEnd if needed.
- placeDebugValues();
-
- Regions[RegionIdx] = std::make_pair(RegionBegin, RegionEnd);
+ // Collect all scheduling regions. The actual scheduling is performed in
+ // GCNScheduleDAGMILive::finalizeSchedule.
+ Regions.push_back(std::make_pair(RegionBegin, RegionEnd));
}
-GCNRegPressure GCNScheduleDAGMILive::getRealRegPressure() const {
+GCNRegPressure
+GCNScheduleDAGMILive::getRealRegPressure(unsigned RegionIdx) const {
GCNDownwardRPTracker RPTracker(*LIS);
RPTracker.advance(begin(), end(), &LiveIns[RegionIdx]);
return RPTracker.moveMaxPressure();
}
-void GCNScheduleDAGMILive::computeBlockPressure(const MachineBasicBlock *MBB) {
+void GCNScheduleDAGMILive::computeBlockPressure(unsigned RegionIdx,
+ const MachineBasicBlock *MBB) {
GCNDownwardRPTracker RPTracker(*LIS);
// If the block has the only successor then live-ins of that successor are
@@ -542,7 +374,7 @@ void GCNScheduleDAGMILive::computeBlockPressure(const MachineBasicBlock *MBB) {
RPTracker.reset(*I, &LRS);
}
- for ( ; ; ) {
+ for (;;) {
I = RPTracker.getNext();
if (Regions[CurRegion].first == I || NonDbgMI == I) {
@@ -588,8 +420,9 @@ GCNScheduleDAGMILive::getBBLiveInMap() const {
}
void GCNScheduleDAGMILive::finalizeSchedule() {
- LLVM_DEBUG(dbgs() << "All regions recorded, starting actual scheduling.\n");
-
+ // Start actual scheduling here. This function is called by the base
+ // MachineScheduler after all regions have been recorded by
+ // GCNScheduleDAGMILive::schedule().
LiveIns.resize(Regions.size());
Pressure.resize(Regions.size());
RescheduleRegions.resize(Regions.size());
@@ -601,142 +434,470 @@ void GCNScheduleDAGMILive::finalizeSchedule() {
RegionsWithHighRP.reset();
RegionsWithMinOcc.reset();
+ runSchedStages();
+}
+
+void GCNScheduleDAGMILive::runSchedStages() {
+ LLVM_DEBUG(dbgs() << "All regions recorded, starting actual scheduling.\n");
+ InitialScheduleStage S0(GCNSchedStageID::InitialSchedule, *this);
+ UnclusteredRescheduleStage S1(GCNSchedStageID::UnclusteredReschedule, *this);
+ ClusteredLowOccStage S2(GCNSchedStageID::ClusteredLowOccupancyReschedule,
+ *this);
+ PreRARematStage S3(GCNSchedStageID::PreRARematerialize, *this);
+ GCNSchedStage *SchedStages[] = {&S0, &S1, &S2, &S3};
+
if (!Regions.empty())
BBLiveInMap = getBBLiveInMap();
- std::vector<std::unique_ptr<ScheduleDAGMutation>> SavedMutations;
+ for (auto *Stage : SchedStages) {
+ if (!Stage->initGCNSchedStage())
+ continue;
- do {
- Stage++;
- RegionIdx = 0;
- MachineBasicBlock *MBB = nullptr;
+ for (auto Region : Regions) {
+ RegionBegin = Region.first;
+ RegionEnd = Region.second;
+ // Setup for scheduling the region and check whether it should be skipped.
+ if (!Stage->initGCNRegion()) {
+ Stage->advanceRegion();
+ exitRegion();
+ continue;
+ }
- if (Stage > InitialSchedule) {
- if (!LIS)
- break;
+ ScheduleDAGMILive::schedule();
+ Stage->finalizeGCNRegion();
+ }
- // Retry function scheduling if we found resulting occupancy and it is
- // lower than used for first pass scheduling. This will give more freedom
- // to schedule low register pressure blocks.
- // Code is partially copied from MachineSchedulerBase::scheduleRegions().
+ Stage->finalizeGCNSchedStage();
+ }
+}
- if (Stage == UnclusteredReschedule) {
- if (RescheduleRegions.none())
- continue;
- LLVM_DEBUG(dbgs() <<
- "Retrying function scheduling without clustering.\n");
- }
+#ifndef NDEBUG
+raw_ostream &llvm::operator<<(raw_ostream &OS, const GCNSchedStageID &StageID) {
+ switch (StageID) {
+ case GCNSchedStageID::InitialSchedule:
+ OS << "Initial Schedule";
+ break;
+ case GCNSchedStageID::UnclusteredReschedule:
+ OS << "Unclustered Reschedule";
+ break;
+ case GCNSchedStageID::ClusteredLowOccupancyReschedule:
+ OS << "Clustered Low Occupancy Reschedule";
+ break;
+ case GCNSchedStageID::PreRARematerialize:
+ OS << "Pre-RA Rematerialize";
+ break;
+ }
+ return OS;
+}
+#endif
- if (Stage == ClusteredLowOccupancyReschedule) {
- if (StartingOccupancy <= MinOccupancy)
- break;
+GCNSchedStage::GCNSchedStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
+ : DAG(DAG), S(static_cast<GCNMaxOccupancySchedStrategy &>(*DAG.SchedImpl)),
+ MF(DAG.MF), MFI(DAG.MFI), ST(DAG.ST), StageID(StageID) {}
- LLVM_DEBUG(
- dbgs()
- << "Retrying function scheduling with lowest recorded occupancy "
- << MinOccupancy << ".\n");
- }
+bool GCNSchedStage::initGCNSchedStage() {
+ if (!DAG.LIS)
+ return false;
- if (Stage == PreRARematerialize) {
- if (RegionsWithMinOcc.none() || Regions.size() == 1)
- break;
-
- const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
- const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
- // Check maximum occupancy
- if (ST.computeOccupancy(MF.getFunction(), MFI.getLDSSize()) ==
- MinOccupancy)
- break;
-
- // FIXME: This pass will invalidate cached MBBLiveIns for regions
- // inbetween the defs and region we sinked the def to. Cached pressure
- // for regions where a def is sinked from will also be invalidated. Will
- // need to be fixed if there is another pass after this pass.
- static_assert(LastStage == PreRARematerialize,
- "Passes after PreRARematerialize are not supported");
-
- collectRematerializableInstructions();
- if (RematerializableInsts.empty() || !sinkTriviallyRematInsts(ST, TII))
- break;
-
- LLVM_DEBUG(
- dbgs() << "Retrying function scheduling with improved occupancy of "
- << MinOccupancy << " from rematerializing\n");
- }
- }
+ LLVM_DEBUG(dbgs() << "Starting scheduling stage: " << StageID << "\n");
+ return true;
+}
- if (Stage == UnclusteredReschedule)
- SavedMutations.swap(Mutations);
+bool UnclusteredRescheduleStage::initGCNSchedStage() {
+ if (!GCNSchedStage::initGCNSchedStage())
+ return false;
- for (auto Region : Regions) {
- if (((Stage == UnclusteredReschedule || Stage == PreRARematerialize) &&
- !RescheduleRegions[RegionIdx]) ||
- (Stage == ClusteredLowOccupancyReschedule &&
- !RegionsWithClusters[RegionIdx] && !RegionsWithHighRP[RegionIdx])) {
+ if (DAG.RescheduleRegions.none())
+ return false;
- ++RegionIdx;
- continue;
- }
+ SavedMutations.swap(DAG.Mutations);
- RegionBegin = Region.first;
- RegionEnd = Region.second;
+ LLVM_DEBUG(dbgs() << "Retrying function scheduling without clustering.\n");
+ return true;
+}
- if (RegionBegin->getParent() != MBB) {
- if (MBB) finishBlock();
- MBB = RegionBegin->getParent();
- startBlock(MBB);
- if (Stage == InitialSchedule)
- computeBlockPressure(MBB);
- }
+bool ClusteredLowOccStage::initGCNSchedStage() {
+ if (!GCNSchedStage::initGCNSchedStage())
+ return false;
- unsigned NumRegionInstrs = std::distance(begin(), end());
- enterRegion(MBB, begin(), end(), NumRegionInstrs);
+ // Don't bother trying to improve ILP in lower RP regions if occupancy has not
+ // been dropped. All regions will have already been scheduled with the ideal
+ // occupancy targets.
+ if (DAG.StartingOccupancy <= DAG.MinOccupancy)
+ return false;
- // Skip empty scheduling regions (0 or 1 schedulable instructions).
- if (begin() == end() || begin() == std::prev(end())) {
- exitRegion();
- ++RegionIdx;
- continue;
- }
+ LLVM_DEBUG(
+ dbgs() << "Retrying function scheduling with lowest recorded occupancy "
+ << DAG.MinOccupancy << ".\n");
+ return true;
+}
- LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
- LLVM_DEBUG(dbgs() << MF.getName() << ":" << printMBBReference(*MBB) << " "
- << MBB->getName() << "\n From: " << *begin()
- << " To: ";
- if (RegionEnd != MBB->end()) dbgs() << *RegionEnd;
- else dbgs() << "End";
- dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
+bool PreRARematStage::initGCNSchedStage() {
+ if (!GCNSchedStage::initGCNSchedStage())
+ return false;
+
+ if (DAG.RegionsWithMinOcc.none() || DAG.Regions.size() == 1)
+ return false;
- schedule();
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ // Check maximum occupancy
+ if (ST.computeOccupancy(MF.getFunction(), MFI.getLDSSize()) ==
+ DAG.MinOccupancy)
+ return false;
+
+ // FIXME: This pass will invalidate cached MBBLiveIns for regions
+ // inbetween the defs and region we sinked the def to. Cached pressure
+ // for regions where a def is sinked from will also be invalidated. Will
+ // need to be fixed if there is another pass after this pass.
+
+ collectRematerializableInstructions();
+ if (RematerializableInsts.empty() || !sinkTriviallyRematInsts(ST, TII))
+ return false;
- exitRegion();
- ++RegionIdx;
+ LLVM_DEBUG(
+ dbgs() << "Retrying function scheduling with improved occupancy of "
+ << DAG.MinOccupancy << " from rematerializing\n");
+ return true;
+}
+
+void GCNSchedStage::finalizeGCNSchedStage() {
+ DAG.finishBlock();
+ LLVM_DEBUG(dbgs() << "Ending scheduling stage: " << StageID << "\n");
+}
+
+void UnclusteredRescheduleStage::finalizeGCNSchedStage() {
+ SavedMutations.swap(DAG.Mutations);
+
+ GCNSchedStage::finalizeGCNSchedStage();
+}
+
+bool GCNSchedStage::initGCNRegion() {
+ // Check whether this new region is also a new block.
+ if (DAG.RegionBegin->getParent() != CurrentMBB)
+ setupNewBlock();
+
+ unsigned NumRegionInstrs = std::distance(DAG.begin(), DAG.end());
+ DAG.enterRegion(CurrentMBB, DAG.begin(), DAG.end(), NumRegionInstrs);
+
+ // Skip empty scheduling regions (0 or 1 schedulable instructions).
+ if (DAG.begin() == DAG.end() || DAG.begin() == std::prev(DAG.end()))
+ return false;
+
+ LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
+ LLVM_DEBUG(dbgs() << MF.getName() << ":" << printMBBReference(*CurrentMBB)
+ << " " << CurrentMBB->getName()
+ << "\n From: " << *DAG.begin() << " To: ";
+ if (DAG.RegionEnd != CurrentMBB->end()) dbgs() << *DAG.RegionEnd;
+ else dbgs() << "End";
+ dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
+
+ // Save original instruction order before scheduling for possible revert.
+ Unsched.clear();
+ Unsched.reserve(DAG.NumRegionInstrs);
+ for (auto &I : DAG)
+ Unsched.push_back(&I);
+
+ PressureBefore = DAG.Pressure[RegionIdx];
+
+ LLVM_DEBUG(
+ dbgs() << "Pressure before scheduling:\nRegion live-ins:";
+ GCNRPTracker::printLiveRegs(dbgs(), DAG.LiveIns[RegionIdx], DAG.MRI);
+ dbgs() << "Region live-in pressure: ";
+ llvm::getRegPressure(DAG.MRI, DAG.LiveIns[RegionIdx]).print(dbgs());
+ dbgs() << "Region register pressure: "; PressureBefore.print(dbgs()));
+
+ // Set HasClusteredNodes to true for late stages where we have already
+ // collected it. That way pickNode() will not scan SDep's when not needed.
+ S.HasClusteredNodes = StageID > GCNSchedStageID::InitialSchedule;
+ S.HasExcessPressure = false;
+
+ return true;
+}
+
+bool UnclusteredRescheduleStage::initGCNRegion() {
+ if (!DAG.RescheduleRegions[RegionIdx])
+ return false;
+
+ return GCNSchedStage::initGCNRegion();
+}
+
+bool ClusteredLowOccStage::initGCNRegion() {
+ // We may need to reschedule this region if it doesn't have clusters so it
+ // wasn't rescheduled in the last stage, or if we found it was testing
+ // critical register pressure limits in the unclustered reschedule stage. The
+ // later is because we may not have been able to raise the min occupancy in
+ // the previous stage so the region may be overly constrained even if it was
+ // already rescheduled.
+ if (!DAG.RegionsWithClusters[RegionIdx] && !DAG.RegionsWithHighRP[RegionIdx])
+ return false;
+
+ return GCNSchedStage::initGCNRegion();
+}
+
+bool PreRARematStage::initGCNRegion() {
+ if (!DAG.RescheduleRegions[RegionIdx])
+ return false;
+
+ return GCNSchedStage::initGCNRegion();
+}
+
+void GCNSchedStage::setupNewBlock() {
+ if (CurrentMBB)
+ DAG.finishBlock();
+
+ CurrentMBB = DAG.RegionBegin->getParent();
+ DAG.startBlock(CurrentMBB);
+ // Get real RP for the region if it hasn't be calculated before. After the
+ // initial schedule stage real RP will be collected after scheduling.
+ if (StageID == GCNSchedStageID::InitialSchedule)
+ DAG.computeBlockPressure(RegionIdx, CurrentMBB);
+}
+
+void GCNSchedStage::finalizeGCNRegion() {
+ DAG.Regions[RegionIdx] = std::make_pair(DAG.RegionBegin, DAG.RegionEnd);
+ DAG.RescheduleRegions[RegionIdx] = false;
+ if (S.HasExcessPressure)
+ DAG.RegionsWithHighRP[RegionIdx] = true;
+
+ // Revert scheduling if we have dropped occupancy or there is some other
+ // reason that the original schedule is better.
+ checkScheduling();
+
+ DAG.exitRegion();
+ RegionIdx++;
+}
+
+void InitialScheduleStage::finalizeGCNRegion() {
+ // Record which regions have clustered nodes for the next unclustered
+ // reschedule stage.
+ assert(nextStage(StageID) == GCNSchedStageID::UnclusteredReschedule);
+ if (S.HasClusteredNodes)
+ DAG.RegionsWithClusters[RegionIdx] = true;
+
+ GCNSchedStage::finalizeGCNRegion();
+}
+
+void GCNSchedStage::checkScheduling() {
+ // Check the results of scheduling.
+ PressureAfter = DAG.getRealRegPressure(RegionIdx);
+ LLVM_DEBUG(dbgs() << "Pressure after scheduling: ";
+ PressureAfter.print(dbgs()));
+
+ if (PressureAfter.getSGPRNum() <= S.SGPRCriticalLimit &&
+ PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) <= S.VGPRCriticalLimit) {
+ DAG.Pressure[RegionIdx] = PressureAfter;
+ DAG.RegionsWithMinOcc[RegionIdx] =
+ PressureAfter.getOccupancy(ST) == DAG.MinOccupancy;
+
+ // Early out if we have achieve the occupancy target.
+ LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n");
+ return;
+ }
+
+ unsigned WavesAfter =
+ std::min(S.getTargetOccupancy(), PressureAfter.getOccupancy(ST));
+ unsigned WavesBefore =
+ std::min(S.getTargetOccupancy(), PressureBefore.getOccupancy(ST));
+ LLVM_DEBUG(dbgs() << "Occupancy before scheduling: " << WavesBefore
+ << ", after " << WavesAfter << ".\n");
+
+ // We may not be able to keep the current target occupancy because of the just
+ // scheduled region. We might still be able to revert scheduling if the
+ // occupancy before was higher, or if the current schedule has register
+ // pressure higher than the excess limits which could lead to more spilling.
+ unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
+
+ // Allow memory bound functions to drop to 4 waves if not limited by an
+ // attribute.
+ if (WavesAfter < WavesBefore && WavesAfter < DAG.MinOccupancy &&
+ WavesAfter >= MFI.getMinAllowedOccupancy()) {
+ LLVM_DEBUG(dbgs() << "Function is memory bound, allow occupancy drop up to "
+ << MFI.getMinAllowedOccupancy() << " waves\n");
+ NewOccupancy = WavesAfter;
+ }
+
+ if (NewOccupancy < DAG.MinOccupancy) {
+ DAG.MinOccupancy = NewOccupancy;
+ MFI.limitOccupancy(DAG.MinOccupancy);
+ DAG.RegionsWithMinOcc.reset();
+ LLVM_DEBUG(dbgs() << "Occupancy lowered for the function to "
+ << DAG.MinOccupancy << ".\n");
+ }
+
+ unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF);
+ unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF);
+ if (PressureAfter.getVGPRNum(false) > MaxVGPRs ||
+ PressureAfter.getAGPRNum() > MaxVGPRs ||
+ PressureAfter.getSGPRNum() > MaxSGPRs) {
+ DAG.RescheduleRegions[RegionIdx] = true;
+ DAG.RegionsWithHighRP[RegionIdx] = true;
+ }
+
+ // Revert if this region's schedule would cause a drop in occupancy or
+ // spilling.
+ if (shouldRevertScheduling(WavesAfter)) {
+ revertScheduling();
+ } else {
+ DAG.Pressure[RegionIdx] = PressureAfter;
+ DAG.RegionsWithMinOcc[RegionIdx] =
+ PressureAfter.getOccupancy(ST) == DAG.MinOccupancy;
+ }
+}
+
+bool GCNSchedStage::shouldRevertScheduling(unsigned WavesAfter) {
+ if (WavesAfter < DAG.MinOccupancy)
+ return true;
+
+ return false;
+}
+
+bool InitialScheduleStage::shouldRevertScheduling(unsigned WavesAfter) {
+ if (GCNSchedStage::shouldRevertScheduling(WavesAfter))
+ return true;
+
+ if (mayCauseSpilling(WavesAfter))
+ return true;
+
+ assert(nextStage(StageID) == GCNSchedStageID::UnclusteredReschedule);
+ // Don't reschedule the region in the next stage if it doesn't have clusters.
+ if (!DAG.RegionsWithClusters[RegionIdx])
+ DAG.RescheduleRegions[RegionIdx] = false;
+
+ return false;
+}
+
+bool UnclusteredRescheduleStage::shouldRevertScheduling(unsigned WavesAfter) {
+ if (GCNSchedStage::shouldRevertScheduling(WavesAfter))
+ return true;
+
+ // If RP is not reduced in the unclustred reschedule stage, revert to the old
+ // schedule.
+ if (!PressureAfter.less(ST, PressureBefore)) {
+ LLVM_DEBUG(dbgs() << "Unclustered reschedule did not help.\n");
+ return true;
+ }
+
+ return false;
+}
+
+bool ClusteredLowOccStage::shouldRevertScheduling(unsigned WavesAfter) {
+ if (GCNSchedStage::shouldRevertScheduling(WavesAfter))
+ return true;
+
+ if (mayCauseSpilling(WavesAfter))
+ return true;
+
+ return false;
+}
+
+bool PreRARematStage::shouldRevertScheduling(unsigned WavesAfter) {
+ if (GCNSchedStage::shouldRevertScheduling(WavesAfter))
+ return true;
+
+ if (mayCauseSpilling(WavesAfter))
+ return true;
+
+ return false;
+}
+
+bool GCNSchedStage::mayCauseSpilling(unsigned WavesAfter) {
+ if (WavesAfter <= MFI.getMinWavesPerEU() &&
+ !PressureAfter.less(ST, PressureBefore) &&
+ DAG.RescheduleRegions[RegionIdx]) {
+ LLVM_DEBUG(dbgs() << "New pressure will result in more spilling.\n");
+ return true;
+ }
+
+ return false;
+}
+
+void GCNSchedStage::revertScheduling() {
+ DAG.RegionsWithMinOcc[RegionIdx] =
+ PressureBefore.getOccupancy(ST) == DAG.MinOccupancy;
+ LLVM_DEBUG(dbgs() << "Attempting to revert scheduling.\n");
+ DAG.RescheduleRegions[RegionIdx] =
+ DAG.RegionsWithClusters[RegionIdx] ||
+ (nextStage(StageID)) != GCNSchedStageID::UnclusteredReschedule;
+ DAG.RegionEnd = DAG.RegionBegin;
+ int SkippedDebugInstr = 0;
+ for (MachineInstr *MI : Unsched) {
+ if (MI->isDebugInstr()) {
+ ++SkippedDebugInstr;
+ continue;
+ }
+
+ if (MI->getIterator() != DAG.RegionEnd) {
+ DAG.BB->remove(MI);
+ DAG.BB->insert(DAG.RegionEnd, MI);
+ if (!MI->isDebugInstr())
+ DAG.LIS->handleMove(*MI, true);
+ }
+
+ // Reset read-undef flags and update them later.
+ for (auto &Op : MI->operands())
+ if (Op.isReg() && Op.isDef())
+ Op.setIsUndef(false);
+ RegisterOperands RegOpers;
+ RegOpers.collect(*MI, *DAG.TRI, DAG.MRI, DAG.ShouldTrackLaneMasks, false);
+ if (!MI->isDebugInstr()) {
+ if (DAG.ShouldTrackLaneMasks) {
+ // Adjust liveness and add missing dead+read-undef flags.
+ SlotIndex SlotIdx = DAG.LIS->getInstructionIndex(*MI).getRegSlot();
+ RegOpers.adjustLaneLiveness(*DAG.LIS, DAG.MRI, SlotIdx, MI);
+ } else {
+ // Adjust for missing dead-def flags.
+ RegOpers.detectDeadDefs(*MI, *DAG.LIS);
+ }
}
- finishBlock();
+ DAG.RegionEnd = MI->getIterator();
+ ++DAG.RegionEnd;
+ LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
+ }
+
+ // After reverting schedule, debug instrs will now be at the end of the block
+ // and RegionEnd will point to the first debug instr. Increment RegionEnd
+ // pass debug instrs to the actual end of the scheduling region.
+ while (SkippedDebugInstr-- > 0)
+ ++DAG.RegionEnd;
+
+ // If Unsched.front() instruction is a debug instruction, this will actually
+ // shrink the region since we moved all debug instructions to the end of the
+ // block. Find the first instruction that is not a debug instruction.
+ DAG.RegionBegin = Unsched.front()->getIterator();
+ if (DAG.RegionBegin->isDebugInstr()) {
+ for (MachineInstr *MI : Unsched) {
+ if (MI->isDebugInstr())
+ continue;
+ DAG.RegionBegin = MI->getIterator();
+ break;
+ }
+ }
+
+ // Then move the debug instructions back into their correct place and set
+ // RegionBegin and RegionEnd if needed.
+ DAG.placeDebugValues();
- if (Stage == UnclusteredReschedule)
- SavedMutations.swap(Mutations);
- } while (Stage != LastStage);
+ DAG.Regions[RegionIdx] = std::make_pair(DAG.RegionBegin, DAG.RegionEnd);
}
-void GCNScheduleDAGMILive::collectRematerializableInstructions() {
- const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo *>(TRI);
- for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
+void PreRARematStage::collectRematerializableInstructions() {
+ const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo *>(DAG.TRI);
+ for (unsigned I = 0, E = DAG.MRI.getNumVirtRegs(); I != E; ++I) {
Register Reg = Register::index2VirtReg(I);
- if (!LIS->hasInterval(Reg))
+ if (!DAG.LIS->hasInterval(Reg))
continue;
// TODO: Handle AGPR and SGPR rematerialization
- if (!SRI->isVGPRClass(MRI.getRegClass(Reg)) || !MRI.hasOneDef(Reg) ||
- !MRI.hasOneNonDBGUse(Reg))
+ if (!SRI->isVGPRClass(DAG.MRI.getRegClass(Reg)) ||
+ !DAG.MRI.hasOneDef(Reg) || !DAG.MRI.hasOneNonDBGUse(Reg))
continue;
- MachineOperand *Op = MRI.getOneDef(Reg);
+ MachineOperand *Op = DAG.MRI.getOneDef(Reg);
MachineInstr *Def = Op->getParent();
if (Op->getSubReg() != 0 || !isTriviallyReMaterializable(*Def))
continue;
- MachineInstr *UseI = &*MRI.use_instr_nodbg_begin(Reg);
+ MachineInstr *UseI = &*DAG.MRI.use_instr_nodbg_begin(Reg);
if (Def->getParent() == UseI->getParent())
continue;
@@ -744,10 +905,10 @@ void GCNScheduleDAGMILive::collectRematerializableInstructions() {
// live-through or used inside regions at MinOccupancy. This means that the
// register must be in the live-in set for the region.
bool AddedToRematList = false;
- for (unsigned I = 0, E = Regions.size(); I != E; ++I) {
- auto It = LiveIns[I].find(Reg);
- if (It != LiveIns[I].end() && !It->second.none()) {
- if (RegionsWithMinOcc[I]) {
+ for (unsigned I = 0, E = DAG.Regions.size(); I != E; ++I) {
+ auto It = DAG.LiveIns[I].find(Reg);
+ if (It != DAG.LiveIns[I].end() && !It->second.none()) {
+ if (DAG.RegionsWithMinOcc[I]) {
RematerializableInsts[I][Def] = UseI;
AddedToRematList = true;
}
@@ -762,8 +923,8 @@ void GCNScheduleDAGMILive::collectRematerializableInstructions() {
}
}
-bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
- const TargetInstrInfo *TII) {
+bool PreRARematStage::sinkTriviallyRematInsts(const GCNSubtarget &ST,
+ const TargetInstrInfo *TII) {
// Temporary copies of cached variables we will be modifying and replacing if
// sinking succeeds.
SmallVector<
@@ -772,9 +933,10 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
DenseMap<unsigned, GCNRPTracker::LiveRegSet> NewLiveIns;
DenseMap<unsigned, GCNRegPressure> NewPressure;
BitVector NewRescheduleRegions;
+ LiveIntervals *LIS = DAG.LIS;
- NewRegions.resize(Regions.size());
- NewRescheduleRegions.resize(Regions.size());
+ NewRegions.resize(DAG.Regions.size());
+ NewRescheduleRegions.resize(DAG.Regions.size());
// Collect only regions that has a rematerializable def as a live-in.
SmallSet<unsigned, 16> ImpactedRegions;
@@ -784,16 +946,16 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
// Make copies of register pressure and live-ins cache that will be updated
// as we rematerialize.
for (auto Idx : ImpactedRegions) {
- NewPressure[Idx] = Pressure[Idx];
- NewLiveIns[Idx] = LiveIns[Idx];
+ NewPressure[Idx] = DAG.Pressure[Idx];
+ NewLiveIns[Idx] = DAG.LiveIns[Idx];
}
- NewRegions = Regions;
+ NewRegions = DAG.Regions;
NewRescheduleRegions.reset();
DenseMap<MachineInstr *, MachineInstr *> InsertedMIToOldDef;
bool Improved = false;
for (auto I : ImpactedRegions) {
- if (!RegionsWithMinOcc[I])
+ if (!DAG.RegionsWithMinOcc[I])
continue;
Improved = false;
@@ -802,12 +964,12 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
// TODO: Handle occupancy drop due to AGPR and SGPR.
// Check if cause of occupancy drop is due to VGPR usage and not SGPR.
- if (ST.getOccupancyWithNumSGPRs(SGPRUsage) == MinOccupancy)
+ if (ST.getOccupancyWithNumSGPRs(SGPRUsage) == DAG.MinOccupancy)
break;
// The occupancy of this region could have been improved by a previous
// iteration's sinking of defs.
- if (NewPressure[I].getOccupancy(ST) > MinOccupancy) {
+ if (NewPressure[I].getOccupancy(ST) > DAG.MinOccupancy) {
NewRescheduleRegions[I] = true;
Improved = true;
continue;
@@ -827,7 +989,7 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
unsigned OptimisticOccupancy = ST.getOccupancyWithNumVGPRs(VGPRsAfterSink);
// If in the most optimistic scenario, we cannot improve occupancy, then do
// not attempt to sink any instructions.
- if (OptimisticOccupancy <= MinOccupancy)
+ if (OptimisticOccupancy <= DAG.MinOccupancy)
break;
unsigned ImproveOccupancy = 0;
@@ -842,7 +1004,7 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
// call LiveRangeEdit::allUsesAvailableAt() and
// LiveRangeEdit::canRematerializeAt().
TII->reMaterialize(*InsertPos->getParent(), InsertPos, Reg,
- Def->getOperand(0).getSubReg(), *Def, *TRI);
+ Def->getOperand(0).getSubReg(), *Def, *DAG.TRI);
MachineInstr *NewMI = &*(--InsertPos);
LIS->InsertMachineInstrInMaps(*NewMI);
LIS->removeInterval(Reg);
@@ -851,11 +1013,11 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
// Update region boundaries in scheduling region we sinked from since we
// may sink an instruction that was at the beginning or end of its region
- updateRegionBoundaries(NewRegions, Def, /*NewMI =*/nullptr,
- /*Removing =*/true);
+ DAG.updateRegionBoundaries(NewRegions, Def, /*NewMI =*/nullptr,
+ /*Removing =*/true);
// Update region boundaries in region we sinked to.
- updateRegionBoundaries(NewRegions, InsertPos, NewMI);
+ DAG.updateRegionBoundaries(NewRegions, InsertPos, NewMI);
LaneBitmask PrevMask = NewLiveIns[I][Reg];
// FIXME: Also update cached pressure for where the def was sinked from.
@@ -863,9 +1025,9 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
// the reg from all regions as a live-in.
for (auto Idx : RematDefToLiveInRegions[Def]) {
NewLiveIns[Idx].erase(Reg);
- if (InsertPos->getParent() != Regions[Idx].first->getParent()) {
+ if (InsertPos->getParent() != DAG.Regions[Idx].first->getParent()) {
// Def is live-through and not used in this block.
- NewPressure[Idx].inc(Reg, PrevMask, LaneBitmask::getNone(), MRI);
+ NewPressure[Idx].inc(Reg, PrevMask, LaneBitmask::getNone(), DAG.MRI);
} else {
// Def is used and rematerialized into this block.
GCNDownwardRPTracker RPT(*LIS);
@@ -879,7 +1041,7 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
SinkedDefs.push_back(Def);
ImproveOccupancy = NewPressure[I].getOccupancy(ST);
- if (ImproveOccupancy > MinOccupancy)
+ if (ImproveOccupancy > DAG.MinOccupancy)
break;
}
@@ -888,7 +1050,7 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
for (auto TrackedIdx : RematDefToLiveInRegions[Def])
RematerializableInsts[TrackedIdx].erase(Def);
- if (ImproveOccupancy <= MinOccupancy)
+ if (ImproveOccupancy <= DAG.MinOccupancy)
break;
NewRescheduleRegions[I] = true;
@@ -917,7 +1079,7 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
MachineInstr *OldMI = Entry.second;
// Remove OldMI from BBLiveInMap since we are sinking it from its MBB.
- BBLiveInMap.erase(OldMI);
+ DAG.BBLiveInMap.erase(OldMI);
// Remove OldMI and update LIS
Register Reg = MI->getOperand(0).getReg();
@@ -929,22 +1091,22 @@ bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST,
// Update live-ins, register pressure, and regions caches.
for (auto Idx : ImpactedRegions) {
- LiveIns[Idx] = NewLiveIns[Idx];
- Pressure[Idx] = NewPressure[Idx];
- MBBLiveIns.erase(Regions[Idx].first->getParent());
+ DAG.LiveIns[Idx] = NewLiveIns[Idx];
+ DAG.Pressure[Idx] = NewPressure[Idx];
+ DAG.MBBLiveIns.erase(DAG.Regions[Idx].first->getParent());
}
- Regions = NewRegions;
- RescheduleRegions = NewRescheduleRegions;
+ DAG.Regions = NewRegions;
+ DAG.RescheduleRegions = NewRescheduleRegions;
SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
- MFI.increaseOccupancy(MF, ++MinOccupancy);
+ MFI.increaseOccupancy(MF, ++DAG.MinOccupancy);
return true;
}
// Copied from MachineLICM
-bool GCNScheduleDAGMILive::isTriviallyReMaterializable(const MachineInstr &MI) {
- if (!TII->isTriviallyReMaterializable(MI))
+bool PreRARematStage::isTriviallyReMaterializable(const MachineInstr &MI) {
+ if (!DAG.TII->isTriviallyReMaterializable(MI))
return false;
for (const MachineOperand &MO : MI.operands())
diff --git a/llvm/lib/Target/AMDGPU/GCNSchedStrategy.h b/llvm/lib/Target/AMDGPU/GCNSchedStrategy.h
index c3db849cf81a..7aadf89e0bf7 100644
--- a/llvm/lib/Target/AMDGPU/GCNSchedStrategy.h
+++ b/llvm/lib/Target/AMDGPU/GCNSchedStrategy.h
@@ -28,8 +28,6 @@ class GCNSubtarget;
/// heuristics to determine excess/critical pressure sets. Its goal is to
/// maximize kernel occupancy (i.e. maximum number of waves per simd).
class GCNMaxOccupancySchedStrategy final : public GenericScheduler {
- friend class GCNScheduleDAGMILive;
-
SUnit *pickNodeBidirectional(bool &IsTopNode);
void pickNodeFromQueue(SchedBoundary &Zone, const CandPolicy &ZonePolicy,
@@ -42,15 +40,18 @@ class GCNMaxOccupancySchedStrategy final : public GenericScheduler {
unsigned SGPRPressure, unsigned VGPRPressure);
std::vector<unsigned> Pressure;
+
std::vector<unsigned> MaxPressure;
unsigned SGPRExcessLimit;
+
unsigned VGPRExcessLimit;
- unsigned SGPRCriticalLimit;
- unsigned VGPRCriticalLimit;
unsigned TargetOccupancy;
+ MachineFunction *MF;
+
+public:
// schedule() have seen a clustered memory operation. Set it to false
// before a region scheduling to know if the region had such clusters.
bool HasClusteredNodes;
@@ -59,28 +60,53 @@ class GCNMaxOccupancySchedStrategy final : public GenericScheduler {
// register pressure for actual scheduling heuristics.
bool HasExcessPressure;
- MachineFunction *MF;
+ unsigned SGPRCriticalLimit;
+
+ unsigned VGPRCriticalLimit;
-public:
GCNMaxOccupancySchedStrategy(const MachineSchedContext *C);
SUnit *pickNode(bool &IsTopNode) override;
void initialize(ScheduleDAGMI *DAG) override;
+ unsigned getTargetOccupancy() { return TargetOccupancy; }
+
void setTargetOccupancy(unsigned Occ) { TargetOccupancy = Occ; }
};
-class GCNScheduleDAGMILive final : public ScheduleDAGMILive {
+enum class GCNSchedStageID : unsigned {
+ InitialSchedule = 0,
+ UnclusteredReschedule = 1,
+ ClusteredLowOccupancyReschedule = 2,
+ PreRARematerialize = 3,
+ LastStage = PreRARematerialize
+};
+
+#ifndef NDEBUG
+raw_ostream &operator<<(raw_ostream &OS, const GCNSchedStageID &StageID);
+#endif
+
+inline GCNSchedStageID &operator++(GCNSchedStageID &Stage, int) {
+ assert(Stage != GCNSchedStageID::PreRARematerialize);
+ Stage = static_cast<GCNSchedStageID>(static_cast<unsigned>(Stage) + 1);
+ return Stage;
+}
+
+inline GCNSchedStageID nextStage(const GCNSchedStageID Stage) {
+ return static_cast<GCNSchedStageID>(static_cast<unsigned>(Stage) + 1);
+}
- enum : unsigned {
- Collect,
- InitialSchedule,
- UnclusteredReschedule,
- ClusteredLowOccupancyReschedule,
- PreRARematerialize,
- LastStage = PreRARematerialize
- };
+inline bool operator>(GCNSchedStageID &LHS, GCNSchedStageID &RHS) {
+ return static_cast<unsigned>(LHS) > static_cast<unsigned>(RHS);
+}
+
+class GCNScheduleDAGMILive final : public ScheduleDAGMILive {
+ friend class GCNSchedStage;
+ friend class InitialScheduleStage;
+ friend class UnclusteredRescheduleStage;
+ friend class ClusteredLowOccStage;
+ friend class PreRARematStage;
const GCNSubtarget &ST;
@@ -92,12 +118,6 @@ class GCNScheduleDAGMILive final : public ScheduleDAGMILive {
// Minimal real occupancy recorder for the function.
unsigned MinOccupancy;
- // Scheduling stage number.
- unsigned Stage;
-
- // Current region index.
- size_t RegionIdx;
-
// Vector of regions recorder for later rescheduling
SmallVector<std::pair<MachineBasicBlock::iterator,
MachineBasicBlock::iterator>, 32> Regions;
@@ -121,6 +141,148 @@ class GCNScheduleDAGMILive final : public ScheduleDAGMILive {
// Region pressure cache.
SmallVector<GCNRegPressure, 32> Pressure;
+ // Temporary basic block live-in cache.
+ DenseMap<const MachineBasicBlock *, GCNRPTracker::LiveRegSet> MBBLiveIns;
+
+ DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> BBLiveInMap;
+
+ DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> getBBLiveInMap() const;
+
+ // Return current region pressure.
+ GCNRegPressure getRealRegPressure(unsigned RegionIdx) const;
+
+ // Compute and cache live-ins and pressure for all regions in block.
+ void computeBlockPressure(unsigned RegionIdx, const MachineBasicBlock *MBB);
+
+ // Update region boundaries when removing MI or inserting NewMI before MI.
+ void updateRegionBoundaries(
+ SmallVectorImpl<std::pair<MachineBasicBlock::iterator,
+ MachineBasicBlock::iterator>> &RegionBoundaries,
+ MachineBasicBlock::iterator MI, MachineInstr *NewMI,
+ bool Removing = false);
+
+ void runSchedStages();
+
+public:
+ GCNScheduleDAGMILive(MachineSchedContext *C,
+ std::unique_ptr<MachineSchedStrategy> S);
+
+ void schedule() override;
+
+ void finalizeSchedule() override;
+};
+
+// GCNSchedStrategy applies multiple scheduling stages to a function.
+class GCNSchedStage {
+protected:
+ GCNScheduleDAGMILive &DAG;
+
+ GCNMaxOccupancySchedStrategy &S;
+
+ MachineFunction &MF;
+
+ SIMachineFunctionInfo &MFI;
+
+ const GCNSubtarget &ST;
+
+ const GCNSchedStageID StageID;
+
+ // The current block being scheduled.
+ MachineBasicBlock *CurrentMBB = nullptr;
+
+ // Current region index.
+ unsigned RegionIdx = 0;
+
+ // Record the original order of instructions before scheduling.
+ std::vector<MachineInstr *> Unsched;
+
+ // RP before scheduling the current region.
+ GCNRegPressure PressureBefore;
+
+ // RP after scheduling the current region.
+ GCNRegPressure PressureAfter;
+
+ GCNSchedStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG);
+
+public:
+ // Initialize state for a scheduling stage. Returns false if the current stage
+ // should be skipped.
+ virtual bool initGCNSchedStage();
+
+ // Finalize state after finishing a scheduling pass on the function.
+ virtual void finalizeGCNSchedStage();
+
+ // Setup for scheduling a region. Returns false if the current region should
+ // be skipped.
+ virtual bool initGCNRegion();
+
+ // Track whether a new region is also a new MBB.
+ void setupNewBlock();
+
+ // Finalize state after scheudling a region.
+ virtual void finalizeGCNRegion();
+
+ // Check result of scheduling.
+ void checkScheduling();
+
+ // Returns true if scheduling should be reverted.
+ virtual bool shouldRevertScheduling(unsigned WavesAfter);
+
+ // Returns true if the new schedule may result in more spilling.
+ bool mayCauseSpilling(unsigned WavesAfter);
+
+ // Attempt to revert scheduling for this region.
+ void revertScheduling();
+
+ void advanceRegion() { RegionIdx++; }
+
+ virtual ~GCNSchedStage() = default;
+};
+
+class InitialScheduleStage : public GCNSchedStage {
+public:
+ void finalizeGCNRegion() override;
+
+ bool shouldRevertScheduling(unsigned WavesAfter) override;
+
+ InitialScheduleStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
+ : GCNSchedStage(StageID, DAG) {}
+};
+
+class UnclusteredRescheduleStage : public GCNSchedStage {
+private:
+ std::vector<std::unique_ptr<ScheduleDAGMutation>> SavedMutations;
+
+public:
+ bool initGCNSchedStage() override;
+
+ void finalizeGCNSchedStage() override;
+
+ bool initGCNRegion() override;
+
+ bool shouldRevertScheduling(unsigned WavesAfter) override;
+
+ UnclusteredRescheduleStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
+ : GCNSchedStage(StageID, DAG) {}
+};
+
+// Retry function scheduling if we found resulting occupancy and it is
+// lower than used for other scheduling passes. This will give more freedom
+// to schedule low register pressure blocks.
+class ClusteredLowOccStage : public GCNSchedStage {
+public:
+ bool initGCNSchedStage() override;
+
+ bool initGCNRegion() override;
+
+ bool shouldRevertScheduling(unsigned WavesAfter) override;
+
+ ClusteredLowOccStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
+ : GCNSchedStage(StageID, DAG) {}
+};
+
+class PreRARematStage : public GCNSchedStage {
+private:
// Each region at MinOccupancy will have their own list of trivially
// rematerializable instructions we can remat to reduce RP. The list maps an
// instruction to the position we should remat before, usually the MI using
@@ -132,12 +294,6 @@ class GCNScheduleDAGMILive final : public ScheduleDAGMILive {
// that has the defined reg as a live-in.
DenseMap<MachineInstr *, SmallVector<unsigned, 4>> RematDefToLiveInRegions;
- // Temporary basic block live-in cache.
- DenseMap<const MachineBasicBlock*, GCNRPTracker::LiveRegSet> MBBLiveIns;
-
- DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> BBLiveInMap;
- DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> getBBLiveInMap() const;
-
// Collect all trivially rematerializable VGPR instructions with a single def
// and single use outside the defining block into RematerializableInsts.
void collectRematerializableInstructions();
@@ -150,26 +306,15 @@ class GCNScheduleDAGMILive final : public ScheduleDAGMILive {
bool sinkTriviallyRematInsts(const GCNSubtarget &ST,
const TargetInstrInfo *TII);
- // Return current region pressure.
- GCNRegPressure getRealRegPressure() const;
-
- // Compute and cache live-ins and pressure for all regions in block.
- void computeBlockPressure(const MachineBasicBlock *MBB);
-
- // Update region boundaries when removing MI or inserting NewMI before MI.
- void updateRegionBoundaries(
- SmallVectorImpl<std::pair<MachineBasicBlock::iterator,
- MachineBasicBlock::iterator>> &RegionBoundaries,
- MachineBasicBlock::iterator MI, MachineInstr *NewMI,
- bool Removing = false);
-
public:
- GCNScheduleDAGMILive(MachineSchedContext *C,
- std::unique_ptr<MachineSchedStrategy> S);
+ bool initGCNSchedStage() override;
- void schedule() override;
+ bool initGCNRegion() override;
- void finalizeSchedule() override;
+ bool shouldRevertScheduling(unsigned WavesAfter) override;
+
+ PreRARematStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
+ : GCNSchedStage(StageID, DAG) {}
};
} // End namespace llvm
diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
index e093d78b2cc6..d9d7d4efa8c3 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
@@ -309,6 +309,11 @@ uint64_t SIMCCodeEmitter::getImplicitOpSelHiEncoding(int Opcode) const {
return OP_SEL_HI_0 | OP_SEL_HI_1 | OP_SEL_HI_2;
}
+static bool isVCMPX64(const MCInstrDesc &Desc) {
+ return (Desc.TSFlags & SIInstrFlags::VOP3) &&
+ Desc.hasImplicitDefOfPhysReg(AMDGPU::EXEC);
+}
+
void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
@@ -326,6 +331,17 @@ void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
Encoding |= getImplicitOpSelHiEncoding(Opcode);
}
+ // GFX11 v_cmpx opcodes promoted to VOP3 have implied dst=EXEC.
+ // Documentation requires dst to be encoded as EXEC (0x7E),
+ // but it looks like the actual value encoded for dst operand
+ // is ignored by HW. It was decided to define dst as "do not care"
+ // in td files to allow disassembler accept any dst value.
+ // However, dst is encoded as EXEC for compatibility with SP3.
+ if (AMDGPU::isGFX11Plus(STI) && isVCMPX64(Desc)) {
+ assert((Encoding & 0xFF) == 0);
+ Encoding |= MRI.getEncodingValue(AMDGPU::EXEC_LO);
+ }
+
for (unsigned i = 0; i < bytes; i++) {
OS.write((uint8_t)Encoding.extractBitsAsZExtValue(8, 8 * i));
}
diff --git a/llvm/lib/Target/AMDGPU/R600ISelLowering.h b/llvm/lib/Target/AMDGPU/R600ISelLowering.h
index e7706fa0ef5c..1ed79add64c9 100644
--- a/llvm/lib/Target/AMDGPU/R600ISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/R600ISelLowering.h
@@ -54,8 +54,8 @@ public:
MachineMemOperand::Flags Flags = MachineMemOperand::MONone,
bool *IsFast = nullptr) const override;
- virtual bool canCombineTruncStore(EVT ValVT, EVT MemVT,
- bool LegalOperations) const override {
+ bool canCombineTruncStore(EVT ValVT, EVT MemVT,
+ bool LegalOperations) const override {
// R600 has "custom" lowering for truncating stores despite not supporting
// those instructions. If we allow that custom lowering in the DAG combiner
// then all truncates are merged into truncating stores, giving worse code
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 438e8b200ecc..f7d139adc63b 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -2132,7 +2132,8 @@ void SITargetLowering::allocateSystemSGPRs(CCState &CCInfo,
SIMachineFunctionInfo &Info,
CallingConv::ID CallConv,
bool IsShader) const {
- if (Subtarget->hasUserSGPRInit16Bug()) {
+ if (Subtarget->hasUserSGPRInit16Bug() && !IsShader) {
+ // Note: user SGPRs are handled by the front-end for graphics shaders
// Pad up the used user SGPRs with dead inputs.
unsigned CurrentUserSGPRs = Info.getNumUserSGPRs();
@@ -2195,7 +2196,8 @@ void SITargetLowering::allocateSystemSGPRs(CCState &CCInfo,
CCInfo.AllocateReg(PrivateSegmentWaveByteOffsetReg);
}
- assert(!Subtarget->hasUserSGPRInit16Bug() || Info.getNumPreloadedSGPRs() >= 16);
+ assert(!Subtarget->hasUserSGPRInit16Bug() || IsShader ||
+ Info.getNumPreloadedSGPRs() >= 16);
}
static void reservePrivateMemoryRegs(const TargetMachine &TM,
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index d1fecc1afc7f..e0101f53880f 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -487,10 +487,10 @@ public:
AtomicExpansionKind
shouldExpandAtomicCmpXchgInIR(AtomicCmpXchgInst *AI) const override;
- virtual const TargetRegisterClass *
- getRegClassFor(MVT VT, bool isDivergent) const override;
- virtual bool requiresUniformRegister(MachineFunction &MF,
- const Value *V) const override;
+ const TargetRegisterClass *getRegClassFor(MVT VT,
+ bool isDivergent) const override;
+ bool requiresUniformRegister(MachineFunction &MF,
+ const Value *V) const override;
Align getPrefLoopAlignment(MachineLoop *ML) const override;
void allocateHSAUserSGPRs(CCState &CCInfo,
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
index ffe8dce79816..fccb08f86e6d 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
@@ -349,7 +349,7 @@ def M0_CLASS_LO16 : SIRegisterClass<"AMDGPU", [i16, f16], 16, (add M0_LO16)> {
def SGPR_LO16 : SIRegisterClass<"AMDGPU", [i16, f16], 16,
(add (sequence "SGPR%u_LO16", 0, 105))> {
- let AllocationPriority = 9;
+ let AllocationPriority = 0;
let Size = 16;
let GeneratePressureSet = 0;
let HasSGPR = 1;
@@ -368,7 +368,7 @@ def SGPR_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32,
(add (sequence "SGPR%u", 0, 105))> {
// Give all SGPR classes higher priority than VGPR classes, because
// we want to spill SGPRs to VGPRs.
- let AllocationPriority = 9;
+ let AllocationPriority = 0;
let GeneratePressureSet = 0;
let HasSGPR = 1;
}
@@ -528,14 +528,14 @@ def Reg32Types : RegisterTypes<[i32, f32, v2i16, v2f16, p2, p3, p5, p6]>;
let HasVGPR = 1 in {
def VGPR_LO16 : SIRegisterClass<"AMDGPU", Reg16Types.types, 16,
(add (sequence "VGPR%u_LO16", 0, 255))> {
- let AllocationPriority = 1;
+ let AllocationPriority = 0;
let Size = 16;
let GeneratePressureSet = 0;
}
def VGPR_HI16 : SIRegisterClass<"AMDGPU", Reg16Types.types, 16,
(add (sequence "VGPR%u_HI16", 0, 255))> {
- let AllocationPriority = 1;
+ let AllocationPriority = 0;
let Size = 16;
let GeneratePressureSet = 0;
}
@@ -544,7 +544,7 @@ def VGPR_HI16 : SIRegisterClass<"AMDGPU", Reg16Types.types, 16,
// i16/f16 only on VI+
def VGPR_32 : SIRegisterClass<"AMDGPU", !listconcat(Reg32Types.types, Reg16Types.types), 32,
(add (sequence "VGPR%u", 0, 255))> {
- let AllocationPriority = 1;
+ let AllocationPriority = 0;
let Size = 32;
let Weight = 1;
}
@@ -588,7 +588,7 @@ def AGPR_LO16 : SIRegisterClass<"AMDGPU", Reg16Types.types, 16,
// AccVGPR 32-bit registers
def AGPR_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32,
(add (sequence "AGPR%u", 0, 255))> {
- let AllocationPriority = 1;
+ let AllocationPriority = 0;
let Size = 32;
let Weight = 1;
}
@@ -653,7 +653,7 @@ def SReg_32_XM0_XEXEC : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2
SGPR_NULL, SGPR_NULL_HI, TTMP_32, TMA_LO, TMA_HI, TBA_LO, TBA_HI, SRC_SHARED_BASE,
SRC_SHARED_LIMIT, SRC_PRIVATE_BASE, SRC_PRIVATE_LIMIT, SRC_POPS_EXITING_WAVE_ID,
SRC_VCCZ, SRC_EXECZ, SRC_SCC)> {
- let AllocationPriority = 10;
+ let AllocationPriority = 0;
}
def SReg_LO16_XM0_XEXEC : SIRegisterClass<"AMDGPU", [i16, f16], 16,
@@ -663,42 +663,42 @@ def SReg_LO16_XM0_XEXEC : SIRegisterClass<"AMDGPU", [i16, f16], 16,
SRC_SHARED_LIMIT_LO16, SRC_PRIVATE_BASE_LO16, SRC_PRIVATE_LIMIT_LO16,
SRC_POPS_EXITING_WAVE_ID_LO16, SRC_VCCZ_LO16, SRC_EXECZ_LO16, SRC_SCC_LO16)> {
let Size = 16;
- let AllocationPriority = 10;
+ let AllocationPriority = 0;
}
def SReg_32_XEXEC_HI : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32,
(add SReg_32_XM0_XEXEC, EXEC_LO, M0_CLASS)> {
- let AllocationPriority = 10;
+ let AllocationPriority = 0;
}
def SReg_LO16_XEXEC_HI : SIRegisterClass<"AMDGPU", [i16, f16], 16,
(add SReg_LO16_XM0_XEXEC, EXEC_LO_LO16, M0_CLASS_LO16)> {
let Size = 16;
- let AllocationPriority = 10;
+ let AllocationPriority = 0;
}
def SReg_32_XM0 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32,
(add SReg_32_XM0_XEXEC, EXEC_LO, EXEC_HI)> {
- let AllocationPriority = 10;
+ let AllocationPriority = 0;
}
def SReg_LO16_XM0 : SIRegisterClass<"AMDGPU", [i16, f16], 16,
(add SReg_LO16_XM0_XEXEC, EXEC_LO_LO16, EXEC_HI_LO16)> {
let Size = 16;
- let AllocationPriority = 10;
+ let AllocationPriority = 0;
}
def SReg_LO16 : SIRegisterClass<"AMDGPU", [i16, f16], 16,
(add SGPR_LO16, SReg_LO16_XM0, M0_CLASS_LO16, EXEC_LO_LO16, EXEC_HI_LO16, SReg_LO16_XEXEC_HI)> {
let Size = 16;
- let AllocationPriority = 10;
+ let AllocationPriority = 0;
}
} // End GeneratePressureSet = 0
// Register class for all scalar registers (SGPRs + Special Registers)
def SReg_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32,
(add SReg_32_XM0, M0_CLASS, EXEC_LO, EXEC_HI, SReg_32_XEXEC_HI)> {
- let AllocationPriority = 10;
+ let AllocationPriority = 0;
let HasSGPR = 1;
}
@@ -712,7 +712,7 @@ def SRegOrLds_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16],
def SGPR_64 : SIRegisterClass<"AMDGPU", [v2i32, i64, v2f32, f64, v4i16, v4f16], 32,
(add SGPR_64Regs)> {
let CopyCost = 1;
- let AllocationPriority = 11;
+ let AllocationPriority = 1;
let HasSGPR = 1;
}
@@ -725,14 +725,14 @@ def TTMP_64 : SIRegisterClass<"AMDGPU", [v2i32, i64, f64, v4i16, v4f16], 32,
def SReg_64_XEXEC : SIRegisterClass<"AMDGPU", [v2i32, i64, v2f32, f64, i1, v4i16, v4f16], 32,
(add SGPR_64, VCC, FLAT_SCR, XNACK_MASK, SGPR_NULL64, TTMP_64, TBA, TMA)> {
let CopyCost = 1;
- let AllocationPriority = 13;
+ let AllocationPriority = 1;
let HasSGPR = 1;
}
def SReg_64 : SIRegisterClass<"AMDGPU", [v2i32, i64, v2f32, f64, i1, v4i16, v4f16], 32,
(add SReg_64_XEXEC, EXEC)> {
let CopyCost = 1;
- let AllocationPriority = 13;
+ let AllocationPriority = 1;
let HasSGPR = 1;
}
@@ -750,7 +750,7 @@ def SReg_1 : SIRegisterClass<"AMDGPU", [i1], 32,
let HasSGPR = 1;
}
-multiclass SRegClass<int numRegs, int priority,
+multiclass SRegClass<int numRegs,
list<ValueType> regTypes,
SIRegisterTuples regList,
SIRegisterTuples ttmpList = regList,
@@ -760,7 +760,7 @@ multiclass SRegClass<int numRegs, int priority,
defvar sgprName = !strconcat("SGPR_", suffix);
defvar ttmpName = !strconcat("TTMP_", suffix);
- let AllocationPriority = priority, CopyCost = copyCost, HasSGPR = 1 in {
+ let AllocationPriority = !sub(numRegs, 1), CopyCost = copyCost, HasSGPR = 1 in {
def "" # sgprName : SIRegisterClass<"AMDGPU", regTypes, 32, (add regList)> {
}
@@ -781,14 +781,14 @@ multiclass SRegClass<int numRegs, int priority,
}
}
-defm "" : SRegClass<3, 14, [v3i32, v3f32], SGPR_96Regs, TTMP_96Regs>;
-defm "" : SRegClass<4, 15, [v4i32, v4f32, v2i64, v2f64, v8i16, v8f16], SGPR_128Regs, TTMP_128Regs>;
-defm "" : SRegClass<5, 16, [v5i32, v5f32], SGPR_160Regs, TTMP_160Regs>;
-defm "" : SRegClass<6, 17, [v6i32, v6f32, v3i64, v3f64], SGPR_192Regs, TTMP_192Regs>;
-defm "" : SRegClass<7, 18, [v7i32, v7f32], SGPR_224Regs, TTMP_224Regs>;
-defm "" : SRegClass<8, 19, [v8i32, v8f32, v4i64, v4f64, v16i16, v16f16], SGPR_256Regs, TTMP_256Regs>;
-defm "" : SRegClass<16, 20, [v16i32, v16f32, v8i64, v8f64], SGPR_512Regs, TTMP_512Regs>;
-defm "" : SRegClass<32, 21, [v32i32, v32f32, v16i64, v16f64], SGPR_1024Regs>;
+defm "" : SRegClass<3, [v3i32, v3f32], SGPR_96Regs, TTMP_96Regs>;
+defm "" : SRegClass<4, [v4i32, v4f32, v2i64, v2f64, v8i16, v8f16], SGPR_128Regs, TTMP_128Regs>;
+defm "" : SRegClass<5, [v5i32, v5f32], SGPR_160Regs, TTMP_160Regs>;
+defm "" : SRegClass<6, [v6i32, v6f32, v3i64, v3f64], SGPR_192Regs, TTMP_192Regs>;
+defm "" : SRegClass<7, [v7i32, v7f32], SGPR_224Regs, TTMP_224Regs>;
+defm "" : SRegClass<8, [v8i32, v8f32, v4i64, v4f64, v16i16, v16f16], SGPR_256Regs, TTMP_256Regs>;
+defm "" : SRegClass<16, [v16i32, v16f32, v8i64, v8f64], SGPR_512Regs, TTMP_512Regs>;
+defm "" : SRegClass<32, [v32i32, v32f32, v16i64, v16f64], SGPR_1024Regs>;
def VRegOrLds_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32,
(add VGPR_32, LDS_DIRECT_CLASS)> {
@@ -803,7 +803,7 @@ class VRegClassBase<int numRegs, list<ValueType> regTypes, dag regList> :
// Requires n v_mov_b32 to copy
let CopyCost = numRegs;
- let AllocationPriority = numRegs;
+ let AllocationPriority = !sub(numRegs, 1);
let Weight = numRegs;
}
diff --git a/llvm/lib/Target/AMDGPU/VOPCInstructions.td b/llvm/lib/Target/AMDGPU/VOPCInstructions.td
index d489a089ac78..5973d32c91d6 100644
--- a/llvm/lib/Target/AMDGPU/VOPCInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPCInstructions.td
@@ -718,7 +718,7 @@ class VOPC_Class_Profile<list<SchedReadWrite> sched, ValueType vt> :
// DPP8 forbids modifiers and can inherit from VOPC_Profile
let Ins64 = (ins Src0Mod:$src0_modifiers, Src0RC64:$src0, Src1RC64:$src1);
- dag InsPartVOP3DPP = (ins Src0Mod:$src0_modifiers, VGPRSrc_32:$src0, VGPRSrc_32:$src1);
+ dag InsPartVOP3DPP = (ins FPVRegInputMods:$src0_modifiers, VGPRSrc_32:$src0, VGPRSrc_32:$src1);
let InsVOP3Base = !con(InsPartVOP3DPP, !if(HasOpSel, (ins op_sel0:$op_sel),
(ins)));
let Asm64 = "$sdst, $src0_modifiers, $src1";
diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
index 9acd49292268..f81495985405 100644
--- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
+++ b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
@@ -139,6 +139,9 @@ public:
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &CStream) const override;
+ uint64_t suggestBytesToSkip(ArrayRef<uint8_t> Bytes,
+ uint64_t Address) const override;
+
private:
DecodeStatus getARMInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes, uint64_t Address,
@@ -739,6 +742,33 @@ static DecodeStatus checkDecodedInstruction(MCInst &MI, uint64_t &Size,
}
}
+uint64_t ARMDisassembler::suggestBytesToSkip(ArrayRef<uint8_t> Bytes,
+ uint64_t Address) const {
+ // In Arm state, instructions are always 4 bytes wide, so there's no
+ // point in skipping any smaller number of bytes if an instruction
+ // can't be decoded.
+ if (!STI.getFeatureBits()[ARM::ModeThumb])
+ return 4;
+
+ // In a Thumb instruction stream, a halfword is a standalone 2-byte
+ // instruction if and only if its value is less than 0xE800.
+ // Otherwise, it's the first halfword of a 4-byte instruction.
+ //
+ // So, if we can see the upcoming halfword, we can judge on that
+ // basis, and maybe skip a whole 4-byte instruction that we don't
+ // know how to decode, without accidentally trying to interpret its
+ // second half as something else.
+ //
+ // If we don't have the instruction data available, we just have to
+ // recommend skipping the minimum sensible distance, which is 2
+ // bytes.
+ if (Bytes.size() < 2)
+ return 2;
+
+ uint16_t Insn16 = (Bytes[1] << 8) | Bytes[0];
+ return Insn16 < 0xE800 ? 2 : 4;
+}
+
DecodeStatus ARMDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
ArrayRef<uint8_t> Bytes,
uint64_t Address,
diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
new file mode 100644
index 000000000000..1985bee8e0ae
--- /dev/null
+++ b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
@@ -0,0 +1,324 @@
+//===- DXILOpBuilder.cpp - Helper class for build DIXLOp functions --------===//
+//
+// 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 class to help build DXIL op functions.
+//===----------------------------------------------------------------------===//
+
+#include "DXILOpBuilder.h"
+#include "DXILConstants.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/DXILOperationCommon.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+using namespace llvm::DXIL;
+
+constexpr StringLiteral DXILOpNamePrefix = "dx.op.";
+
+namespace {
+
+enum OverloadKind : uint16_t {
+ VOID = 1,
+ HALF = 1 << 1,
+ FLOAT = 1 << 2,
+ DOUBLE = 1 << 3,
+ I1 = 1 << 4,
+ I8 = 1 << 5,
+ I16 = 1 << 6,
+ I32 = 1 << 7,
+ I64 = 1 << 8,
+ UserDefineType = 1 << 9,
+ ObjectType = 1 << 10,
+};
+
+} // namespace
+
+static const char *getOverloadTypeName(OverloadKind Kind) {
+ switch (Kind) {
+ case OverloadKind::HALF:
+ return "f16";
+ case OverloadKind::FLOAT:
+ return "f32";
+ case OverloadKind::DOUBLE:
+ return "f64";
+ case OverloadKind::I1:
+ return "i1";
+ case OverloadKind::I8:
+ return "i8";
+ case OverloadKind::I16:
+ return "i16";
+ case OverloadKind::I32:
+ return "i32";
+ case OverloadKind::I64:
+ return "i64";
+ case OverloadKind::VOID:
+ case OverloadKind::ObjectType:
+ case OverloadKind::UserDefineType:
+ break;
+ }
+ llvm_unreachable("invalid overload type for name");
+ return "void";
+}
+
+static OverloadKind getOverloadKind(Type *Ty) {
+ Type::TypeID T = Ty->getTypeID();
+ switch (T) {
+ case Type::VoidTyID:
+ return OverloadKind::VOID;
+ case Type::HalfTyID:
+ return OverloadKind::HALF;
+ case Type::FloatTyID:
+ return OverloadKind::FLOAT;
+ case Type::DoubleTyID:
+ return OverloadKind::DOUBLE;
+ case Type::IntegerTyID: {
+ IntegerType *ITy = cast<IntegerType>(Ty);
+ unsigned Bits = ITy->getBitWidth();
+ switch (Bits) {
+ case 1:
+ return OverloadKind::I1;
+ case 8:
+ return OverloadKind::I8;
+ case 16:
+ return OverloadKind::I16;
+ case 32:
+ return OverloadKind::I32;
+ case 64:
+ return OverloadKind::I64;
+ default:
+ llvm_unreachable("invalid overload type");
+ return OverloadKind::VOID;
+ }
+ }
+ case Type::PointerTyID:
+ return OverloadKind::UserDefineType;
+ case Type::StructTyID:
+ return OverloadKind::ObjectType;
+ default:
+ llvm_unreachable("invalid overload type");
+ return OverloadKind::VOID;
+ }
+}
+
+static std::string getTypeName(OverloadKind Kind, Type *Ty) {
+ if (Kind < OverloadKind::UserDefineType) {
+ return getOverloadTypeName(Kind);
+ } else if (Kind == OverloadKind::UserDefineType) {
+ StructType *ST = cast<StructType>(Ty);
+ return ST->getStructName().str();
+ } else if (Kind == OverloadKind::ObjectType) {
+ StructType *ST = cast<StructType>(Ty);
+ return ST->getStructName().str();
+ } else {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ Ty->print(OS);
+ return OS.str();
+ }
+}
+
+// Static properties.
+struct OpCodeProperty {
+ DXIL::OpCode OpCode;
+ // Offset in DXILOpCodeNameTable.
+ unsigned OpCodeNameOffset;
+ DXIL::OpCodeClass OpCodeClass;
+ // Offset in DXILOpCodeClassNameTable.
+ unsigned OpCodeClassNameOffset;
+ uint16_t OverloadTys;
+ llvm::Attribute::AttrKind FuncAttr;
+ int OverloadParamIndex; // parameter index which control the overload.
+ // When < 0, should be only 1 overload type.
+ unsigned NumOfParameters; // Number of parameters include return value.
+ unsigned ParameterTableOffset; // Offset in ParameterTable.
+};
+
+// Include getOpCodeClassName getOpCodeProperty, getOpCodeName and
+// getOpCodeParameterKind which generated by tableGen.
+#define DXIL_OP_OPERATION_TABLE
+#include "DXILOperation.inc"
+#undef DXIL_OP_OPERATION_TABLE
+
+static std::string constructOverloadName(OverloadKind Kind, Type *Ty,
+ const OpCodeProperty &Prop) {
+ if (Kind == OverloadKind::VOID) {
+ return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop)).str();
+ }
+ return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop) + "." +
+ getTypeName(Kind, Ty))
+ .str();
+}
+
+static std::string constructOverloadTypeName(OverloadKind Kind,
+ StringRef TypeName) {
+ if (Kind == OverloadKind::VOID)
+ return TypeName.str();
+
+ assert(Kind < OverloadKind::UserDefineType && "invalid overload kind");
+ return (Twine(TypeName) + getOverloadTypeName(Kind)).str();
+}
+
+static StructType *getOrCreateStructType(StringRef Name,
+ ArrayRef<Type *> EltTys,
+ LLVMContext &Ctx) {
+ StructType *ST = StructType::getTypeByName(Ctx, Name);
+ if (ST)
+ return ST;
+
+ return StructType::create(Ctx, EltTys, Name);
+}
+
+static StructType *getResRetType(Type *OverloadTy, LLVMContext &Ctx) {
+ OverloadKind Kind = getOverloadKind(OverloadTy);
+ std::string TypeName = constructOverloadTypeName(Kind, "dx.types.ResRet.");
+ Type *FieldTypes[5] = {OverloadTy, OverloadTy, OverloadTy, OverloadTy,
+ Type::getInt32Ty(Ctx)};
+ return getOrCreateStructType(TypeName, FieldTypes, Ctx);
+}
+
+static StructType *getHandleType(LLVMContext &Ctx) {
+ return getOrCreateStructType("dx.types.Handle", Type::getInt8PtrTy(Ctx), Ctx);
+}
+
+static Type *getTypeFromParameterKind(ParameterKind Kind, Type *OverloadTy) {
+ auto &Ctx = OverloadTy->getContext();
+ switch (Kind) {
+ case ParameterKind::VOID:
+ return Type::getVoidTy(Ctx);
+ case ParameterKind::HALF:
+ return Type::getHalfTy(Ctx);
+ case ParameterKind::FLOAT:
+ return Type::getFloatTy(Ctx);
+ case ParameterKind::DOUBLE:
+ return Type::getDoubleTy(Ctx);
+ case ParameterKind::I1:
+ return Type::getInt1Ty(Ctx);
+ case ParameterKind::I8:
+ return Type::getInt8Ty(Ctx);
+ case ParameterKind::I16:
+ return Type::getInt16Ty(Ctx);
+ case ParameterKind::I32:
+ return Type::getInt32Ty(Ctx);
+ case ParameterKind::I64:
+ return Type::getInt64Ty(Ctx);
+ case ParameterKind::OVERLOAD:
+ return OverloadTy;
+ case ParameterKind::RESOURCE_RET:
+ return getResRetType(OverloadTy, Ctx);
+ case ParameterKind::DXIL_HANDLE:
+ return getHandleType(Ctx);
+ default:
+ break;
+ }
+ llvm_unreachable("Invalid parameter kind");
+ return nullptr;
+}
+
+static FunctionType *getDXILOpFunctionType(const OpCodeProperty *Prop,
+ Type *OverloadTy) {
+ SmallVector<Type *> ArgTys;
+
+ auto ParamKinds = getOpCodeParameterKind(*Prop);
+
+ for (unsigned I = 0; I < Prop->NumOfParameters; ++I) {
+ ParameterKind Kind = ParamKinds[I];
+ ArgTys.emplace_back(getTypeFromParameterKind(Kind, OverloadTy));
+ }
+ return FunctionType::get(
+ ArgTys[0], ArrayRef<Type *>(&ArgTys[1], ArgTys.size() - 1), false);
+}
+
+static FunctionCallee getOrCreateDXILOpFunction(DXIL::OpCode DXILOp,
+ Type *OverloadTy, Module &M) {
+ const OpCodeProperty *Prop = getOpCodeProperty(DXILOp);
+
+ OverloadKind Kind = getOverloadKind(OverloadTy);
+ // FIXME: find the issue and report error in clang instead of check it in
+ // backend.
+ if ((Prop->OverloadTys & (uint16_t)Kind) == 0) {
+ llvm_unreachable("invalid overload");
+ }
+
+ std::string FnName = constructOverloadName(Kind, OverloadTy, *Prop);
+ // Dependent on name to dedup.
+ if (auto *Fn = M.getFunction(FnName))
+ return FunctionCallee(Fn);
+
+ FunctionType *DXILOpFT = getDXILOpFunctionType(Prop, OverloadTy);
+ return M.getOrInsertFunction(FnName, DXILOpFT);
+}
+
+namespace llvm {
+namespace DXIL {
+
+CallInst *DXILOpBuilder::createDXILOpCall(DXIL::OpCode OpCode, Type *OverloadTy,
+ llvm::iterator_range<Use *> Args) {
+ auto Fn = getOrCreateDXILOpFunction(OpCode, OverloadTy, M);
+ SmallVector<Value *> FullArgs;
+ FullArgs.emplace_back(B.getInt32((int32_t)OpCode));
+ FullArgs.append(Args.begin(), Args.end());
+ return B.CreateCall(Fn, FullArgs);
+}
+
+Type *DXILOpBuilder::getOverloadTy(DXIL::OpCode OpCode, FunctionType *FT,
+ bool NoOpCodeParam) {
+
+ const OpCodeProperty *Prop = getOpCodeProperty(OpCode);
+ if (Prop->OverloadParamIndex < 0) {
+ auto &Ctx = FT->getContext();
+ // When only has 1 overload type, just return it.
+ switch (Prop->OverloadTys) {
+ case OverloadKind::VOID:
+ return Type::getVoidTy(Ctx);
+ case OverloadKind::HALF:
+ return Type::getHalfTy(Ctx);
+ case OverloadKind::FLOAT:
+ return Type::getFloatTy(Ctx);
+ case OverloadKind::DOUBLE:
+ return Type::getDoubleTy(Ctx);
+ case OverloadKind::I1:
+ return Type::getInt1Ty(Ctx);
+ case OverloadKind::I8:
+ return Type::getInt8Ty(Ctx);
+ case OverloadKind::I16:
+ return Type::getInt16Ty(Ctx);
+ case OverloadKind::I32:
+ return Type::getInt32Ty(Ctx);
+ case OverloadKind::I64:
+ return Type::getInt64Ty(Ctx);
+ default:
+ llvm_unreachable("invalid overload type");
+ return nullptr;
+ }
+ }
+
+ // Prop->OverloadParamIndex is 0, overload type is FT->getReturnType().
+ Type *OverloadType = FT->getReturnType();
+ if (Prop->OverloadParamIndex != 0) {
+ // Skip Return Type and Type for DXIL opcode.
+ const unsigned SkipedParam = NoOpCodeParam ? 2 : 1;
+ OverloadType = FT->getParamType(Prop->OverloadParamIndex - SkipedParam);
+ }
+
+ auto ParamKinds = getOpCodeParameterKind(*Prop);
+ auto Kind = ParamKinds[Prop->OverloadParamIndex];
+ // For ResRet and CBufferRet, OverloadTy is in field of StructType.
+ if (Kind == ParameterKind::CBUFFER_RET ||
+ Kind == ParameterKind::RESOURCE_RET) {
+ auto *ST = cast<StructType>(OverloadType);
+ OverloadType = ST->getElementType(0);
+ }
+ return OverloadType;
+}
+
+const char *DXILOpBuilder::getOpCodeName(DXIL::OpCode DXILOp) {
+ return ::getOpCodeName(DXILOp);
+}
+} // namespace DXIL
+} // namespace llvm
diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.h b/llvm/lib/Target/DirectX/DXILOpBuilder.h
new file mode 100644
index 000000000000..0cc39e845b71
--- /dev/null
+++ b/llvm/lib/Target/DirectX/DXILOpBuilder.h
@@ -0,0 +1,46 @@
+//===- DXILOpBuilder.h - Helper class for build DIXLOp functions ----------===//
+//
+// 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 class to help build DXIL op functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_DIRECTX_DXILOPBUILDER_H
+#define LLVM_LIB_TARGET_DIRECTX_DXILOPBUILDER_H
+
+#include "DXILConstants.h"
+#include "llvm/ADT/iterator_range.h"
+
+namespace llvm {
+class Module;
+class IRBuilderBase;
+class CallInst;
+class Value;
+class Type;
+class FunctionType;
+class Use;
+
+namespace DXIL {
+
+class DXILOpBuilder {
+public:
+ DXILOpBuilder(Module &M, IRBuilderBase &B) : M(M), B(B) {}
+ CallInst *createDXILOpCall(DXIL::OpCode OpCode, Type *OverloadTy,
+ llvm::iterator_range<Use *> Args);
+ Type *getOverloadTy(DXIL::OpCode OpCode, FunctionType *FT,
+ bool NoOpCodeParam);
+ static const char *getOpCodeName(DXIL::OpCode DXILOp);
+
+private:
+ Module &M;
+ IRBuilderBase &B;
+};
+
+} // namespace DXIL
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index 11b89e4ec890..20c08f47745d 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "DXILConstants.h"
+#include "DXILOpBuilder.h"
#include "DirectX.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/Passes.h"
@@ -28,168 +29,12 @@
using namespace llvm;
using namespace llvm::DXIL;
-constexpr StringLiteral DXILOpNamePrefix = "dx.op.";
-
-enum OverloadKind : uint16_t {
- VOID = 1,
- HALF = 1 << 1,
- FLOAT = 1 << 2,
- DOUBLE = 1 << 3,
- I1 = 1 << 4,
- I8 = 1 << 5,
- I16 = 1 << 6,
- I32 = 1 << 7,
- I64 = 1 << 8,
- UserDefineType = 1 << 9,
- ObjectType = 1 << 10,
-};
-
-static const char *getOverloadTypeName(OverloadKind Kind) {
- switch (Kind) {
- case OverloadKind::HALF:
- return "f16";
- case OverloadKind::FLOAT:
- return "f32";
- case OverloadKind::DOUBLE:
- return "f64";
- case OverloadKind::I1:
- return "i1";
- case OverloadKind::I8:
- return "i8";
- case OverloadKind::I16:
- return "i16";
- case OverloadKind::I32:
- return "i32";
- case OverloadKind::I64:
- return "i64";
- case OverloadKind::VOID:
- case OverloadKind::ObjectType:
- case OverloadKind::UserDefineType:
- break;
- }
- llvm_unreachable("invalid overload type for name");
- return "void";
-}
-
-static OverloadKind getOverloadKind(Type *Ty) {
- Type::TypeID T = Ty->getTypeID();
- switch (T) {
- case Type::VoidTyID:
- return OverloadKind::VOID;
- case Type::HalfTyID:
- return OverloadKind::HALF;
- case Type::FloatTyID:
- return OverloadKind::FLOAT;
- case Type::DoubleTyID:
- return OverloadKind::DOUBLE;
- case Type::IntegerTyID: {
- IntegerType *ITy = cast<IntegerType>(Ty);
- unsigned Bits = ITy->getBitWidth();
- switch (Bits) {
- case 1:
- return OverloadKind::I1;
- case 8:
- return OverloadKind::I8;
- case 16:
- return OverloadKind::I16;
- case 32:
- return OverloadKind::I32;
- case 64:
- return OverloadKind::I64;
- default:
- llvm_unreachable("invalid overload type");
- return OverloadKind::VOID;
- }
- }
- case Type::PointerTyID:
- return OverloadKind::UserDefineType;
- case Type::StructTyID:
- return OverloadKind::ObjectType;
- default:
- llvm_unreachable("invalid overload type");
- return OverloadKind::VOID;
- }
-}
-
-static std::string getTypeName(OverloadKind Kind, Type *Ty) {
- if (Kind < OverloadKind::UserDefineType) {
- return getOverloadTypeName(Kind);
- } else if (Kind == OverloadKind::UserDefineType) {
- StructType *ST = cast<StructType>(Ty);
- return ST->getStructName().str();
- } else if (Kind == OverloadKind::ObjectType) {
- StructType *ST = cast<StructType>(Ty);
- return ST->getStructName().str();
- } else {
- std::string Str;
- raw_string_ostream OS(Str);
- Ty->print(OS);
- return OS.str();
- }
-}
-
-// Static properties.
-struct OpCodeProperty {
- DXIL::OpCode OpCode;
- // Offset in DXILOpCodeNameTable.
- unsigned OpCodeNameOffset;
- DXIL::OpCodeClass OpCodeClass;
- // Offset in DXILOpCodeClassNameTable.
- unsigned OpCodeClassNameOffset;
- uint16_t OverloadTys;
- llvm::Attribute::AttrKind FuncAttr;
-};
-
-// Include getOpCodeClassName getOpCodeProperty and getOpCodeName which
-// generated by tableGen.
-#define DXIL_OP_OPERATION_TABLE
-#include "DXILOperation.inc"
-#undef DXIL_OP_OPERATION_TABLE
-
-static std::string constructOverloadName(OverloadKind Kind, Type *Ty,
- const OpCodeProperty &Prop) {
- if (Kind == OverloadKind::VOID) {
- return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop)).str();
- }
- return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop) + "." +
- getTypeName(Kind, Ty))
- .str();
-}
-
-static FunctionCallee createDXILOpFunction(DXIL::OpCode DXILOp, Function &F,
- Module &M) {
- const OpCodeProperty *Prop = getOpCodeProperty(DXILOp);
-
- // Get return type as overload type for DXILOp.
- // Only simple mapping case here, so return type is good enough.
- Type *OverloadTy = F.getReturnType();
-
- OverloadKind Kind = getOverloadKind(OverloadTy);
- // FIXME: find the issue and report error in clang instead of check it in
- // backend.
- if ((Prop->OverloadTys & (uint16_t)Kind) == 0) {
- llvm_unreachable("invalid overload");
- }
-
- std::string FnName = constructOverloadName(Kind, OverloadTy, *Prop);
- assert(!M.getFunction(FnName) && "Function already exists");
-
- auto &Ctx = M.getContext();
- Type *OpCodeTy = Type::getInt32Ty(Ctx);
-
- SmallVector<Type *> ArgTypes;
- // DXIL has i32 opcode as first arg.
- ArgTypes.emplace_back(OpCodeTy);
- FunctionType *FT = F.getFunctionType();
- ArgTypes.append(FT->param_begin(), FT->param_end());
- FunctionType *DXILOpFT = FunctionType::get(OverloadTy, ArgTypes, false);
- return M.getOrInsertFunction(FnName, DXILOpFT);
-}
-
static void lowerIntrinsic(DXIL::OpCode DXILOp, Function &F, Module &M) {
- auto DXILOpFn = createDXILOpFunction(DXILOp, F, M);
IRBuilder<> B(M.getContext());
Value *DXILOpArg = B.getInt32(static_cast<unsigned>(DXILOp));
+ DXILOpBuilder DXILB(M, B);
+ Type *OverloadTy =
+ DXILB.getOverloadTy(DXILOp, F.getFunctionType(), /*NoOpCodeParam*/ true);
for (User *U : make_early_inc_range(F.users())) {
CallInst *CI = dyn_cast<CallInst>(U);
if (!CI)
@@ -199,8 +44,8 @@ static void lowerIntrinsic(DXIL::OpCode DXILOp, Function &F, Module &M) {
Args.emplace_back(DXILOpArg);
Args.append(CI->arg_begin(), CI->arg_end());
B.SetInsertPoint(CI);
- CallInst *DXILCI = B.CreateCall(DXILOpFn, Args);
- LLVM_DEBUG(DXILCI->setName(getOpCodeName(DXILOp)));
+ CallInst *DXILCI = DXILB.createDXILOpCall(DXILOp, OverloadTy, CI->args());
+
CI->replaceAllUsesWith(DXILCI);
CI->eraseFromParent();
}
diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp
index e2a41515de38..a873662f730d 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp
@@ -260,9 +260,7 @@ static void predictValueUseListOrderImpl(const Value *V, const Function *F,
return LU->getOperandNo() > RU->getOperandNo();
});
- if (llvm::is_sorted(List, [](const Entry &L, const Entry &R) {
- return L.second < R.second;
- }))
+ if (llvm::is_sorted(List, llvm::less_second()))
// Order is already correct.
return;
diff --git a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h
index 1e50385a7b4b..505c90f66f43 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h
+++ b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h
@@ -95,7 +95,6 @@ public:
void SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl);
void SelectStore(SDNode *N);
void SelectSHL(SDNode *N);
- void SelectZeroExtend(SDNode *N);
void SelectIntrinsicWChain(SDNode *N);
void SelectIntrinsicWOChain(SDNode *N);
void SelectConstant(SDNode *N);
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
index 9561dfe8a35d..1dc6a4cb9c89 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
@@ -107,9 +107,6 @@ class HexagonTargetLowering : public TargetLowering {
const HexagonTargetMachine &HTM;
const HexagonSubtarget &Subtarget;
- bool CanReturnSmallStruct(const Function* CalleeFn, unsigned& RetSize)
- const;
-
public:
explicit HexagonTargetLowering(const TargetMachine &TM,
const HexagonSubtarget &ST);
diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
index c8e6276aa4de..b8671f26d124 100644
--- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
@@ -2253,15 +2253,6 @@ bool HexagonInstrInfo::isDuplexPair(const MachineInstr &MIa,
return (isDuplexPairMatch(MIaG, MIbG) || isDuplexPairMatch(MIbG, MIaG));
}
-bool HexagonInstrInfo::isEarlySourceInstr(const MachineInstr &MI) const {
- if (MI.mayLoadOrStore() || MI.isCompare())
- return true;
-
- // Multiply
- unsigned SchedClass = MI.getDesc().getSchedClass();
- return is_TC4x(SchedClass) || is_TC3x(SchedClass);
-}
-
bool HexagonInstrInfo::isEndLoopN(unsigned Opcode) const {
return (Opcode == Hexagon::ENDLOOP0 ||
Opcode == Hexagon::ENDLOOP1);
@@ -2417,43 +2408,6 @@ bool HexagonInstrInfo::isJumpWithinBranchRange(const MachineInstr &MI,
}
}
-bool HexagonInstrInfo::isLateInstrFeedsEarlyInstr(const MachineInstr &LRMI,
- const MachineInstr &ESMI) const {
- bool isLate = isLateResultInstr(LRMI);
- bool isEarly = isEarlySourceInstr(ESMI);
-
- LLVM_DEBUG(dbgs() << "V60" << (isLate ? "-LR " : " -- "));
- LLVM_DEBUG(LRMI.dump());
- LLVM_DEBUG(dbgs() << "V60" << (isEarly ? "-ES " : " -- "));
- LLVM_DEBUG(ESMI.dump());
-
- if (isLate && isEarly) {
- LLVM_DEBUG(dbgs() << "++Is Late Result feeding Early Source\n");
- return true;
- }
-
- return false;
-}
-
-bool HexagonInstrInfo::isLateResultInstr(const MachineInstr &MI) const {
- switch (MI.getOpcode()) {
- case TargetOpcode::EXTRACT_SUBREG:
- case TargetOpcode::INSERT_SUBREG:
- case TargetOpcode::SUBREG_TO_REG:
- case TargetOpcode::REG_SEQUENCE:
- case TargetOpcode::IMPLICIT_DEF:
- case TargetOpcode::COPY:
- case TargetOpcode::INLINEASM:
- case TargetOpcode::PHI:
- return false;
- default:
- break;
- }
-
- unsigned SchedClass = MI.getDesc().getSchedClass();
- return !is_TC1(SchedClass);
-}
-
bool HexagonInstrInfo::isLateSourceInstr(const MachineInstr &MI) const {
// Instructions with iclass A_CVI_VX and attribute A_CVI_LATE uses a multiply
// resource, but all operands can be received late like an ALU instruction.
diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h
index 2af09c857d86..703a894132bb 100644
--- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h
+++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h
@@ -363,7 +363,6 @@ public:
bool isDotCurInst(const MachineInstr &MI) const;
bool isDotNewInst(const MachineInstr &MI) const;
bool isDuplexPair(const MachineInstr &MIa, const MachineInstr &MIb) const;
- bool isEarlySourceInstr(const MachineInstr &MI) const;
bool isEndLoopN(unsigned Opcode) const;
bool isExpr(unsigned OpType) const;
bool isExtendable(const MachineInstr &MI) const;
@@ -375,9 +374,6 @@ public:
bool isIndirectL4Return(const MachineInstr &MI) const;
bool isJumpR(const MachineInstr &MI) const;
bool isJumpWithinBranchRange(const MachineInstr &MI, unsigned offset) const;
- bool isLateInstrFeedsEarlyInstr(const MachineInstr &LRMI,
- const MachineInstr &ESMI) const;
- bool isLateResultInstr(const MachineInstr &MI) const;
bool isLateSourceInstr(const MachineInstr &MI) const;
bool isLoopN(const MachineInstr &MI) const;
bool isMemOp(const MachineInstr &MI) const;
diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
index d11f5a9080a0..9793c7bc3532 100644
--- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
+++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
@@ -248,7 +248,7 @@ public:
addExpr(Inst, getImm());
}
};
-} // end anonymous namespace
+} // end namespace
#define GET_REGISTER_MATCHER
#define GET_SUBTARGET_FEATURE_NAME
diff --git a/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp b/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp
index 215d061f11f2..beb757c78596 100644
--- a/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp
+++ b/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp
@@ -39,7 +39,7 @@ public:
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &CStream) const override;
};
-} // end anonymous namespace
+} // end namespace
static MCDisassembler *createLoongArchDisassembler(const Target &T,
const MCSubtargetInfo &STI,
diff --git a/llvm/lib/Target/LoongArch/LoongArch.h b/llvm/lib/Target/LoongArch/LoongArch.h
index caa7bd31e28b..e6c9c24dd1b2 100644
--- a/llvm/lib/Target/LoongArch/LoongArch.h
+++ b/llvm/lib/Target/LoongArch/LoongArch.h
@@ -33,6 +33,6 @@ bool lowerLoongArchMachineOperandToMCOperand(const MachineOperand &MO,
const AsmPrinter &AP);
FunctionPass *createLoongArchISelDag(LoongArchTargetMachine &TM);
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_LOONGARCH_H
diff --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
index 014b666de711..72d8e006a0bb 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
@@ -52,5 +52,5 @@ private:
const DebugLoc &DL, Register DestReg, Register SrcReg,
int64_t Val, MachineInstr::MIFlag Flag) const;
};
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_LOONGARCHFRAMELOWERING_H
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h
index 7ad329a64424..8c9357d75979 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h
@@ -55,6 +55,6 @@ public:
#include "LoongArchGenDAGISel.inc"
};
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_LOONGARCHISELDAGTODAG_H
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 279550482675..141f1fd3a55d 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -45,7 +45,7 @@ enum NodeType : unsigned {
BSTRPICK,
};
-} // namespace LoongArchISD
+} // end namespace LoongArchISD
class LoongArchTargetLowering : public TargetLowering {
const LoongArchSubtarget &Subtarget;
diff --git a/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.h b/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.h
index 02c9156e2b87..cca130c3bc3a 100644
--- a/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.h
+++ b/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.h
@@ -45,6 +45,6 @@ struct LoongArchRegisterInfo : public LoongArchGenRegisterInfo {
Register getFrameRegister(const MachineFunction &MF) const override;
};
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_LOONGARCHREGISTERINFO_H
diff --git a/llvm/lib/Target/LoongArch/LoongArchSubtarget.h b/llvm/lib/Target/LoongArch/LoongArchSubtarget.h
index 95c2c676cc3c..fbe7a176b371 100644
--- a/llvm/lib/Target/LoongArch/LoongArchSubtarget.h
+++ b/llvm/lib/Target/LoongArch/LoongArchSubtarget.h
@@ -84,6 +84,6 @@ public:
unsigned getGRLen() const { return GRLen; }
LoongArchABI::ABI getTargetABI() const { return TargetABI; }
};
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_LOONGARCHSUBTARGET_H
diff --git a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp
index 2d08d5c674bc..7ba5848e0997 100644
--- a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp
@@ -103,7 +103,7 @@ public:
void addIRPasses() override;
bool addInstSelector() override;
};
-} // namespace
+} // end namespace
TargetPassConfig *
LoongArchTargetMachine::createPassConfig(PassManagerBase &PM) {
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h
index 77bbfb095747..a5f0b816c972 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h
@@ -58,6 +58,6 @@ public:
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override;
};
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHASMBACKEND_H
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp
index f0c985883125..de2ba2833414 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp
@@ -35,6 +35,6 @@ ABI getTargetABI(StringRef ABIName) {
// FIXME: other register?
MCRegister getBPReg() { return LoongArch::R31; }
-} // namespace LoongArchABI
+} // end namespace LoongArchABI
-} // namespace llvm
+} // end namespace llvm
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
index e26f22de0cbc..fee247a0c02c 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
@@ -37,8 +37,8 @@ ABI getTargetABI(StringRef ABIName);
// Returns the register used to hold the stack pointer after realignment.
MCRegister getBPReg();
-} // namespace LoongArchABI
+} // end namespace LoongArchABI
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHBASEINFO_H
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
index 95e1314f363a..1850b0d8a756 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
@@ -33,7 +33,7 @@ protected:
unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
const MCFixup &Fixup, bool IsPCRel) const override;
};
-} // namespace
+} // end namespace
LoongArchELFObjectWriter::LoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit)
: MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_LOONGARCH,
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.h
index 727fc6a3e1f3..0cbb3d73cd03 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.h
@@ -44,6 +44,6 @@ private:
void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
raw_ostream &O);
};
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHINSTPRINTER_H
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.h
index 1cf8a2fdf8aa..ed1abbf46153 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.h
@@ -25,6 +25,6 @@ public:
explicit LoongArchMCAsmInfo(const Triple &TargetTriple);
};
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHMCASMINFO_H
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
index 9c6a4f39b9ea..01a370a90403 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
@@ -69,7 +69,7 @@ public:
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
};
-} // end anonymous namespace
+} // end namespace
unsigned
LoongArchMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp
index e50761ab1e27..8d71235f6a81 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp
@@ -95,7 +95,7 @@ public:
}
};
-} // end anonymous namespace
+} // end namespace
static MCInstrAnalysis *createLoongArchInstrAnalysis(const MCInstrInfo *Info) {
return new LoongArchMCInstrAnalysis(Info);
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.h
index a606ccdbc47c..ab35a0096c8a 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.h
@@ -38,7 +38,7 @@ MCAsmBackend *createLoongArchAsmBackend(const Target &T,
std::unique_ptr<MCObjectTargetWriter>
createLoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit);
-} // namespace llvm
+} // end namespace llvm
// Defines symbolic names for LoongArch registers.
#define GET_REGINFO_ENUM
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.h
index 945aa91e40c0..be1b425894de 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.h
@@ -24,7 +24,7 @@ using InstSeq = SmallVector<Inst, 4>;
// Helper to generate an instruction sequence that will materialise the given
// immediate value into a register.
InstSeq generateInstSeq(int64_t Val);
-} // namespace LoongArchMatInt
-} // namespace llvm
+} // end namespace LoongArchMatInt
+} // end namespace llvm
#endif
diff --git a/llvm/lib/Target/LoongArch/TargetInfo/LoongArchTargetInfo.h b/llvm/lib/Target/LoongArch/TargetInfo/LoongArchTargetInfo.h
index 6fc13d52c065..b24cf879512c 100644
--- a/llvm/lib/Target/LoongArch/TargetInfo/LoongArchTargetInfo.h
+++ b/llvm/lib/Target/LoongArch/TargetInfo/LoongArchTargetInfo.h
@@ -16,6 +16,6 @@ class Target;
Target &getTheLoongArch32Target();
Target &getTheLoongArch64Target();
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LOONGARCH_TARGETINFO_LOONGARCHTARGETINFO_H
diff --git a/llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp b/llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp
index cb6d53ec0a12..5dc2bf07ddd5 100644
--- a/llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp
@@ -31,8 +31,8 @@ public:
: CombinerInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,
/*LegalizerInfo*/ nullptr, /*EnableOpt*/ false,
/*EnableOptSize*/ false, /*EnableMinSize*/ false) {}
- virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
- MachineIRBuilder &B) const override;
+ bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
+ MachineIRBuilder &B) const override;
};
bool MipsPreLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp
index b700a9ede39b..a19253da440e 100644
--- a/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/PatternMatch.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
@@ -81,6 +82,20 @@ bool RISCVCodeGenPrepare::optimizeZExt(ZExtInst *ZExt) {
return true;
}
+ // Convert (zext (abs(i32 X, i1 1))) -> (sext (abs(i32 X, i1 1))). If abs of
+ // INT_MIN is poison, the sign bit is zero.
+ using namespace PatternMatch;
+ if (match(Src, m_Intrinsic<Intrinsic::abs>(m_Value(), m_One()))) {
+ auto *SExt = new SExtInst(Src, ZExt->getType(), "", ZExt);
+ SExt->takeName(ZExt);
+ SExt->setDebugLoc(ZExt->getDebugLoc());
+
+ ZExt->replaceAllUsesWith(SExt);
+ ZExt->eraseFromParent();
+ ++NumZExtToSExt;
+ return true;
+ }
+
return false;
}
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 1702546b58a6..baa19e81e436 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -1313,6 +1313,25 @@ bool RISCVTargetLowering::shouldSinkOperands(
return true;
}
+bool RISCVTargetLowering::shouldScalarizeBinop(SDValue VecOp) const {
+ unsigned Opc = VecOp.getOpcode();
+
+ // Assume target opcodes can't be scalarized.
+ // TODO - do we have any exceptions?
+ if (Opc >= ISD::BUILTIN_OP_END)
+ return false;
+
+ // If the vector op is not supported, try to convert to scalar.
+ EVT VecVT = VecOp.getValueType();
+ if (!isOperationLegalOrCustomOrPromote(Opc, VecVT))
+ return true;
+
+ // If the vector op is supported, but the scalar op is not, the transform may
+ // not be worthwhile.
+ EVT ScalarVT = VecVT.getScalarType();
+ return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
+}
+
bool RISCVTargetLowering::isOffsetFoldingLegal(
const GlobalAddressSDNode *GA) const {
// In order to maximise the opportunity for common subexpression elimination,
@@ -1387,18 +1406,28 @@ static void translateSetCCForBranch(const SDLoc &DL, SDValue &LHS, SDValue &RHS,
}
}
- // Convert X > -1 to X >= 0.
- if (CC == ISD::SETGT && isAllOnesConstant(RHS)) {
- RHS = DAG.getConstant(0, DL, RHS.getValueType());
- CC = ISD::SETGE;
- return;
- }
- // Convert X < 1 to 0 >= X.
- if (CC == ISD::SETLT && isOneConstant(RHS)) {
- RHS = LHS;
- LHS = DAG.getConstant(0, DL, RHS.getValueType());
- CC = ISD::SETGE;
- return;
+ if (auto *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
+ int64_t C = RHSC->getSExtValue();
+ switch (CC) {
+ default: break;
+ case ISD::SETGT:
+ // Convert X > -1 to X >= 0.
+ if (C == -1) {
+ RHS = DAG.getConstant(0, DL, RHS.getValueType());
+ CC = ISD::SETGE;
+ return;
+ }
+ break;
+ case ISD::SETLT:
+ // Convert X < 1 to 0 <= X.
+ if (C == 1) {
+ RHS = LHS;
+ LHS = DAG.getConstant(0, DL, RHS.getValueType());
+ CC = ISD::SETGE;
+ return;
+ }
+ break;
+ }
}
switch (CC) {
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index 5e15176de59c..6ecf8b8324d4 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -376,6 +376,7 @@ public:
SelectionDAG &DAG) const override;
bool shouldSinkOperands(Instruction *I,
SmallVectorImpl<Use *> &Ops) const override;
+ bool shouldScalarizeBinop(SDValue VecOp) const override;
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
bool isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const override;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
index 4aa9ded5b3a2..beb49f5f6249 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
@@ -134,14 +134,13 @@ public:
getSerializableDirectMachineOperandTargetFlags() const override;
// Return true if the function can safely be outlined from.
- virtual bool
- isFunctionSafeToOutlineFrom(MachineFunction &MF,
- bool OutlineFromLinkOnceODRs) const override;
+ bool isFunctionSafeToOutlineFrom(MachineFunction &MF,
+ bool OutlineFromLinkOnceODRs) const override;
// Return true if MBB is safe to outline from, and return any target-specific
// information in Flags.
- virtual bool isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
- unsigned &Flags) const override;
+ bool isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
+ unsigned &Flags) const override;
bool shouldOutlineFromFunctionByDefault(MachineFunction &MF) const override;
@@ -150,17 +149,15 @@ public:
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const override;
// Return if/how a given MachineInstr should be outlined.
- virtual outliner::InstrType
- getOutliningType(MachineBasicBlock::iterator &MBBI,
- unsigned Flags) const override;
+ outliner::InstrType getOutliningType(MachineBasicBlock::iterator &MBBI,
+ unsigned Flags) const override;
// Insert a custom frame for outlined functions.
- virtual void
- buildOutlinedFrame(MachineBasicBlock &MBB, MachineFunction &MF,
- const outliner::OutlinedFunction &OF) const override;
+ void buildOutlinedFrame(MachineBasicBlock &MBB, MachineFunction &MF,
+ const outliner::OutlinedFunction &OF) const override;
// Insert a call to an outlined function into a given basic block.
- virtual MachineBasicBlock::iterator
+ MachineBasicBlock::iterator
insertOutlinedCall(Module &M, MachineBasicBlock &MBB,
MachineBasicBlock::iterator &It, MachineFunction &MF,
outliner::Candidate &C) const override;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
index d204c85d6179..cd1da4360002 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
@@ -696,52 +696,36 @@ def C_SRAI64_HINT : RVInst16CI<0b100, 0b01, (outs GPRC:$rd_wb),
//===----------------------------------------------------------------------===//
let EmitPriority = 0 in {
-let Predicates = [HasStdExtC, HasStdExtD] in
-def : InstAlias<"c.fld $rd, (${rs1})", (C_FLD FPR64C:$rd, GPRC:$rs1, 0)>;
-
+let Predicates = [HasStdExtC] in {
def : InstAlias<"c.lw $rd, (${rs1})", (C_LW GPRC:$rd, GPRC:$rs1, 0)>;
-
-let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in
-def : InstAlias<"c.flw $rd, (${rs1})", (C_FLW FPR32C:$rd, GPRC:$rs1, 0)>;
-
-let Predicates = [HasStdExtC, IsRV64] in
-def : InstAlias<"c.ld $rd, (${rs1})", (C_LD GPRC:$rd, GPRC:$rs1, 0)>;
-
-let Predicates = [HasStdExtC, HasStdExtD] in
-def : InstAlias<"c.fsd $rs2, (${rs1})", (C_FSD FPR64C:$rs2, GPRC:$rs1, 0)>;
-
def : InstAlias<"c.sw $rs2, (${rs1})", (C_SW GPRC:$rs2, GPRC:$rs1, 0)>;
-
-let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in
-def : InstAlias<"c.fsw $rs2, (${rs1})", (C_FSW FPR32C:$rs2, GPRC:$rs1, 0)>;
-
-let Predicates = [HasStdExtC, IsRV64] in
-def : InstAlias<"c.sd $rs2, (${rs1})", (C_SD GPRC:$rs2, GPRC:$rs1, 0)>;
-
-let Predicates = [HasStdExtC, HasStdExtD] in
-def : InstAlias<"c.fldsp $rd, (${rs1})", (C_FLDSP FPR64C:$rd, SP:$rs1, 0)>;
-
def : InstAlias<"c.lwsp $rd, (${rs1})", (C_LWSP GPRC:$rd, SP:$rs1, 0)>;
+def : InstAlias<"c.swsp $rs2, (${rs1})", (C_SWSP GPRC:$rs2, SP:$rs1, 0)>;
+}
-let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in
-def : InstAlias<"c.flwsp $rd, (${rs1})", (C_FLWSP FPR32C:$rd, SP:$rs1, 0)>;
-
-let Predicates = [HasStdExtC, IsRV64] in
+let Predicates = [HasStdExtC, IsRV64] in {
+def : InstAlias<"c.ld $rd, (${rs1})", (C_LD GPRC:$rd, GPRC:$rs1, 0)>;
+def : InstAlias<"c.sd $rs2, (${rs1})", (C_SD GPRC:$rs2, GPRC:$rs1, 0)>;
def : InstAlias<"c.ldsp $rd, (${rs1})", (C_LDSP GPRC:$rd, SP:$rs1, 0)>;
+def : InstAlias<"c.sdsp $rs2, (${rs1})", (C_SDSP GPRC:$rs2, SP:$rs1, 0)>;
+}
-let Predicates = [HasStdExtC, HasStdExtD] in
-def : InstAlias<"c.fsdsp $rs2, (${rs1})", (C_FSDSP FPR64C:$rs2, SP:$rs1, 0)>;
-
-def : InstAlias<"c.swsp $rs2, (${rs1})", (C_SWSP GPRC:$rs2, SP:$rs1, 0)>;
-
-let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in
+let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in {
+def : InstAlias<"c.flw $rd, (${rs1})", (C_FLW FPR32C:$rd, GPRC:$rs1, 0)>;
+def : InstAlias<"c.fsw $rs2, (${rs1})", (C_FSW FPR32C:$rs2, GPRC:$rs1, 0)>;
+def : InstAlias<"c.flwsp $rd, (${rs1})", (C_FLWSP FPR32C:$rd, SP:$rs1, 0)>;
def : InstAlias<"c.fswsp $rs2, (${rs1})", (C_FSWSP FPR32C:$rs2, SP:$rs1, 0)>;
+}
-let Predicates = [HasStdExtC, IsRV64] in
-def : InstAlias<"c.sdsp $rs2, (${rs1})", (C_SDSP GPRC:$rs2, SP:$rs1, 0)>;
+let Predicates = [HasStdExtC, HasStdExtD] in {
+def : InstAlias<"c.fld $rd, (${rs1})", (C_FLD FPR64C:$rd, GPRC:$rs1, 0)>;
+def : InstAlias<"c.fsd $rs2, (${rs1})", (C_FSD FPR64C:$rs2, GPRC:$rs1, 0)>;
+def : InstAlias<"c.fldsp $rd, (${rs1})", (C_FLDSP FPR64C:$rd, SP:$rs1, 0)>;
+def : InstAlias<"c.fsdsp $rs2, (${rs1})", (C_FSDSP FPR64C:$rs2, SP:$rs1, 0)>;
}
+} // EmitPriority = 0
-//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===/i
// Compress Instruction tablegen backend.
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.h b/llvm/lib/Target/RISCV/RISCVTargetMachine.h
index 087646fb5ed9..4b2a403c5c5b 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.h
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.h
@@ -44,8 +44,7 @@ public:
TargetTransformInfo getTargetTransformInfo(const Function &F) const override;
- virtual bool isNoopAddrSpaceCast(unsigned SrcAS,
- unsigned DstAS) const override;
+ bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DstAS) const override;
yaml::MachineFunctionInfo *createDefaultFuncInfoYAML() const override;
yaml::MachineFunctionInfo *
diff --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
index 93ffa9847f06..db0936f3f56b 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
@@ -81,25 +81,22 @@ public:
/// Particular to z/OS when in 64 bit mode
class SystemZXPLINK64Registers : public SystemZCallingConventionRegisters {
public:
- int getReturnFunctionAddressRegister() override final {
- return SystemZ::R7D;
- };
+ int getReturnFunctionAddressRegister() final { return SystemZ::R7D; };
- int getStackPointerRegister() override final { return SystemZ::R4D; };
+ int getStackPointerRegister() final { return SystemZ::R4D; };
- int getFramePointerRegister() override final { return SystemZ::R8D; };
+ int getFramePointerRegister() final { return SystemZ::R8D; };
int getAddressOfCalleeRegister() { return SystemZ::R6D; };
- const MCPhysReg *
- getCalleeSavedRegs(const MachineFunction *MF) const override final;
+ const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const final;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
- CallingConv::ID CC) const override final;
+ CallingConv::ID CC) const final;
- int getCallFrameSize() override final { return 128; }
+ int getCallFrameSize() final { return 128; }
- int getStackPointerBias() override final { return 2048; }
+ int getStackPointerBias() final { return 2048; }
/// Destroys the object. Bogus destructor overriding base class destructor
~SystemZXPLINK64Registers() = default;
@@ -109,23 +106,20 @@ public:
/// Particular when on zLinux in 64 bit mode
class SystemZELFRegisters : public SystemZCallingConventionRegisters {
public:
- int getReturnFunctionAddressRegister() override final {
- return SystemZ::R14D;
- };
+ int getReturnFunctionAddressRegister() final { return SystemZ::R14D; };
- int getStackPointerRegister() override final { return SystemZ::R15D; };
+ int getStackPointerRegister() final { return SystemZ::R15D; };
- int getFramePointerRegister() override final { return SystemZ::R11D; };
+ int getFramePointerRegister() final { return SystemZ::R11D; };
- const MCPhysReg *
- getCalleeSavedRegs(const MachineFunction *MF) const override final;
+ const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const final;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
- CallingConv::ID CC) const override final;
+ CallingConv::ID CC) const final;
- int getCallFrameSize() override final { return SystemZMC::ELFCallFrameSize; }
+ int getCallFrameSize() final { return SystemZMC::ELFCallFrameSize; }
- int getStackPointerBias() override final { return 0; }
+ int getStackPointerBias() final { return 0; }
/// Destroys the object. Bogus destructor overriding base class destructor
~SystemZELFRegisters() = default;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 2636acaf1604..ab6d6b4f7ef1 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -577,8 +577,9 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
CallParams.removeOperand(0);
// For funcrefs, call_indirect is done through __funcref_call_table and the
- // funcref is always installed in slot 0 of the table, therefore instead of having
- // the function pointer added at the end of the params list, a zero (the index in
+ // funcref is always installed in slot 0 of the table, therefore instead of
+ // having the function pointer added at the end of the params list, a zero
+ // (the index in
// __funcref_call_table is added).
if (IsFuncrefCall) {
Register RegZero =
@@ -1156,7 +1157,7 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
// If the callee is a GlobalAddress node (quite common, every direct call
// is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
// doesn't at MO_GOT which is not needed for direct calls.
- GlobalAddressSDNode* GA = cast<GlobalAddressSDNode>(Callee);
+ GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Callee);
Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL,
getPointerTy(DAG.getDataLayout()),
GA->getOffset());
@@ -1719,20 +1720,12 @@ WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op,
const GlobalValue *GV = GA->getGlobal();
- // Currently Emscripten does not support dynamic linking with threads.
- // Therefore, if we have thread-local storage, only the local-exec model
- // is possible.
- // TODO: remove this and implement proper TLS models once Emscripten
- // supports dynamic linking with threads.
- if (GV->getThreadLocalMode() != GlobalValue::LocalExecTLSModel &&
- !Subtarget->getTargetTriple().isOSEmscripten()) {
- report_fatal_error("only -ftls-model=local-exec is supported for now on "
- "non-Emscripten OSes: variable " +
- GV->getName(),
- false);
- }
-
- auto model = GV->getThreadLocalMode();
+ // Currently only Emscripten supports dynamic linking with threads. Therefore,
+ // on other targets, if we have thread-local storage, only the local-exec
+ // model is possible.
+ auto model = Subtarget->getTargetTriple().isOSEmscripten()
+ ? GV->getThreadLocalMode()
+ : GlobalValue::LocalExecTLSModel;
// Unsupported TLS modes
assert(model != GlobalValue::NotThreadLocal);
@@ -1791,8 +1784,7 @@ SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
if (GV->getValueType()->isFunctionTy()) {
BaseName = MF.createExternalSymbolName("__table_base");
OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL;
- }
- else {
+ } else {
BaseName = MF.createExternalSymbolName("__memory_base");
OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL;
}
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 5a4533c4bac4..b080ab7e138c 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -1041,6 +1041,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::SMULO, MVT::v16i8, Custom);
setOperationAction(ISD::UMULO, MVT::v16i8, Custom);
+ setOperationAction(ISD::UMULO, MVT::v2i32, Custom);
setOperationAction(ISD::FNEG, MVT::v2f64, Custom);
setOperationAction(ISD::FABS, MVT::v2f64, Custom);
@@ -1255,6 +1256,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
// FIXME: Do we need to handle scalar-to-vector here?
setOperationAction(ISD::MUL, MVT::v4i32, Legal);
+ setOperationAction(ISD::SMULO, MVT::v2i32, Custom);
// We directly match byte blends in the backend as they match the VSELECT
// condition form.
@@ -19302,6 +19304,44 @@ static bool canonicalizeShuffleMaskWithCommute(ArrayRef<int> Mask) {
return false;
}
+static bool canCombineAsMaskOperation(SDValue V1, SDValue V2,
+ const X86Subtarget &Subtarget) {
+ if (!Subtarget.hasAVX512())
+ return false;
+
+ MVT VT = V1.getSimpleValueType().getScalarType();
+ if ((VT == MVT::i16 || VT == MVT::i8) && !Subtarget.hasBWI())
+ return false;
+
+ // i8 is better to be widen to i16, because there is PBLENDW for vXi16
+ // when the vector bit size is 128 or 256.
+ if (VT == MVT::i8 && V1.getSimpleValueType().getSizeInBits() < 512)
+ return false;
+
+ auto HasMaskOperation = [&](SDValue V) {
+ // TODO: Currently we only check limited opcode. We probably extend
+ // it to all binary operation by checking TLI.isBinOp().
+ switch (V->getOpcode()) {
+ default:
+ return false;
+ case ISD::ADD:
+ case ISD::SUB:
+ case ISD::AND:
+ case ISD::XOR:
+ break;
+ }
+ if (!V->hasOneUse())
+ return false;
+
+ return true;
+ };
+
+ if (HasMaskOperation(V1) || HasMaskOperation(V2))
+ return true;
+
+ return false;
+}
+
// Forward declaration.
static SDValue canonicalizeShuffleMaskWithHorizOp(
MutableArrayRef<SDValue> Ops, MutableArrayRef<int> Mask,
@@ -19377,6 +19417,7 @@ static SDValue lowerVECTOR_SHUFFLE(SDValue Op, const X86Subtarget &Subtarget,
// integers to handle flipping the low and high halves of AVX 256-bit vectors.
SmallVector<int, 16> WidenedMask;
if (VT.getScalarSizeInBits() < 64 && !Is1BitVector &&
+ !canCombineAsMaskOperation(V1, V2, Subtarget) &&
canWidenShuffleElements(OrigMask, Zeroable, V2IsZero, WidenedMask)) {
// Shuffle mask widening should not interfere with a broadcast opportunity
// by obfuscating the operands with bitcasts.
@@ -32379,6 +32420,43 @@ void X86TargetLowering::ReplaceNodeResults(SDNode *N,
Results.push_back(Res);
return;
}
+ case ISD::SMULO:
+ case ISD::UMULO: {
+ EVT VT = N->getValueType(0);
+ assert(getTypeAction(*DAG.getContext(), VT) == TypeWidenVector &&
+ VT == MVT::v2i32 && "Unexpected VT!");
+ bool IsSigned = N->getOpcode() == ISD::SMULO;
+ unsigned ExtOpc = IsSigned ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
+ SDValue Op0 = DAG.getNode(ExtOpc, dl, MVT::v2i64, N->getOperand(0));
+ SDValue Op1 = DAG.getNode(ExtOpc, dl, MVT::v2i64, N->getOperand(1));
+ SDValue Res = DAG.getNode(ISD::MUL, dl, MVT::v2i64, Op0, Op1);
+ // Extract the high 32 bits from each result using PSHUFD.
+ // TODO: Could use SRL+TRUNCATE but that doesn't become a PSHUFD.
+ SDValue Hi = DAG.getBitcast(MVT::v4i32, Res);
+ Hi = DAG.getVectorShuffle(MVT::v4i32, dl, Hi, Hi, {1, 3, -1, -1});
+ Hi = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, Hi,
+ DAG.getIntPtrConstant(0, dl));
+
+ // Truncate the low bits of the result. This will become PSHUFD.
+ Res = DAG.getNode(ISD::TRUNCATE, dl, VT, Res);
+
+ SDValue HiCmp;
+ if (IsSigned) {
+ // SMULO overflows if the high bits don't match the sign of the low.
+ HiCmp = DAG.getNode(ISD::SRA, dl, VT, Res, DAG.getConstant(31, dl, VT));
+ } else {
+ // UMULO overflows if the high bits are non-zero.
+ HiCmp = DAG.getConstant(0, dl, VT);
+ }
+ SDValue Ovf = DAG.getSetCC(dl, N->getValueType(1), Hi, HiCmp, ISD::SETNE);
+
+ // Widen the result with by padding with undef.
+ Res = DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v4i32, Res,
+ DAG.getUNDEF(VT));
+ Results.push_back(Res);
+ Results.push_back(Ovf);
+ return;
+ }
case X86ISD::VPMADDWD: {
// Legalize types for X86ISD::VPMADDWD by widening.
assert(Subtarget.hasSSE2() && "Requires at least SSE2!");
@@ -37522,8 +37600,8 @@ static bool matchBinaryShuffle(MVT MaskVT, ArrayRef<int> Mask,
break;
}
if (IsBlend) {
- if (DAG.computeKnownBits(V1, DemandedZeroV1).isZero() &&
- DAG.computeKnownBits(V2, DemandedZeroV2).isZero()) {
+ if (DAG.MaskedVectorIsZero(V1, DemandedZeroV1) &&
+ DAG.MaskedVectorIsZero(V2, DemandedZeroV2)) {
Shuffle = ISD::OR;
SrcVT = DstVT = MaskVT.changeTypeToInteger();
return true;
@@ -41191,7 +41269,7 @@ bool X86TargetLowering::SimplifyDemandedVectorEltsForTargetNode(
SDValue Src = Op.getOperand(0);
APInt DemandedUpperElts = DemandedElts;
DemandedUpperElts.clearLowBits(1);
- if (TLO.DAG.computeKnownBits(Src, DemandedUpperElts, Depth + 1).isZero())
+ if (TLO.DAG.MaskedVectorIsZero(Src, DemandedUpperElts, Depth + 1))
return TLO.CombineTo(Op, Src);
break;
}
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index af110884049b..85e5d0ba4c34 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -1409,7 +1409,7 @@ namespace llvm {
Register
getExceptionSelectorRegister(const Constant *PersonalityFn) const override;
- virtual bool needsFixedCatchObjects() const override;
+ bool needsFixedCatchObjects() const override;
/// This method returns a target specific FastISel object,
/// or null if the target does not support "fast" ISel.
diff --git a/llvm/lib/Target/X86/X86InstrInfo.h b/llvm/lib/Target/X86/X86InstrInfo.h
index 98da00c39bdb..81729e3618d8 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.h
+++ b/llvm/lib/Target/X86/X86InstrInfo.h
@@ -544,7 +544,7 @@ public:
ArrayRef<std::pair<unsigned, const char *>>
getSerializableDirectMachineOperandTargetFlags() const override;
- virtual outliner::OutlinedFunction getOutliningCandidateInfo(
+ outliner::OutlinedFunction getOutliningCandidateInfo(
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const override;
bool isFunctionSafeToOutlineFrom(MachineFunction &MF,
diff --git a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
index 1fd8b88dd776..35adaa3bde65 100644
--- a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
+++ b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
@@ -31,6 +31,7 @@
#include "llvm/IR/PatternMatch.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
+#include "llvm/Transforms/Utils/BuildLibCalls.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace llvm;
@@ -427,27 +428,73 @@ static bool tryToFPToSat(Instruction &I, TargetTransformInfo &TTI) {
return true;
}
+/// Try to replace a mathlib call to sqrt with the LLVM intrinsic. This avoids
+/// pessimistic codegen that has to account for setting errno and can enable
+/// vectorization.
+static bool
+foldSqrt(Instruction &I, TargetTransformInfo &TTI, TargetLibraryInfo &TLI) {
+ // Match a call to sqrt mathlib function.
+ auto *Call = dyn_cast<CallInst>(&I);
+ if (!Call)
+ return false;
+
+ Module *M = Call->getModule();
+ LibFunc Func;
+ if (!TLI.getLibFunc(*Call, Func) || !isLibFuncEmittable(M, &TLI, Func))
+ return false;
+
+ if (Func != LibFunc_sqrt && Func != LibFunc_sqrtf && Func != LibFunc_sqrtl)
+ return false;
+
+ // If (1) this is a sqrt libcall, (2) we can assume that NAN is not created,
+ // and (3) we would not end up lowering to a libcall anyway (which could
+ // change the value of errno), then:
+ // (1) the operand arg must not be less than -0.0.
+ // (2) errno won't be set.
+ // (3) it is safe to convert this to an intrinsic call.
+ // TODO: Check if the arg is known non-negative.
+ Type *Ty = Call->getType();
+ if (TTI.haveFastSqrt(Ty) && Call->hasNoNaNs()) {
+ IRBuilder<> Builder(&I);
+ IRBuilderBase::FastMathFlagGuard Guard(Builder);
+ Builder.setFastMathFlags(Call->getFastMathFlags());
+
+ Function *Sqrt = Intrinsic::getDeclaration(M, Intrinsic::sqrt, Ty);
+ Value *NewSqrt = Builder.CreateCall(Sqrt, Call->getArgOperand(0), "sqrt");
+ I.replaceAllUsesWith(NewSqrt);
+
+ // Explicitly erase the old call because a call with side effects is not
+ // trivially dead.
+ I.eraseFromParent();
+ return true;
+ }
+
+ return false;
+}
+
/// This is the entry point for folds that could be implemented in regular
/// InstCombine, but they are separated because they are not expected to
/// occur frequently and/or have more than a constant-length pattern match.
static bool foldUnusualPatterns(Function &F, DominatorTree &DT,
- TargetTransformInfo &TTI) {
+ TargetTransformInfo &TTI,
+ TargetLibraryInfo &TLI) {
bool MadeChange = false;
for (BasicBlock &BB : F) {
// Ignore unreachable basic blocks.
if (!DT.isReachableFromEntry(&BB))
continue;
- // Do not delete instructions under here and invalidate the iterator.
+
// Walk the block backwards for efficiency. We're matching a chain of
// use->defs, so we're more likely to succeed by starting from the bottom.
// Also, we want to avoid matching partial patterns.
// TODO: It would be more efficient if we removed dead instructions
// iteratively in this loop rather than waiting until the end.
- for (Instruction &I : llvm::reverse(BB)) {
+ for (Instruction &I : make_early_inc_range(llvm::reverse(BB))) {
MadeChange |= foldAnyOrAllBitsSet(I);
MadeChange |= foldGuardedFunnelShift(I, DT);
MadeChange |= tryToRecognizePopCount(I);
MadeChange |= tryToFPToSat(I, TTI);
+ MadeChange |= foldSqrt(I, TTI, TLI);
}
}
@@ -467,7 +514,7 @@ static bool runImpl(Function &F, AssumptionCache &AC, TargetTransformInfo &TTI,
const DataLayout &DL = F.getParent()->getDataLayout();
TruncInstCombine TIC(AC, TLI, DL, DT);
MadeChange |= TIC.run(F);
- MadeChange |= foldUnusualPatterns(F, DT, TTI);
+ MadeChange |= foldUnusualPatterns(F, DT, TTI, TLI);
return MadeChange;
}
diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
index 62cfc3294968..8c77b6937737 100644
--- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
+++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
@@ -249,7 +249,8 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
{LLVMContext::MD_range, LLVMContext::MD_nonnull,
LLVMContext::MD_dereferenceable,
LLVMContext::MD_dereferenceable_or_null,
- LLVMContext::MD_align, LLVMContext::MD_noundef});
+ LLVMContext::MD_align, LLVMContext::MD_noundef,
+ LLVMContext::MD_nontemporal});
}
Args.push_back(LI);
ArgAttrVec.push_back(AttributeSet());
@@ -631,8 +632,7 @@ static bool findArgParts(Argument *Arg, const DataLayout &DL, AAResults &AAR,
// Sort parts by offset.
append_range(ArgPartsVec, ArgParts);
- sort(ArgPartsVec,
- [](const auto &A, const auto &B) { return A.first < B.first; });
+ sort(ArgPartsVec, llvm::less_first());
// Make sure the parts are non-overlapping.
int64_t Offset = ArgPartsVec[0].first;
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 660ff3ee9563..83252fec3ea8 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -3328,7 +3328,7 @@ struct AANoAliasReturned final : AANoAliasImpl {
}
/// See AbstractAttribute::updateImpl(...).
- virtual ChangeStatus updateImpl(Attributor &A) override {
+ ChangeStatus updateImpl(Attributor &A) override {
auto CheckReturnValue = [&](Value &RV) -> bool {
if (Constant *C = dyn_cast<Constant>(&RV))
@@ -3427,7 +3427,7 @@ struct AAIsDeadValueImpl : public AAIsDead {
}
/// See AbstractAttribute::getAsStr().
- virtual const std::string getAsStr() const override {
+ const std::string getAsStr() const override {
return isAssumedDead() ? "assumed-dead" : "assumed-live";
}
@@ -4500,9 +4500,8 @@ struct AAAlignImpl : AAAlign {
// to avoid making the alignment explicit if it did not improve.
/// See AbstractAttribute::getDeducedAttributes
- virtual void
- getDeducedAttributes(LLVMContext &Ctx,
- SmallVectorImpl<Attribute> &Attrs) const override {
+ void getDeducedAttributes(LLVMContext &Ctx,
+ SmallVectorImpl<Attribute> &Attrs) const override {
if (getAssumedAlign() > 1)
Attrs.emplace_back(
Attribute::getWithAlignment(Ctx, Align(getAssumedAlign())));
@@ -4709,7 +4708,7 @@ struct AANoReturnImpl : public AANoReturn {
}
/// See AbstractAttribute::updateImpl(Attributor &A).
- virtual ChangeStatus updateImpl(Attributor &A) override {
+ ChangeStatus updateImpl(Attributor &A) override {
auto CheckForNoReturn = [](Instruction &) { return false; };
bool UsedAssumedInformation = false;
if (!A.checkForAllInstructions(CheckForNoReturn, *this,
@@ -4972,9 +4971,8 @@ struct AANoCaptureImpl : public AANoCapture {
ChangeStatus updateImpl(Attributor &A) override;
/// see AbstractAttribute::isAssumedNoCaptureMaybeReturned(...).
- virtual void
- getDeducedAttributes(LLVMContext &Ctx,
- SmallVectorImpl<Attribute> &Attrs) const override {
+ void getDeducedAttributes(LLVMContext &Ctx,
+ SmallVectorImpl<Attribute> &Attrs) const override {
if (!isAssumedNoCaptureMaybeReturned())
return;
@@ -6848,7 +6846,7 @@ struct AAPrivatizablePtrFloating : public AAPrivatizablePtrImpl {
: AAPrivatizablePtrImpl(IRP, A) {}
/// See AbstractAttribute::initialize(...).
- virtual void initialize(Attributor &A) override {
+ void initialize(Attributor &A) override {
// TODO: We can privatize more than arguments.
indicatePessimisticFixpoint();
}
@@ -7222,7 +7220,7 @@ struct AAMemoryBehaviorFunction final : public AAMemoryBehaviorImpl {
: AAMemoryBehaviorImpl(IRP, A) {}
/// See AbstractAttribute::updateImpl(Attributor &A).
- virtual ChangeStatus updateImpl(Attributor &A) override;
+ ChangeStatus updateImpl(Attributor &A) override;
/// See AbstractAttribute::manifest(...).
ChangeStatus manifest(Attributor &A) override {
@@ -7934,7 +7932,7 @@ struct AAMemoryLocationFunction final : public AAMemoryLocationImpl {
: AAMemoryLocationImpl(IRP, A) {}
/// See AbstractAttribute::updateImpl(Attributor &A).
- virtual ChangeStatus updateImpl(Attributor &A) override {
+ ChangeStatus updateImpl(Attributor &A) override {
const auto &MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(*this, getIRPosition(), DepClassTy::NONE);
@@ -9332,13 +9330,13 @@ struct AANoUndefCallSiteReturned final
struct AACallEdgesImpl : public AACallEdges {
AACallEdgesImpl(const IRPosition &IRP, Attributor &A) : AACallEdges(IRP, A) {}
- virtual const SetVector<Function *> &getOptimisticEdges() const override {
+ const SetVector<Function *> &getOptimisticEdges() const override {
return CalledFunctions;
}
- virtual bool hasUnknownCallee() const override { return HasUnknownCallee; }
+ bool hasUnknownCallee() const override { return HasUnknownCallee; }
- virtual bool hasNonAsmUnknownCallee() const override {
+ bool hasNonAsmUnknownCallee() const override {
return HasUnknownCalleeNonAsm;
}
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index 49077f92884f..50710eaa1b57 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -931,10 +931,9 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
// a value can't capture arguments. Don't analyze them.
if (F->onlyReadsMemory() && F->doesNotThrow() &&
F->getReturnType()->isVoidTy()) {
- for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E;
- ++A) {
- if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) {
- A->addAttr(Attribute::NoCapture);
+ for (Argument &A : F->args()) {
+ if (A.getType()->isPointerTy() && !A.hasNoCaptureAttr()) {
+ A.addAttr(Attribute::NoCapture);
++NumNoCapture;
Changed.insert(F);
}
@@ -942,44 +941,43 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
continue;
}
- for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E;
- ++A) {
- if (!A->getType()->isPointerTy())
+ for (Argument &A : F->args()) {
+ if (!A.getType()->isPointerTy())
continue;
bool HasNonLocalUses = false;
- if (!A->hasNoCaptureAttr()) {
+ if (!A.hasNoCaptureAttr()) {
ArgumentUsesTracker Tracker(SCCNodes);
- PointerMayBeCaptured(&*A, &Tracker);
+ PointerMayBeCaptured(&A, &Tracker);
if (!Tracker.Captured) {
if (Tracker.Uses.empty()) {
// If it's trivially not captured, mark it nocapture now.
- A->addAttr(Attribute::NoCapture);
+ A.addAttr(Attribute::NoCapture);
++NumNoCapture;
Changed.insert(F);
} else {
// If it's not trivially captured and not trivially not captured,
// then it must be calling into another function in our SCC. Save
// its particulars for Argument-SCC analysis later.
- ArgumentGraphNode *Node = AG[&*A];
+ ArgumentGraphNode *Node = AG[&A];
for (Argument *Use : Tracker.Uses) {
Node->Uses.push_back(AG[Use]);
- if (Use != &*A)
+ if (Use != &A)
HasNonLocalUses = true;
}
}
}
// Otherwise, it's captured. Don't bother doing SCC analysis on it.
}
- if (!HasNonLocalUses && !A->onlyReadsMemory()) {
+ if (!HasNonLocalUses && !A.onlyReadsMemory()) {
// Can we determine that it's readonly/readnone/writeonly without doing
// an SCC? Note that we don't allow any calls at all here, or else our
// result will be dependent on the iteration order through the
// functions in the SCC.
SmallPtrSet<Argument *, 8> Self;
- Self.insert(&*A);
- Attribute::AttrKind R = determinePointerAccessAttrs(&*A, Self);
+ Self.insert(&A);
+ Attribute::AttrKind R = determinePointerAccessAttrs(&A, Self);
if (R != Attribute::None)
- if (addAccessAttr(A, R))
+ if (addAccessAttr(&A, R))
Changed.insert(F);
}
}
@@ -1017,12 +1015,10 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
}
bool SCCCaptured = false;
- for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end();
- I != E && !SCCCaptured; ++I) {
- ArgumentGraphNode *Node = *I;
- if (Node->Uses.empty()) {
- if (!Node->Definition->hasNoCaptureAttr())
- SCCCaptured = true;
+ for (ArgumentGraphNode *Node : ArgumentSCC) {
+ if (Node->Uses.empty() && !Node->Definition->hasNoCaptureAttr()) {
+ SCCCaptured = true;
+ break;
}
}
if (SCCCaptured)
@@ -1035,9 +1031,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
ArgumentSCCNodes.insert(I->Definition);
}
- for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end();
- I != E && !SCCCaptured; ++I) {
- ArgumentGraphNode *N = *I;
+ for (ArgumentGraphNode *N : ArgumentSCC) {
for (ArgumentGraphNode *Use : N->Uses) {
Argument *A = Use->Definition;
if (A->hasNoCaptureAttr() || ArgumentSCCNodes.count(A))
@@ -1045,12 +1039,14 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
SCCCaptured = true;
break;
}
+ if (SCCCaptured)
+ break;
}
if (SCCCaptured)
continue;
- for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
- Argument *A = ArgumentSCC[i]->Definition;
+ for (ArgumentGraphNode *N : ArgumentSCC) {
+ Argument *A = N->Definition;
A->addAttr(Attribute::NoCapture);
++NumNoCapture;
Changed.insert(A->getParent());
@@ -1078,16 +1074,17 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
};
Attribute::AttrKind AccessAttr = Attribute::ReadNone;
- for (unsigned i = 0, e = ArgumentSCC.size();
- i != e && AccessAttr != Attribute::None; ++i) {
- Argument *A = ArgumentSCC[i]->Definition;
+ for (ArgumentGraphNode *N : ArgumentSCC) {
+ Argument *A = N->Definition;
Attribute::AttrKind K = determinePointerAccessAttrs(A, ArgumentSCCNodes);
AccessAttr = meetAccessAttr(AccessAttr, K);
+ if (AccessAttr == Attribute::None)
+ break;
}
if (AccessAttr != Attribute::None) {
- for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
- Argument *A = ArgumentSCC[i]->Definition;
+ for (ArgumentGraphNode *N : ArgumentSCC) {
+ Argument *A = N->Definition;
if (addAccessAttr(A, AccessAttr))
Changed.insert(A->getParent());
}
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index ec26db8bfc0b..6df0409256bb 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -470,8 +470,7 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {
// Sort by offset.
SmallVector<std::pair<uint64_t, Type *>, 16> TypesVector;
append_range(TypesVector, Types);
- sort(TypesVector,
- [](const auto &A, const auto &B) { return A.first < B.first; });
+ sort(TypesVector, llvm::less_first());
// Check that the types are non-overlapping.
uint64_t Offset = 0;
diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
index 6bf25df101fa..e3e4908f085b 100644
--- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
+++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
@@ -1778,35 +1778,48 @@ void LowerTypeTestsModule::replaceDirectCalls(Value *Old, Value *New) {
Old->replaceUsesWithIf(New, isDirectCall);
}
+static void dropTypeTests(Module &M, Function &TypeTestFunc) {
+ for (Use &U : llvm::make_early_inc_range(TypeTestFunc.uses())) {
+ auto *CI = cast<CallInst>(U.getUser());
+ // Find and erase llvm.assume intrinsics for this llvm.type.test call.
+ for (Use &CIU : llvm::make_early_inc_range(CI->uses()))
+ if (auto *Assume = dyn_cast<AssumeInst>(CIU.getUser()))
+ Assume->eraseFromParent();
+ // If the assume was merged with another assume, we might have a use on a
+ // phi (which will feed the assume). Simply replace the use on the phi
+ // with "true" and leave the merged assume.
+ if (!CI->use_empty()) {
+ assert(
+ all_of(CI->users(), [](User *U) -> bool { return isa<PHINode>(U); }));
+ CI->replaceAllUsesWith(ConstantInt::getTrue(M.getContext()));
+ }
+ CI->eraseFromParent();
+ }
+}
+
bool LowerTypeTestsModule::lower() {
Function *TypeTestFunc =
M.getFunction(Intrinsic::getName(Intrinsic::type_test));
- if (DropTypeTests && TypeTestFunc) {
- for (Use &U : llvm::make_early_inc_range(TypeTestFunc->uses())) {
- auto *CI = cast<CallInst>(U.getUser());
- // Find and erase llvm.assume intrinsics for this llvm.type.test call.
- for (Use &CIU : llvm::make_early_inc_range(CI->uses()))
- if (auto *Assume = dyn_cast<AssumeInst>(CIU.getUser()))
- Assume->eraseFromParent();
- // If the assume was merged with another assume, we might have a use on a
- // phi (which will feed the assume). Simply replace the use on the phi
- // with "true" and leave the merged assume.
- if (!CI->use_empty()) {
- assert(all_of(CI->users(),
- [](User *U) -> bool { return isa<PHINode>(U); }));
- CI->replaceAllUsesWith(ConstantInt::getTrue(M.getContext()));
- }
- CI->eraseFromParent();
+ if (DropTypeTests) {
+ if (TypeTestFunc)
+ dropTypeTests(M, *TypeTestFunc);
+ // Normally we'd have already removed all @llvm.public.type.test calls,
+ // except for in the case where we originally were performing ThinLTO but
+ // decided not to in the backend.
+ Function *PublicTypeTestFunc =
+ M.getFunction(Intrinsic::getName(Intrinsic::public_type_test));
+ if (PublicTypeTestFunc)
+ dropTypeTests(M, *PublicTypeTestFunc);
+ if (TypeTestFunc || PublicTypeTestFunc) {
+ // We have deleted the type intrinsics, so we no longer have enough
+ // information to reason about the liveness of virtual function pointers
+ // in GlobalDCE.
+ for (GlobalVariable &GV : M.globals())
+ GV.eraseMetadata(LLVMContext::MD_vcall_visibility);
+ return true;
}
-
- // We have deleted the type intrinsics, so we no longer have enough
- // information to reason about the liveness of virtual function pointers
- // in GlobalDCE.
- for (GlobalVariable &GV : M.globals())
- GV.eraseMetadata(LLVMContext::MD_vcall_visibility);
-
- return true;
+ return false;
}
// If only some of the modules were split, we cannot correctly perform
diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp
index 0b42fc151991..ef2384faa273 100644
--- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp
+++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp
@@ -499,18 +499,6 @@ struct OMPInformationCache : public InformationCache {
}
#include "llvm/Frontend/OpenMP/OMPKinds.def"
- // Remove the `noinline` attribute from `__kmpc`, `_OMP::` and `omp_`
- // functions, except if `optnone` is present.
- if (isOpenMPDevice(M)) {
- for (Function &F : M) {
- for (StringRef Prefix : {"__kmpc", "_ZN4_OMP", "omp_"})
- if (F.hasFnAttribute(Attribute::NoInline) &&
- F.getName().startswith(Prefix) &&
- !F.hasFnAttribute(Attribute::OptimizeNone))
- F.removeFnAttr(Attribute::NoInline);
- }
- }
-
// TODO: We should attach the attributes defined in OMPKinds.def.
}
diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp
index 26fb7d676429..0453af184a72 100644
--- a/llvm/lib/Transforms/IPO/SCCP.cpp
+++ b/llvm/lib/Transforms/IPO/SCCP.cpp
@@ -148,7 +148,7 @@ struct FunctionSpecializationLegacyPass : public ModulePass {
AU.addRequired<TargetTransformInfoWrapperPass>();
}
- virtual bool runOnModule(Module &M) override {
+ bool runOnModule(Module &M) override {
if (skipModule(M))
return false;
diff --git a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
index a360a768a2bc..ef7af551a328 100644
--- a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
+++ b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
@@ -132,6 +132,14 @@ void promoteTypeIds(Module &M, StringRef ModuleId) {
}
}
+ if (Function *PublicTypeTestFunc =
+ M.getFunction(Intrinsic::getName(Intrinsic::public_type_test))) {
+ for (const Use &U : PublicTypeTestFunc->uses()) {
+ auto CI = cast<CallInst>(U.getUser());
+ ExternalizeTypeId(CI, 1);
+ }
+ }
+
if (Function *TypeCheckedLoadFunc =
M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load))) {
for (const Use &U : TypeCheckedLoadFunc->uses()) {
diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index ad00c116ce0a..18efe99f7cb4 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -773,15 +773,14 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
return PreservedAnalyses::none();
}
+namespace llvm {
// Enable whole program visibility if enabled by client (e.g. linker) or
// internal option, and not force disabled.
-static bool hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO) {
+bool hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO) {
return (WholeProgramVisibilityEnabledInLTO || WholeProgramVisibility) &&
!DisableWholeProgramVisibility;
}
-namespace llvm {
-
/// If whole program visibility asserted, then upgrade all public vcall
/// visibility metadata on vtable definitions to linkage unit visibility in
/// Module IR (for regular or hybrid LTO).
@@ -790,7 +789,7 @@ void updateVCallVisibilityInModule(
const DenseSet<GlobalValue::GUID> &DynamicExportSymbols) {
if (!hasWholeProgramVisibility(WholeProgramVisibilityEnabledInLTO))
return;
- for (GlobalVariable &GV : M.globals())
+ for (GlobalVariable &GV : M.globals()) {
// Add linkage unit visibility to any variable with type metadata, which are
// the vtable definitions. We won't have an existing vcall_visibility
// metadata on vtable definitions with public visibility.
@@ -800,6 +799,34 @@ void updateVCallVisibilityInModule(
// linker, as we have no information on their eventual use.
!DynamicExportSymbols.count(GV.getGUID()))
GV.setVCallVisibilityMetadata(GlobalObject::VCallVisibilityLinkageUnit);
+ }
+}
+
+void updatePublicTypeTestCalls(Module &M,
+ bool WholeProgramVisibilityEnabledInLTO) {
+ Function *PublicTypeTestFunc =
+ M.getFunction(Intrinsic::getName(Intrinsic::public_type_test));
+ if (!PublicTypeTestFunc)
+ return;
+ if (hasWholeProgramVisibility(WholeProgramVisibilityEnabledInLTO)) {
+ Function *TypeTestFunc =
+ Intrinsic::getDeclaration(&M, Intrinsic::type_test);
+ for (Use &U : make_early_inc_range(PublicTypeTestFunc->uses())) {
+ auto *CI = cast<CallInst>(U.getUser());
+ auto *NewCI = CallInst::Create(
+ TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, None, "",
+ CI);
+ CI->replaceAllUsesWith(NewCI);
+ CI->eraseFromParent();
+ }
+ } else {
+ auto *True = ConstantInt::getTrue(M.getContext());
+ for (Use &U : make_early_inc_range(PublicTypeTestFunc->uses())) {
+ auto *CI = cast<CallInst>(U.getUser());
+ CI->replaceAllUsesWith(True);
+ CI->eraseFromParent();
+ }
+ }
}
/// If whole program visibility asserted, then upgrade all public vcall
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 827b25533513..664226ec187b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -597,10 +597,9 @@ public:
/// demanded bits.
bool SimplifyDemandedInstructionBits(Instruction &Inst);
- virtual Value *
- SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, APInt &UndefElts,
- unsigned Depth = 0,
- bool AllowMultipleUsers = false) override;
+ Value *SimplifyDemandedVectorElts(Value *V, APInt DemandedElts,
+ APInt &UndefElts, unsigned Depth = 0,
+ bool AllowMultipleUsers = false) override;
/// Canonicalize the position of binops relative to shufflevector.
Instruction *foldVectorBinop(BinaryOperator &Inst);
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index cf2754b1dd60..3274e36ab71a 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -1232,7 +1232,9 @@ bool AddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
// dynamic alloca instrumentation for them as well.
!AI.isUsedWithInAlloca() &&
// swifterror allocas are register promoted by ISel
- !AI.isSwiftError());
+ !AI.isSwiftError() &&
+ // safe allocas are not interesting
+ !(SSGI && SSGI->isSafe(AI)));
ProcessedAllocas[&AI] = IsInteresting;
return IsInteresting;
diff --git a/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp b/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp
index fd2eaee8b47d..013a119c5096 100644
--- a/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp
@@ -213,10 +213,12 @@ bool LoopDataPrefetchLegacyPass::runOnFunction(Function &F) {
bool LoopDataPrefetch::run() {
// If PrefetchDistance is not set, don't run the pass. This gives an
// opportunity for targets to run this pass for selected subtargets only
- // (whose TTI sets PrefetchDistance).
- if (getPrefetchDistance() == 0)
+ // (whose TTI sets PrefetchDistance and CacheLineSize).
+ if (getPrefetchDistance() == 0 || TTI->getCacheLineSize() == 0) {
+ LLVM_DEBUG(dbgs() << "Please set both PrefetchDistance and CacheLineSize "
+ "for loop data prefetch.\n");
return false;
- assert(TTI->getCacheLineSize() && "Cache line size is not set for target");
+ }
bool MadeChange = false;
diff --git a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
index c05906649f16..f1e1359255bd 100644
--- a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
+++ b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
@@ -338,6 +338,9 @@ class LowerMatrixIntrinsics {
Value *extractVector(unsigned I, unsigned J, unsigned NumElts,
IRBuilder<> &Builder) const {
Value *Vec = isColumnMajor() ? getColumn(J) : getRow(I);
+ assert(cast<FixedVectorType>(Vec->getType())->getNumElements() >=
+ NumElts &&
+ "Extracted vector will contain poison values");
return Builder.CreateShuffleVector(
Vec, createSequentialMask(isColumnMajor() ? I : J, NumElts, 0),
"block");
@@ -1423,13 +1426,13 @@ public:
FixedVectorType::get(MatMul->getType()->getScalarType(), TileSize);
MatrixTy TileResult;
// Insert in the inner loop header.
- Builder.SetInsertPoint(TI.InnerLoopHeader->getTerminator());
+ Builder.SetInsertPoint(TI.KLoop.Header->getTerminator());
// Create PHI nodes for the result columns to accumulate across iterations.
SmallVector<PHINode *, 4> ColumnPhis;
for (unsigned I = 0; I < TileSize; I++) {
auto *Phi = Builder.CreatePHI(TileVecTy, 2, "result.vec." + Twine(I));
Phi->addIncoming(ConstantAggregateZero::get(TileVecTy),
- TI.RowLoopHeader->getSingleSuccessor());
+ TI.RowLoop.Header->getSingleSuccessor());
TileResult.addVector(Phi);
ColumnPhis.push_back(Phi);
}
@@ -1438,27 +1441,29 @@ public:
// Res += Load(CurrentRow, K) * Load(K, CurrentColumn)
Builder.SetInsertPoint(InnerBody->getTerminator());
// Load tiles of the operands.
- MatrixTy A = loadMatrix(LPtr, {}, false, LShape, TI.CurrentRow, TI.CurrentK,
- {TileSize, TileSize}, EltType, Builder);
- MatrixTy B = loadMatrix(RPtr, {}, false, RShape, TI.CurrentK, TI.CurrentCol,
- {TileSize, TileSize}, EltType, Builder);
+ MatrixTy A =
+ loadMatrix(LPtr, {}, false, LShape, TI.RowLoop.Index, TI.KLoop.Index,
+ {TileSize, TileSize}, EltType, Builder);
+ MatrixTy B =
+ loadMatrix(RPtr, {}, false, RShape, TI.KLoop.Index, TI.ColumnLoop.Index,
+ {TileSize, TileSize}, EltType, Builder);
emitMatrixMultiply(TileResult, A, B, Builder, true, false,
getFastMathFlags(MatMul));
// Store result after the inner loop is done.
- Builder.SetInsertPoint(TI.RowLoopLatch->getTerminator());
+ Builder.SetInsertPoint(TI.RowLoop.Latch->getTerminator());
storeMatrix(TileResult, Store->getPointerOperand(), Store->getAlign(),
Store->isVolatile(), {LShape.NumRows, RShape.NumColumns},
- TI.CurrentRow, TI.CurrentCol, EltType, Builder);
+ TI.RowLoop.Index, TI.ColumnLoop.Index, EltType, Builder);
for (unsigned I = 0; I < TileResult.getNumVectors(); I++)
- ColumnPhis[I]->addIncoming(TileResult.getVector(I), TI.InnerLoopLatch);
+ ColumnPhis[I]->addIncoming(TileResult.getVector(I), TI.KLoop.Latch);
// Force unrolling of a few iterations of the inner loop, to make sure there
// is enough work per iteration.
// FIXME: The unroller should make this decision directly instead, but
// currently the cost-model is not up to the task.
unsigned InnerLoopUnrollCount = std::min(10u, LShape.NumColumns / TileSize);
- addStringMetadataToLoop(LI->getLoopFor(TI.InnerLoopHeader),
+ addStringMetadataToLoop(LI->getLoopFor(TI.KLoop.Header),
"llvm.loop.unroll.count", InnerLoopUnrollCount);
}
diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp
index 240fb5e60687..cd2ce8ce336e 100644
--- a/llvm/lib/Transforms/Scalar/Reassociate.cpp
+++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp
@@ -147,27 +147,27 @@ XorOpnd::XorOpnd(Value *V) {
/// Instruction::isAssociative() because it includes operations like fsub.
/// (This routine is only intended to be called for floating-point operations.)
static bool hasFPAssociativeFlags(Instruction *I) {
- assert(I && I->getType()->isFPOrFPVectorTy() && "Should only check FP ops");
+ assert(I && isa<FPMathOperator>(I) && "Should only check FP ops");
return I->hasAllowReassoc() && I->hasNoSignedZeros();
}
/// Return true if V is an instruction of the specified opcode and if it
/// only has one use.
static BinaryOperator *isReassociableOp(Value *V, unsigned Opcode) {
- auto *I = dyn_cast<Instruction>(V);
- if (I && I->hasOneUse() && I->getOpcode() == Opcode)
- if (!isa<FPMathOperator>(I) || hasFPAssociativeFlags(I))
- return cast<BinaryOperator>(I);
+ auto *BO = dyn_cast<BinaryOperator>(V);
+ if (BO && BO->hasOneUse() && BO->getOpcode() == Opcode)
+ if (!isa<FPMathOperator>(BO) || hasFPAssociativeFlags(BO))
+ return BO;
return nullptr;
}
static BinaryOperator *isReassociableOp(Value *V, unsigned Opcode1,
unsigned Opcode2) {
- auto *I = dyn_cast<Instruction>(V);
- if (I && I->hasOneUse() &&
- (I->getOpcode() == Opcode1 || I->getOpcode() == Opcode2))
- if (!isa<FPMathOperator>(I) || hasFPAssociativeFlags(I))
- return cast<BinaryOperator>(I);
+ auto *BO = dyn_cast<BinaryOperator>(V);
+ if (BO && BO->hasOneUse() &&
+ (BO->getOpcode() == Opcode1 || BO->getOpcode() == Opcode2))
+ if (!isa<FPMathOperator>(BO) || hasFPAssociativeFlags(BO))
+ return BO;
return nullptr;
}
@@ -778,7 +778,7 @@ void ReassociatePass::RewriteExprTree(BinaryOperator *I,
Constant *Undef = UndefValue::get(I->getType());
NewOp = BinaryOperator::Create(Instruction::BinaryOps(Opcode),
Undef, Undef, "", I);
- if (NewOp->getType()->isFPOrFPVectorTy())
+ if (isa<FPMathOperator>(NewOp))
NewOp->setFastMathFlags(I->getFastMathFlags());
} else {
NewOp = NodesToRewrite.pop_back_val();
@@ -2227,7 +2227,7 @@ void ReassociatePass::OptimizeInst(Instruction *I) {
// Don't optimize floating-point instructions unless they have the
// appropriate FastMathFlags for reassociation enabled.
- if (I->getType()->isFPOrFPVectorTy() && !hasFPAssociativeFlags(I))
+ if (isa<FPMathOperator>(I) && !hasFPAssociativeFlags(I))
return;
// Do not reassociate boolean (i1) expressions. We want to preserve the
diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp
index 00387ec426bf..878f9477a29d 100644
--- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -825,6 +825,35 @@ static void PropagateCallSiteMetadata(CallBase &CB, Function::iterator FStart,
}
}
+/// Bundle operands of the inlined function must be added to inlined call sites.
+static void PropagateOperandBundles(Function::iterator InlinedBB,
+ Instruction *CallSiteEHPad) {
+ for (Instruction &II : llvm::make_early_inc_range(*InlinedBB)) {
+ CallBase *I = dyn_cast<CallBase>(&II);
+ if (!I)
+ continue;
+ // Skip call sites which already have a "funclet" bundle.
+ if (I->getOperandBundle(LLVMContext::OB_funclet))
+ continue;
+ // Skip call sites which are nounwind intrinsics (as long as they don't
+ // lower into regular function calls in the course of IR transformations).
+ auto *CalledFn =
+ dyn_cast<Function>(I->getCalledOperand()->stripPointerCasts());
+ if (CalledFn && CalledFn->isIntrinsic() && I->doesNotThrow() &&
+ !IntrinsicInst::mayLowerToFunctionCall(CalledFn->getIntrinsicID()))
+ continue;
+
+ SmallVector<OperandBundleDef, 1> OpBundles;
+ I->getOperandBundlesAsDefs(OpBundles);
+ OpBundles.emplace_back("funclet", CallSiteEHPad);
+
+ Instruction *NewInst = CallBase::Create(I, OpBundles, I);
+ NewInst->takeName(I);
+ I->replaceAllUsesWith(NewInst);
+ I->eraseFromParent();
+ }
+}
+
namespace {
/// Utility for cloning !noalias and !alias.scope metadata. When a code region
/// using scoped alias metadata is inlined, the aliasing relationships may not
@@ -2304,38 +2333,12 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
// Update the lexical scopes of the new funclets and callsites.
// Anything that had 'none' as its parent is now nested inside the callsite's
// EHPad.
-
if (CallSiteEHPad) {
for (Function::iterator BB = FirstNewBlock->getIterator(),
E = Caller->end();
BB != E; ++BB) {
- // Add bundle operands to any top-level call sites.
- SmallVector<OperandBundleDef, 1> OpBundles;
- for (Instruction &II : llvm::make_early_inc_range(*BB)) {
- CallBase *I = dyn_cast<CallBase>(&II);
- if (!I)
- continue;
-
- // Skip call sites which are nounwind intrinsics.
- auto *CalledFn =
- dyn_cast<Function>(I->getCalledOperand()->stripPointerCasts());
- if (CalledFn && CalledFn->isIntrinsic() && I->doesNotThrow())
- continue;
-
- // Skip call sites which already have a "funclet" bundle.
- if (I->getOperandBundle(LLVMContext::OB_funclet))
- continue;
-
- I->getOperandBundlesAsDefs(OpBundles);
- OpBundles.emplace_back("funclet", CallSiteEHPad);
-
- Instruction *NewInst = CallBase::Create(I, OpBundles, I);
- NewInst->takeName(I);
- I->replaceAllUsesWith(NewInst);
- I->eraseFromParent();
-
- OpBundles.clear();
- }
+ // Add bundle operands to inlined call sites.
+ PropagateOperandBundles(BB, CallSiteEHPad);
// It is problematic if the inlinee has a cleanupret which unwinds to
// caller and we inline it into a call site which doesn't unwind but into
diff --git a/llvm/lib/Transforms/Utils/MatrixUtils.cpp b/llvm/lib/Transforms/Utils/MatrixUtils.cpp
index 6a137630deeb..e218773cf5da 100644
--- a/llvm/lib/Transforms/Utils/MatrixUtils.cpp
+++ b/llvm/lib/Transforms/Utils/MatrixUtils.cpp
@@ -70,35 +70,35 @@ BasicBlock *TileInfo::CreateLoop(BasicBlock *Preheader, BasicBlock *Exit,
BasicBlock *TileInfo::CreateTiledLoops(BasicBlock *Start, BasicBlock *End,
IRBuilderBase &B, DomTreeUpdater &DTU,
LoopInfo &LI) {
- Loop *ColLoop = LI.AllocateLoop();
- Loop *RowLoop = LI.AllocateLoop();
- Loop *InnerLoop = LI.AllocateLoop();
- RowLoop->addChildLoop(InnerLoop);
- ColLoop->addChildLoop(RowLoop);
+ Loop *ColumnLoopInfo = LI.AllocateLoop();
+ Loop *RowLoopInfo = LI.AllocateLoop();
+ Loop *KLoopInfo = LI.AllocateLoop();
+ RowLoopInfo->addChildLoop(KLoopInfo);
+ ColumnLoopInfo->addChildLoop(RowLoopInfo);
if (Loop *ParentL = LI.getLoopFor(Start))
- ParentL->addChildLoop(ColLoop);
+ ParentL->addChildLoop(ColumnLoopInfo);
else
- LI.addTopLevelLoop(ColLoop);
+ LI.addTopLevelLoop(ColumnLoopInfo);
BasicBlock *ColBody =
CreateLoop(Start, End, B.getInt64(NumColumns), B.getInt64(TileSize),
- "cols", B, DTU, ColLoop, LI);
- BasicBlock *ColLatch = ColBody->getSingleSuccessor();
+ "cols", B, DTU, ColumnLoopInfo, LI);
+ ColumnLoop.Latch = ColBody->getSingleSuccessor();
BasicBlock *RowBody =
- CreateLoop(ColBody, ColLatch, B.getInt64(NumRows), B.getInt64(TileSize),
- "rows", B, DTU, RowLoop, LI);
- RowLoopLatch = RowBody->getSingleSuccessor();
+ CreateLoop(ColBody, ColumnLoop.Latch, B.getInt64(NumRows),
+ B.getInt64(TileSize), "rows", B, DTU, RowLoopInfo, LI);
+ RowLoop.Latch = RowBody->getSingleSuccessor();
BasicBlock *InnerBody =
- CreateLoop(RowBody, RowLoopLatch, B.getInt64(NumInner),
- B.getInt64(TileSize), "inner", B, DTU, InnerLoop, LI);
- InnerLoopLatch = InnerBody->getSingleSuccessor();
- ColumnLoopHeader = ColBody->getSinglePredecessor();
- RowLoopHeader = RowBody->getSinglePredecessor();
- InnerLoopHeader = InnerBody->getSinglePredecessor();
- CurrentRow = &*RowLoopHeader->begin();
- CurrentCol = &*ColumnLoopHeader->begin();
- CurrentK = &*InnerLoopHeader->begin();
+ CreateLoop(RowBody, RowLoop.Latch, B.getInt64(NumInner),
+ B.getInt64(TileSize), "inner", B, DTU, KLoopInfo, LI);
+ KLoop.Latch = InnerBody->getSingleSuccessor();
+ ColumnLoop.Header = ColBody->getSinglePredecessor();
+ RowLoop.Header = RowBody->getSinglePredecessor();
+ KLoop.Header = InnerBody->getSinglePredecessor();
+ RowLoop.Index = &*RowLoop.Header->begin();
+ ColumnLoop.Index = &*ColumnLoop.Header->begin();
+ KLoop.Index = &*KLoop.Header->begin();
return InnerBody;
}
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index bca3b0538c5d..03087d8370d5 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -75,39 +75,109 @@ static bool callHasFP128Argument(const CallInst *CI) {
});
}
-static Value *convertStrToNumber(CallInst *CI, StringRef &Str, Value *EndPtr,
- int64_t Base, IRBuilderBase &B) {
+// Convert the entire string Str representing an integer in Base, up to
+// the terminating nul if present, to a constant according to the rules
+// of strtoul[l] or, when AsSigned is set, of strtol[l]. On success
+// return the result, otherwise null.
+// The function assumes the string is encoded in ASCII and carefully
+// avoids converting sequences (including "") that the corresponding
+// library call might fail and set errno for.
+static Value *convertStrToInt(CallInst *CI, StringRef &Str, Value *EndPtr,
+ uint64_t Base, bool AsSigned, IRBuilderBase &B) {
if (Base < 2 || Base > 36)
- // handle special zero base
if (Base != 0)
+ // Fail for an invalid base (required by POSIX).
return nullptr;
- char *End;
- std::string nptr = Str.str();
- errno = 0;
- long long int Result = strtoll(nptr.c_str(), &End, Base);
- if (errno)
- return nullptr;
+ // Strip leading whitespace.
+ for (unsigned i = 0; i != Str.size(); ++i)
+ if (!isSpace((unsigned char)Str[i])) {
+ Str = Str.substr(i);
+ break;
+ }
- // if we assume all possible target locales are ASCII supersets,
- // then if strtoll successfully parses a number on the host,
- // it will also successfully parse the same way on the target
- if (*End != '\0')
+ if (Str.empty())
+ // Fail for empty subject sequences (POSIX allows but doesn't require
+ // strtol[l]/strtoul[l] to fail with EINVAL).
return nullptr;
- if (!isIntN(CI->getType()->getPrimitiveSizeInBits(), Result))
- return nullptr;
+ // Strip but remember the sign.
+ bool Negate = Str[0] == '-';
+ if (Str[0] == '-' || Str[0] == '+') {
+ Str = Str.drop_front();
+ if (Str.empty())
+ // Fail for a sign with nothing after it.
+ return nullptr;
+ }
+
+ // Set Max to the absolute value of the minimum (for signed), or
+ // to the maximum (for unsigned) value representable in the type.
+ Type *RetTy = CI->getType();
+ unsigned NBits = RetTy->getPrimitiveSizeInBits();
+ uint64_t Max = AsSigned && Negate ? 1 : 0;
+ Max += AsSigned ? maxIntN(NBits) : maxUIntN(NBits);
+
+ // Autodetect Base if it's zero and consume the "0x" prefix.
+ if (Str.size() > 1) {
+ if (Str[0] == '0') {
+ if (toUpper((unsigned char)Str[1]) == 'X') {
+ if (Str.size() == 2 || (Base && Base != 16))
+ // Fail if Base doesn't allow the "0x" prefix or for the prefix
+ // alone that implementations like BSD set errno to EINVAL for.
+ return nullptr;
+
+ Str = Str.drop_front(2);
+ Base = 16;
+ }
+ else if (Base == 0)
+ Base = 8;
+ } else if (Base == 0)
+ Base = 10;
+ }
+ else if (Base == 0)
+ Base = 10;
+
+ // Convert the rest of the subject sequence, not including the sign,
+ // to its uint64_t representation (this assumes the source character
+ // set is ASCII).
+ uint64_t Result = 0;
+ for (unsigned i = 0; i != Str.size(); ++i) {
+ unsigned char DigVal = Str[i];
+ if (isDigit(DigVal))
+ DigVal = DigVal - '0';
+ else {
+ DigVal = toUpper(DigVal);
+ if (isAlpha(DigVal))
+ DigVal = DigVal - 'A' + 10;
+ else
+ return nullptr;
+ }
+
+ if (DigVal >= Base)
+ // Fail if the digit is not valid in the Base.
+ return nullptr;
+
+ // Add the digit and fail if the result is not representable in
+ // the (unsigned form of the) destination type.
+ bool VFlow;
+ Result = SaturatingMultiplyAdd(Result, Base, (uint64_t)DigVal, &VFlow);
+ if (VFlow || Result > Max)
+ return nullptr;
+ }
if (EndPtr) {
// Store the pointer to the end.
- uint64_t ILen = End - nptr.c_str();
- Value *Off = B.getInt64(ILen);
+ Value *Off = B.getInt64(Str.size());
Value *StrBeg = CI->getArgOperand(0);
Value *StrEnd = B.CreateInBoundsGEP(B.getInt8Ty(), StrBeg, Off, "endptr");
B.CreateStore(StrEnd, EndPtr);
}
- return ConstantInt::get(CI->getType(), Result);
+ if (Negate)
+ // Unsigned negation doesn't overflow.
+ Result = -Result;
+
+ return ConstantInt::get(RetTy, Result);
}
static bool isOnlyUsedInComparisonWithZero(Value *V) {
@@ -2531,27 +2601,35 @@ Value *LibCallSimplifier::optimizeToAscii(CallInst *CI, IRBuilderBase &B) {
ConstantInt::get(CI->getType(), 0x7F));
}
+// Fold calls to atoi, atol, and atoll.
Value *LibCallSimplifier::optimizeAtoi(CallInst *CI, IRBuilderBase &B) {
+ CI->addParamAttr(0, Attribute::NoCapture);
+
StringRef Str;
if (!getConstantStringInfo(CI->getArgOperand(0), Str))
return nullptr;
- return convertStrToNumber(CI, Str, nullptr, 10, B);
+ return convertStrToInt(CI, Str, nullptr, 10, /*AsSigned=*/true, B);
}
-Value *LibCallSimplifier::optimizeStrtol(CallInst *CI, IRBuilderBase &B) {
- StringRef Str;
- if (!getConstantStringInfo(CI->getArgOperand(0), Str))
- return nullptr;
-
+// Fold calls to strtol, strtoll, strtoul, and strtoull.
+Value *LibCallSimplifier::optimizeStrToInt(CallInst *CI, IRBuilderBase &B,
+ bool AsSigned) {
Value *EndPtr = CI->getArgOperand(1);
- if (isa<ConstantPointerNull>(EndPtr))
+ if (isa<ConstantPointerNull>(EndPtr)) {
+ // With a null EndPtr, this function won't capture the main argument.
+ // It would be readonly too, except that it still may write to errno.
+ CI->addParamAttr(0, Attribute::NoCapture);
EndPtr = nullptr;
- else if (!isKnownNonZero(EndPtr, DL))
+ } else if (!isKnownNonZero(EndPtr, DL))
+ return nullptr;
+
+ StringRef Str;
+ if (!getConstantStringInfo(CI->getArgOperand(0), Str))
return nullptr;
if (ConstantInt *CInt = dyn_cast<ConstantInt>(CI->getArgOperand(2))) {
- return convertStrToNumber(CI, Str, EndPtr, CInt->getSExtValue(), B);
+ return convertStrToInt(CI, Str, EndPtr, CInt->getSExtValue(), AsSigned, B);
}
return nullptr;
@@ -3390,7 +3468,10 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI, IRBuilderBase &Builder) {
return optimizeAtoi(CI, Builder);
case LibFunc_strtol:
case LibFunc_strtoll:
- return optimizeStrtol(CI, Builder);
+ return optimizeStrToInt(CI, Builder, /*AsSigned=*/true);
+ case LibFunc_strtoul:
+ case LibFunc_strtoull:
+ return optimizeStrToInt(CI, Builder, /*AsSigned=*/false);
case LibFunc_printf:
return optimizePrintF(CI, Builder);
case LibFunc_sprintf:
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index b887ea41676b..238b074089aa 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -798,8 +798,7 @@ public:
// Override this function to handle the more complex control flow around the
// three loops.
- std::pair<BasicBlock *, Value *>
- createVectorizedLoopSkeleton() final override {
+ std::pair<BasicBlock *, Value *> createVectorizedLoopSkeleton() final {
return createEpilogueVectorizedLoopSkeleton();
}
@@ -835,8 +834,7 @@ public:
EPI, LVL, CM, BFI, PSI, Check) {}
/// Implements the interface for creating a vectorized skeleton using the
/// *main loop* strategy (ie the first pass of vplan execution).
- std::pair<BasicBlock *, Value *>
- createEpilogueVectorizedLoopSkeleton() final override;
+ std::pair<BasicBlock *, Value *> createEpilogueVectorizedLoopSkeleton() final;
protected:
/// Emits an iteration count bypass check once for the main loop (when \p
@@ -866,8 +864,7 @@ public:
}
/// Implements the interface for creating a vectorized skeleton using the
/// *epilogue loop* strategy (ie the second pass of vplan execution).
- std::pair<BasicBlock *, Value *>
- createEpilogueVectorizedLoopSkeleton() final override;
+ std::pair<BasicBlock *, Value *> createEpilogueVectorizedLoopSkeleton() final;
protected:
/// Emits an iteration count bypass check after the main vector loop has
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index cd044c78d900..d69d1e3d19f3 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -10972,9 +10972,7 @@ public:
It != E; ++It) {
PossibleRedValsVect.emplace_back();
auto RedValsVect = It->second.takeVector();
- stable_sort(RedValsVect, [](const auto &P1, const auto &P2) {
- return P1.second < P2.second;
- });
+ stable_sort(RedValsVect, llvm::less_second());
for (const std::pair<Value *, unsigned> &Data : RedValsVect)
PossibleRedValsVect.back().append(Data.second, Data.first);
}
diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
index 458a58c12ca7..3e70f460bc58 100644
--- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
+++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
@@ -8,6 +8,7 @@
#include "DebugInfoLinker.h"
#include "Error.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/DWARFLinker/DWARFLinker.h"
#include "llvm/DWARFLinker/DWARFStreamer.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -210,8 +211,29 @@ private:
const Options &Opts;
};
-bool linkDebugInfo(object::ObjectFile &File, const Options &Options,
- raw_pwrite_stream &OutStream) {
+static bool knownByDWARFUtil(StringRef SecName) {
+ return llvm::StringSwitch<bool>(SecName)
+ .Case(".debug_info", true)
+ .Case(".debug_types", true)
+ .Case(".debug_abbrev", true)
+ .Case(".debug_loc", true)
+ .Case(".debug_loclists", true)
+ .Case(".debug_frame", true)
+ .Case(".debug_aranges", true)
+ .Case(".debug_ranges", true)
+ .Case(".debug_rnglists", true)
+ .Case(".debug_line", true)
+ .Case(".debug_line_str", true)
+ .Case(".debug_addr", true)
+ .Case(".debug_macro", true)
+ .Case(".debug_macinfo", true)
+ .Case(".debug_str", true)
+ .Case(".debug_str_offsets", true)
+ .Default(false);
+}
+
+Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
+ raw_pwrite_stream &OutStream) {
auto ReportWarn = [&](const Twine &Message, StringRef Context,
const DWARFDie *Die) {
@@ -235,8 +257,11 @@ bool linkDebugInfo(object::ObjectFile &File, const Options &Options,
// Create output streamer.
DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr,
ReportWarn, ReportWarn);
- if (!OutStreamer.init(File.makeTriple(), ""))
- return false;
+ Triple TargetTriple = File.makeTriple();
+ if (!OutStreamer.init(TargetTriple, formatv("cannot create a stream for {0}",
+ TargetTriple.getTriple())
+ .str()))
+ return createStringError(std::errc::invalid_argument, "");
// Create DWARF linker.
DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD);
@@ -256,6 +281,16 @@ bool linkDebugInfo(object::ObjectFile &File, const Options &Options,
std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
+ // Unknown debug sections would be removed. Display warning
+ // for such sections.
+ for (SectionName Sec : Context->getDWARFObj().getSectionNames()) {
+ if (isDebugSection(Sec.Name) && !knownByDWARFUtil(Sec.Name))
+ warning(
+ formatv("'{0}' is not currently supported: section will be skipped",
+ Sec.Name),
+ Options.InputFileName);
+ }
+
// Add object files to the DWARFLinker.
AddresssMapForLinking[0] =
std::make_unique<ObjFileAddressMap>(*Context, Options, File);
@@ -268,9 +303,11 @@ bool linkDebugInfo(object::ObjectFile &File, const Options &Options,
DebugInfoLinker.addObjectFile(*ObjectsForLinking[I]);
// Link debug info.
- DebugInfoLinker.link();
+ if (Error Err = DebugInfoLinker.link())
+ return Err;
+
OutStreamer.finish();
- return true;
+ return Error::success();
}
} // end of namespace dwarfutil
diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
index e95c83cb9609..d9d99ffc8747 100644
--- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
+++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
@@ -22,8 +22,8 @@ inline bool isDebugSection(StringRef SecName) {
SecName == ".gdb_index";
}
-bool linkDebugInfo(object::ObjectFile &file, const Options &Options,
- raw_pwrite_stream &OutStream);
+Error linkDebugInfo(object::ObjectFile &file, const Options &Options,
+ raw_pwrite_stream &OutStream);
} // end of namespace dwarfutil
} // end of namespace llvm
diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
index e77c82e0fad9..a6466be37513 100644
--- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
+++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
@@ -292,7 +292,7 @@ using DebugInfoBits = SmallString<10000>;
static Error addSectionsFromLinkedData(objcopy::ConfigManager &Config,
ObjectFile &InputFile,
DebugInfoBits &LinkedDebugInfoBits) {
- if (dyn_cast<ELFObjectFile<ELF32LE>>(&InputFile)) {
+ if (isa<ELFObjectFile<ELF32LE>>(&InputFile)) {
Expected<ELFObjectFile<ELF32LE>> MemFile = ELFObjectFile<ELF32LE>::create(
MemoryBufferRef(LinkedDebugInfoBits, ""));
if (!MemFile)
@@ -300,7 +300,7 @@ static Error addSectionsFromLinkedData(objcopy::ConfigManager &Config,
if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
return Err;
- } else if (dyn_cast<ELFObjectFile<ELF64LE>>(&InputFile)) {
+ } else if (isa<ELFObjectFile<ELF64LE>>(&InputFile)) {
Expected<ELFObjectFile<ELF64LE>> MemFile = ELFObjectFile<ELF64LE>::create(
MemoryBufferRef(LinkedDebugInfoBits, ""));
if (!MemFile)
@@ -308,7 +308,7 @@ static Error addSectionsFromLinkedData(objcopy::ConfigManager &Config,
if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
return Err;
- } else if (dyn_cast<ELFObjectFile<ELF32BE>>(&InputFile)) {
+ } else if (isa<ELFObjectFile<ELF32BE>>(&InputFile)) {
Expected<ELFObjectFile<ELF32BE>> MemFile = ELFObjectFile<ELF32BE>::create(
MemoryBufferRef(LinkedDebugInfoBits, ""));
if (!MemFile)
@@ -316,7 +316,7 @@ static Error addSectionsFromLinkedData(objcopy::ConfigManager &Config,
if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
return Err;
- } else if (dyn_cast<ELFObjectFile<ELF64BE>>(&InputFile)) {
+ } else if (isa<ELFObjectFile<ELF64BE>>(&InputFile)) {
Expected<ELFObjectFile<ELF64BE>> MemFile = ELFObjectFile<ELF64BE>::create(
MemoryBufferRef(LinkedDebugInfoBits, ""));
if (!MemFile)
@@ -426,16 +426,14 @@ static Error applyCLOptions(const struct Options &Opts, ObjectFile &InputFile) {
DebugInfoBits LinkedDebugInfo;
raw_svector_ostream OutStream(LinkedDebugInfo);
- if (linkDebugInfo(InputFile, Opts, OutStream)) {
- if (Error Err =
- saveLinkedDebugInfo(Opts, InputFile, std::move(LinkedDebugInfo)))
- return Err;
+ if (Error Err = linkDebugInfo(InputFile, Opts, OutStream))
+ return Err;
- return Error::success();
- }
+ if (Error Err =
+ saveLinkedDebugInfo(Opts, InputFile, std::move(LinkedDebugInfo)))
+ return Err;
- return createStringError(std::errc::invalid_argument,
- "possible broken debug info");
+ return Error::success();
} else if (Opts.BuildSeparateDebugFile) {
if (Error Err = splitDebugIntoSeparateFile(Opts, InputFile))
return Err;
diff --git a/llvm/tools/llvm-lto/llvm-lto.cpp b/llvm/tools/llvm-lto/llvm-lto.cpp
index c8266616b73d..64c8c1954ec9 100644
--- a/llvm/tools/llvm-lto/llvm-lto.cpp
+++ b/llvm/tools/llvm-lto/llvm-lto.cpp
@@ -261,6 +261,10 @@ static cl::opt<bool>
cl::desc("Print pass management debugging information"),
cl::cat(LTOCategory));
+static cl::opt<bool>
+ LTOSaveBeforeOpt("lto-save-before-opt", cl::init(false),
+ cl::desc("Save the IR before running optimizations"));
+
namespace {
struct ModuleInfo {
@@ -1069,6 +1073,9 @@ int main(int argc, char **argv) {
CodeGen.setFileType(*FT);
if (!OutputFilename.empty()) {
+ if (LTOSaveBeforeOpt)
+ CodeGen.setSaveIRBeforeOptPath(OutputFilename + ".0.preopt.bc");
+
if (SaveLinkedModuleFile) {
std::string ModuleFilename = OutputFilename;
ModuleFilename += ".linked.bc";
diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
index cb8e1822ee30..cdecfba9a375 100644
--- a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
+++ b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
@@ -48,8 +48,8 @@ public:
: MCStreamer(Context), Regions(R) {}
// We only want to intercept the emission of new instructions.
- virtual void emitInstruction(const MCInst &Inst,
- const MCSubtargetInfo & /* unused */) override {
+ void emitInstruction(const MCInst &Inst,
+ const MCSubtargetInfo & /* unused */) override {
Regions.addInstruction(Inst);
}
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 8a2b4855501b..7db1e79f3e49 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -719,24 +719,15 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
}
}
- if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
- OBJCOPY_compress_debug_sections_eq)) {
- Config.CompressionType = DebugCompressionType::Z;
-
- if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
- Config.CompressionType =
- StringSwitch<DebugCompressionType>(
- InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
- .Case("zlib", DebugCompressionType::Z)
- .Default(DebugCompressionType::None);
- if (Config.CompressionType == DebugCompressionType::None)
- return createStringError(
- errc::invalid_argument,
- "invalid or unsupported --compress-debug-sections format: %s",
- InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)
- .str()
- .c_str());
- }
+ if (const auto *A = InputArgs.getLastArg(OBJCOPY_compress_debug_sections)) {
+ Config.CompressionType = StringSwitch<DebugCompressionType>(A->getValue())
+ .Case("zlib", DebugCompressionType::Z)
+ .Default(DebugCompressionType::None);
+ if (Config.CompressionType == DebugCompressionType::None)
+ return createStringError(
+ errc::invalid_argument,
+ "invalid or unsupported --compress-debug-sections format: %s",
+ A->getValue());
if (!compression::zlib::isAvailable())
return createStringError(
errc::invalid_argument,
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index 962028da47a0..d3713b5ec3c3 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -29,12 +29,13 @@ defm new_symbol_visibility : Eq<"new-symbol-visibility", "Visibility of "
" with --add-symbol unless otherwise"
" specified. The default value is 'default'.">;
-def compress_debug_sections : Flag<["--"], "compress-debug-sections">;
-def compress_debug_sections_eq
+def compress_debug_sections
: Joined<["--"], "compress-debug-sections=">,
- MetaVarName<"[ zlib ]">,
- HelpText<"Compress DWARF debug sections using specified style. Supported "
- "formats: 'zlib'">;
+ MetaVarName<"format">,
+ HelpText<"Compress DWARF debug sections using specified format. Supported "
+ "formats: zlib">;
+def : Flag<["--"], "compress-debug-sections">, Alias<compress_debug_sections>,
+ AliasArgs<["zlib"]>;
def decompress_debug_sections : Flag<["--"], "decompress-debug-sections">,
HelpText<"Decompress DWARF debug sections.">;
defm split_dwo
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 9e4fa7c0d9dd..fd83dc197fe9 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -466,6 +466,15 @@ static void printRelocation(formatted_raw_ostream &OS, StringRef FileName,
OS << format(Fmt.data(), Address) << Name << "\t" << Val;
}
+static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI,
+ raw_ostream &OS) {
+ // The output of printInst starts with a tab. Print some spaces so that
+ // the tab has 1 column and advances to the target tab stop.
+ unsigned TabStop = getInstStartColumn(STI);
+ unsigned Column = OS.tell() - Start;
+ OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8);
+}
+
class PrettyPrinter {
public:
virtual ~PrettyPrinter() = default;
@@ -487,11 +496,7 @@ public:
dumpBytes(Bytes, OS);
}
- // The output of printInst starts with a tab. Print some spaces so that
- // the tab has 1 column and advances to the target tab stop.
- unsigned TabStop = getInstStartColumn(STI);
- unsigned Column = OS.tell() - Start;
- OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8);
+ AlignToInstStartColumn(Start, STI, OS);
if (MI) {
// See MCInstPrinter::printInst. On targets where a PC relative immediate
@@ -664,6 +669,91 @@ public:
};
BPFPrettyPrinter BPFPrettyPrinterInst;
+class ARMPrettyPrinter : public PrettyPrinter {
+public:
+ void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
+ object::SectionedAddress Address, formatted_raw_ostream &OS,
+ StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
+ StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
+ LiveVariablePrinter &LVP) override {
+ if (SP && (PrintSource || PrintLines))
+ SP->printSourceLine(OS, Address, ObjectFilename, LVP);
+ LVP.printBetweenInsts(OS, false);
+
+ size_t Start = OS.tell();
+ if (LeadingAddr)
+ OS << format("%8" PRIx64 ":", Address.Address);
+ if (ShowRawInsn) {
+ size_t Pos = 0, End = Bytes.size();
+ if (STI.checkFeatures("+thumb-mode")) {
+ for (; Pos + 2 <= End; Pos += 2)
+ OS << ' '
+ << format_hex_no_prefix(
+ llvm::support::endian::read<uint16_t>(
+ Bytes.data() + Pos, llvm::support::little),
+ 4);
+ } else {
+ for (; Pos + 4 <= End; Pos += 4)
+ OS << ' '
+ << format_hex_no_prefix(
+ llvm::support::endian::read<uint32_t>(
+ Bytes.data() + Pos, llvm::support::little),
+ 8);
+ }
+ if (Pos < End) {
+ OS << ' ';
+ dumpBytes(Bytes.slice(Pos), OS);
+ }
+ }
+
+ AlignToInstStartColumn(Start, STI, OS);
+
+ if (MI) {
+ IP.printInst(MI, Address.Address, "", STI, OS);
+ } else
+ OS << "\t<unknown>";
+ }
+};
+ARMPrettyPrinter ARMPrettyPrinterInst;
+
+class AArch64PrettyPrinter : public PrettyPrinter {
+public:
+ void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
+ object::SectionedAddress Address, formatted_raw_ostream &OS,
+ StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
+ StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
+ LiveVariablePrinter &LVP) override {
+ if (SP && (PrintSource || PrintLines))
+ SP->printSourceLine(OS, Address, ObjectFilename, LVP);
+ LVP.printBetweenInsts(OS, false);
+
+ size_t Start = OS.tell();
+ if (LeadingAddr)
+ OS << format("%8" PRIx64 ":", Address.Address);
+ if (ShowRawInsn) {
+ size_t Pos = 0, End = Bytes.size();
+ for (; Pos + 4 <= End; Pos += 4)
+ OS << ' '
+ << format_hex_no_prefix(
+ llvm::support::endian::read<uint32_t>(Bytes.data() + Pos,
+ llvm::support::little),
+ 8);
+ if (Pos < End) {
+ OS << ' ';
+ dumpBytes(Bytes.slice(Pos), OS);
+ }
+ }
+
+ AlignToInstStartColumn(Start, STI, OS);
+
+ if (MI) {
+ IP.printInst(MI, Address.Address, "", STI, OS);
+ } else
+ OS << "\t<unknown>";
+ }
+};
+AArch64PrettyPrinter AArch64PrettyPrinterInst;
+
PrettyPrinter &selectPrettyPrinter(Triple const &Triple) {
switch(Triple.getArch()) {
default:
@@ -675,6 +765,15 @@ PrettyPrinter &selectPrettyPrinter(Triple const &Triple) {
case Triple::bpfel:
case Triple::bpfeb:
return BPFPrettyPrinterInst;
+ case Triple::arm:
+ case Triple::armeb:
+ case Triple::thumb:
+ case Triple::thumbeb:
+ return ARMPrettyPrinterInst;
+ case Triple::aarch64:
+ case Triple::aarch64_be:
+ case Triple::aarch64_32:
+ return AArch64PrettyPrinterInst;
}
}
}
@@ -895,12 +994,14 @@ static uint64_t dumpARMELFData(uint64_t SectionAddr, uint64_t Index,
uint64_t End, const ObjectFile &Obj,
ArrayRef<uint8_t> Bytes,
ArrayRef<MappingSymbolPair> MappingSymbols,
- raw_ostream &OS) {
+ const MCSubtargetInfo &STI, raw_ostream &OS) {
support::endianness Endian =
Obj.isLittleEndian() ? support::little : support::big;
- OS << format("%8" PRIx64 ":\t", SectionAddr + Index);
+ size_t Start = OS.tell();
+ OS << format("%8" PRIx64 ": ", SectionAddr + Index);
if (Index + 4 <= End) {
dumpBytes(Bytes.slice(Index, 4), OS);
+ AlignToInstStartColumn(Start, STI, OS);
OS << "\t.word\t"
<< format_hex(support::endian::read32(Bytes.data() + Index, Endian),
10);
@@ -908,13 +1009,14 @@ static uint64_t dumpARMELFData(uint64_t SectionAddr, uint64_t Index,
}
if (Index + 2 <= End) {
dumpBytes(Bytes.slice(Index, 2), OS);
- OS << "\t\t.short\t"
- << format_hex(support::endian::read16(Bytes.data() + Index, Endian),
- 6);
+ AlignToInstStartColumn(Start, STI, OS);
+ OS << "\t.short\t"
+ << format_hex(support::endian::read16(Bytes.data() + Index, Endian), 6);
return 2;
}
dumpBytes(Bytes.slice(Index, 1), OS);
- OS << "\t\t.byte\t" << format_hex(Bytes[0], 4);
+ AlignToInstStartColumn(Start, STI, OS);
+ OS << "\t.byte\t" << format_hex(Bytes[Index], 4);
return 1;
}
@@ -1022,10 +1124,12 @@ static void collectLocalBranchTargets(
// Disassemble a real instruction and record function-local branch labels.
MCInst Inst;
uint64_t Size;
- bool Disassembled = DisAsm->getInstruction(
- Inst, Size, Bytes.slice(Index - SectionAddr), Index, nulls());
+ ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index - SectionAddr);
+ bool Disassembled =
+ DisAsm->getInstruction(Inst, Size, ThisBytes, Index, nulls());
if (Size == 0)
- Size = 1;
+ Size = std::min<uint64_t>(ThisBytes.size(),
+ DisAsm->suggestBytesToSkip(ThisBytes, Index));
if (Disassembled && MIA) {
uint64_t Target;
@@ -1068,10 +1172,11 @@ static void addSymbolizer(
for (size_t Index = 0; Index != Bytes.size();) {
MCInst Inst;
uint64_t Size;
- DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), SectionAddr + Index,
- nulls());
+ ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index - SectionAddr);
+ DisAsm->getInstruction(Inst, Size, ThisBytes, Index, nulls());
if (Size == 0)
- Size = 1;
+ Size = std::min<uint64_t>(ThisBytes.size(),
+ DisAsm->suggestBytesToSkip(ThisBytes, Index));
Index += Size;
}
ArrayRef<uint64_t> LabelAddrsRef = SymbolizerPtr->getReferencedAddresses();
@@ -1504,7 +1609,7 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
if (DumpARMELFData) {
Size = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes,
- MappingSymbols, FOS);
+ MappingSymbols, *STI, FOS);
} else {
// When -z or --disassemble-zeroes are given we always dissasemble
// them. Otherwise we might want to skip zero bytes we see.
@@ -1538,11 +1643,14 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
// Disassemble a real instruction or a data when disassemble all is
// provided
MCInst Inst;
- bool Disassembled =
- DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
- SectionAddr + Index, CommentStream);
+ ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index);
+ uint64_t ThisAddr = SectionAddr + Index;
+ bool Disassembled = DisAsm->getInstruction(Inst, Size, ThisBytes,
+ ThisAddr, CommentStream);
if (Size == 0)
- Size = 1;
+ Size = std::min<uint64_t>(
+ ThisBytes.size(),
+ DisAsm->suggestBytesToSkip(ThisBytes, ThisAddr));
LVP.update({Index, Section.getIndex()},
{Index + Size, Section.getIndex()}, Index + Size != End);
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 0c23d7c1435f..3af8f800adcb 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -2200,8 +2200,7 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
Builder.addRecord(Func);
if (ShowCovered) {
- if (std::any_of(Func.Counts.begin(), Func.Counts.end(),
- [](uint64_t C) { return C; }))
+ if (llvm::any_of(Func.Counts, [](uint64_t C) { return C; }))
OS << Func.Name << "\n";
continue;
}
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index ae2dec5d15fb..ba7bae96ade3 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -1648,6 +1648,15 @@ const EnumEntry<unsigned> ElfHeaderAVRFlags[] = {
ENUM_ENT(EF_AVR_LINKRELAX_PREPARED, "relaxable"),
};
+const EnumEntry<unsigned> ElfHeaderLoongArchFlags[] = {
+ ENUM_ENT(EF_LOONGARCH_BASE_ABI_ILP32S, "ILP32, SOFT-FLOAT"),
+ ENUM_ENT(EF_LOONGARCH_BASE_ABI_ILP32F, "ILP32, SINGLE-FLOAT"),
+ ENUM_ENT(EF_LOONGARCH_BASE_ABI_ILP32D, "ILP32, DOUBLE-FLOAT"),
+ ENUM_ENT(EF_LOONGARCH_BASE_ABI_LP64S, "LP64, SOFT-FLOAT"),
+ ENUM_ENT(EF_LOONGARCH_BASE_ABI_LP64F, "LP64, SINGLE-FLOAT"),
+ ENUM_ENT(EF_LOONGARCH_BASE_ABI_LP64D, "LP64, DOUBLE-FLOAT"),
+};
+
const EnumEntry<unsigned> ElfSymOtherFlags[] = {
LLVM_READOBJ_ENUM_ENT(ELF, STV_INTERNAL),
@@ -3357,6 +3366,9 @@ template <class ELFT> void GNUELFDumper<ELFT>::printFileHeaders() {
else if (e.e_machine == EM_AVR)
ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderAVRFlags),
unsigned(ELF::EF_AVR_ARCH_MASK));
+ else if (e.e_machine == EM_LOONGARCH)
+ ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderLoongArchFlags),
+ unsigned(ELF::EF_LOONGARCH_BASE_ABI_MASK));
Str = "0x" + utohexstr(e.e_flags);
if (!ElfFlags.empty())
Str = Str + ", " + ElfFlags;
@@ -6507,6 +6519,9 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printFileHeaders() {
else if (E.e_machine == EM_AVR)
W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderAVRFlags),
unsigned(ELF::EF_AVR_ARCH_MASK));
+ else if (E.e_machine == EM_LOONGARCH)
+ W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderLoongArchFlags),
+ unsigned(ELF::EF_LOONGARCH_BASE_ABI_MASK));
else
W.printFlags("Flags", E.e_flags);
W.printNumber("HeaderSize", E.e_ehsize);
diff --git a/llvm/tools/llvm-xray/xray-graph.cpp b/llvm/tools/llvm-xray/xray-graph.cpp
index 39d2c5c153ef..ff47eb64e947 100644
--- a/llvm/tools/llvm-xray/xray-graph.cpp
+++ b/llvm/tools/llvm-xray/xray-graph.cpp
@@ -232,10 +232,11 @@ Error GraphRenderer::accountRecord(const XRayRecord &Record) {
if (!DeduceSiblingCalls)
return make_error<StringError>("No matching ENTRY record",
make_error_code(errc::invalid_argument));
- auto Parent = std::find_if(
- ThreadStack.rbegin(), ThreadStack.rend(),
- [&](const FunctionAttr &A) { return A.FuncId == Record.FuncId; });
- if (Parent == ThreadStack.rend())
+ bool FoundParent =
+ llvm::any_of(llvm::reverse(ThreadStack), [&](const FunctionAttr &A) {
+ return A.FuncId == Record.FuncId;
+ });
+ if (!FoundParent)
return make_error<StringError>(
"No matching Entry record in stack",
make_error_code(errc::invalid_argument)); // There is no matching
diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp
index b9c563c62bbe..cd41fbaa6ca1 100644
--- a/llvm/utils/TableGen/DXILEmitter.cpp
+++ b/llvm/utils/TableGen/DXILEmitter.cpp
@@ -16,10 +16,12 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/DXILOperationCommon.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
using namespace llvm;
+using namespace llvm::DXIL;
namespace {
@@ -27,25 +29,16 @@ struct DXILShaderModel {
int Major;
int Minor;
};
+
struct DXILParam {
- int Pos; // position in parameter list
- StringRef Type; // llvm type name, $o for overload, $r for resource
- // type, $cb for legacy cbuffer, $u4 for u4 struct
+ int Pos; // position in parameter list
+ ParameterKind Kind;
StringRef Name; // short, unique name
StringRef Doc; // the documentation description of this parameter
bool IsConst; // whether this argument requires a constant value in the IR
StringRef EnumName; // the name of the enum type if applicable
int MaxValue; // the maximum value for this parameter if applicable
- DXILParam(const Record *R) {
- Name = R->getValueAsString("name");
- Pos = R->getValueAsInt("pos");
- Type = R->getValueAsString("llvm_type");
- if (R->getValue("doc"))
- Doc = R->getValueAsString("doc");
- IsConst = R->getValueAsBit("is_const");
- EnumName = R->getValueAsString("enum_name");
- MaxValue = R->getValueAsInt("max_value");
- }
+ DXILParam(const Record *R);
};
struct DXILOperationData {
@@ -74,7 +67,9 @@ struct DXILOperationData {
DXILShaderModel ShaderModel; // minimum shader model required
DXILShaderModel ShaderModelTranslated; // minimum shader model required with
// translation by linker
- SmallVector<StringRef, 4> counters; // counters for this inst.
+ int OverloadParamIndex; // parameter index which control the overload.
+ // When < 0, should be only 1 overload type.
+ SmallVector<StringRef, 4> counters; // counters for this inst.
DXILOperationData(const Record *R) {
Name = R->getValueAsString("name");
DXILOp = R->getValueAsString("dxil_op");
@@ -93,9 +88,13 @@ struct DXILOperationData {
Doc = R->getValueAsString("doc");
ListInit *ParamList = R->getValueAsListInit("ops");
- for (unsigned i = 0; i < ParamList->size(); ++i) {
- Record *Param = ParamList->getElementAsRecord(i);
+ OverloadParamIndex = -1;
+ for (unsigned I = 0; I < ParamList->size(); ++I) {
+ Record *Param = ParamList->getElementAsRecord(I);
Params.emplace_back(DXILParam(Param));
+ auto &CurParam = Params.back();
+ if (CurParam.Kind >= ParameterKind::OVERLOAD)
+ OverloadParamIndex = I;
}
OverloadTypes = R->getValueAsString("oload_types");
FnAttr = R->getValueAsString("fn_attr");
@@ -103,6 +102,51 @@ struct DXILOperationData {
};
} // end anonymous namespace
+DXILParam::DXILParam(const Record *R) {
+ Name = R->getValueAsString("name");
+ Pos = R->getValueAsInt("pos");
+ Kind = parameterTypeNameToKind(R->getValueAsString("llvm_type"));
+ if (R->getValue("doc"))
+ Doc = R->getValueAsString("doc");
+ IsConst = R->getValueAsBit("is_const");
+ EnumName = R->getValueAsString("enum_name");
+ MaxValue = R->getValueAsInt("max_value");
+}
+
+static std::string parameterKindToString(ParameterKind Kind) {
+ switch (Kind) {
+ case ParameterKind::INVALID:
+ return "INVALID";
+ case ParameterKind::VOID:
+ return "VOID";
+ case ParameterKind::HALF:
+ return "HALF";
+ case ParameterKind::FLOAT:
+ return "FLOAT";
+ case ParameterKind::DOUBLE:
+ return "DOUBLE";
+ case ParameterKind::I1:
+ return "I1";
+ case ParameterKind::I8:
+ return "I8";
+ case ParameterKind::I16:
+ return "I16";
+ case ParameterKind::I32:
+ return "I32";
+ case ParameterKind::I64:
+ return "I64";
+ case ParameterKind::OVERLOAD:
+ return "OVERLOAD";
+ case ParameterKind::CBUFFER_RET:
+ return "CBUFFER_RET";
+ case ParameterKind::RESOURCE_RET:
+ return "RESOURCE_RET";
+ case ParameterKind::DXIL_HANDLE:
+ return "DXIL_HANDLE";
+ }
+ llvm_unreachable("Unknown llvm::DXIL::ParameterKind enum");
+}
+
static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) {
// Name = ID, // Doc
OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc
@@ -271,7 +315,9 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
// Collect Names.
SequenceToOffsetTable<std::string> OpClassStrings;
SequenceToOffsetTable<std::string> OpStrings;
+ SequenceToOffsetTable<SmallVector<ParameterKind>> Parameters;
+ StringMap<SmallVector<ParameterKind>> ParameterMap;
StringSet<> ClassSet;
for (auto &DXILOp : DXILOps) {
OpStrings.add(DXILOp.DXILOp.str());
@@ -280,16 +326,24 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
continue;
ClassSet.insert(DXILOp.DXILClass);
OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass));
+ SmallVector<ParameterKind> ParamKindVec;
+ for (auto &Param : DXILOp.Params) {
+ ParamKindVec.emplace_back(Param.Kind);
+ }
+ ParameterMap[DXILOp.DXILClass] = ParamKindVec;
+ Parameters.add(ParamKindVec);
}
// Layout names.
OpStrings.layout();
OpClassStrings.layout();
+ Parameters.layout();
// Emit the DXIL operation table.
//{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary,
// OpCodeClassNameIndex,
- // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone},
+ // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone, 0,
+ // 3, ParameterTableOffset},
OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) "
"{\n";
@@ -300,7 +354,9 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
<< ", OpCodeClass::" << DXILOp.DXILClass << ", "
<< OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", "
<< getDXILOperationOverload(DXILOp.OverloadTypes) << ", "
- << emitDXILOperationFnAttr(DXILOp.FnAttr) << " },\n";
+ << emitDXILOperationFnAttr(DXILOp.FnAttr) << ", "
+ << DXILOp.OverloadParamIndex << ", " << DXILOp.Params.size() << ", "
+ << Parameters.get(ParameterMap[DXILOp.DXILClass]) << " },\n";
}
OS << " };\n";
@@ -338,6 +394,21 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
OS << " unsigned Index = Prop.OpCodeClassNameOffset;\n";
OS << " return DXILOpCodeClassNameTable + Index;\n";
OS << "}\n ";
+
+ OS << "static const ParameterKind *getOpCodeParameterKind(const "
+ "OpCodeProperty &Prop) "
+ "{\n\n";
+ OS << " static const ParameterKind DXILOpParameterKindTable[] = {\n";
+ Parameters.emit(
+ OS,
+ [](raw_ostream &ParamOS, ParameterKind Kind) {
+ ParamOS << "ParameterKind::" << parameterKindToString(Kind);
+ },
+ "ParameterKind::INVALID");
+ OS << " };\n\n";
+ OS << " unsigned Index = Prop.ParameterTableOffset;\n";
+ OS << " return DXILOpParameterKindTable + Index;\n";
+ OS << "}\n ";
}
namespace llvm {
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h b/llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h
index 08e541b76a5a..96fef21b7627 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h
@@ -96,7 +96,7 @@ public:
void printDescription(raw_ostream &OS) const override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- virtual LLVM_DUMP_METHOD void dump() const override { print(errs()); }
+ LLVM_DUMP_METHOD void dump() const override { print(errs()); }
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
};
@@ -119,7 +119,7 @@ public:
void printDescription(raw_ostream &OS) const override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- virtual LLVM_DUMP_METHOD void dump() const override { print(errs()); }
+ LLVM_DUMP_METHOD void dump() const override { print(errs()); }
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
};
@@ -134,7 +134,7 @@ public:
void printDescription(raw_ostream &OS) const override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- virtual LLVM_DUMP_METHOD void dump() const override { print(errs()); }
+ LLVM_DUMP_METHOD void dump() const override { print(errs()); }
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
};